Merge branch 'serialization'
This commit is contained in:
commit
07b80d75df
|
@ -24,8 +24,7 @@ module SpaceTac {
|
|||
newGame(): Game.Universe {
|
||||
// Currently create a quick battle
|
||||
var universe = new Game.Universe();
|
||||
universe.battle = Game.Battle.newQuickRandom(true);
|
||||
universe.player = universe.battle.fleets[0].player;
|
||||
universe.startQuickBattle();
|
||||
return universe;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
|
@ -46,7 +48,7 @@ module SpaceTac.Game {
|
|||
// Value computed from equipment
|
||||
// This value can be altered by effects
|
||||
// Example attributes are health points, action points recovery...
|
||||
export class Attribute {
|
||||
export class Attribute extends Serializable {
|
||||
// Identifying code of this attribute
|
||||
code: AttributeCode;
|
||||
|
||||
|
@ -58,6 +60,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create an attribute
|
||||
constructor(code: AttributeCode = AttributeCode.Misc, current: number = 0, maximal: number = null) {
|
||||
super();
|
||||
|
||||
this.code = code;
|
||||
this.maximal = maximal;
|
||||
this.current = current;
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Collection of several attributes
|
||||
export class AttributeCollection {
|
||||
export class AttributeCollection extends Serializable {
|
||||
// Attributes
|
||||
private attributes: Attribute[];
|
||||
|
||||
// Base constructor
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.attributes = [];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// A turn-based battle between fleets
|
||||
export class Battle {
|
||||
export class Battle extends Serializable {
|
||||
// Flag indicating if the battle is ended
|
||||
ended: boolean;
|
||||
|
||||
|
@ -27,6 +29,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create a battle between two fleets
|
||||
constructor(fleet1: Fleet = null, fleet2: Fleet = null) {
|
||||
super();
|
||||
|
||||
this.log = new BattleLog();
|
||||
this.fleets = [fleet1 || new Fleet(), fleet2 || new Fleet()];
|
||||
this.play_order = [];
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Log of a battle
|
||||
// This keeps track of all events in a battle
|
||||
// It also allows to register a callback to receive these events
|
||||
export class BattleLog {
|
||||
export class BattleLog extends Serializable {
|
||||
// Full list of battle events
|
||||
events: BaseLogEvent[];
|
||||
|
||||
|
@ -16,6 +18,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create an initially empty log
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.events = [];
|
||||
this.subscribers = [];
|
||||
this.filters = [];
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Result of an ended battle
|
||||
export class BattleOutcome {
|
||||
export class BattleOutcome extends Serializable {
|
||||
// Indicates if the battle is a draw (no winner)
|
||||
draw: boolean;
|
||||
|
||||
|
@ -13,6 +15,8 @@ module SpaceTac.Game {
|
|||
loot: Equipment[];
|
||||
|
||||
constructor(winner: Fleet) {
|
||||
super();
|
||||
|
||||
this.winner = winner;
|
||||
this.draw = winner ? false : true;
|
||||
this.loot = [];
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Piece of equipment to attach in slots
|
||||
export class Equipment {
|
||||
export class Equipment extends Serializable {
|
||||
// Actual slot this equipment is attached to
|
||||
attached_to: Slot;
|
||||
|
||||
|
@ -44,6 +46,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Basic constructor
|
||||
constructor(slot: SlotType = null, code: string = null) {
|
||||
super();
|
||||
|
||||
this.slot = slot;
|
||||
this.code = code;
|
||||
this.name = code;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// A fleet of ships
|
||||
export class Fleet {
|
||||
export class Fleet extends Serializable {
|
||||
// Fleet owner
|
||||
player: Player;
|
||||
|
||||
|
@ -17,6 +19,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create a fleet, bound to a player
|
||||
constructor(player: Player = null) {
|
||||
super();
|
||||
|
||||
this.level = 1;
|
||||
this.player = player || new Player();
|
||||
this.ships = [];
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Template used to generate a loot equipment
|
||||
export class LootTemplate {
|
||||
export class LootTemplate extends Serializable {
|
||||
// Type of slot this equipment will fit in
|
||||
slot: SlotType;
|
||||
|
||||
|
@ -35,6 +37,7 @@ module SpaceTac.Game {
|
|||
|
||||
// Create a loot template
|
||||
constructor(slot: SlotType, name: string) {
|
||||
super();
|
||||
this.slot = slot;
|
||||
this.name = name;
|
||||
this.requirements = [];
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// One player (human or IA)
|
||||
export class Player {
|
||||
export class Player extends Serializable {
|
||||
// Current fleet
|
||||
fleet: Fleet;
|
||||
|
||||
|
@ -11,6 +13,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create a player, with an empty fleet
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.fleet = new Fleet(this);
|
||||
this.ai = null;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Range of number values
|
||||
export class Range {
|
||||
export class Range extends Serializable {
|
||||
// Minimal value
|
||||
min: number;
|
||||
|
||||
|
@ -11,6 +13,7 @@ module SpaceTac.Game {
|
|||
|
||||
// Create a range of values
|
||||
constructor(min: number, max: number = null) {
|
||||
super();
|
||||
this.set(min, max);
|
||||
}
|
||||
|
||||
|
|
21
src/scripts/game/Serializable.ts
Normal file
21
src/scripts/game/Serializable.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Base class for serializable objects
|
||||
export class Serializable {
|
||||
static _next_sid: number = 0;
|
||||
|
||||
private _sid: string;
|
||||
|
||||
constructor() {
|
||||
this._sid = null;
|
||||
}
|
||||
|
||||
getSerializeId(): string {
|
||||
if (this._sid === null) {
|
||||
this._sid = (Serializable._next_sid++).toString();
|
||||
}
|
||||
return this._sid;
|
||||
}
|
||||
}
|
||||
}
|
142
src/scripts/game/Serializer.ts
Normal file
142
src/scripts/game/Serializer.ts
Normal file
|
@ -0,0 +1,142 @@
|
|||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Serializer to cascade through Serializable objects
|
||||
export class Serializer {
|
||||
// Mapping of IDs to objects
|
||||
refs: {[index: string]: any};
|
||||
|
||||
// Serializable classes
|
||||
classes: {[index: string]: typeof Serializable};
|
||||
|
||||
constructor() {
|
||||
this.refs = {};
|
||||
this.classes = this.collectSerializableClasses();
|
||||
}
|
||||
|
||||
// List all classes that implement "Serializable", with their full path in SpaceTac.Game namespace
|
||||
collectSerializableClasses(container: any = null, path: string = ""): {[index: string]: typeof Serializable} {
|
||||
if (container) {
|
||||
var result: {[index: string]: typeof Serializable} = {};
|
||||
for (var obj_name in container) {
|
||||
if (container.hasOwnProperty(obj_name)) {
|
||||
var obj = container[obj_name];
|
||||
var obj_path = path + "." + obj_name;
|
||||
if (typeof obj === "object") {
|
||||
result = Tools.merge(result, this.collectSerializableClasses(obj, obj_path));
|
||||
} else if (typeof obj === "function" && obj.prototype instanceof Serializable) {
|
||||
result[obj_path] = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return this.collectSerializableClasses(SpaceTac.Game, "SpaceTac.Game");
|
||||
}
|
||||
}
|
||||
|
||||
// Get the full path in SpaceTac namespace, of a serializable object
|
||||
getClassPath(obj: Serializable): string {
|
||||
for (var class_path in this.classes) {
|
||||
if (this.classes.hasOwnProperty(class_path)) {
|
||||
var class_obj = this.classes[class_path];
|
||||
if (class_obj.prototype === obj.constructor.prototype) {
|
||||
return class_path;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Serialize an object to a string
|
||||
serialize(obj: Serializable): string {
|
||||
this.refs = {};
|
||||
var data = {
|
||||
refs: this.refs,
|
||||
root: this.toData(obj)
|
||||
};
|
||||
return JSON.stringify(data);
|
||||
}
|
||||
|
||||
// Load an object from a serialized string
|
||||
unserialize(sdata: string): Serializable {
|
||||
var data = JSON.parse(sdata);
|
||||
this.refs = data.refs;
|
||||
return this.fromData(data.root);
|
||||
}
|
||||
|
||||
private toData(obj: Serializable): any {
|
||||
var sid = obj.getSerializeId();
|
||||
var cached = this.refs[sid];
|
||||
var data = {
|
||||
_s: "r",
|
||||
_i: sid
|
||||
};
|
||||
if (typeof cached !== "undefined") {
|
||||
return data;
|
||||
}
|
||||
|
||||
var fields = {};
|
||||
this.refs[sid] = {
|
||||
_s: "o",
|
||||
path: this.getClassPath(obj),
|
||||
fields: fields
|
||||
};
|
||||
|
||||
for (var field_name in obj) {
|
||||
if (obj.hasOwnProperty(field_name)) {
|
||||
var field_value = obj[field_name];
|
||||
if (field_value instanceof Serializable) {
|
||||
fields[field_name] = this.toData(field_value);
|
||||
} else if (Array.isArray(field_value) && field_value.length > 0 && field_value[0] instanceof Serializable) {
|
||||
var items: Serializable[] = [];
|
||||
field_value.forEach((item: any) => {
|
||||
items.push(this.toData(item));
|
||||
});
|
||||
fields[field_name] = {
|
||||
_s: "a",
|
||||
items: items
|
||||
};
|
||||
} else {
|
||||
if (Object.prototype.toString.call(field_value) === "[object Object]") {
|
||||
console.error("Non Serializable object", field_value);
|
||||
}
|
||||
fields[field_name] = field_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private fromData(data: any): Serializable {
|
||||
var sid = data._i;
|
||||
var cached = this.refs[sid];
|
||||
|
||||
if (cached._s === "o") {
|
||||
var class_info = this.classes[cached.path];
|
||||
var obj = Object.create(class_info.prototype);
|
||||
this.refs[sid] = obj;
|
||||
for (var field_name in cached.fields) {
|
||||
if (cached.fields.hasOwnProperty(field_name)) {
|
||||
var field_value = cached.fields[field_name];
|
||||
if (field_value !== null && typeof field_value === "object" && field_value._s === "r") {
|
||||
obj[field_name] = this.fromData(field_value);
|
||||
} else if (field_value !== null && typeof field_value === "object" && field_value._s === "a") {
|
||||
var items: Serializable[] = [];
|
||||
field_value.items.forEach((item: any) => {
|
||||
items.push(this.fromData(item));
|
||||
});
|
||||
obj[field_name] = items;
|
||||
} else {
|
||||
obj[field_name] = field_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return obj;
|
||||
} else {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// A single ship in a Fleet
|
||||
export class Ship {
|
||||
export class Ship extends Serializable {
|
||||
// Fleet this ship is a member of
|
||||
fleet: Fleet;
|
||||
|
||||
|
@ -56,6 +58,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create a new ship inside a fleet
|
||||
constructor(fleet: Fleet = null, name: string = null) {
|
||||
super();
|
||||
|
||||
this.attributes = new AttributeCollection();
|
||||
this.fleet = fleet || new Fleet();
|
||||
this.name = name;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
|
@ -11,7 +13,7 @@ module SpaceTac.Game {
|
|||
}
|
||||
|
||||
// Slot to attach an equipment to a ship
|
||||
export class Slot {
|
||||
export class Slot extends Serializable {
|
||||
// Link to the ship
|
||||
ship: Ship;
|
||||
|
||||
|
@ -23,6 +25,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create an empty slot for a ship
|
||||
constructor(ship: Ship, type: SlotType) {
|
||||
super();
|
||||
|
||||
this.ship = ship;
|
||||
this.type = type;
|
||||
this.attached = null;
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Target for a capability
|
||||
// This could be a location in space, or a ship
|
||||
export class Target {
|
||||
export class Target extends Serializable {
|
||||
// Coordinates of the target
|
||||
x: number;
|
||||
y: number;
|
||||
|
@ -13,6 +15,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Standard constructor
|
||||
constructor(x: number, y: number, ship: Ship) {
|
||||
super();
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.ship = ship;
|
||||
|
|
|
@ -16,5 +16,16 @@ module SpaceTac.Game {
|
|||
|
||||
return objectCopy;
|
||||
}
|
||||
|
||||
// Merge an object into another
|
||||
static merge(base: any, incoming: any): any {
|
||||
var result = Tools.copyObject(base);
|
||||
for (var obj_name in incoming) {
|
||||
if (obj_name) {
|
||||
result[obj_name] = incoming[obj_name];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,32 @@
|
|||
/// <reference path="Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Main game universe
|
||||
export class Universe {
|
||||
export class Universe extends Serializable {
|
||||
// Current connected player
|
||||
player: Player;
|
||||
|
||||
// Currently played battle
|
||||
battle: Battle;
|
||||
|
||||
// Load a game state from a string
|
||||
static loadFromString(serialized: string): Universe {
|
||||
var serializer = new Serializer();
|
||||
return <Universe>serializer.unserialize(serialized);
|
||||
}
|
||||
|
||||
// Start a new "quick battle" game
|
||||
startQuickBattle(): void {
|
||||
this.battle = Game.Battle.newQuickRandom(true);
|
||||
this.player = this.battle.fleets[0].player;
|
||||
}
|
||||
|
||||
// Serializes the game state to a string
|
||||
saveToString(): string {
|
||||
var serializer = new Serializer();
|
||||
return serializer.serialize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="../Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Base class for action definitions
|
||||
export class BaseAction {
|
||||
export class BaseAction extends Serializable {
|
||||
// Identifier code for the type of action
|
||||
code: string;
|
||||
|
||||
|
@ -14,6 +16,8 @@ module SpaceTac.Game {
|
|||
|
||||
// Create the action
|
||||
constructor(code: string, needs_target: boolean, equipment: Equipment = null) {
|
||||
super();
|
||||
|
||||
this.code = code;
|
||||
this.needs_target = needs_target;
|
||||
this.equipment = equipment;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="../Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game.AI {
|
||||
"use strict";
|
||||
|
||||
// Base class for all Artificial Intelligence interaction
|
||||
export class AbstractAI {
|
||||
export class AbstractAI extends Serializable {
|
||||
// The battle this AI is involved in
|
||||
battle: Battle;
|
||||
|
||||
|
@ -25,6 +27,8 @@ module SpaceTac.Game.AI {
|
|||
private workqueue: Function[];
|
||||
|
||||
constructor(fleet: Fleet) {
|
||||
super();
|
||||
|
||||
this.fleet = fleet;
|
||||
this.battle = fleet.battle;
|
||||
this.async = true;
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
/// <reference path="../Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Base class for effects of actions
|
||||
// Effects can be permanent or temporary (for a number of turns)
|
||||
export class BaseEffect {
|
||||
export class BaseEffect extends Serializable {
|
||||
// Identifier code for the type of effect
|
||||
code: string;
|
||||
|
||||
// Base constructor
|
||||
constructor(code: string) {
|
||||
super();
|
||||
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
/// <reference path="../Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game {
|
||||
"use strict";
|
||||
|
||||
// Base class for a BattleLog event
|
||||
export class BaseLogEvent {
|
||||
export class BaseLogEvent extends Serializable {
|
||||
// Code of the event (its type)
|
||||
code: string;
|
||||
|
||||
|
@ -13,6 +15,8 @@ module SpaceTac.Game {
|
|||
target: Target;
|
||||
|
||||
constructor(code: string, ship: Ship = null, target: Target = null) {
|
||||
super();
|
||||
|
||||
this.code = code;
|
||||
this.ship = ship;
|
||||
this.target = target;
|
||||
|
|
116
src/scripts/game/specs/Serializer.spec.ts
Normal file
116
src/scripts/game/specs/Serializer.spec.ts
Normal file
|
@ -0,0 +1,116 @@
|
|||
/// <reference path="../../definitions/jasmine.d.ts"/>
|
||||
/// <reference path="../Serializable.ts"/>
|
||||
|
||||
module SpaceTac.Game.Specs {
|
||||
"use strict";
|
||||
|
||||
export class SerializableTestObj3 extends Serializable {
|
||||
a: boolean;
|
||||
b: SerializableTestObj1;
|
||||
}
|
||||
|
||||
export class SerializableTestObj2 extends Serializable {
|
||||
a: string;
|
||||
|
||||
b: SerializableTestObj3;
|
||||
|
||||
constructor(a: string = "test") {
|
||||
super();
|
||||
this.a = a;
|
||||
this.b = null;
|
||||
}
|
||||
|
||||
prepend(prefix: string): string {
|
||||
return prefix + this.a;
|
||||
}
|
||||
}
|
||||
|
||||
export class SerializableTestObj1 extends Serializable {
|
||||
a: number;
|
||||
|
||||
b: SerializableTestObj2;
|
||||
|
||||
c: SerializableTestObj2[];
|
||||
|
||||
constructor(a: number = 5, b: SerializableTestObj2 = null) {
|
||||
super();
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.c = [];
|
||||
}
|
||||
}
|
||||
|
||||
describe("Serializer", () => {
|
||||
it("collects serializable classes", () => {
|
||||
var serializer = new Serializer();
|
||||
var classes = serializer.collectSerializableClasses();
|
||||
|
||||
expect(classes["SpaceTac.Game.Specs.SerializableTestObj1"]).toBe(SerializableTestObj1);
|
||||
expect(classes["SpaceTac.Game.Specs.SerializableTestObj2"]).toBe(SerializableTestObj2);
|
||||
expect(classes["SpaceTac.Game.Specs.SerializableTestObj3"]).toBe(SerializableTestObj3);
|
||||
expect(classes["SpaceTac.Game.Range"]).toBe(Range);
|
||||
expect(classes["SpaceTac.Game.Equipments.GatlingGun"]).toBe(Equipments.GatlingGun);
|
||||
});
|
||||
|
||||
it("gets an object's full path in namespace", () => {
|
||||
var serializer = new Serializer();
|
||||
|
||||
expect(serializer.getClassPath(new SerializableTestObj1())).toBe("SpaceTac.Game.Specs.SerializableTestObj1");
|
||||
expect(serializer.getClassPath(new Range(0, 1))).toBe("SpaceTac.Game.Range");
|
||||
});
|
||||
|
||||
it("serializes and deserializes simple typescript objects", () => {
|
||||
var serializer = new Serializer();
|
||||
var obj = new SerializableTestObj2("a string");
|
||||
var dumped = serializer.serialize(obj);
|
||||
var loaded = serializer.unserialize(dumped);
|
||||
|
||||
expect(loaded).toEqual(obj);
|
||||
expect((<SerializableTestObj2>loaded).prepend("this is ")).toEqual("this is a string");
|
||||
});
|
||||
|
||||
it("serializes and deserializes nested typescript objects", () => {
|
||||
var serializer = new Serializer();
|
||||
var obj = new SerializableTestObj1(8, new SerializableTestObj2("test"));
|
||||
obj.c.push(new SerializableTestObj2("second test"));
|
||||
obj.c.push(new SerializableTestObj2("third test"));
|
||||
|
||||
var dumped = serializer.serialize(obj);
|
||||
var loaded = serializer.unserialize(dumped);
|
||||
|
||||
expect(loaded).toEqual(obj);
|
||||
expect((<SerializableTestObj1>loaded).b.prepend("this is a ")).toEqual("this is a test");
|
||||
expect((<SerializableTestObj1>loaded).c[1].prepend("this is a ")).toEqual("this is a third test");
|
||||
});
|
||||
|
||||
it("does not create copies of same object", () => {
|
||||
var serializer = new Serializer();
|
||||
var obj = new SerializableTestObj1(8, new SerializableTestObj2("test"));
|
||||
obj.c.push(obj.b);
|
||||
|
||||
var dumped = serializer.serialize(obj);
|
||||
var loaded = serializer.unserialize(dumped);
|
||||
|
||||
expect(loaded).toEqual(obj);
|
||||
expect((<SerializableTestObj1>loaded).b).toBe((<SerializableTestObj1>loaded).c[0]);
|
||||
});
|
||||
|
||||
it("handles reference cycles", () => {
|
||||
var serializer = new Serializer();
|
||||
var obj3 = new SerializableTestObj3();
|
||||
obj3.a = true;
|
||||
var obj2 = new SerializableTestObj2("test");
|
||||
var obj1 = new SerializableTestObj1(8, obj2);
|
||||
|
||||
obj3.b = obj1;
|
||||
obj2.b = obj3;
|
||||
|
||||
var dumped = serializer.serialize(obj1);
|
||||
var loaded = serializer.unserialize(dumped);
|
||||
|
||||
expect(loaded).toEqual(obj1);
|
||||
expect((<SerializableTestObj1>loaded).b.b.a).toBe(true);
|
||||
expect((<SerializableTestObj1>loaded).b.b.b).toBe(loaded);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -28,5 +28,11 @@ module SpaceTac.Game.Specs {
|
|||
|
||||
expect(cop.get()).toEqual("test");
|
||||
});
|
||||
|
||||
it("merges objects", () => {
|
||||
expect(Tools.merge({}, {})).toEqual({});
|
||||
expect(Tools.merge({"a": 1}, {"b": 2})).toEqual({"a": 1, "b": 2});
|
||||
expect(Tools.merge({"a": 1}, {"a": 3, "b": 2})).toEqual({"a": 3, "b": 2});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
32
src/scripts/game/specs/Universe.spec.ts
Normal file
32
src/scripts/game/specs/Universe.spec.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
/// <reference path="../../definitions/jasmine.d.ts"/>
|
||||
|
||||
module SpaceTac.Game.Specs {
|
||||
"use strict";
|
||||
|
||||
function applyGameSteps(universe: Universe): void {
|
||||
universe.battle.advanceToNextShip();
|
||||
// TODO Make some moves (IA?)
|
||||
universe.battle.endBattle(universe.battle.fleets[0]);
|
||||
}
|
||||
|
||||
describe("Universe", () => {
|
||||
it("serializes to a string", () => {
|
||||
var universe = new Universe();
|
||||
universe.startQuickBattle();
|
||||
|
||||
// Dump and reload
|
||||
var dumped = universe.saveToString();
|
||||
var loaded_universe = Universe.loadFromString(dumped);
|
||||
|
||||
// Check equality
|
||||
expect(loaded_universe).toEqual(universe);
|
||||
|
||||
// Apply game steps
|
||||
applyGameSteps(universe);
|
||||
applyGameSteps(loaded_universe);
|
||||
|
||||
// Check equality after game steps
|
||||
expect(loaded_universe).toEqual(universe);
|
||||
});
|
||||
});
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
/// <reference path="../../definitions/jasmine.d.ts"/>
|
||||
/// <reference path="../battle/BattleView.ts"/>
|
||||
|
||||
module SpaceTac.View.Specs {
|
||||
"use strict";
|
||||
|
|
Loading…
Reference in a new issue