Skip to content

Commit

Permalink
feat(api): Implements Game.postUndoCommand
Browse files Browse the repository at this point in the history
  • Loading branch information
jcowman2 committed Sep 8, 2018
1 parent de22bb8 commit 69dcfa5
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 5 deletions.
35 changes: 35 additions & 0 deletions src/agents/agent-revert.ts
@@ -0,0 +1,35 @@
import { EventRecord, noop, on } from "../events";
import { Agent } from "./agent-model";
import { AgentRecord } from "./agent-record";
import { InstanceAgents, propertyIsAgentId } from "./instance-agents";

// TODO - test more completely; especially with static agents

export const buildRevertFunction = (agents: InstanceAgents) => {
const agentKeys = Object.keys(agents).filter(propertyIsAgentId);
const agentRecords = agentKeys.map(key => agents[key] as AgentRecord);

return on("REVERT", game => {
const target = game.agents;

agentRecords.forEach(record => {
const recordKeys = Object.keys(record);
const id = record.getProperty("_id");

const agent = new Agent(id, target.game);

recordKeys
.filter(key => key !== "game" && key !== "_id")
.forEach(key => {
const changelog = record[key];
if (changelog.length > 1) {
const firstValue =
changelog[changelog.length - 1].final;
agent[key] = firstValue;
}
});
});

return noop;
});
};
1 change: 1 addition & 0 deletions src/agents/index.ts
Expand Up @@ -4,3 +4,4 @@ export { AgentRecord, PropertyOperation, PropertyChange } from "./agent-record";
export { AgentReference } from "./agent-reference";
export { InstanceAgents } from "./instance-agents";
export { InstanceState } from "./instance-state";
export { buildRevertFunction } from "./agent-revert";
33 changes: 29 additions & 4 deletions src/game-api.ts
@@ -1,6 +1,6 @@
import { StaticAgentRegistry } from "./agents";
import { buildRevertFunction, StaticAgentRegistry } from "./agents";
import { HookManager } from "./api-hooks";
import { GameOptions, OPTION_KEYS } from "./config";
import { GameOptions, MetadataManager, OPTION_KEYS } from "./config";
import { RegalError } from "./error";
import GameInstance from "./game-instance";
import { GameOutput } from "./output";
Expand Down Expand Up @@ -121,8 +121,33 @@ export class Game {
}

public static postUndoCommand(instance: GameInstance): GameResponse {
// TODO
throw new Error("Method not implemented.");
let newInstance: GameInstance;
let err: RegalError;

try {
validateGameInstance(instance);

// TODO - include onBeforeUndoCommand hook

newInstance = instance.cycle();
buildRevertFunction(instance.agents)(newInstance);
} catch (error) {
err = wrapApiErrorAsRegalError(error);
}

return err !== undefined
? {
output: {
error: err,
wasSuccessful: false
}
}
: {
instance: newInstance,
output: {
wasSuccessful: true
}
};
}

public static postOptionCommand(
Expand Down
38 changes: 37 additions & 1 deletion test/game-api.test.ts
Expand Up @@ -7,7 +7,7 @@ import { noop } from "../src/events";
import GameInstance from "../src/game-instance";
import { OutputLineType } from "../src/output";
import { log, getDemoMetadata, metadataWithOptions } from "./test-utils";
import { Agent } from "../src/agents";
import { Agent, buildRevertFunction } from "../src/agents";
import {
DEFAULT_GAME_OPTIONS,
OPTION_KEYS,
Expand All @@ -16,6 +16,12 @@ import {
GameMetadata
} from "../src/config";

class Dummy extends Agent {
constructor(public name: string, public health: number) {
super();
}
}

describe("Game API", function() {
before(function() {
MetadataManager.forceConfig(getDemoMetadata());
Expand Down Expand Up @@ -374,4 +380,34 @@ describe("Game API", function() {
);
});
});

describe("Game.postUndoCommand", function() {
it("Undo a simple operation", function() {
onStartCommand(game => {
game.state.foo = true;
game.state.dummy = new Dummy("Lars", 10);
return noop;
});

onPlayerCommand(command => game => {
game.state.foo = false;
game.state.dummy.name = command;
return noop;
});

const initResponse = Game.postPlayerCommand(
Game.postStartCommand().instance,
"Jimbo"
);

expect(initResponse.instance.state.foo).to.be.false;
expect(initResponse.instance.state.dummy.name).to.equal("Jimbo");

const undoResponse = Game.postUndoCommand(initResponse.instance);

expect(undoResponse.output.wasSuccessful).to.be.true;
expect(undoResponse.instance.state.foo).to.be.true;
expect(undoResponse.instance.state.dummy.name).to.equal("Lars");
});
});
});

0 comments on commit 69dcfa5

Please sign in to comment.