Skip to content

Commit

Permalink
docs: In-text documentation for agents
Browse files Browse the repository at this point in the history
  • Loading branch information
jcowman2 committed Sep 17, 2018
1 parent 6af18dc commit 399475a
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 8 deletions.
54 changes: 52 additions & 2 deletions src/agents/agent-model.ts
@@ -1,11 +1,24 @@
/**
* Contains the Agent model and the handler for proxying interaction with it.
* Agents are objects in a Regal game that can be modified and tracked by events.
*
* Copyright (c) 2018 Joseph R Cowman
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { RegalError } from "../error";
import GameInstance from "../game-instance";
import { StaticAgentRegistry } from "./static-agent";

/** Determines whether an object is an `Agent`. */
export const isAgent = (o: any): o is Agent =>
o && (o as Agent).isRegistered !== undefined;

/**
* Proxy handler that controls access to `Agent` objects.
*/
export const AGENT_PROXY_HANDLER = {
// Gets an agent property, either from `InstanceAgents` or the agent itself.
get(target: Agent, propertyKey: PropertyKey, receiver: object): any {
let value: any;

Expand All @@ -16,7 +29,7 @@ export const AGENT_PROXY_HANDLER = {
) {
value = target.game.agents.getAgentProperty(target.id, propertyKey);
}
// If the property never existed in the instance state (i.e. wasn't deleted), return the Reflect.get.
// If the property never existed in the instance state (i.e. wasn't deleted), return the `Reflect.get`.
else if (
target.game === undefined ||
!target.game.agents.agentPropertyWasDeleted(target.id, propertyKey)
Expand All @@ -27,6 +40,7 @@ export const AGENT_PROXY_HANDLER = {
return value;
},

// Redirects agent property changes to `InstanceAgents` if said agent is registered.
set(
target: Agent,
propertyKey: PropertyKey,
Expand All @@ -50,18 +64,20 @@ export const AGENT_PROXY_HANDLER = {
return result;
},

// Redirects checking if an agent has a property to `InstanceAgents` if said agent is registered.
has(target: Agent, propertyKey: PropertyKey): boolean {
return target.isRegistered
? target.game.agents.hasAgentProperty(target.id, propertyKey)
: Reflect.has(target, propertyKey);
},

// Redirects deleting an agent property to `InstanceAgents` if said agent is registered.
deleteProperty(target: Agent, propertyKey: PropertyKey): boolean {
let result: boolean;

if (
target.isRegistered &&
target.game.agents.hasAgentProperty(target.id, propertyKey)
target.game.agents.hasAgentProperty(target.id, propertyKey) // No use deleting a property if `InstanceAgents` doesn't have it
) {
const currentEvent = target.game.events.current;
result = target.game.agents.deleteAgentProperty(
Expand All @@ -77,23 +93,37 @@ export const AGENT_PROXY_HANDLER = {
}
};

/**
* A game object that can be modified and tracked by events in a game instance.
*/
export class Agent {
/**
* Constructs a new `Agent`. This constructor should almost never be called
* directly in the context of a game, but rather should be called with `super()`.
*
* @param _id The agent's numeric id (use with caution).
* @param game The agent's assigned game instance (use with caution).
*/
constructor(private _id?: number, public game?: GameInstance) {
return new Proxy(this, AGENT_PROXY_HANDLER);
}

/** Whether the agent is being tracked by a `GameInstance`. */
get isRegistered(): boolean {
return this.game !== undefined && this.game.agents.hasAgent(this.id);
}

/** Whether the agent is registered in the game's static context. */
get isStatic(): boolean {
return this._id !== undefined && StaticAgentRegistry.hasAgent(this._id);
}

/** The agent's numeric id. If the agent is not registered, this will not be defined. */
get id() {
return this._id;
}

/** If you attempt to set the id after one has already been set, an error will be thrown. */
set id(value: number) {
if (this._id !== undefined) {
throw new RegalError(
Expand All @@ -103,6 +133,15 @@ export class Agent {
this._id = value;
}

/**
* Registers the agent with the current game instance's `InstanceAgents`
* so that all changes to it are tracked.
*
* @param game The current game instance.
* @param newId The numeric id to assign to the new agent (optional).
*
* @returns A proxy to manage all interaction with the newly registered agent.
*/
public register(game: GameInstance, newId?: number): this {
if (!game) {
throw new RegalError(
Expand Down Expand Up @@ -136,6 +175,17 @@ export class Agent {
return this;
}

/**
* Adds the agent to the game's static agent registry so that
* its data is stored in the static context of the game, rather than
* every game instance.
*
* Note that modifications to this agent, once it is registered,
* will not modify the static version, but rather will record the
* changes in the current game instance's `InstanceAgents`.
*
* @returns A proxy to manage all interaction with the static agent.
*/
public static(): this {
return StaticAgentRegistry.addAgent(this);
}
Expand Down
65 changes: 65 additions & 0 deletions src/agents/agent-record.ts
@@ -1,23 +1,66 @@
/**
* Contains models for tracking changes made to registered agents.
*
* Copyright (c) 2018 Joseph R Cowman
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { EventRecord } from "../events";
import { StaticAgentRegistry } from "./static-agent";

/** Type of modification done to an agent's property. */
export enum PropertyOperation {
/** The property was added to the agent. */
ADDED = "ADDED",

/** The property's value was changed. */
MODIFIED = "MODIFIED",

/** The property was deleted. */
DELETED = "DELETED"
}

/**
* Describes a single operation on a registered agent's property.
*/
export interface PropertyChange {
/** The numeric id of the `TrackedEvent` during which the change took place (optional). */
eventId?: number;

/** The name of the `TrackedEvent` during which the change took place (optional). */
eventName?: string;

/** The numeric id of the registered `Agent` (optional). */
agentId?: number;

/** The operation performed on the agent's property. */
op: PropertyOperation;

/** The property's value before the operation (optional). */
init?: any;

/** The property's value after the operation (optional). */
final?: any;

/** The property's name (optional). */
property?: string;
}

/**
* Container for all changes made to a registered agent during the current game cycle.
*
* For each property of the agent being tracked, the `AgentRecord` will have a
* property of the same name that has an array of `PropertyChange`s that occurred
* during the current game cycle.
*
* When one of these properties is accessed, the `AgentRecord` will return the most recent value.
*/
export class AgentRecord {
/**
* Get the most recent value of the agent's property.
* @param propertyKey The name of the property to be retrieved.
* @returns The most recent value of the property, if it exists.
*/
public getProperty(propertyKey: PropertyKey): any {
const changes: PropertyChange[] = this[propertyKey];
let property: any;
Expand All @@ -29,6 +72,14 @@ export class AgentRecord {
return property;
}

/**
* Records a change to the registered agent's property.
*
* @param event The event that caused the change.
* @param agentId The id of the agent being updated.
* @param property The name of the property being updated.
* @param value The new value of the property.
*/
public setProperty<T>(
event: EventRecord,
agentId: number,
Expand All @@ -53,6 +104,15 @@ export class AgentRecord {
event.trackChange(agentId, property, op, initValue, value);
}

/**
* Deletes a property of the registered agent.
*
* @param event The event that caused the change.
* @param agentId The id of the agent being updated.
* @param property The name of the property being updated.
*
* @returns Whether the property was deleted.
*/
public deleteProperty(
event: EventRecord,
agentId: number,
Expand Down Expand Up @@ -82,6 +142,10 @@ export class AgentRecord {
return true;
}

/**
* Whether the registered agent used to have the property and it was deleted.
* @param propertyKey The name of the property in question.
*/
public propertyWasDeleted(propertyKey: PropertyKey): boolean {
if (this.hasOwnProperty(propertyKey)) {
const lastChange: PropertyChange = this[propertyKey][0];
Expand All @@ -94,6 +158,7 @@ export class AgentRecord {
return false;
}

/** Internal helper method to add a `PropertyChange` record to the `AgentRecord`. */
private _addRecord<T>(
event: EventRecord,
property: PropertyKey,
Expand Down
18 changes: 18 additions & 0 deletions src/agents/agent-reference.ts
@@ -1,6 +1,24 @@
/**
* Contains mock object that is used in place of registered agent circular references.
*
* Copyright (c) 2018 Joseph R Cowman
* Licensed under MIT License (see https://github.com/regal/regal)
*/

// tslint:disable-next-line
true; // This does nothing; it's only so the jsdocs won't conflict

/** Whether the given object is an `AgentReference`. */
export const isAgentReference = (o: any): o is AgentReference =>
o && (o as AgentReference).refId !== undefined;

/**
* Mock object that is used in place of registered agent circular references.
*/
export class AgentReference {
/**
* Constructs a new `AgentReference` in place of a registered agent.
* @param refId The mocked agent's numeric id.
*/
constructor(public refId: number) {}
}
8 changes: 8 additions & 0 deletions src/agents/agent-revert.ts
@@ -1,3 +1,10 @@
/**
* Contains the `buildRevertFunction` for reverting changes to the instance state.
*
* Copyright (c) 2018 Joseph R Cowman
* Licensed under MIT License (see https://github.com/regal/regal)
*/

import { noop, on } from "../events";
import { Agent } from "./agent-model";
import { AgentRecord, PropertyChange } from "./agent-record";
Expand All @@ -11,6 +18,7 @@ import { StaticAgentRegistry } from "./static-agent";
*
* @param agents The agent history on which the revert function will be based.
* @param revertTo The id of the `TrackedEvent` to which the state will be reverted. Defaults to 0 (the default event id).
*
* @returns A `TrackedEvent` that will perform the revert function onto the `GameInstance` on which it's invoked.
*/
export const buildRevertFunction = (
Expand Down
7 changes: 7 additions & 0 deletions src/agents/index.ts
@@ -1,3 +1,10 @@
/**
* Component for controlling tracked game objects called Agents within the Regal Game Library.
*
* Copyright (c) 2018 Joseph R Cowman
* Licensed under MIT License (see https://github.com/regal/regal)
*/

export { Agent } from "./agent-model";
export { StaticAgentRegistry } from "./static-agent";
export { AgentRecord, PropertyOperation, PropertyChange } from "./agent-record";
Expand Down

0 comments on commit 399475a

Please sign in to comment.