diff --git a/src/domain/event-publisher.ts b/src/domain/event-publisher.ts index b8167ed..6a2c038 100644 --- a/src/domain/event-publisher.ts +++ b/src/domain/event-publisher.ts @@ -7,7 +7,7 @@ export interface EventPublisher { export class Publisher implements EventPublisher { constructor(private subscribers: EventSubscriber[]) {} - publish (event: any): void { + publish(event: any): void { this.subscribers.forEach(subscriber => { subscriber.handle(event); }); diff --git a/src/domain/game-state-event-subscriber.ts b/src/domain/game-state-event-subscriber.ts index 267ecbf..4698699 100644 --- a/src/domain/game-state-event-subscriber.ts +++ b/src/domain/game-state-event-subscriber.ts @@ -2,27 +2,16 @@ import { EventSubscriber } from './event-subscriber'; import { GameState } from '../state/game-state'; -import { GameMap } from '../domain/game-map'; +import { StateChangeHandler } from './state-change-handler/state-change-handler'; export class GameStateEventSubscriber implements EventSubscriber { - constructor(private map: GameMap, private gameState: GameState) {} + constructor(private gameState: GameState, private handlers: StateChangeHandler[]) {} handle(event: any): void { - switch (event.topic) { - case 'player.location.moved': - this.gameState.setCurrentLocation(this.map.get(event.currentNode.id)); - break; - case 'player.inventory.added': - this.gameState.addInventory(event.item, event.count); - break; - case 'player.inventory.item-equipped': - this.gameState.equip(event.item); - break; - case 'game.started': - this.gameState.start(); - break; - case 'game.stopped': - this.gameState.stop(); + const handler = this.handlers.find(element => element.handles(event)); + + if (handler) { + handler.handle(event, this.gameState); } } } diff --git a/src/domain/state-change-handler/game-started-handler.ts b/src/domain/state-change-handler/game-started-handler.ts new file mode 100644 index 0000000..dfd96d3 --- /dev/null +++ b/src/domain/state-change-handler/game-started-handler.ts @@ -0,0 +1,12 @@ +import { StateChangeHandler } from './state-change-handler'; +import { GameState } from '../../state/game-state'; + +export class GameStartedHandler implements StateChangeHandler { + public handles(event: any): boolean { + return event.topic === 'game.started'; + } + + public handle(event: any, gameState: GameState): void { + gameState.start(); + } +} diff --git a/src/domain/state-change-handler/game-stopped-handler.ts b/src/domain/state-change-handler/game-stopped-handler.ts new file mode 100644 index 0000000..bd78204 --- /dev/null +++ b/src/domain/state-change-handler/game-stopped-handler.ts @@ -0,0 +1,12 @@ +import { StateChangeHandler } from './state-change-handler'; +import { GameState } from '../../state/game-state'; + +export class GameStoppedHandler implements StateChangeHandler { + public handles(event: any): boolean { + return event.topic === 'game.stopped'; + } + + public handle(event: any, gameState: GameState): void { + gameState.stop(); + } +} diff --git a/src/domain/state-change-handler/player-inventory-added-handler.ts b/src/domain/state-change-handler/player-inventory-added-handler.ts new file mode 100644 index 0000000..96440d6 --- /dev/null +++ b/src/domain/state-change-handler/player-inventory-added-handler.ts @@ -0,0 +1,12 @@ +import { StateChangeHandler } from './state-change-handler'; +import { GameState } from '../../state/game-state'; + +export class PlayerInventoryAddedHandler implements StateChangeHandler { + public handles(event: any): boolean { + return event.topic === 'player.inventory.added'; + } + + public handle(event: any, gameState: GameState): void { + gameState.addInventory(event.item, event.count); + } +} diff --git a/src/domain/state-change-handler/player-inventory-equipped-handler.ts b/src/domain/state-change-handler/player-inventory-equipped-handler.ts new file mode 100644 index 0000000..da50397 --- /dev/null +++ b/src/domain/state-change-handler/player-inventory-equipped-handler.ts @@ -0,0 +1,12 @@ +import { StateChangeHandler } from './state-change-handler'; +import { GameState } from '../../state/game-state'; + +export class PlayerInventoryEquippedHandler implements StateChangeHandler { + public handles(event: any): boolean { + return event.topic === 'player.inventory.equipped'; + } + + public handle(event: any, gameState: GameState): void { + gameState.equip(event.item); + } +} diff --git a/src/domain/state-change-handler/player-location-moved-handler.ts b/src/domain/state-change-handler/player-location-moved-handler.ts new file mode 100644 index 0000000..bb2abb2 --- /dev/null +++ b/src/domain/state-change-handler/player-location-moved-handler.ts @@ -0,0 +1,16 @@ +import { StateChangeHandler } from './state-change-handler'; +import { GameState } from '../../state/game-state'; +import { MapNodeRepository } from '../../map-node-repository'; + +export class PlayerLocationMovedHandler implements StateChangeHandler { + constructor(private mapNodeRepository: MapNodeRepository) {} + + public handles(event: any): boolean { + return event.topic === 'player.location.moved'; + } + + public handle(event: any, gameState: GameState): void { + const targetNode = this.mapNodeRepository.getMap().get(event.currentNode.id); + gameState.setCurrentLocation(targetNode); + } +} diff --git a/src/domain/state-change-handler/state-change-handler.ts b/src/domain/state-change-handler/state-change-handler.ts new file mode 100644 index 0000000..bf27063 --- /dev/null +++ b/src/domain/state-change-handler/state-change-handler.ts @@ -0,0 +1,6 @@ +import { GameState } from '../../state/game-state'; + +export interface StateChangeHandler { + handles(event: any): boolean; + handle(event: any, gameState: GameState): void; +} \ No newline at end of file diff --git a/src/game-engine.ts b/src/game-engine.ts index d26e7ed..2c3f11c 100644 --- a/src/game-engine.ts +++ b/src/game-engine.ts @@ -8,6 +8,12 @@ import { QueueingEventSubscriber } from './domain/queueing-event-subscriber'; import { GameStateEventSubscriber } from './domain/game-state-event-subscriber'; import { Publisher } from './domain/event-publisher'; +import { GameStartedHandler } from './domain/state-change-handler/game-started-handler'; +import { GameStoppedHandler } from './domain/state-change-handler/game-stopped-handler'; +import { PlayerInventoryAddedHandler } from './domain/state-change-handler/player-inventory-added-handler'; +import { PlayerInventoryEquippedHandler } from './domain/state-change-handler/player-inventory-equipped-handler'; +import { PlayerLocationMovedHandler } from './domain/state-change-handler/player-location-moved-handler'; + // game command handlers export class GameEngine { constructor( @@ -32,7 +38,7 @@ export class GameEngine { // this subscriber queues events for the current command then those events are returned at the end of the function const queueingSubscriber = new QueueingEventSubscriber(); // this subscriber updates the gamestate each time an event is published. Giving event sourcing a try, but have to only let the events drive changes to the state - const stateSubscriber = new GameStateEventSubscriber(this.mapNodeRepository.getMap(), gameState); + const stateSubscriber = this.createStateSubscriber(gameState); const publisher = new Publisher([queueingSubscriber, stateSubscriber]); const command = this.parser.parse(inputText); @@ -50,4 +56,16 @@ export class GameEngine { return { command: inputText, session: gameState.sessionToken, events: queueingSubscriber.events }; } + + private createStateSubscriber(gameState: GameState) { + const handlers = [ + new PlayerLocationMovedHandler(this.mapNodeRepository), + new PlayerInventoryAddedHandler(), + new PlayerInventoryEquippedHandler(), + new GameStartedHandler(), + new GameStoppedHandler() + ]; + + return new GameStateEventSubscriber(gameState, handlers); + } }