Skip to content

Commit

Permalink
feat(state): Adds internal interface for GameInstance
Browse files Browse the repository at this point in the history
  • Loading branch information
jcowman2 committed Nov 21, 2018
1 parent 838eb18 commit fbb2356
Show file tree
Hide file tree
Showing 20 changed files with 209 additions and 138 deletions.
4 changes: 2 additions & 2 deletions src/agents/impl/activate-agent.ts
Expand Up @@ -6,7 +6,7 @@
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { GameInstance } from "../../state";
import { GameInstanceInternal } from "../../state";
import { Agent } from "../agent";
import { propertyIsAgentId } from "../instance-agents-internal";
import {
Expand All @@ -24,7 +24,7 @@ import {
* @param agent The agent to be activated (not modified).
*/
export const activateAgent = <T extends Agent>(
game: GameInstance,
game: GameInstanceInternal,
agent: T
): T => {
let id = agent.id;
Expand Down
12 changes: 7 additions & 5 deletions src/agents/impl/active-agent-proxy.ts
Expand Up @@ -5,11 +5,11 @@
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { GameInstance } from "../../state";
import { GameInstanceInternal } from "../../state";
import { Agent } from "../agent";

/** Builds the proxy handler for an active agent proxy. */
const activeAgentProxyHandler = (id: number, game: GameInstance) => ({
const activeAgentProxyHandler = (id: number, game: GameInstanceInternal) => ({
get(target: Agent, property: PropertyKey) {
return game.agents.hasAgentProperty(id, property)
? game.agents.getAgentProperty(id, property)
Expand Down Expand Up @@ -60,8 +60,10 @@ const activeAgentProxyHandler = (id: number, game: GameInstance) => ({
* @param id The proxy agent's id.
* @param game The `GameInstance` of the current context.
*/
export const buildActiveAgentProxy = (id: number, game: GameInstance): Agent =>
new Proxy({} as any, activeAgentProxyHandler(id, game));
export const buildActiveAgentProxy = (
id: number,
game: GameInstanceInternal
): Agent => new Proxy({} as any, activeAgentProxyHandler(id, game));

/**
* Builds a proxy for an active agent array. An agent array is an array
Expand All @@ -75,5 +77,5 @@ export const buildActiveAgentProxy = (id: number, game: GameInstance): Agent =>
*/
export const buildActiveAgentArrayProxy = (
id: number,
game: GameInstance
game: GameInstanceInternal
): Agent => new Proxy([] as any, activeAgentProxyHandler(id, game));
6 changes: 3 additions & 3 deletions src/agents/impl/agent-manager-impl.ts
Expand Up @@ -7,7 +7,7 @@

import { RegalError } from "../../error";
import { DEFAULT_EVENT_ID, EventRecord } from "../../events";
import { GameInstance } from "../../state";
import { GameInstance, GameInstanceInternal } from "../../state";
import { AgentManager } from "../agent-manager";
import {
pcForAgentManager,
Expand All @@ -21,12 +21,12 @@ import { StaticAgentRegistry } from "../static-agent-registry";
/** Builds an implementation of `AgentManager` for the given `Agent` id and `GameInstance`. */
export const buildAgentManager = (
id: number,
game: GameInstance
game: GameInstanceInternal
): AgentManager => new AgentManagerImpl(id, game);

/** Implementation of `AgentManager`. */
class AgentManagerImpl implements AgentManager {
constructor(public id: number, public game: GameInstance) {}
constructor(public id: number, public game: GameInstanceInternal) {}

public hasPropertyRecord(property: PropertyKey): boolean {
if (property === "constructor") {
Expand Down
10 changes: 5 additions & 5 deletions src/agents/impl/instance-agents-impl.ts
Expand Up @@ -7,7 +7,7 @@

import { RegalError } from "../../error";
import { on } from "../../events";
import { GameInstance } from "../../state";
import { GameInstance, GameInstanceInternal } from "../../state";
import { isAgent } from "../agent";
import {
AgentArrayReference,
Expand All @@ -32,15 +32,15 @@ import { buildAgentManager } from "./agent-manager-impl";
* @param nextId The next agent ID to start activation at (optional).
*/
export const buildInstanceAgents = (
game: GameInstance,
game: GameInstanceInternal,
nextId?: number
): InstanceAgentsInternal => new InstanceAgentsImpl(game, nextId);

/** Implementation of `InstanceAgentsInternal`. */
class InstanceAgentsImpl implements InstanceAgentsInternal {
private _nextId: number;

constructor(public game: GameInstance, nextId?: number) {
constructor(public game: GameInstanceInternal, nextId?: number) {
this.createAgentManager(0);
this._nextId =
nextId !== undefined
Expand Down Expand Up @@ -225,7 +225,7 @@ class InstanceAgentsImpl implements InstanceAgentsInternal {
return undefined;
}

public recycle(newInstance: GameInstance): InstanceAgentsInternal {
public recycle(newInstance: GameInstanceInternal): InstanceAgentsInternal {
const newAgents = buildInstanceAgents(newInstance, this.nextId);

for (const formerAgent of this.agentManagers()) {
Expand Down Expand Up @@ -289,7 +289,7 @@ class InstanceAgentsImpl implements InstanceAgentsInternal {
revertTo: number = 0
): void {
// Build revert function
on("REVERT", game => {
on("REVERT", (game: GameInstanceInternal) => {
const target = game.agents;

for (const am of source.agentManagers()) {
Expand Down
6 changes: 3 additions & 3 deletions src/agents/instance-agents-internal.ts
Expand Up @@ -5,7 +5,7 @@
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { GameInstance } from "../state";
import { GameInstanceInternal } from "../state";
import { AgentManager } from "./agent-manager";

/**
Expand All @@ -16,7 +16,7 @@ import { AgentManager } from "./agent-manager";
*/
export interface InstanceAgentsInternal {
/** The `GameInstance` that owns this `InstanceAgentsInternal`. */
readonly game: GameInstance;
readonly game: GameInstanceInternal;

/** The ID that will be assigned to the next activated agent. */
readonly nextId: number;
Expand Down Expand Up @@ -103,7 +103,7 @@ export interface InstanceAgentsInternal {
*
* @param newInstance The new `GameInstance` that will own the new `InstanceAgentsInternal`.
*/
recycle(newInstance: GameInstance): InstanceAgentsInternal;
recycle(newInstance: GameInstanceInternal): InstanceAgentsInternal;

/**
* Traverses all agents that are accessible from the `GameInstance`'s
Expand Down
36 changes: 22 additions & 14 deletions src/api/game-api.ts
Expand Up @@ -11,15 +11,20 @@
import { StaticAgentRegistry } from "../agents";
import { GameMetadata, GameOptions, MetadataManager } from "../config";
import { RegalError } from "../error";
import { buildGameInstance, ContextManager, GameInstance } from "../state";
import {
buildGameInstance,
ContextManager,
GameInstance,
GameInstanceInternal
} from "../state";
import { HookManager } from "./api-hook-manager";
import { GameResponse, GameResponseOutput } from "./game-response";

/**
* Throws an error if `instance` or any of its properties are undefined.
* @param instance The `GameInstance` to validate.
*/
const validateGameInstance = (instance: GameInstance): void => {
const validateGameInstance = (instance: GameInstanceInternal): void => {
if (
instance === undefined ||
instance.agents === undefined ||
Expand Down Expand Up @@ -157,11 +162,12 @@ export class Game {
instance: GameInstance,
command: string
): GameResponse {
let newInstance: GameInstance;
let newInstance: GameInstanceInternal;
let err: RegalError;

try {
validateGameInstance(instance);
const oldInstance = instance as GameInstanceInternal;
validateGameInstance(oldInstance);

Game.init();

Expand All @@ -174,7 +180,7 @@ export class Game {
);
}

newInstance = instance.recycle();
newInstance = oldInstance.recycle();
newInstance.agents.scrubAgents();

const activatedEvent = HookManager.playerCommandHook(command);
Expand Down Expand Up @@ -236,20 +242,21 @@ export class Game {
* values, if the request was successful. Otherwise, the response will contain an error.
*/
public static postUndoCommand(instance: GameInstance): GameResponse {
let newInstance: GameInstance;
let newInstance: GameInstanceInternal;
let err: RegalError;

try {
validateGameInstance(instance);
const oldInstance = instance as GameInstanceInternal;
validateGameInstance(oldInstance);

Game.init();

if (!HookManager.beforeUndoCommandHook(instance)) {
throw new RegalError("Undo is not allowed here.");
}

newInstance = instance.recycle();
newInstance.agents.simulateRevert(instance.agents);
newInstance = oldInstance.recycle();
newInstance.agents.simulateRevert(oldInstance.agents);
} catch (error) {
err = wrapApiErrorAsRegalError(error);
}
Expand Down Expand Up @@ -283,25 +290,26 @@ export class Game {
instance: GameInstance,
options: Partial<GameOptions>
): GameResponse {
let newInstance: GameInstance;
let newInstance: GameInstanceInternal;
let err: RegalError;

try {
validateGameInstance(instance);
const oldInstance = instance as GameInstanceInternal;
validateGameInstance(oldInstance);

Game.init();

const oldOverrideKeys = Object.keys(instance.options.overrides);
const oldOverrideKeys = Object.keys(oldInstance.options.overrides);
const newOptionKeys = Object.keys(options);

const newOptions: Partial<GameOptions> = {};

oldOverrideKeys
.filter(key => !newOptionKeys.includes(key))
.forEach(key => (newOptions[key] = instance.options[key]));
.forEach(key => (newOptions[key] = oldInstance.options[key]));
newOptionKeys.forEach(key => (newOptions[key] = options[key]));

newInstance = instance.recycle(newOptions);
newInstance = oldInstance.recycle(newOptions);
} catch (error) {
err = wrapApiErrorAsRegalError(error);
}
Expand Down
6 changes: 3 additions & 3 deletions src/config/impl/instance-options-impl.ts
Expand Up @@ -7,7 +7,7 @@

import { RegalError } from "../../error";
import { generateSeed } from "../../random";
import { GameInstance } from "../../state";
import { GameInstance, GameInstanceInternal } from "../../state";
import { DEFAULT_GAME_OPTIONS, GameOptions } from "../game-options";
import { InstanceOptionsInternal } from "../instance-options-internal";
import { MetadataManager } from "../metadata-manager";
Expand Down Expand Up @@ -52,7 +52,7 @@ const INSTANCE_OPTIONS_PROXY_HANDLER = {
* @param generatedSeed Include if the previous GameInstance had a default-generated seed
*/
export const buildInstanceOptions = (
game: GameInstance,
game: GameInstanceInternal,
overrides: Partial<GameOptions>,
generatedSeed?: string
): InstanceOptionsInternal =>
Expand All @@ -68,7 +68,7 @@ class InstanceOptionsImpl implements InstanceOptionsInternal {
public readonly overrides: Partial<GameOptions>;

constructor(
public game: GameInstance,
public game: GameInstanceInternal,
overrides: Partial<GameOptions>,
generatedSeed?: string
) {
Expand Down
4 changes: 2 additions & 2 deletions src/config/instance-options-internal.ts
Expand Up @@ -5,7 +5,7 @@
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { GameInstance } from "../state";
import { GameInstanceInternal } from "../state";
import { GameOptions } from "./game-options";
import { InstanceOptions } from "./instance-options";

Expand All @@ -14,7 +14,7 @@ import { InstanceOptions } from "./instance-options";
*/
export interface InstanceOptionsInternal extends InstanceOptions {
/** The `GameInstance that owns this `InstanceOptions` */
readonly game: GameInstance;
readonly game: GameInstanceInternal;

/** Options that have had their static values overridden by the client. */
readonly overrides: Partial<GameOptions>;
Expand Down
32 changes: 18 additions & 14 deletions src/events/impl/instance-events-impl.ts
Expand Up @@ -5,7 +5,7 @@
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { GameInstance } from "../../state";
import { GameInstanceInternal } from "../../state";
import { DEFAULT_EVENT_ID, EventRecord } from "../event-record";
import {
isEventQueue,
Expand All @@ -22,14 +22,29 @@ import { buildEventRecord } from "./event-record-impl";
* @param startingEventId Optional starting ID for new `EventRecord`s.
*/
export const buildInstanceEvents = (
game: GameInstance,
game: GameInstanceInternal,
startingEventId?: number
): InstanceEventsInternal =>
startingEventId !== undefined
? new InstanceEventsImpl(game, startingEventId)
: new InstanceEventsImpl(game);

class InstanceEventsImpl implements InstanceEventsInternal {
public history: EventRecord[] = [];

/** Internal member for the ID of the most recently generated `EventRecord`. */
private _lastEventId: number;

/** Internal queue of events that have yet to be executed. */
private _queue: EventRecord[] = [];

constructor(
public game: GameInstanceInternal,
startingEventId = DEFAULT_EVENT_ID
) {
this._lastEventId = startingEventId;
}

get current(): EventRecord {
let event = this._queue[0];

Expand All @@ -43,24 +58,13 @@ class InstanceEventsImpl implements InstanceEventsInternal {
get lastEventId() {
return this._lastEventId;
}
public history: EventRecord[] = [];

/** Internal member for the ID of the most recently generated `EventRecord`. */
private _lastEventId: number;

/** Internal queue of events that have yet to be executed. */
private _queue: EventRecord[] = [];

constructor(public game: GameInstance, startingEventId = DEFAULT_EVENT_ID) {
this._lastEventId = startingEventId;
}

public invoke(event: TrackedEvent): void {
this._addEvent(event);
this._executeCurrent();
}

public recycle(newInstance: GameInstance): InstanceEventsInternal {
public recycle(newInstance: GameInstanceInternal): InstanceEventsInternal {
return new InstanceEventsImpl(newInstance, this.lastEventId);
}

Expand Down
6 changes: 3 additions & 3 deletions src/events/instance-events-internal.ts
Expand Up @@ -5,7 +5,7 @@
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { GameInstance } from "../state";
import { GameInstanceInternal } from "../state";
import { EventRecord } from "./event-record";
import { InstanceEvents } from "./instance-events";

Expand All @@ -24,13 +24,13 @@ export interface InstanceEventsInternal extends InstanceEvents {
history: EventRecord[];

/** The `GameInstance` that owns this `InstanceEventsInternal`. */
readonly game: GameInstance;
readonly game: GameInstanceInternal;

/**
* Creates a new `InstanceEventsInternal` for the new game cycle, clearing all
* old events but preserving the last event ID.
*
* @param newInstance The new `GameInstance` that will own this `InstanceEventsInternal`.
*/
recycle(newInstance: GameInstance): InstanceEventsInternal;
recycle(newInstance: GameInstanceInternal): InstanceEventsInternal;
}

0 comments on commit fbb2356

Please sign in to comment.