Comparing version 0.0.9 to 0.1.0
@@ -1,2 +0,2 @@ | ||
declare const ComponentA_base: import("../Component").SerializedComponentType<{ | ||
declare const ComponentA_base: import("../Component.js").SerializedComponentType<{ | ||
value: number; | ||
@@ -6,3 +6,3 @@ }>; | ||
} | ||
declare const ComponentB_base: import("../Component").SerializedComponentType<{ | ||
declare const ComponentB_base: import("../Component.js").SerializedComponentType<{ | ||
value: string; | ||
@@ -12,3 +12,3 @@ }>; | ||
} | ||
declare const ComponentC_base: import("../Component").SerializedComponentType<{ | ||
declare const ComponentC_base: import("../Component.js").SerializedComponentType<{ | ||
value: boolean; | ||
@@ -18,3 +18,3 @@ }>; | ||
} | ||
declare const ComponentD_base: import("../Component").SerializedComponentType<{ | ||
declare const ComponentD_base: import("../Component.js").SerializedComponentType<{ | ||
value: number[]; | ||
@@ -21,0 +21,0 @@ }>; |
@@ -1,62 +0,22 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ComponentD = exports.ComponentC = exports.ComponentB = exports.ComponentA = void 0; | ||
var Component_1 = require("../Component"); | ||
var ComponentA = /** @class */ (function (_super) { | ||
__extends(ComponentA, _super); | ||
function ComponentA() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return ComponentA; | ||
}(Component_1.Component(function () { return ({ | ||
import { Component } from '../Component.js'; | ||
export class ComponentA extends Component(() => ({ | ||
value: 10, | ||
}); }))); | ||
exports.ComponentA = ComponentA; | ||
})) { | ||
} | ||
ComponentA.id = 1; | ||
var ComponentB = /** @class */ (function (_super) { | ||
__extends(ComponentB, _super); | ||
function ComponentB() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return ComponentB; | ||
}(Component_1.Component(function () { return ({ | ||
export class ComponentB extends Component(() => ({ | ||
value: 'hello', | ||
}); }))); | ||
exports.ComponentB = ComponentB; | ||
})) { | ||
} | ||
ComponentB.id = 2; | ||
var ComponentC = /** @class */ (function (_super) { | ||
__extends(ComponentC, _super); | ||
function ComponentC() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return ComponentC; | ||
}(Component_1.Component(function () { return ({ | ||
export class ComponentC extends Component(() => ({ | ||
value: true, | ||
}); }))); | ||
exports.ComponentC = ComponentC; | ||
})) { | ||
} | ||
ComponentC.id = 3; | ||
var ComponentD = /** @class */ (function (_super) { | ||
__extends(ComponentD, _super); | ||
function ComponentD() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return ComponentD; | ||
}(Component_1.Component(function () { return ({ | ||
export class ComponentD extends Component(() => ({ | ||
value: [3], | ||
}); }))); | ||
exports.ComponentD = ComponentD; | ||
})) { | ||
} | ||
ComponentD.id = 4; | ||
//# sourceMappingURL=componentFixtures.js.map |
export {}; |
@@ -1,109 +0,50 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
import { Component } from '../Component.js'; | ||
import { makeEffect } from '../Effect.js'; | ||
import { changed, not } from '../filters.js'; | ||
import { Game } from '../Game.js'; | ||
import { logger } from '../logger.js'; | ||
import { makeSystem } from '../System.js'; | ||
import { describe, it, expect } from 'vitest'; | ||
const delta = 16 + 2 / 3; | ||
describe('integration tests', () => { | ||
class OutputComponent extends Component(() => ({ | ||
removablePresent: false, | ||
})) { | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Component_1 = require("../Component"); | ||
var Effect_1 = require("../Effect"); | ||
var filters_1 = require("../filters"); | ||
var Game_1 = require("../Game"); | ||
var logger_1 = require("../logger"); | ||
var System_1 = require("../System"); | ||
var delta = 16 + 2 / 3; | ||
describe('integration tests', function () { | ||
var OutputComponent = /** @class */ (function (_super) { | ||
__extends(OutputComponent, _super); | ||
function OutputComponent() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return OutputComponent; | ||
}(Component_1.Component(function () { return ({ | ||
removablePresent: false, | ||
}); }))); | ||
var RemovableComponent = /** @class */ (function (_super) { | ||
__extends(RemovableComponent, _super); | ||
function RemovableComponent() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return RemovableComponent; | ||
}(Component_1.Component(function () { return ({ | ||
class RemovableComponent extends Component(() => ({ | ||
stepsSinceAdded: 0, | ||
}); }))); | ||
var stepsTillToggle = 3; | ||
var SetFlagEffect = Effect_1.makeEffect([RemovableComponent, OutputComponent], function (ent) { | ||
return __generator(this, function (_a) { | ||
logger_1.logger.debug('Setting removablePresent: true'); | ||
ent.get(OutputComponent).update(function (output) { | ||
output.removablePresent = true; | ||
}); | ||
return [2 /*return*/]; | ||
})) { | ||
} | ||
const stepsTillToggle = 3; | ||
const SetFlagEffect = makeEffect([RemovableComponent, OutputComponent], function (ent) { | ||
logger.debug('Setting removablePresent: true'); | ||
ent.get(OutputComponent).update((output) => { | ||
output.removablePresent = true; | ||
}); | ||
}, function (ent) { | ||
return __generator(this, function (_a) { | ||
logger_1.logger.debug('Setting removablePresent: false'); | ||
ent.get(OutputComponent).update(function (output) { | ||
return () => { | ||
logger.debug('Setting removablePresent: false'); | ||
ent.get(OutputComponent).update((output) => { | ||
output.removablePresent = false; | ||
}); | ||
return [2 /*return*/]; | ||
}); | ||
}; | ||
}); | ||
var ReAddRemovableEffect = Effect_1.makeEffect([filters_1.not(RemovableComponent)], function (ent, game) { | ||
return __generator(this, function (_a) { | ||
logger_1.logger.debug('Adding RemovableComponent'); | ||
game.add(ent.id, RemovableComponent); | ||
return [2 /*return*/]; | ||
}); | ||
const ReAddRemovableEffect = makeEffect([not(RemovableComponent)], function (ent, game) { | ||
logger.debug('Adding RemovableComponent'); | ||
game.add(ent.id, RemovableComponent); | ||
}); | ||
var IncrementRemoveTimerSystem = System_1.makeSystem([RemovableComponent], function (ent) { | ||
logger_1.logger.debug('Incrementing stepsSinceAdded'); | ||
ent.get(RemovableComponent).update(function (comp) { | ||
const IncrementRemoveTimerSystem = makeSystem([RemovableComponent], (ent) => { | ||
logger.debug('Incrementing stepsSinceAdded'); | ||
ent.get(RemovableComponent).update((comp) => { | ||
comp.stepsSinceAdded++; | ||
logger_1.logger.debug("stepsSinceAdded: " + comp.stepsSinceAdded); | ||
logger.debug(`stepsSinceAdded: ${comp.stepsSinceAdded}`); | ||
}); | ||
}); | ||
var RemoveSystem = System_1.makeSystem([filters_1.changed(RemovableComponent)], function (ent, game) { | ||
const RemoveSystem = makeSystem([changed(RemovableComponent)], (ent, game) => { | ||
if (ent.get(RemovableComponent).stepsSinceAdded >= stepsTillToggle) { | ||
logger_1.logger.debug('Removing RemovableComponent'); | ||
logger.debug('Removing RemovableComponent'); | ||
game.remove(ent.id, RemovableComponent); | ||
} | ||
}); | ||
it('adds and removes components, and queries for those operations', function () { | ||
var game = new Game_1.Game({ | ||
it('adds and removes components, and queries for those operations', () => { | ||
const game = new Game({ | ||
components: [OutputComponent, RemovableComponent], | ||
@@ -117,10 +58,10 @@ systems: [ | ||
}); | ||
var a = game.create(); | ||
const a = game.create(); | ||
game.add(a, OutputComponent); | ||
logger_1.logger.debug('Step 1'); | ||
logger.debug('Step 1'); | ||
game.step(delta); | ||
var entity = game.get(a); | ||
let entity = game.get(a); | ||
expect(entity.maybeGet(OutputComponent)).not.toBe(null); | ||
expect(entity.get(OutputComponent).removablePresent).toBe(false); | ||
logger_1.logger.debug('Step 2'); | ||
logger.debug('Step 2'); | ||
game.step(delta); | ||
@@ -131,3 +72,3 @@ entity = game.get(a); | ||
expect(entity.maybeGet(RemovableComponent).stepsSinceAdded).toBe(0); | ||
logger_1.logger.debug('Step 3'); | ||
logger.debug('Step 3'); | ||
game.step(delta); | ||
@@ -138,3 +79,3 @@ entity = game.get(a); | ||
expect(entity.maybeGet(RemovableComponent).stepsSinceAdded).toBe(1); | ||
logger_1.logger.debug('Step 4'); | ||
logger.debug('Step 4'); | ||
game.step(delta); | ||
@@ -145,3 +86,3 @@ entity = game.get(a); | ||
expect(entity.maybeGet(RemovableComponent).stepsSinceAdded).toBe(2); | ||
logger_1.logger.debug('Step 5'); | ||
logger.debug('Step 5'); | ||
game.step(delta); | ||
@@ -151,3 +92,3 @@ entity = game.get(a); | ||
expect(entity.maybeGet(RemovableComponent)).toBe(null); | ||
logger_1.logger.debug('Step 6'); | ||
logger.debug('Step 6'); | ||
game.step(delta); | ||
@@ -154,0 +95,0 @@ entity = game.get(a); |
@@ -1,14 +0,8 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import { ComponentType } from './Component'; | ||
import { Entity } from './Entity'; | ||
export interface ArchetypeEvents { | ||
import { EventSubscriber } from '@a-type/utils'; | ||
import { ComponentType } from './Component.js'; | ||
import { Entity } from './Entity.js'; | ||
export type ArchetypeEvents = { | ||
entityAdded(entity: Entity<any, any>): any; | ||
entityRemoved(entityId: number): any; | ||
} | ||
export declare interface Archetype { | ||
on<U extends keyof ArchetypeEvents>(ev: U, cb: ArchetypeEvents[U]): this; | ||
off<U extends keyof ArchetypeEvents>(ev: U, cb: ArchetypeEvents[U]): this; | ||
emit<U extends keyof ArchetypeEvents>(ev: U, ...args: Parameters<ArchetypeEvents[U]>): boolean; | ||
} | ||
}; | ||
/** | ||
@@ -22,3 +16,3 @@ * Archetype is a group of Entities which share a common component signature. | ||
*/ | ||
export declare class Archetype<T extends ComponentType<any>[] = ComponentType<any>[]> extends EventEmitter { | ||
export declare class Archetype<T extends ComponentType<any>[] = ComponentType<any>[]> extends EventSubscriber<ArchetypeEvents> { | ||
id: string; | ||
@@ -25,0 +19,0 @@ private entities; |
@@ -1,45 +0,2 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Archetype = void 0; | ||
var events_1 = require("events"); | ||
import { EventSubscriber } from '@a-type/utils'; | ||
/** | ||
@@ -53,45 +10,31 @@ * Archetype is a group of Entities which share a common component signature. | ||
*/ | ||
var Archetype = /** @class */ (function (_super) { | ||
__extends(Archetype, _super); | ||
function Archetype(id) { | ||
var _this = _super.call(this) || this; | ||
_this.id = id; | ||
_this.entities = new Array(); | ||
export class Archetype extends EventSubscriber { | ||
constructor(id) { | ||
super(); | ||
this.id = id; | ||
this.entities = new Array(); | ||
/** Maps entity ID -> index in entity array */ | ||
_this.entityIndexLookup = new Array(); | ||
_this.hasAll = function (types) { | ||
var masked = types | ||
.reduce(function (m, T) { | ||
this.entityIndexLookup = new Array(); | ||
this.hasAll = (types) => { | ||
const masked = types | ||
.reduce((m, T) => { | ||
m[T.id] = '1'; | ||
return m; | ||
}, _this.id.split('')) | ||
}, this.id.split('')) | ||
.join(''); | ||
return _this.id === masked; | ||
return this.id === masked; | ||
}; | ||
_this.hasSome = function (types) { | ||
var e_1, _a; | ||
try { | ||
for (var types_1 = __values(types), types_1_1 = types_1.next(); !types_1_1.done; types_1_1 = types_1.next()) { | ||
var T = types_1_1.value; | ||
if (_this.id[T.id] === '1') | ||
return true; | ||
} | ||
this.hasSome = (types) => { | ||
for (var T of types) { | ||
if (this.id[T.id] === '1') | ||
return true; | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (types_1_1 && !types_1_1.done && (_a = types_1.return)) _a.call(types_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
return false; | ||
}; | ||
_this.includes = function (Type) { | ||
return _this.id[Type.id] === '1'; | ||
this.includes = (Type) => { | ||
return this.id[Type.id] === '1'; | ||
}; | ||
_this.omits = function (Type) { | ||
return !_this.includes(Type); | ||
this.omits = (Type) => { | ||
return !this.includes(Type); | ||
}; | ||
_this.setMaxListeners(10000000); | ||
return _this; | ||
} | ||
@@ -102,8 +45,8 @@ /** | ||
*/ | ||
Archetype.prototype[Symbol.iterator] = function () { | ||
[Symbol.iterator]() { | ||
return this.entities[Symbol.iterator](); | ||
}; | ||
Archetype.prototype.addEntity = function (entity) { | ||
} | ||
addEntity(entity) { | ||
// this is the index ("column") of this entity in the table | ||
var index = this.entities.length; | ||
const index = this.entities.length; | ||
// for lookup later when presented with an entityId | ||
@@ -114,3 +57,3 @@ this.entityIndexLookup[entity.id] = index; | ||
this.emit('entityAdded', entity); | ||
}; | ||
} | ||
/** | ||
@@ -120,12 +63,12 @@ * Removes an entity from the archetype table, returning its | ||
*/ | ||
Archetype.prototype.removeEntity = function (entityId) { | ||
var index = this.entityIndexLookup[entityId]; | ||
removeEntity(entityId) { | ||
const index = this.entityIndexLookup[entityId]; | ||
if (index === undefined) { | ||
throw new Error("Tried to remove " + entityId + " from archetype " + this.id + ", but was not present"); | ||
throw new Error(`Tried to remove ${entityId} from archetype ${this.id}, but was not present`); | ||
} | ||
this.entityIndexLookup[entityId] = undefined; | ||
var _a = __read(this.entities.splice(index, 1), 1), entity = _a[0]; | ||
const [entity] = this.entities.splice(index, 1); | ||
// FIXME: improve this!!! Maybe look into a linked list like that one blog post... | ||
// decrement all entity index lookups that fall after this index | ||
for (var i = 0; i < this.entityIndexLookup.length; i++) { | ||
for (let i = 0; i < this.entityIndexLookup.length; i++) { | ||
if (this.entityIndexLookup[i] && this.entityIndexLookup[i] > index) { | ||
@@ -137,16 +80,14 @@ this.entityIndexLookup[i]--; | ||
return entity; | ||
}; | ||
Archetype.prototype.getEntity = function (entityId) { | ||
var index = this.entityIndexLookup[entityId]; | ||
} | ||
getEntity(entityId) { | ||
const index = this.entityIndexLookup[entityId]; | ||
if (index === undefined) { | ||
throw new Error("Could not find entity " + entityId + " in archetype " + this.id); | ||
throw new Error(`Could not find entity ${entityId} in archetype ${this.id}`); | ||
} | ||
return this.entities[index]; | ||
}; | ||
Archetype.prototype.toString = function () { | ||
} | ||
toString() { | ||
return this.id; | ||
}; | ||
return Archetype; | ||
}(events_1.EventEmitter)); | ||
exports.Archetype = Archetype; | ||
} | ||
} | ||
//# sourceMappingURL=Archetype.js.map |
export {}; |
@@ -1,72 +0,16 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Archetype_1 = require("./Archetype"); | ||
var Component_1 = require("./Component"); | ||
var Entity_1 = require("./Entity"); | ||
var A = /** @class */ (function (_super) { | ||
__extends(A, _super); | ||
function A() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return A; | ||
}(Component_1.Component(function () { return ({}); }))); | ||
var B = /** @class */ (function (_super) { | ||
__extends(B, _super); | ||
function B() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return B; | ||
}(Component_1.Component(function () { return ({}); }))); | ||
var C = /** @class */ (function (_super) { | ||
__extends(C, _super); | ||
function C() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return C; | ||
}(Component_1.Component(function () { return ({}); }))); | ||
import { Archetype } from './Archetype.js'; | ||
import { Component } from './Component.js'; | ||
import { Entity } from './Entity.js'; | ||
import { describe, it, expect } from 'vitest'; | ||
class A extends Component(() => ({})) { | ||
} | ||
class B extends Component(() => ({})) { | ||
} | ||
class C extends Component(() => ({})) { | ||
} | ||
A.id = 0; | ||
B.id = 1; | ||
C.id = 2; | ||
describe('Archetypes', function () { | ||
var entities = [ | ||
describe('Archetypes', () => { | ||
const entities = [ | ||
[[new A(), new B(), new C()], 1], | ||
@@ -76,8 +20,6 @@ [[new A(), new B(), new C()], 5], | ||
]; | ||
it('stores and iterates entities', function () { | ||
var e_1, _a; | ||
var arch = new Archetype_1.Archetype('111'); | ||
entities.forEach(function (_a) { | ||
var _b = __read(_a, 2), components = _b[0], id = _b[1]; | ||
var entity = new Entity_1.Entity(); | ||
it('stores and iterates entities', () => { | ||
const arch = new Archetype('111'); | ||
entities.forEach(([components, id]) => { | ||
const entity = new Entity(); | ||
entity.__set(id, components); | ||
@@ -88,27 +30,15 @@ arch.addEntity(entity); | ||
// an intermediate array | ||
var i = 0; | ||
try { | ||
for (var arch_1 = __values(arch), arch_1_1 = arch_1.next(); !arch_1_1.done; arch_1_1 = arch_1.next()) { | ||
var item = arch_1_1.value; | ||
expect(item.id).toBe(entities[i][1]); | ||
expect(item.get(A)).toEqual(entities[i][0][0]); | ||
expect(item.get(B)).toEqual(entities[i][0][1]); | ||
expect(item.get(C)).toEqual(entities[i][0][2]); | ||
i++; | ||
} | ||
let i = 0; | ||
for (const item of arch) { | ||
expect(item.id).toBe(entities[i][1]); | ||
expect(item.get(A)).toEqual(entities[i][0][0]); | ||
expect(item.get(B)).toEqual(entities[i][0][1]); | ||
expect(item.get(C)).toEqual(entities[i][0][2]); | ||
i++; | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (arch_1_1 && !arch_1_1.done && (_a = arch_1.return)) _a.call(arch_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}); | ||
it('removes entities', function () { | ||
var e_2, _a; | ||
var arch = new Archetype_1.Archetype('111'); | ||
entities.forEach(function (_a) { | ||
var _b = __read(_a, 2), components = _b[0], id = _b[1]; | ||
var entity = new Entity_1.Entity(); | ||
it('removes entities', () => { | ||
const arch = new Archetype('111'); | ||
entities.forEach(([components, id]) => { | ||
const entity = new Entity(); | ||
entity.__set(id, components); | ||
@@ -118,21 +48,10 @@ arch.addEntity(entity); | ||
arch.removeEntity(entities[1][1]); | ||
try { | ||
for (var arch_2 = __values(arch), arch_2_1 = arch_2.next(); !arch_2_1.done; arch_2_1 = arch_2.next()) { | ||
var item = arch_2_1.value; | ||
expect(item.id).not.toEqual(5); | ||
} | ||
for (const item of arch) { | ||
expect(item.id).not.toEqual(5); | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (arch_2_1 && !arch_2_1.done && (_a = arch_2.return)) _a.call(arch_2); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
}); | ||
it('keeps entity locations consistent after removal', function () { | ||
var arch = new Archetype_1.Archetype('111'); | ||
entities.forEach(function (_a) { | ||
var _b = __read(_a, 2), components = _b[0], id = _b[1]; | ||
var entity = new Entity_1.Entity(); | ||
it('keeps entity locations consistent after removal', () => { | ||
const arch = new Archetype('111'); | ||
entities.forEach(([components, id]) => { | ||
const entity = new Entity(); | ||
entity.__set(id, components); | ||
@@ -139,0 +58,0 @@ arch.addEntity(entity); |
@@ -1,7 +0,6 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import { Archetype } from './Archetype'; | ||
import { ComponentInstanceFor, ComponentType, ComponentInstance } from './Component'; | ||
import { Game } from './Game'; | ||
export interface ArchetypeManagerEvents { | ||
import { EventSubscriber } from '@a-type/utils'; | ||
import { Archetype } from './Archetype.js'; | ||
import { ComponentInstanceFor, ComponentType, ComponentInstance } from './Component.js'; | ||
import { Game } from './Game.js'; | ||
export type ArchetypeManagerEvents = { | ||
archetypeCreated(archetype: Archetype): void; | ||
@@ -12,9 +11,4 @@ entityCreated(entityId: number): void; | ||
entityDestroyed(entityId: number): void; | ||
} | ||
export declare interface ArchetypeManager { | ||
on<U extends keyof ArchetypeManagerEvents>(ev: U, cb: ArchetypeManagerEvents[U]): this; | ||
off<U extends keyof ArchetypeManagerEvents>(ev: U, cb: ArchetypeManagerEvents[U]): this; | ||
emit<U extends keyof ArchetypeManagerEvents>(ev: U, ...args: Parameters<ArchetypeManagerEvents[U]>): boolean; | ||
} | ||
export declare class ArchetypeManager extends EventEmitter { | ||
}; | ||
export declare class ArchetypeManager extends EventSubscriber<ArchetypeManagerEvents> { | ||
private game; | ||
@@ -28,6 +22,6 @@ emptyId: string; | ||
removeComponent(entityId: number, componentType: number): any; | ||
destroyEntity(entityId: number): import("./Entity").Entity<ComponentType<any>, any>; | ||
getEntity(entityId: number): import("./Entity").Entity<ComponentType<any>, any> | null; | ||
destroyEntity(entityId: number): import("./Entity.js").Entity<ComponentType<any>, any>; | ||
getEntity(entityId: number): import("./Entity.js").Entity<ComponentType<any>, any> | null; | ||
private getOrCreate; | ||
private flipBit; | ||
} |
@@ -1,119 +0,98 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ArchetypeManager = void 0; | ||
var events_1 = require("events"); | ||
var Archetype_1 = require("./Archetype"); | ||
var logger_1 = require("./logger"); | ||
var ArchetypeManager = /** @class */ (function (_super) { | ||
__extends(ArchetypeManager, _super); | ||
function ArchetypeManager(game) { | ||
var _this = _super.call(this) || this; | ||
_this.game = game; | ||
import { EventSubscriber } from '@a-type/utils'; | ||
import { Archetype } from './Archetype.js'; | ||
import { logger } from './logger.js'; | ||
export class ArchetypeManager extends EventSubscriber { | ||
constructor(game) { | ||
super(); | ||
this.game = game; | ||
// maps entity ids to archetypes | ||
_this.entityLookup = new Array(); | ||
this.entityLookup = new Array(); | ||
// maps archetype id bitstrings to Archetype instances | ||
_this.archetypes = {}; | ||
this.archetypes = {}; | ||
// FIXME: why +1 here? Component ids are not starting at 0... this | ||
// should be more elegant | ||
_this.emptyId = new Array(_this.game.componentManager.componentTypes.length + 1) | ||
this.emptyId = new Array(this.game.componentManager.componentTypes.length + 1) | ||
.fill('0') | ||
.join(''); | ||
_this.archetypes[_this.emptyId] = new Archetype_1.Archetype(_this.emptyId); | ||
_this.setMaxListeners(1000000); | ||
return _this; | ||
this.archetypes[this.emptyId] = new Archetype(this.emptyId); | ||
} | ||
ArchetypeManager.prototype.createEntity = function (entityId) { | ||
logger_1.logger.debug("Creating entity " + entityId); | ||
createEntity(entityId) { | ||
logger.debug(`Creating entity ${entityId}`); | ||
this.entityLookup[entityId] = this.emptyId; | ||
// allocate an Entity | ||
var entity = this.game.entityPool.acquire(); | ||
const entity = this.game.entityPool.acquire(); | ||
entity.__set(entityId, []); | ||
this.getOrCreate(this.emptyId).addEntity(entity); | ||
this.emit('entityCreated', entityId); | ||
}; | ||
ArchetypeManager.prototype.addComponent = function (entityId, instance) { | ||
logger_1.logger.debug("Adding " + Object.getPrototypeOf(instance).constructor.name + " to entity " + entityId); | ||
var oldArchetypeId = this.entityLookup[entityId]; | ||
} | ||
addComponent(entityId, instance) { | ||
logger.debug(`Adding ${Object.getPrototypeOf(instance).constructor.name} to entity ${entityId}`); | ||
const oldArchetypeId = this.entityLookup[entityId]; | ||
if (oldArchetypeId === undefined) { | ||
throw new Error("Tried to add component " + instance.__type + " to " + entityId + ", but it was not found in the archetype registry"); | ||
throw new Error(`Tried to add component ${instance.__type} to ${entityId}, but it was not found in the archetype registry`); | ||
} | ||
var oldArchetype = this.getOrCreate(oldArchetypeId); | ||
const oldArchetype = this.getOrCreate(oldArchetypeId); | ||
// remove data from old archetype | ||
var entity = oldArchetype.removeEntity(entityId); | ||
const entity = oldArchetype.removeEntity(entityId); | ||
entity.__addComponent(instance); | ||
var newArchetypeId = (this.entityLookup[entityId] = this.flipBit(oldArchetypeId, instance.__type)); | ||
var archetype = this.getOrCreate(newArchetypeId); | ||
const newArchetypeId = (this.entityLookup[entityId] = this.flipBit(oldArchetypeId, instance.__type)); | ||
const archetype = this.getOrCreate(newArchetypeId); | ||
// copy entity from old to new | ||
archetype.addEntity(entity); | ||
logger_1.logger.debug("Entity " + entityId + " moved to archetype " + newArchetypeId); | ||
logger.debug(`Entity ${entityId} moved to archetype ${newArchetypeId}`); | ||
this.emit('entityComponentAdded', entityId, instance); | ||
}; | ||
ArchetypeManager.prototype.removeComponent = function (entityId, componentType) { | ||
logger_1.logger.debug("Removing " + this.game.componentManager.getTypeName(componentType) + " from entity " + entityId); | ||
var oldArchetypeId = this.entityLookup[entityId]; | ||
} | ||
removeComponent(entityId, componentType) { | ||
logger.debug(`Removing ${this.game.componentManager.getTypeName(componentType)} from entity ${entityId}`); | ||
const oldArchetypeId = this.entityLookup[entityId]; | ||
if (oldArchetypeId === undefined) { | ||
logger_1.logger.warn("Tried to remove component " + this.game.componentManager.getTypeName(componentType) + " from " + entityId + ", but it was not found in the archetype registry"); | ||
logger.warn(`Tried to remove component ${this.game.componentManager.getTypeName(componentType)} from ${entityId}, but it was not found in the archetype registry`); | ||
return; | ||
} | ||
var oldArchetype = this.getOrCreate(oldArchetypeId); | ||
var entity = oldArchetype.removeEntity(entityId); | ||
var removed = entity.__removeComponent(componentType); | ||
var newArchetypeId = (this.entityLookup[entityId] = this.flipBit(oldArchetypeId, componentType)); | ||
var archetype = this.getOrCreate(newArchetypeId); | ||
const oldArchetype = this.getOrCreate(oldArchetypeId); | ||
const entity = oldArchetype.removeEntity(entityId); | ||
const removed = entity.__removeComponent(componentType); | ||
const newArchetypeId = (this.entityLookup[entityId] = this.flipBit(oldArchetypeId, componentType)); | ||
const archetype = this.getOrCreate(newArchetypeId); | ||
archetype.addEntity(entity); | ||
logger_1.logger.debug("Entity " + entityId + " moved to archetype " + newArchetypeId); | ||
logger.debug(`Entity ${entityId} moved to archetype ${newArchetypeId}`); | ||
this.emit('entityComponentRemoved', entityId, componentType); | ||
return removed; | ||
}; | ||
ArchetypeManager.prototype.destroyEntity = function (entityId) { | ||
logger_1.logger.debug("Destroying entity " + entityId); | ||
var archetypeId = this.entityLookup[entityId]; | ||
} | ||
destroyEntity(entityId) { | ||
logger.debug(`Destroying entity ${entityId}`); | ||
const archetypeId = this.entityLookup[entityId]; | ||
if (archetypeId === undefined) { | ||
throw new Error("Tried to destroy " + entityId + ", but it was not found in archetype registry"); | ||
throw new Error(`Tried to destroy ${entityId}, but it was not found in archetype registry`); | ||
} | ||
this.entityLookup[entityId] = undefined; | ||
var archetype = this.archetypes[archetypeId]; | ||
var entity = archetype.removeEntity(entityId); | ||
const archetype = this.archetypes[archetypeId]; | ||
const entity = archetype.removeEntity(entityId); | ||
this.emit('entityDestroyed', entityId); | ||
return entity; | ||
}; | ||
ArchetypeManager.prototype.getEntity = function (entityId) { | ||
var archetypeId = this.entityLookup[entityId]; | ||
} | ||
getEntity(entityId) { | ||
const archetypeId = this.entityLookup[entityId]; | ||
if (archetypeId === undefined) { | ||
logger_1.logger.debug("Could not find Archetype for Entity " + entityId); | ||
logger.debug(`Could not find Archetype for Entity ${entityId}`); | ||
return null; | ||
} | ||
var archetype = this.archetypes[archetypeId]; | ||
const archetype = this.archetypes[archetypeId]; | ||
return archetype.getEntity(entityId); | ||
}; | ||
ArchetypeManager.prototype.getOrCreate = function (id) { | ||
var archetype = this.archetypes[id]; | ||
} | ||
getOrCreate(id) { | ||
let archetype = this.archetypes[id]; | ||
if (!archetype) { | ||
archetype = this.archetypes[id] = new Archetype_1.Archetype(id); | ||
logger_1.logger.debug("New Archetype " + id + " created"); | ||
archetype = this.archetypes[id] = new Archetype(id); | ||
logger.debug(`New Archetype ${id} created`); | ||
this.emit('archetypeCreated', archetype); | ||
} | ||
return archetype; | ||
}; | ||
ArchetypeManager.prototype.flipBit = function (id, typeId) { | ||
} | ||
flipBit(id, typeId) { | ||
return (id.substr(0, typeId) + | ||
(id[typeId] === '1' ? '0' : '1') + | ||
id.substr(typeId + 1)); | ||
}; | ||
return ArchetypeManager; | ||
}(events_1.EventEmitter)); | ||
exports.ArchetypeManager = ArchetypeManager; | ||
} | ||
} | ||
//# sourceMappingURL=ArchetypeManager.js.map |
@@ -1,3 +0,3 @@ | ||
export declare type AssetLoader<T = any> = (key: string) => Promise<T>; | ||
declare type InferAsset<Loader extends AssetLoader<any>> = Loader extends AssetLoader<infer T> ? T : never; | ||
export type AssetLoader<T = any> = (key: string) => Promise<T>; | ||
type InferAsset<Loader extends AssetLoader<any>> = Loader extends AssetLoader<infer T> ? T : never; | ||
export declare class Assets<Loaders extends Record<string, AssetLoader>> { | ||
@@ -4,0 +4,0 @@ private _loaders; |
@@ -1,23 +0,19 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Assets = void 0; | ||
var objectPool_1 = require("./internal/objectPool"); | ||
var ResourceHandle_1 = require("./ResourceHandle"); | ||
var Assets = /** @class */ (function () { | ||
function Assets(_loaders) { | ||
var _this = this; | ||
import { ObjectPool } from './internal/objectPool.js'; | ||
import { ResourceHandle } from './ResourceHandle.js'; | ||
export class Assets { | ||
constructor(_loaders) { | ||
this._loaders = _loaders; | ||
this.handlePool = new objectPool_1.ObjectPool(function () { return new ResourceHandle_1.ResourceHandle(); }); | ||
this.handlePool = new ObjectPool(() => new ResourceHandle()); | ||
this.handles = new Map(); | ||
this.load = function (loader, key) { | ||
var handle = _this.handles.get(_this.getKey(loader, key)); | ||
this.load = (loader, key) => { | ||
let handle = this.handles.get(this.getKey(loader, key)); | ||
if (!handle) { | ||
handle = _this.handlePool.acquire(); | ||
_this.handles.set(_this.getKey(loader, key), handle); | ||
_this._loaders[loader](key).then(function (value) { return handle.resolve(value); }); | ||
handle = this.handlePool.acquire(); | ||
this.handles.set(this.getKey(loader, key), handle); | ||
this._loaders[loader](key).then((value) => handle.resolve(value)); | ||
} | ||
return handle.promise; | ||
}; | ||
this.immediate = function (loader, key) { | ||
var handle = _this.handles.get(_this.getKey(loader, key)); | ||
this.immediate = (loader, key) => { | ||
const handle = this.handles.get(this.getKey(loader, key)); | ||
if (!handle) | ||
@@ -27,7 +23,5 @@ return null; | ||
}; | ||
this.getKey = function (loader, key) { return loader + ":" + key; }; | ||
this.getKey = (loader, key) => `${loader.toString()}:${key}`; | ||
} | ||
return Assets; | ||
}()); | ||
exports.Assets = Assets; | ||
} | ||
//# sourceMappingURL=Assets.js.map |
@@ -1,8 +0,8 @@ | ||
import { Poolable } from './internal/objectPool'; | ||
import { Poolable } from './internal/objectPool.js'; | ||
export declare const COMPONENT_CHANGE_HANDLE: unique symbol; | ||
declare type ComponentUpdateFn<T> = (updater: (self: T) => void) => void; | ||
declare type ComponentInitializeFn<T> = (instance: T, overrides: Partial<T>, id: number) => void; | ||
declare type ComponentSerialize<Comp> = (instance: Comp) => string; | ||
declare type ComponentDeserialize<Comp> = (serialized: string, additionalProperties: PropertyDescriptorMap) => Comp; | ||
export declare type ComponentInstance<T> = Poolable & T & { | ||
type ComponentUpdateFn<T> = (updater: (self: T) => void) => void; | ||
type ComponentInitializeFn<T> = (instance: T, overrides: Partial<T>, id: number) => void; | ||
type ComponentSerialize<Comp> = (instance: Comp) => string; | ||
type ComponentDeserialize<Comp> = (serialized: string, additionalProperties: PropertyDescriptorMap) => Comp; | ||
export type ComponentInstance<T> = Poolable & T & { | ||
update: ComponentUpdateFn<T>; | ||
@@ -14,3 +14,3 @@ updated: boolean; | ||
}; | ||
export declare type BaseComponentType<T> = { | ||
export type BaseComponentType<T> = { | ||
new (): ComponentInstance<T>; | ||
@@ -29,3 +29,3 @@ id: number; | ||
} | ||
export declare type ComponentType<T> = SerializedComponentType<T> | UnserializedComponentType<T>; | ||
export type ComponentType<T> = SerializedComponentType<T> | UnserializedComponentType<T>; | ||
export declare function Component<T>(defaults: () => T, { serialize, deserialize, }?: { | ||
@@ -36,3 +36,3 @@ serialize?: ComponentSerialize<T>; | ||
export declare function State<T>(defaults: () => T): UnserializedComponentType<T>; | ||
export declare type ComponentInstanceFor<T extends ComponentType<any>> = T extends ComponentType<infer Shape> ? ComponentInstance<Shape> : never; | ||
export type ComponentInstanceFor<T extends ComponentType<any>> = T extends ComponentType<infer Shape> ? ComponentInstance<Shape> : never; | ||
export {}; |
@@ -1,11 +0,8 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.State = exports.Component = exports.COMPONENT_CHANGE_HANDLE = void 0; | ||
exports.COMPONENT_CHANGE_HANDLE = Symbol('Component change handle'); | ||
export const COMPONENT_CHANGE_HANDLE = Symbol('Component change handle'); | ||
function defaultSerialize(instance) { | ||
var gettersAndSetters = {}; | ||
var data = {}; | ||
var descriptors = Object.getOwnPropertyDescriptors(instance); | ||
Object.keys(descriptors).forEach(function (key) { | ||
var descriptor = descriptors[key]; | ||
const gettersAndSetters = {}; | ||
const data = {}; | ||
const descriptors = Object.getOwnPropertyDescriptors(instance); | ||
Object.keys(descriptors).forEach((key) => { | ||
const descriptor = descriptors[key]; | ||
if (typeof (descriptor === null || descriptor === void 0 ? void 0 : descriptor.get) === 'function' || | ||
@@ -24,3 +21,3 @@ typeof (descriptor === null || descriptor === void 0 ? void 0 : descriptor.set) === 'function') { | ||
function defaultDeserialize(serialized, additionalProperties) { | ||
var data = JSON.parse(serialized); | ||
const data = JSON.parse(serialized); | ||
Object.defineProperties(data, additionalProperties); | ||
@@ -33,12 +30,10 @@ return data; | ||
} | ||
function BaseComponent(_a) { | ||
var _b; | ||
var defaults = _a.defaults; | ||
return _b = /** @class */ (function () { | ||
function BaseComponent() { | ||
var _this = this; | ||
function BaseComponent({ defaults, }) { | ||
var _a; | ||
return _a = class BaseComponent { | ||
constructor() { | ||
this.id = 0; | ||
this.__type = Object.getPrototypeOf(this).constructor.id; | ||
this.reset = function () { | ||
Object.getPrototypeOf(_this).constructor.initialize(_this, defaults(), 0); | ||
this.reset = () => { | ||
Object.getPrototypeOf(this).constructor.initialize(this, defaults(), 0); | ||
}; | ||
@@ -59,31 +54,25 @@ /** | ||
*/ | ||
this.update = function (updater) { | ||
updater(_this); | ||
_this.updated = true; | ||
this.update = (updater) => { | ||
updater(this); | ||
this.updated = true; | ||
}; | ||
Object.assign(this, defaults()); | ||
} | ||
Object.defineProperty(BaseComponent.prototype, "updated", { | ||
/** | ||
* This flag must be set whenever you make changes to a | ||
* Component instance which you want to be reported to | ||
* changed() filters in queries. | ||
*/ | ||
set: function (_) { | ||
var _a; | ||
(_a = this[exports.COMPONENT_CHANGE_HANDLE]) === null || _a === void 0 ? void 0 : _a.call(this, this); | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return BaseComponent; | ||
}()), | ||
_b.id = 0, | ||
_b.defaults = defaults, | ||
_b.initialize = defaultInitialize, | ||
_b; | ||
/** | ||
* This flag must be set whenever you make changes to a | ||
* Component instance which you want to be reported to | ||
* changed() filters in queries. | ||
*/ | ||
set updated(_) { | ||
var _b; | ||
(_b = this[COMPONENT_CHANGE_HANDLE]) === null || _b === void 0 ? void 0 : _b.call(this, this); | ||
} | ||
}, | ||
_a.id = 0, | ||
_a.defaults = defaults, | ||
_a.initialize = defaultInitialize, | ||
_a; | ||
} | ||
function Component(defaults, _a) { | ||
var _b = _a === void 0 ? {} : _a, _c = _b.serialize, serialize = _c === void 0 ? defaultSerialize : _c, _d = _b.deserialize, deserialize = _d === void 0 ? defaultDeserialize : _d; | ||
var Type = BaseComponent({ defaults: defaults }); | ||
export function Component(defaults, { serialize = defaultSerialize, deserialize = defaultDeserialize, } = {}) { | ||
const Type = BaseComponent({ defaults }); | ||
Type.serialize = serialize; | ||
@@ -94,9 +83,7 @@ Type.deserialize = deserialize; | ||
} | ||
exports.Component = Component; | ||
function State(defaults) { | ||
var Type = BaseComponent({ defaults: defaults }); | ||
export function State(defaults) { | ||
const Type = BaseComponent({ defaults }); | ||
Type.serialized = false; | ||
return Type; | ||
} | ||
exports.State = State; | ||
//# sourceMappingURL=Component.js.map |
@@ -1,3 +0,3 @@ | ||
import { ComponentType, ComponentInstance } from './Component'; | ||
import { Game } from './Game'; | ||
import { ComponentType, ComponentInstance } from './Component.js'; | ||
import { Game } from './Game.js'; | ||
/** | ||
@@ -12,2 +12,3 @@ * Manages pools of Components based on their Type, and | ||
private changed; | ||
private unsubscribes; | ||
constructor(componentTypes: ComponentType<any>[], game: Game); | ||
@@ -21,2 +22,3 @@ acquire: (typeId: number, initialValues: any) => any; | ||
getTypeName: (typeId: number) => string; | ||
destroy: () => void; | ||
} |
@@ -1,6 +0,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ComponentManager = void 0; | ||
var ComponentPool_1 = require("./ComponentPool"); | ||
var Component_1 = require("./Component"); | ||
import { ComponentPool } from './ComponentPool.js'; | ||
import { COMPONENT_CHANGE_HANDLE, } from './Component.js'; | ||
/** | ||
@@ -10,5 +7,4 @@ * Manages pools of Components based on their Type, and | ||
*/ | ||
var ComponentManager = /** @class */ (function () { | ||
function ComponentManager(componentTypes, game) { | ||
var _this = this; | ||
export class ComponentManager { | ||
constructor(componentTypes, game) { | ||
this.componentTypes = componentTypes; | ||
@@ -18,16 +14,17 @@ this.game = game; | ||
this.changed = new Array(); | ||
this.acquire = function (typeId, initialValues) { | ||
var component = _this.pools[typeId].acquire(initialValues, _this.game.idManager.get()); | ||
component[Component_1.COMPONENT_CHANGE_HANDLE] = _this.onComponentChanged; | ||
this.unsubscribes = new Array(); | ||
this.acquire = (typeId, initialValues) => { | ||
const component = this.pools[typeId].acquire(initialValues, this.game.idManager.get()); | ||
component[COMPONENT_CHANGE_HANDLE] = this.onComponentChanged; | ||
return component; | ||
}; | ||
this.release = function (instance) { | ||
delete instance[Component_1.COMPONENT_CHANGE_HANDLE]; | ||
return _this.pools[instance.__type].release(instance); | ||
this.release = (instance) => { | ||
delete instance[COMPONENT_CHANGE_HANDLE]; | ||
return this.pools[instance.__type].release(instance); | ||
}; | ||
this.wasChangedLastFrame = function (componentInstanceId) { | ||
return !!_this.changed[componentInstanceId]; | ||
this.wasChangedLastFrame = (componentInstanceId) => { | ||
return !!this.changed[componentInstanceId]; | ||
}; | ||
this.onComponentChanged = function (component) { | ||
_this.game.enqueueOperation({ | ||
this.onComponentChanged = (component) => { | ||
this.game.enqueueOperation({ | ||
op: 'markChanged', | ||
@@ -37,24 +34,26 @@ componentId: component.id, | ||
}; | ||
this.markChanged = function (component) { | ||
_this.changed[component.id] = true; | ||
this.markChanged = (component) => { | ||
this.changed[component.id] = true; | ||
}; | ||
this.resetChanged = function () { | ||
_this.changed.length = 0; | ||
this.resetChanged = () => { | ||
this.changed.length = 0; | ||
}; | ||
this.getTypeName = function (typeId) { | ||
return _this.pools[typeId].ComponentType.name; | ||
this.getTypeName = (typeId) => { | ||
return this.pools[typeId].ComponentType.name; | ||
}; | ||
this.destroy = () => { | ||
this.unsubscribes.forEach((unsub) => unsub()); | ||
this.pools.forEach((pool) => pool.destroy()); | ||
}; | ||
// initialize pools, one for each ComponentType by ID. ComponentType IDs are incrementing integers. | ||
Object.values(componentTypes).forEach(function (Type) { | ||
Object.values(componentTypes).forEach((Type) => { | ||
// assign an ID | ||
Type.id = game.idManager.get(); | ||
// create a pool | ||
_this.pools[Type.id] = new ComponentPool_1.ComponentPool(Type, _this.game); | ||
this.pools[Type.id] = new ComponentPool(Type, this.game); | ||
}); | ||
// TODO: right time to do this? | ||
game.on('preApplyOperations', this.resetChanged); | ||
this.unsubscribes.push(game.subscribe('preApplyOperations', this.resetChanged)); | ||
} | ||
return ComponentManager; | ||
}()); | ||
exports.ComponentManager = ComponentManager; | ||
} | ||
//# sourceMappingURL=ComponentManager.js.map |
@@ -1,3 +0,3 @@ | ||
import { Game } from './Game'; | ||
import { ComponentInstance, ComponentType } from './Component'; | ||
import { Game } from './Game.js'; | ||
import { ComponentInstance, ComponentType } from './Component.js'; | ||
export declare class ComponentPool<S> { | ||
@@ -8,5 +8,6 @@ private Type; | ||
constructor(Type: ComponentType<S>, game: Game); | ||
acquire(initial: Partial<S> | undefined, id: number): NonNullable<ComponentInstance<S>>; | ||
acquire(initial: Partial<S> | undefined, id: number): ComponentInstance<S>; | ||
release(instance: ComponentInstance<S>): void; | ||
get ComponentType(): ComponentType<S>; | ||
destroy: () => void; | ||
} |
@@ -1,31 +0,23 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ComponentPool = void 0; | ||
var objectPool_1 = require("./internal/objectPool"); | ||
var ComponentPool = /** @class */ (function () { | ||
function ComponentPool(Type, game) { | ||
var _this = this; | ||
import { ObjectPool } from './internal/objectPool.js'; | ||
export class ComponentPool { | ||
constructor(Type, game) { | ||
this.Type = Type; | ||
this.game = game; | ||
this.pool = new objectPool_1.ObjectPool(function () { return new _this.Type(); }); | ||
this.destroy = () => { | ||
this.pool.destory(); | ||
}; | ||
this.pool = new ObjectPool(() => new this.Type()); | ||
} | ||
ComponentPool.prototype.acquire = function (initial, id) { | ||
if (initial === void 0) { initial = {}; } | ||
var instance = this.pool.acquire(); | ||
acquire(initial = {}, id) { | ||
const instance = this.pool.acquire(); | ||
this.Type.initialize(instance, initial, id); | ||
return instance; | ||
}; | ||
ComponentPool.prototype.release = function (instance) { | ||
} | ||
release(instance) { | ||
this.pool.release(instance); | ||
}; | ||
Object.defineProperty(ComponentPool.prototype, "ComponentType", { | ||
get: function () { | ||
return this.Type; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return ComponentPool; | ||
}()); | ||
exports.ComponentPool = ComponentPool; | ||
} | ||
get ComponentType() { | ||
return this.Type; | ||
} | ||
} | ||
//# sourceMappingURL=ComponentPool.js.map |
@@ -1,2 +0,2 @@ | ||
import { Game } from './Game'; | ||
import { Game } from './Game.js'; | ||
export declare function compose(...systems: ((game: Game) => () => void)[]): (game: Game) => () => void; |
@@ -1,17 +0,9 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.compose = void 0; | ||
function compose() { | ||
var systems = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
systems[_i] = arguments[_i]; | ||
} | ||
return function (game) { | ||
var cleanups = systems.map(function (sys) { return sys(game); }); | ||
return function () { | ||
cleanups.forEach(function (cleanup) { return cleanup(); }); | ||
export function compose(...systems) { | ||
return (game) => { | ||
const cleanups = systems.map((sys) => sys(game)); | ||
return () => { | ||
cleanups.forEach((cleanup) => cleanup()); | ||
}; | ||
}; | ||
} | ||
exports.compose = compose; | ||
//# sourceMappingURL=compose.js.map |
@@ -1,4 +0,9 @@ | ||
import { Game } from './Game'; | ||
import { QueryComponentFilter } from './Query'; | ||
import { EntityImpostorFor } from './QueryIterator'; | ||
export declare function makeEffect<Filter extends QueryComponentFilter>(filter: Filter, effect: (entity: EntityImpostorFor<Filter>, game: Game, abortSignal: AbortSignal) => Generator<any> | void, cleanup?: (entity: EntityImpostorFor<Filter>, game: Game) => Generator<any> | void): (game: Game) => () => void; | ||
import { Game } from './Game.js'; | ||
import { QueryComponentFilter } from './Query.js'; | ||
import { EntityImpostorFor } from './QueryIterator.js'; | ||
type CleanupFn = () => void | Promise<void>; | ||
type CleanupResult = Promise<CleanupFn | void> | CleanupFn | void; | ||
export declare function makeEffect<Filter extends QueryComponentFilter>(filter: Filter, effect: (entity: EntityImpostorFor<Filter>, game: Game, info: { | ||
abortSignal: AbortSignal; | ||
}) => CleanupResult): (game: Game) => () => void; | ||
export {}; |
@@ -1,159 +0,46 @@ | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
export function makeEffect(filter, effect) { | ||
return function (game) { | ||
const query = game.queryManager.create(filter); | ||
const abortControllers = new Array(); | ||
const cleanups = new Array(); | ||
async function onEntityAdded(entityId) { | ||
const entity = game.get(entityId); | ||
if (!entity) { | ||
throw new Error(`Effect triggered for entity ${entityId}, but it was not found`); | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.makeEffect = void 0; | ||
function makeEffect(filter, effect, cleanup) { | ||
return function (game) { | ||
var query = game.queryManager.create(filter); | ||
var abortControllers = new Array(); | ||
function onEntityAdded(entityId) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var entity, abortController, result; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
entity = game.get(entityId); | ||
if (!entity) { | ||
throw new Error("Effect triggered for entity " + entityId + ", but it was not found"); | ||
} | ||
abortController = new AbortController(); | ||
abortControllers[entityId] = abortController; | ||
result = effect(entity, game, abortController.signal); | ||
if (!result) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, pullCancelable(result, abortController.signal)]; | ||
case 1: | ||
_a.sent(); | ||
_a.label = 2; | ||
case 2: return [2 /*return*/]; | ||
} | ||
}); | ||
const abortController = new AbortController(); | ||
abortControllers[entityId] = abortController; | ||
const result = effect(entity, game, { | ||
abortSignal: abortController.signal, | ||
}); | ||
if (result instanceof Promise) { | ||
cleanups[entityId] = () => { | ||
result.then((clean) => { | ||
clean === null || clean === void 0 ? void 0 : clean(); | ||
}); | ||
}; | ||
} | ||
else if (result) { | ||
cleanups[entityId] = result; | ||
} | ||
} | ||
function onEntityRemoved(entityId) { | ||
var _a; | ||
return __awaiter(this, void 0, void 0, function () { | ||
var entity, result; | ||
return __generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
(_a = abortControllers[entityId]) === null || _a === void 0 ? void 0 : _a.abort(); | ||
entity = game.get(entityId); | ||
if (!entity) { | ||
throw new Error("Effect cleanup triggered for entity " + entityId + ", but it was not found"); | ||
} | ||
result = cleanup(entity, game); | ||
if (!result) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, pull(result)]; | ||
case 1: | ||
_b.sent(); | ||
_b.label = 2; | ||
case 2: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
async function onEntityRemoved(entityId) { | ||
var _a, _b; | ||
(_a = abortControllers[entityId]) === null || _a === void 0 ? void 0 : _a.abort(); | ||
(_b = cleanups[entityId]) === null || _b === void 0 ? void 0 : _b.call(cleanups); | ||
} | ||
query.on('entityAdded', onEntityAdded); | ||
if (cleanup) { | ||
query.on('entityRemoved', onEntityRemoved); | ||
} | ||
return function () { | ||
query.off('entityAdded', onEntityAdded); | ||
if (cleanup) { | ||
query.off('entityRemoved', onEntityRemoved); | ||
const unsubscribes = [ | ||
query.subscribe('entityAdded', onEntityAdded), | ||
query.subscribe('entityRemoved', onEntityRemoved), | ||
]; | ||
return () => { | ||
for (const unsubscribe of unsubscribes) { | ||
unsubscribe(); | ||
} | ||
for (const cleanup of cleanups) { | ||
cleanup(); | ||
} | ||
}; | ||
}; | ||
} | ||
exports.makeEffect = makeEffect; | ||
function pull(generator, input) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _a, done, value, nextInput, _b; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
_a = generator.next(input), done = _a.done, value = _a.value; | ||
if (!(value instanceof Promise)) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, value]; | ||
case 1: | ||
_b = _c.sent(); | ||
return [3 /*break*/, 3]; | ||
case 2: | ||
_b = value; | ||
_c.label = 3; | ||
case 3: | ||
nextInput = _b; | ||
if (!!done) return [3 /*break*/, 5]; | ||
return [4 /*yield*/, pull(generator, nextInput)]; | ||
case 4: | ||
_c.sent(); | ||
_c.label = 5; | ||
case 5: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
function pullCancelable(generator, abortSignal, input) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var _a, done, value, nextInput, _b; | ||
return __generator(this, function (_c) { | ||
switch (_c.label) { | ||
case 0: | ||
if (abortSignal.aborted) | ||
return [2 /*return*/]; | ||
_a = generator.next(input), done = _a.done, value = _a.value; | ||
if (!(value instanceof Promise)) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, value]; | ||
case 1: | ||
_b = _c.sent(); | ||
return [3 /*break*/, 3]; | ||
case 2: | ||
_b = value; | ||
_c.label = 3; | ||
case 3: | ||
nextInput = _b; | ||
if (!!done) return [3 /*break*/, 5]; | ||
return [4 /*yield*/, pullCancelable(generator, abortSignal, nextInput)]; | ||
case 4: | ||
_c.sent(); | ||
_c.label = 5; | ||
case 5: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
} | ||
//# sourceMappingURL=Effect.js.map |
@@ -1,4 +0,4 @@ | ||
import { ComponentInstance, ComponentType } from './Component'; | ||
import { Poolable } from './internal/objectPool'; | ||
declare type DefinedInstance<Present extends ComponentType<any>, Omitted extends ComponentType<any>, Type extends ComponentType<any>> = Type extends Present ? InstanceType<Type> : Type extends Omitted ? never : InstanceType<Type> | null; | ||
import { ComponentInstance, ComponentType } from './Component.js'; | ||
import { Poolable } from './internal/objectPool.js'; | ||
type DefinedInstance<Present extends ComponentType<any>, Omitted extends ComponentType<any>, Type extends ComponentType<any>> = Type extends Present ? InstanceType<Type> : Type extends Omitted ? never : InstanceType<Type> | null; | ||
export declare class Entity<DefiniteComponents extends ComponentType<any> = ComponentType<any>, OmittedComponents extends ComponentType<any> = any> implements Poolable { | ||
@@ -5,0 +5,0 @@ private _id; |
@@ -1,7 +0,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Entity = void 0; | ||
var Entity = /** @class */ (function () { | ||
function Entity() { | ||
var _this = this; | ||
export class Entity { | ||
constructor() { | ||
this._id = 0; | ||
@@ -12,44 +8,36 @@ // TODO: make array | ||
// TODO: hide these behind Symbols? | ||
this.__set = function (entityId, components) { | ||
_this._id = entityId; | ||
_this.components.clear(); | ||
components.forEach(function (comp) { | ||
_this.components.set(comp.__type, comp); | ||
this.__set = (entityId, components) => { | ||
this._id = entityId; | ||
this.components.clear(); | ||
components.forEach((comp) => { | ||
this.components.set(comp.__type, comp); | ||
}); | ||
_this._destroyed = false; | ||
this._destroyed = false; | ||
}; | ||
this.__addComponent = function (instance) { | ||
_this.components.set(instance.__type, instance); | ||
this.__addComponent = (instance) => { | ||
this.components.set(instance.__type, instance); | ||
}; | ||
this.__removeComponent = function (typeId) { | ||
var instance = _this.components.get(typeId); | ||
_this.components.delete(typeId); | ||
this.__removeComponent = (typeId) => { | ||
const instance = this.components.get(typeId); | ||
this.components.delete(typeId); | ||
return instance; | ||
}; | ||
this.get = function (Type) { | ||
this.get = (Type) => { | ||
var _a; | ||
var instance = ((_a = _this.components.get(Type.id)) !== null && _a !== void 0 ? _a : null); | ||
console.assert(!instance || instance.id !== 0, "Entity tried to access recycled Component instance of type " + Type.name); | ||
const instance = ((_a = this.components.get(Type.id)) !== null && _a !== void 0 ? _a : null); | ||
console.assert(!instance || instance.id !== 0, `Entity tried to access recycled Component instance of type ${Type.name}`); | ||
return instance; | ||
}; | ||
this.maybeGet = function (Type) { | ||
this.maybeGet = (Type) => { | ||
var _a; | ||
return ((_a = _this.components.get(Type.id)) !== null && _a !== void 0 ? _a : null); | ||
return ((_a = this.components.get(Type.id)) !== null && _a !== void 0 ? _a : null); | ||
}; | ||
} | ||
Object.defineProperty(Entity.prototype, "id", { | ||
get: function () { | ||
return this._id; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Entity.prototype, "destroyed", { | ||
get: function () { | ||
return this._destroyed; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Entity.prototype.reset = function () { | ||
get id() { | ||
return this._id; | ||
} | ||
get destroyed() { | ||
return this._destroyed; | ||
} | ||
reset() { | ||
this.components.clear(); | ||
@@ -59,13 +47,10 @@ // disabled to diagnose issues... | ||
this._destroyed = true; | ||
}; | ||
Entity.prototype.clone = function (other) { | ||
var _this = this; | ||
other.components.forEach(function (value, key) { | ||
_this.components.set(key, value); | ||
} | ||
clone(other) { | ||
other.components.forEach((value, key) => { | ||
this.components.set(key, value); | ||
}); | ||
this._id = other.id; | ||
}; | ||
return Entity; | ||
}()); | ||
exports.Entity = Entity; | ||
} | ||
} | ||
//# sourceMappingURL=Entity.js.map |
@@ -1,3 +0,3 @@ | ||
import { ComponentType } from './Component'; | ||
export declare type Has<Comp extends ComponentType<any>> = { | ||
import { ComponentType } from './Component.js'; | ||
export type Has<Comp extends ComponentType<any>> = { | ||
Component: Comp; | ||
@@ -9,3 +9,3 @@ kind: 'has'; | ||
export declare const has: <Comp extends ComponentType<any>>(Component: Comp) => Has<Comp>; | ||
export declare type Not<Comp extends ComponentType<any>> = { | ||
export type Not<Comp extends ComponentType<any>> = { | ||
Component: Comp; | ||
@@ -17,3 +17,3 @@ kind: 'not'; | ||
export declare const not: <Comp extends ComponentType<any>>(Component: Comp) => Not<Comp>; | ||
export declare type Changed<Comp extends ComponentType<any>> = { | ||
export type Changed<Comp extends ComponentType<any>> = { | ||
Component: Comp; | ||
@@ -25,3 +25,3 @@ kind: 'changed'; | ||
export declare const changed: <Comp extends ComponentType<any>>(Component: Comp) => Changed<Comp>; | ||
export declare type Any<Comps extends ComponentType<any>[]> = { | ||
export type Any<Comps extends ComponentType<any>[]> = { | ||
Components: Comps; | ||
@@ -33,3 +33,3 @@ kind: 'any'; | ||
export declare const any: <Comps extends ComponentType<any>[]>(...Components: Comps) => Any<Comps>; | ||
export declare type Filter<Comp extends ComponentType<any>> = Not<Comp> | Has<Comp> | Changed<Comp> | Any<Comp[]>; | ||
export type Filter<Comp extends ComponentType<any>> = Not<Comp> | Has<Comp> | Changed<Comp> | Any<Comp[]>; | ||
export declare const isFilter: (thing: any) => thing is Filter<any>; | ||
@@ -36,0 +36,0 @@ export declare const isNotFilter: (fil: Filter<any>) => fil is Not<ComponentType<any>>; |
@@ -1,62 +0,38 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.isAnyFilter = exports.isChangedFilter = exports.isHasFilter = exports.isNotFilter = exports.isFilter = exports.any = exports.changed = exports.not = exports.has = void 0; | ||
var has = function (Component) { return ({ | ||
Component: Component, | ||
export const has = (Component) => ({ | ||
Component, | ||
kind: 'has', | ||
__isFilter: true, | ||
toString: function () { | ||
return "has(" + Component.name + ")"; | ||
toString() { | ||
return `has(${Component.name})`; | ||
}, | ||
}); }; | ||
exports.has = has; | ||
var not = function (Component) { return ({ | ||
Component: Component, | ||
}); | ||
export const not = (Component) => ({ | ||
Component, | ||
kind: 'not', | ||
__isFilter: true, | ||
toString: function () { | ||
return "not(" + Component.name + ")"; | ||
toString() { | ||
return `not(${Component.name})`; | ||
}, | ||
}); }; | ||
exports.not = not; | ||
var changed = function (Component) { return ({ | ||
Component: Component, | ||
}); | ||
export const changed = (Component) => ({ | ||
Component, | ||
kind: 'changed', | ||
__isFilter: true, | ||
toString: function () { | ||
return "changed(" + Component.name + ")"; | ||
toString() { | ||
return `changed(${Component.name})`; | ||
}, | ||
}); }; | ||
exports.changed = changed; | ||
var any = function () { | ||
var Components = []; | ||
for (var _i = 0; _i < arguments.length; _i++) { | ||
Components[_i] = arguments[_i]; | ||
} | ||
return ({ | ||
Components: Components, | ||
kind: 'any', | ||
__isFilter: true, | ||
toString: function () { | ||
return "any(" + Components.map(function (Comp) { return Comp.name; }).join(', ') + ")"; | ||
}, | ||
}); | ||
}; | ||
exports.any = any; | ||
var isFilter = function (thing) { | ||
return thing.__isFilter === true; | ||
}; | ||
exports.isFilter = isFilter; | ||
var isNotFilter = function (fil) { | ||
return fil.kind === 'not'; | ||
}; | ||
exports.isNotFilter = isNotFilter; | ||
var isHasFilter = function (fil) { | ||
return fil.kind === 'has'; | ||
}; | ||
exports.isHasFilter = isHasFilter; | ||
var isChangedFilter = function (fil) { return fil.kind === 'changed'; }; | ||
exports.isChangedFilter = isChangedFilter; | ||
var isAnyFilter = function (fil) { return fil.kind === 'any'; }; | ||
exports.isAnyFilter = isAnyFilter; | ||
}); | ||
export const any = (...Components) => ({ | ||
Components, | ||
kind: 'any', | ||
__isFilter: true, | ||
toString() { | ||
return `any(${Components.map((Comp) => Comp.name).join(', ')})`; | ||
}, | ||
}); | ||
export const isFilter = (thing) => thing.__isFilter === true; | ||
export const isNotFilter = (fil) => fil.kind === 'not'; | ||
export const isHasFilter = (fil) => fil.kind === 'has'; | ||
export const isChangedFilter = (fil) => fil.kind === 'changed'; | ||
export const isAnyFilter = (fil) => fil.kind === 'any'; | ||
//# sourceMappingURL=filters.js.map |
@@ -1,21 +0,20 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import { QueryManager } from './QueryManager'; | ||
import { ComponentType } from './Component'; | ||
import { ComponentManager } from './ComponentManager'; | ||
import { IdManager } from './IdManager'; | ||
import { ArchetypeManager } from './ArchetypeManager'; | ||
import { Operation } from './operations'; | ||
import { Entity } from './Entity'; | ||
import { Resources } from './Resources'; | ||
import { ObjectPool } from './internal/objectPool'; | ||
import { AssetLoaders, Globals } from '.'; | ||
import { Assets } from './Assets'; | ||
import { QueryComponentFilter } from './Query'; | ||
import { EntityImpostorFor } from './QueryIterator'; | ||
export declare type GameConstants = { | ||
import { QueryManager } from './QueryManager.js'; | ||
import { ComponentType } from './Component.js'; | ||
import { ComponentManager } from './ComponentManager.js'; | ||
import { IdManager } from './IdManager.js'; | ||
import { ArchetypeManager } from './ArchetypeManager.js'; | ||
import { Operation } from './operations.js'; | ||
import { Entity } from './Entity.js'; | ||
import { Resources } from './Resources.js'; | ||
import { ObjectPool } from './internal/objectPool.js'; | ||
import { Assets } from './Assets.js'; | ||
import { QueryComponentFilter } from './Query.js'; | ||
import { EntityImpostorFor } from './QueryIterator.js'; | ||
import type { AssetLoaders, Globals } from './index.js'; | ||
import { EventSubscriber } from '@a-type/utils'; | ||
export type GameConstants = { | ||
maxComponentId: number; | ||
maxEntities: number; | ||
}; | ||
export interface GameEvents { | ||
export type GameEvents = { | ||
preStep(): any; | ||
@@ -27,9 +26,4 @@ step(): any; | ||
destroyEntities(): any; | ||
} | ||
export declare interface Game { | ||
on<U extends keyof GameEvents>(event: U, callback: GameEvents[U]): this; | ||
off<U extends keyof GameEvents>(event: U, callback: GameEvents[U]): this; | ||
emit<U extends keyof GameEvents>(event: U, ...args: Parameters<GameEvents[U]>): boolean; | ||
} | ||
export declare class Game extends EventEmitter { | ||
}; | ||
export declare class Game extends EventSubscriber<GameEvents> { | ||
private _queryManager; | ||
@@ -75,3 +69,3 @@ private _idManager; | ||
*/ | ||
add: <ComponentShape>(entityId: number, Type: ComponentType<ComponentShape>, initial?: Partial<ComponentShape> | undefined) => void; | ||
add: <ComponentShape>(entityId: number, Type: ComponentType<ComponentShape>, initial?: Partial<ComponentShape>) => void; | ||
/** | ||
@@ -78,0 +72,0 @@ * Remove a component by type from an entity |
296
dist/Game.js
@@ -1,55 +0,26 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Game = void 0; | ||
var events_1 = require("events"); | ||
var QueryManager_1 = require("./QueryManager"); | ||
var ComponentManager_1 = require("./ComponentManager"); | ||
var IdManager_1 = require("./IdManager"); | ||
var ArchetypeManager_1 = require("./ArchetypeManager"); | ||
var Entity_1 = require("./Entity"); | ||
var Resources_1 = require("./Resources"); | ||
var objectPool_1 = require("./internal/objectPool"); | ||
var RemovedList_1 = require("./RemovedList"); | ||
var Assets_1 = require("./Assets"); | ||
var Game = /** @class */ (function (_super) { | ||
__extends(Game, _super); | ||
function Game(_a) { | ||
var components = _a.components, _b = _a.systems, systems = _b === void 0 ? [] : _b, _c = _a.assetLoaders, assetLoaders = _c === void 0 ? {} : _c; | ||
var _this = _super.call(this) || this; | ||
_this._idManager = new IdManager_1.IdManager(); | ||
_this._operationQueue = []; | ||
_this._globals = new Resources_1.Resources(); | ||
_this._entityPool = new objectPool_1.ObjectPool(function () { return new Entity_1.Entity(); }); | ||
_this._removedList = new RemovedList_1.RemovedList(); | ||
import { QueryManager } from './QueryManager.js'; | ||
import { ComponentManager } from './ComponentManager.js'; | ||
import { IdManager } from './IdManager.js'; | ||
import { ArchetypeManager } from './ArchetypeManager.js'; | ||
import { Entity } from './Entity.js'; | ||
import { Resources } from './Resources.js'; | ||
import { ObjectPool } from './internal/objectPool.js'; | ||
import { RemovedList } from './RemovedList.js'; | ||
import { Assets } from './Assets.js'; | ||
import { EventSubscriber } from '@a-type/utils'; | ||
export class Game extends EventSubscriber { | ||
constructor({ components, systems = [], assetLoaders = {}, }) { | ||
super(); | ||
this._idManager = new IdManager(); | ||
this._operationQueue = []; | ||
this._globals = new Resources(); | ||
this._entityPool = new ObjectPool(() => new Entity()); | ||
this._removedList = new RemovedList(); | ||
// TODO: configurable? | ||
_this._phases = ['preStep', 'step', 'postStep']; | ||
_this._delta = 0; | ||
_this._time = 0; | ||
_this._constants = { | ||
this._phases = ['preStep', 'step', 'postStep']; | ||
this._delta = 0; | ||
this._time = 0; | ||
this._constants = { | ||
maxComponentId: 256, | ||
maxEntities: Math.pow(2, 16), | ||
maxEntities: 2 ** 16, | ||
}; | ||
@@ -59,5 +30,5 @@ /** | ||
*/ | ||
_this.create = function () { | ||
var id = _this.idManager.get(); | ||
_this._operationQueue.push({ | ||
this.create = () => { | ||
const id = this.idManager.get(); | ||
this._operationQueue.push({ | ||
op: 'createEntity', | ||
@@ -71,4 +42,4 @@ entityId: id, | ||
*/ | ||
_this.destroy = function (id) { | ||
_this._operationQueue.push({ | ||
this.destroy = (id) => { | ||
this._operationQueue.push({ | ||
op: 'removeEntity', | ||
@@ -81,6 +52,6 @@ entityId: id, | ||
*/ | ||
_this.add = function (entityId, Type, initial) { | ||
_this._operationQueue.push({ | ||
this.add = (entityId, Type, initial) => { | ||
this._operationQueue.push({ | ||
op: 'addComponent', | ||
entityId: entityId, | ||
entityId, | ||
componentType: Type.id, | ||
@@ -93,6 +64,6 @@ initialValues: initial, | ||
*/ | ||
_this.remove = function (entityId, Type) { | ||
_this._operationQueue.push({ | ||
this.remove = (entityId, Type) => { | ||
this._operationQueue.push({ | ||
op: 'removeComponent', | ||
entityId: entityId, | ||
entityId, | ||
componentType: Type.id, | ||
@@ -104,5 +75,5 @@ }); | ||
*/ | ||
_this.get = function (entityId) { | ||
this.get = (entityId) => { | ||
var _a; | ||
return ((_a = _this.archetypeManager.getEntity(entityId)) !== null && _a !== void 0 ? _a : _this._removedList.get(entityId)); | ||
return ((_a = this.archetypeManager.getEntity(entityId)) !== null && _a !== void 0 ? _a : this._removedList.get(entityId)); | ||
}; | ||
@@ -112,19 +83,8 @@ /** | ||
*/ | ||
_this.query = function (filter, run) { | ||
var e_1, _a; | ||
var query = _this._queryManager.create(filter); | ||
var ent; | ||
try { | ||
for (var query_1 = __values(query), query_1_1 = query_1.next(); !query_1_1.done; query_1_1 = query_1.next()) { | ||
ent = query_1_1.value; | ||
run(ent, _this); | ||
} | ||
this.query = (filter, run) => { | ||
const query = this._queryManager.create(filter); | ||
let ent; | ||
for (ent of query) { | ||
run(ent, this); | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (query_1_1 && !query_1_1.done && (_a = query_1.return)) _a.call(query_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}; | ||
@@ -135,31 +95,31 @@ /** | ||
*/ | ||
_this.step = function (delta) { | ||
_this._delta = delta; | ||
_this._phases.forEach(function (phase) { | ||
_this.emit(phase); | ||
this.step = (delta) => { | ||
this._delta = delta; | ||
this._phases.forEach((phase) => { | ||
this.emit(phase); | ||
}); | ||
_this.emit('destroyEntities'); | ||
_this._removedList.flush(_this.destroyEntity); | ||
_this.emit('preApplyOperations'); | ||
_this.flushOperations(); | ||
_this.emit('stepComplete'); | ||
this.emit('destroyEntities'); | ||
this._removedList.flush(this.destroyEntity); | ||
this.emit('preApplyOperations'); | ||
this.flushOperations(); | ||
this.emit('stepComplete'); | ||
}; | ||
_this.enqueueOperation = function (operation) { | ||
_this._operationQueue.push(operation); | ||
this.enqueueOperation = (operation) => { | ||
this._operationQueue.push(operation); | ||
}; | ||
_this.destroyEntity = function (entity) { | ||
entity.components.forEach(function (instance) { | ||
this.destroyEntity = (entity) => { | ||
entity.components.forEach((instance) => { | ||
if (instance) | ||
_this.componentManager.release(instance); | ||
this.componentManager.release(instance); | ||
}); | ||
_this.entityPool.release(entity); | ||
this.entityPool.release(entity); | ||
}; | ||
_this.flushOperations = function () { | ||
while (_this._operationQueue.length) { | ||
_this.applyOperation(_this._operationQueue.shift()); | ||
this.flushOperations = () => { | ||
while (this._operationQueue.length) { | ||
this.applyOperation(this._operationQueue.shift()); | ||
} | ||
}; | ||
_this.applyOperation = function (operation) { | ||
var instance; | ||
var entity; | ||
this.applyOperation = (operation) => { | ||
let instance; | ||
let entity; | ||
switch (operation.op) { | ||
@@ -169,4 +129,4 @@ case 'addComponent': | ||
break; | ||
instance = _this.componentManager.acquire(operation.componentType, operation.initialValues); | ||
_this.archetypeManager.addComponent(operation.entityId, instance); | ||
instance = this.componentManager.acquire(operation.componentType, operation.initialValues); | ||
this.archetypeManager.addComponent(operation.entityId, instance); | ||
break; | ||
@@ -176,9 +136,9 @@ case 'removeComponent': | ||
break; | ||
instance = _this.archetypeManager.removeComponent(operation.entityId, operation.componentType); | ||
instance = this.archetypeManager.removeComponent(operation.entityId, operation.componentType); | ||
if (instance) { | ||
_this.componentManager.release(instance); | ||
this.componentManager.release(instance); | ||
} | ||
break; | ||
case 'createEntity': | ||
_this.archetypeManager.createEntity(operation.entityId); | ||
this.archetypeManager.createEntity(operation.entityId); | ||
break; | ||
@@ -188,91 +148,47 @@ case 'removeEntity': | ||
break; | ||
entity = _this.archetypeManager.destroyEntity(operation.entityId); | ||
_this._removedList.add(entity); | ||
entity = this.archetypeManager.destroyEntity(operation.entityId); | ||
this._removedList.add(entity); | ||
break; | ||
case 'markChanged': | ||
_this.componentManager.markChanged(operation.componentId); | ||
this.componentManager.markChanged(operation.componentId); | ||
break; | ||
} | ||
}; | ||
_this.setMaxListeners(Infinity); | ||
_this._componentManager = new ComponentManager_1.ComponentManager(components, _this); | ||
_this._assets = new Assets_1.Assets(assetLoaders); | ||
_this._queryManager = new QueryManager_1.QueryManager(_this); | ||
_this._archetypeManager = new ArchetypeManager_1.ArchetypeManager(_this); | ||
_this._runnableCleanups = systems.map(function (sys) { return sys(_this); }); | ||
return _this; | ||
this._componentManager = new ComponentManager(components, this); | ||
this._assets = new Assets(assetLoaders); | ||
this._queryManager = new QueryManager(this); | ||
this._archetypeManager = new ArchetypeManager(this); | ||
this._runnableCleanups = systems.map((sys) => sys(this)); | ||
} | ||
Object.defineProperty(Game.prototype, "idManager", { | ||
get: function () { | ||
return this._idManager; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "componentManager", { | ||
get: function () { | ||
return this._componentManager; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "archetypeManager", { | ||
get: function () { | ||
return this._archetypeManager; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "delta", { | ||
get: function () { | ||
return this._delta; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "time", { | ||
get: function () { | ||
return this._time; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "queryManager", { | ||
get: function () { | ||
return this._queryManager; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "constants", { | ||
get: function () { | ||
return this._constants; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "globals", { | ||
get: function () { | ||
return this._globals; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "assets", { | ||
get: function () { | ||
return this._assets; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Game.prototype, "entityPool", { | ||
get: function () { | ||
return this._entityPool; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return Game; | ||
}(events_1.EventEmitter)); | ||
exports.Game = Game; | ||
get idManager() { | ||
return this._idManager; | ||
} | ||
get componentManager() { | ||
return this._componentManager; | ||
} | ||
get archetypeManager() { | ||
return this._archetypeManager; | ||
} | ||
get delta() { | ||
return this._delta; | ||
} | ||
get time() { | ||
return this._time; | ||
} | ||
get queryManager() { | ||
return this._queryManager; | ||
} | ||
get constants() { | ||
return this._constants; | ||
} | ||
get globals() { | ||
return this._globals; | ||
} | ||
get assets() { | ||
return this._assets; | ||
} | ||
get entityPool() { | ||
return this._entityPool; | ||
} | ||
} | ||
//# sourceMappingURL=Game.js.map |
export {}; |
@@ -1,62 +0,33 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var Game_1 = require("./Game"); | ||
var Component_1 = require("./Component"); | ||
var A = /** @class */ (function (_super) { | ||
__extends(A, _super); | ||
function A() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return A; | ||
}(Component_1.Component(function () { return ({}); }))); | ||
var B = /** @class */ (function (_super) { | ||
__extends(B, _super); | ||
function B() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return B; | ||
}(Component_1.Component(function () { return ({}); }))); | ||
var C = /** @class */ (function (_super) { | ||
__extends(C, _super); | ||
function C() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
} | ||
return C; | ||
}(Component_1.Component(function () { return ({}); }))); | ||
describe('Game', function () { | ||
var game; | ||
beforeEach(function () { | ||
game = new Game_1.Game({ | ||
import { Game } from './Game.js'; | ||
import { Component } from './Component.js'; | ||
import { describe, it, beforeEach, expect } from 'vitest'; | ||
class A extends Component(() => ({})) { | ||
} | ||
class B extends Component(() => ({})) { | ||
} | ||
class C extends Component(() => ({})) { | ||
} | ||
describe('Game', () => { | ||
let game; | ||
beforeEach(() => { | ||
game = new Game({ | ||
components: [A, B, C], | ||
}); | ||
}); | ||
it('can ad-hoc query', function () { | ||
var matches = []; | ||
var withA = game.create(); | ||
it('can ad-hoc query', () => { | ||
const matches = []; | ||
const withA = game.create(); | ||
game.add(withA, A); | ||
var withAB = game.create(); | ||
const withAB = game.create(); | ||
game.add(withAB, A); | ||
game.add(withAB, B); | ||
var withABC = game.create(); | ||
const withABC = game.create(); | ||
game.add(withABC, A); | ||
game.add(withABC, B); | ||
game.add(withABC, C); | ||
var withC = game.create(); | ||
const withC = game.create(); | ||
game.add(withC, C); | ||
// step to run create enqueued operations | ||
game.step(0); | ||
game.query([A, B], function (ent) { | ||
game.query([A, B], (ent) => { | ||
matches.push(ent.id); | ||
@@ -63,0 +34,0 @@ }); |
@@ -0,0 +0,0 @@ /** |
@@ -1,5 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.IdManager = void 0; | ||
var ids_1 = require("./ids"); | ||
import { incrementIdVersion, SIGNIFIER_MASK } from './ids.js'; | ||
/** | ||
@@ -9,4 +6,4 @@ * Provides monotonically increasing ID numbers. Allows | ||
*/ | ||
var IdManager = /** @class */ (function () { | ||
function IdManager() { | ||
export class IdManager { | ||
constructor() { | ||
this.recycled = new Array(); | ||
@@ -16,7 +13,7 @@ this.active = new Array(); | ||
} | ||
IdManager.prototype.get = function () { | ||
var id; | ||
get() { | ||
let id; | ||
id = this.recycled.shift(); | ||
if (!id) { | ||
if (this.allocatedCount >= ids_1.SIGNIFIER_MASK) { | ||
if (this.allocatedCount >= SIGNIFIER_MASK) { | ||
throw new Error('Ran out of IDs'); | ||
@@ -28,14 +25,12 @@ } | ||
return id; | ||
}; | ||
IdManager.prototype.release = function (id) { | ||
var index = this.active.indexOf(id); | ||
} | ||
release(id) { | ||
const index = this.active.indexOf(id); | ||
if (index === -1) { | ||
throw new Error("Tried to release inactive ID " + id); | ||
throw new Error(`Tried to release inactive ID ${id}`); | ||
} | ||
this.active.splice(index); | ||
this.recycled.push(ids_1.incrementIdVersion(id)); | ||
}; | ||
return IdManager; | ||
}()); | ||
exports.IdManager = IdManager; | ||
this.recycled.push(incrementIdVersion(id)); | ||
} | ||
} | ||
//# sourceMappingURL=IdManager.js.map |
@@ -0,0 +0,0 @@ /** |
@@ -1,2 +0,1 @@ | ||
"use strict"; | ||
/** | ||
@@ -10,6 +9,4 @@ * IDs = 32-bit integers. | ||
*/ | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.incrementIdVersion = exports.setIdVersion = exports.getIdVersion = exports.getIdSignifier = exports.SIGNIFIER_MASK = exports.VERSION_MASK = void 0; | ||
exports.VERSION_MASK = 4278190080; | ||
exports.SIGNIFIER_MASK = 16777215; | ||
export const VERSION_MASK = 0b11111111000000000000000000000000; | ||
export const SIGNIFIER_MASK = 0b00000000111111111111111111111111; | ||
/** | ||
@@ -19,23 +16,19 @@ * Gets only the portion of the ID that signifes the | ||
*/ | ||
function getIdSignifier(id) { | ||
export function getIdSignifier(id) { | ||
// mask out high 8 bits | ||
return exports.SIGNIFIER_MASK & id; | ||
return SIGNIFIER_MASK & id; | ||
} | ||
exports.getIdSignifier = getIdSignifier; | ||
/** | ||
* Gets only the version portion of the ID | ||
*/ | ||
function getIdVersion(id) { | ||
export function getIdVersion(id) { | ||
return id >>> 24; | ||
} | ||
exports.getIdVersion = getIdVersion; | ||
function setIdVersion(id, version) { | ||
export function setIdVersion(id, version) { | ||
version = version % 255 << 24; | ||
return id | version; | ||
} | ||
exports.setIdVersion = setIdVersion; | ||
function incrementIdVersion(id) { | ||
export function incrementIdVersion(id) { | ||
return setIdVersion(id, getIdVersion(id) + 1); | ||
} | ||
exports.incrementIdVersion = incrementIdVersion; | ||
//# sourceMappingURL=ids.js.map |
@@ -1,9 +0,9 @@ | ||
import { AssetLoader } from './Assets'; | ||
export * from './Game'; | ||
export * from './Query'; | ||
export * from './Component'; | ||
export * from './System'; | ||
export * from './filters'; | ||
export * from './Effect'; | ||
export * from './compose'; | ||
import { AssetLoader } from './Assets.js'; | ||
export * from './Game.js'; | ||
export * from './Query.js'; | ||
export * from './Component.js'; | ||
export * from './System.js'; | ||
export * from './filters.js'; | ||
export * from './Effect.js'; | ||
export * from './compose.js'; | ||
export interface Globals { | ||
@@ -10,0 +10,0 @@ [key: string]: any; |
@@ -1,20 +0,8 @@ | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__exportStar(require("./Game"), exports); | ||
__exportStar(require("./Query"), exports); | ||
__exportStar(require("./Component"), exports); | ||
__exportStar(require("./System"), exports); | ||
__exportStar(require("./filters"), exports); | ||
__exportStar(require("./Effect"), exports); | ||
__exportStar(require("./compose"), exports); | ||
export * from './Game.js'; | ||
export * from './Query.js'; | ||
export * from './Component.js'; | ||
export * from './System.js'; | ||
export * from './filters.js'; | ||
export * from './Effect.js'; | ||
export * from './compose.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
export * from './keyboard'; | ||
export * from './pointer'; | ||
export * from './keyboard.js'; | ||
export * from './pointer.js'; |
@@ -1,15 +0,3 @@ | ||
"use strict"; | ||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
}) : (function(o, m, k, k2) { | ||
if (k2 === undefined) k2 = k; | ||
o[k2] = m[k]; | ||
})); | ||
var __exportStar = (this && this.__exportStar) || function(m, exports) { | ||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__exportStar(require("./keyboard"), exports); | ||
__exportStar(require("./pointer"), exports); | ||
export * from './keyboard.js'; | ||
export * from './pointer.js'; | ||
//# sourceMappingURL=index.js.map |
@@ -1,2 +0,2 @@ | ||
export declare type KeyboardKey = 'Alt' | 'Control' | 'Shift' | 'Enter' | 'Tab' | ' ' | 'ArrowDown' | 'ArrowLeft' | 'ArrowUp' | 'ArrowRight' | 'Escape' | 'w' | 'a' | 's' | 'd'; | ||
export type KeyboardKey = string; | ||
export declare class Keyboard { | ||
@@ -9,8 +9,8 @@ private keysPressed; | ||
private handleKeyUp; | ||
getKeyPressed(key: KeyboardKey): boolean; | ||
getKeyDown(key: KeyboardKey): boolean; | ||
getKeyUp(key: KeyboardKey): boolean; | ||
getAllPressedKeys(): Set<string>; | ||
frame(): void; | ||
getKeyPressed: (key: KeyboardKey) => boolean; | ||
getKeyDown: (key: KeyboardKey) => boolean; | ||
getKeyUp: (key: KeyboardKey) => boolean; | ||
getAllPressedKeys: () => Set<string>; | ||
frame: () => void; | ||
} | ||
export declare const keyboard: Keyboard; |
@@ -1,46 +0,43 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.keyboard = exports.Keyboard = void 0; | ||
var Keyboard = /** @class */ (function () { | ||
function Keyboard() { | ||
var _this = this; | ||
export class Keyboard { | ||
constructor() { | ||
this.keysPressed = new Set(); | ||
this.keysDown = new Set(); | ||
this.keysUp = new Set(); | ||
this.handleKeyDown = function (ev) { | ||
var key = ev.key; | ||
this.handleKeyDown = (ev) => { | ||
if (ev.target === document.body) { | ||
ev.preventDefault(); | ||
} | ||
const key = ev.key; | ||
// avoid key-repeat triggering? | ||
if (!_this.keysPressed.has(key)) { | ||
_this.keysPressed.add(key); | ||
_this.keysDown.add(key); | ||
if (!this.keysPressed.has(key)) { | ||
this.keysPressed.add(key); | ||
this.keysDown.add(key); | ||
} | ||
}; | ||
this.handleKeyUp = function (ev) { | ||
var key = ev.key; | ||
_this.keysPressed.delete(ev.key); | ||
_this.keysUp.add(key); | ||
this.handleKeyUp = (ev) => { | ||
const key = ev.key; | ||
this.keysPressed.delete(ev.key); | ||
this.keysUp.add(key); | ||
}; | ||
this.getKeyPressed = (key) => { | ||
return this.keysPressed.has(key); | ||
}; | ||
this.getKeyDown = (key) => { | ||
return this.keysDown.has(key); | ||
}; | ||
this.getKeyUp = (key) => { | ||
return this.keysUp.has(key); | ||
}; | ||
this.getAllPressedKeys = () => { | ||
return this.keysPressed; | ||
}; | ||
this.frame = () => { | ||
this.keysDown.clear(); | ||
this.keysUp.clear(); | ||
}; | ||
window.addEventListener('keydown', this.handleKeyDown); | ||
window.addEventListener('keyup', this.handleKeyUp); | ||
} | ||
Keyboard.prototype.getKeyPressed = function (key) { | ||
return this.keysPressed.has(key); | ||
}; | ||
Keyboard.prototype.getKeyDown = function (key) { | ||
return this.keysDown.has(key); | ||
}; | ||
Keyboard.prototype.getKeyUp = function (key) { | ||
return this.keysUp.has(key); | ||
}; | ||
Keyboard.prototype.getAllPressedKeys = function () { | ||
return this.keysPressed; | ||
}; | ||
Keyboard.prototype.frame = function () { | ||
this.keysDown.clear(); | ||
this.keysUp.clear(); | ||
}; | ||
return Keyboard; | ||
}()); | ||
exports.Keyboard = Keyboard; | ||
exports.keyboard = new Keyboard(); | ||
} | ||
export const keyboard = new Keyboard(); | ||
//# sourceMappingURL=keyboard.js.map |
@@ -23,4 +23,4 @@ export declare class Pointer { | ||
get secondaryUp(): boolean; | ||
frame(): void; | ||
frame: () => void; | ||
} | ||
export declare const pointer: Pointer; |
@@ -1,7 +0,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.pointer = exports.Pointer = void 0; | ||
var Pointer = /** @class */ (function () { | ||
function Pointer() { | ||
var _this = this; | ||
export class Pointer { | ||
constructor() { | ||
this._position = null; | ||
@@ -14,18 +10,18 @@ this._primaryPressed = false; | ||
this._secondaryUp = false; | ||
this.handlePointerDownEvents = function (ev) { | ||
if (!_this._position) { | ||
_this._position = { x: ev.clientX, y: ev.clientY }; | ||
this.handlePointerDownEvents = (ev) => { | ||
if (!this._position) { | ||
this._position = { x: ev.clientX, y: ev.clientY }; | ||
} | ||
else { | ||
_this._position.x = ev.clientX; | ||
_this._position.y = ev.clientY; | ||
this._position.x = ev.clientX; | ||
this._position.y = ev.clientY; | ||
} | ||
if (ev.type === 'pointerdown') { | ||
if (ev.isPrimary) { | ||
_this._primaryDown = true; | ||
_this._primaryPressed = true; | ||
this._primaryDown = true; | ||
this._primaryPressed = true; | ||
} | ||
else { | ||
_this._secondaryDown = true; | ||
_this._secondaryPressed = true; | ||
this._secondaryDown = true; | ||
this._secondaryPressed = true; | ||
} | ||
@@ -35,14 +31,20 @@ } | ||
if (ev.isPrimary) { | ||
_this._primaryUp = true; | ||
_this._primaryPressed = false; | ||
this._primaryUp = true; | ||
this._primaryPressed = false; | ||
} | ||
else { | ||
_this._secondaryUp = true; | ||
_this._secondaryPressed = false; | ||
this._secondaryUp = true; | ||
this._secondaryPressed = false; | ||
} | ||
} | ||
}; | ||
this.handlePointerMoveEvent = function (ev) { | ||
_this._position = { x: ev.clientX, y: ev.clientY }; | ||
this.handlePointerMoveEvent = (ev) => { | ||
this._position = { x: ev.clientX, y: ev.clientY }; | ||
}; | ||
this.frame = () => { | ||
this._primaryDown = false; | ||
this._primaryUp = false; | ||
this._secondaryDown = false; | ||
this._secondaryUp = false; | ||
}; | ||
window.addEventListener('pointerdown', this.handlePointerDownEvents); | ||
@@ -52,62 +54,26 @@ window.addEventListener('pointerup', this.handlePointerDownEvents); | ||
} | ||
Object.defineProperty(Pointer.prototype, "position", { | ||
/** Position might be null - that means no pointer was detected */ | ||
get: function () { | ||
return this._position; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Pointer.prototype, "primaryPressed", { | ||
get: function () { | ||
return this._primaryPressed; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Pointer.prototype, "primaryDown", { | ||
get: function () { | ||
return this._primaryDown; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Pointer.prototype, "primaryUp", { | ||
get: function () { | ||
return this._primaryUp; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Pointer.prototype, "secondaryPressed", { | ||
get: function () { | ||
return this._secondaryPressed; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Pointer.prototype, "secondaryDown", { | ||
get: function () { | ||
return this._secondaryDown; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Pointer.prototype, "secondaryUp", { | ||
get: function () { | ||
return this._secondaryUp; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Pointer.prototype.frame = function () { | ||
this._primaryDown = false; | ||
this._primaryUp = false; | ||
this._secondaryDown = false; | ||
this._secondaryUp = false; | ||
}; | ||
return Pointer; | ||
}()); | ||
exports.Pointer = Pointer; | ||
exports.pointer = new Pointer(); | ||
/** Position might be null - that means no pointer was detected */ | ||
get position() { | ||
return this._position; | ||
} | ||
get primaryPressed() { | ||
return this._primaryPressed; | ||
} | ||
get primaryDown() { | ||
return this._primaryDown; | ||
} | ||
get primaryUp() { | ||
return this._primaryUp; | ||
} | ||
get secondaryPressed() { | ||
return this._secondaryPressed; | ||
} | ||
get secondaryDown() { | ||
return this._secondaryDown; | ||
} | ||
get secondaryUp() { | ||
return this._secondaryUp; | ||
} | ||
} | ||
export const pointer = new Pointer(); | ||
//# sourceMappingURL=pointer.js.map |
export declare function mapValues<V, T extends Record<string, V>, U>(src: T, mapper: (v: V) => U): Record<string, U>; |
@@ -1,35 +0,9 @@ | ||
"use strict"; | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.mapValues = void 0; | ||
function mapValues(src, mapper) { | ||
var e_1, _a; | ||
var mapped = {}; | ||
var entry; | ||
try { | ||
for (var _b = __values(Object.entries(src)), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
entry = _c.value; | ||
mapped[entry[0]] = mapper(entry[1]); | ||
} | ||
export function mapValues(src, mapper) { | ||
const mapped = {}; | ||
let entry; | ||
for (entry of Object.entries(src)) { | ||
mapped[entry[0]] = mapper(entry[1]); | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
return mapped; | ||
} | ||
exports.mapValues = mapValues; | ||
//# sourceMappingURL=mapValues.js.map |
@@ -9,3 +9,3 @@ export interface Poolable { | ||
constructor(factory: () => T, initialSize?: number); | ||
acquire(): NonNullable<T>; | ||
acquire(): T; | ||
release(item: T): void; | ||
@@ -16,2 +16,3 @@ expand(count: number): void; | ||
get usedCount(): number; | ||
destory: () => void; | ||
} |
@@ -1,14 +0,13 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ObjectPool = void 0; | ||
var logger_1 = require("../logger"); | ||
var ObjectPool = /** @class */ (function () { | ||
function ObjectPool(factory, initialSize) { | ||
if (initialSize === void 0) { initialSize = 1; } | ||
import { logger } from '../logger.js'; | ||
export class ObjectPool { | ||
constructor(factory, initialSize = 1) { | ||
this.factory = factory; | ||
this.free = new Array(); | ||
this.count = 0; | ||
this.destory = () => { | ||
this.free.length = 0; | ||
}; | ||
this.expand(initialSize); | ||
} | ||
ObjectPool.prototype.acquire = function () { | ||
acquire() { | ||
// Grow the list by 20%ish if we're out | ||
@@ -20,7 +19,7 @@ if (this.free.length <= 0) { | ||
return item; | ||
}; | ||
ObjectPool.prototype.release = function (item) { | ||
} | ||
release(item) { | ||
var _a; | ||
if (!item) { | ||
logger_1.logger.warn("Tried to release " + item); | ||
logger.warn(`Tried to release ${item}`); | ||
return; | ||
@@ -30,4 +29,4 @@ } | ||
this.free.push(item); | ||
}; | ||
ObjectPool.prototype.expand = function (count) { | ||
} | ||
expand(count) { | ||
for (var n = 0; n < count; n++) { | ||
@@ -38,27 +37,13 @@ var clone = this.factory(); | ||
this.count += count; | ||
}; | ||
Object.defineProperty(ObjectPool.prototype, "size", { | ||
get: function () { | ||
return this.count; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ObjectPool.prototype, "freeCount", { | ||
get: function () { | ||
return this.free.length; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ObjectPool.prototype, "usedCount", { | ||
get: function () { | ||
return this.count - this.free.length; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return ObjectPool; | ||
}()); | ||
exports.ObjectPool = ObjectPool; | ||
} | ||
get size() { | ||
return this.count; | ||
} | ||
get freeCount() { | ||
return this.free.length; | ||
} | ||
get usedCount() { | ||
return this.count - this.free.length; | ||
} | ||
} | ||
//# sourceMappingURL=objectPool.js.map |
@@ -1,5 +0,5 @@ | ||
declare type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; | ||
declare type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never; | ||
declare type Push<T extends any[], V> = [...T, V]; | ||
export declare type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>; | ||
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (k: infer I) => void ? I : never; | ||
type LastOf<T> = UnionToIntersection<T extends any ? () => T : never> extends () => infer R ? R : never; | ||
type Push<T extends any[], V> = [...T, V]; | ||
export type TuplifyUnion<T, L = LastOf<T>, N = [T] extends [never] ? true : false> = true extends N ? [] : Push<TuplifyUnion<Exclude<T, L>>, L>; | ||
export {}; |
@@ -1,3 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
export {}; | ||
//# sourceMappingURL=utilTypes.js.map |
@@ -0,0 +0,0 @@ export declare const logger: { |
@@ -1,34 +0,7 @@ | ||
"use strict"; | ||
var __read = (this && this.__read) || function (o, n) { | ||
var m = typeof Symbol === "function" && o[Symbol.iterator]; | ||
if (!m) return o; | ||
var i = m.call(o), r, ar = [], e; | ||
try { | ||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); | ||
} | ||
catch (error) { e = { error: error }; } | ||
finally { | ||
try { | ||
if (r && !r.done && (m = i["return"])) m.call(i); | ||
} | ||
finally { if (e) throw e.error; } | ||
} | ||
return ar; | ||
}; | ||
var __spread = (this && this.__spread) || function () { | ||
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); | ||
return ar; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.logger = void 0; | ||
var doLog = function (level) { | ||
var messages = []; | ||
for (var _i = 1; _i < arguments.length; _i++) { | ||
messages[_i - 1] = arguments[_i]; | ||
} | ||
const doLog = (level, ...messages) => { | ||
if (localStorage.getItem('DEBUG') === 'true' || window.DEBUG) { | ||
console[level].apply(console, __spread(messages)); | ||
console[level](...messages); | ||
} | ||
}; | ||
exports.logger = { | ||
export const logger = { | ||
info: doLog.bind(null, 'info'), | ||
@@ -35,0 +8,0 @@ warn: doLog.bind(null, 'warn'), |
@@ -29,3 +29,3 @@ export interface AddComponentOperation { | ||
} | ||
export declare type Operation = AddComponentOperation | RemoveComponentOperation | RemoveEntityOperation | CreateEntityOperation | MarkChangedOperation; | ||
export declare type OperationQueue = Operation[]; | ||
export type Operation = AddComponentOperation | RemoveComponentOperation | RemoveEntityOperation | CreateEntityOperation | MarkChangedOperation; | ||
export type OperationQueue = Operation[]; |
@@ -1,3 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
export {}; | ||
//# sourceMappingURL=operations.js.map |
@@ -1,24 +0,18 @@ | ||
/// <reference types="node" /> | ||
import { EventEmitter } from 'events'; | ||
import { ComponentType } from './Component'; | ||
import { Game } from './Game'; | ||
import { Poolable } from './internal/objectPool'; | ||
import { Archetype } from './Archetype'; | ||
import { Filter } from './filters'; | ||
import { EntityImpostorFor, QueryIterator } from './QueryIterator'; | ||
export declare type QueryComponentFilter = Array<Filter<ComponentType<any>> | ComponentType<any>>; | ||
export interface QueryEvents { | ||
import { ComponentType } from './Component.js'; | ||
import { Game } from './Game.js'; | ||
import { Poolable } from './internal/objectPool.js'; | ||
import { Archetype } from './Archetype.js'; | ||
import { Filter } from './filters.js'; | ||
import { EntityImpostorFor, QueryIterator } from './QueryIterator.js'; | ||
import { EventSubscriber } from '@a-type/utils'; | ||
export type QueryComponentFilter = Array<Filter<ComponentType<any>> | ComponentType<any>>; | ||
export type QueryEvents = { | ||
entityAdded(entityId: number): void; | ||
entityRemoved(entityId: number): void; | ||
} | ||
declare type ExtractQueryDef<Q extends Query<any>> = Q extends Query<infer Def> ? Def : never; | ||
export declare type QueryIteratorFn<Q extends Query<any>, Returns = void> = { | ||
}; | ||
type ExtractQueryDef<Q extends Query<any>> = Q extends Query<infer Def> ? Def : never; | ||
export type QueryIteratorFn<Q extends Query<any>, Returns = void> = { | ||
(ent: EntityImpostorFor<ExtractQueryDef<Q>>): Returns; | ||
}; | ||
export declare interface Query<FilterDef extends QueryComponentFilter> { | ||
on<U extends keyof QueryEvents>(ev: U, cb: QueryEvents[U]): this; | ||
off<U extends keyof QueryEvents>(ev: U, cb: QueryEvents[U]): this; | ||
emit<U extends keyof QueryEvents>(ev: U, ...args: Parameters<QueryEvents[U]>): boolean; | ||
} | ||
export declare class Query<FilterDef extends QueryComponentFilter> extends EventEmitter implements Poolable { | ||
export declare class Query<FilterDef extends QueryComponentFilter> extends EventSubscriber<QueryEvents> implements Poolable { | ||
private game; | ||
@@ -32,2 +26,4 @@ filter: Filter<ComponentType<any>>[]; | ||
private addedIterable; | ||
private unsubscribes; | ||
private unsubscribeArchetypes; | ||
constructor(game: Game); | ||
@@ -56,2 +52,3 @@ private processDef; | ||
private emitRemoved; | ||
destroy: () => void; | ||
} | ||
@@ -58,0 +55,0 @@ declare class AddedIterator<Def extends QueryComponentFilter> implements Iterator<EntityImpostorFor<Def>> { |
@@ -1,153 +0,119 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Query = void 0; | ||
var events_1 = require("events"); | ||
var filters_1 = require("./filters"); | ||
var QueryIterator_1 = require("./QueryIterator"); | ||
var logger_1 = require("./logger"); | ||
var Query = /** @class */ (function (_super) { | ||
__extends(Query, _super); | ||
function Query(game) { | ||
var _a; | ||
var _this = _super.call(this) || this; | ||
_this.game = game; | ||
_this.filter = []; | ||
_this.archetypes = new Array(); | ||
_this.trackedEntities = []; | ||
_this.addedThisFrame = []; | ||
_this.removedThisFrame = []; | ||
_this.changesThisFrame = 0; | ||
_this.processDef = function (userDef) { | ||
return userDef.map(function (fil) { return (filters_1.isFilter(fil) ? fil : filters_1.has(fil)); }); | ||
import { isFilter, has } from './filters.js'; | ||
import { QueryIterator } from './QueryIterator.js'; | ||
import { logger } from './logger.js'; | ||
import { EventSubscriber } from '@a-type/utils'; | ||
export class Query extends EventSubscriber { | ||
constructor(game) { | ||
super(); | ||
this.game = game; | ||
this.filter = []; | ||
this.archetypes = new Array(); | ||
this.trackedEntities = []; | ||
this.addedThisFrame = []; | ||
this.removedThisFrame = []; | ||
this.changesThisFrame = 0; | ||
this.unsubscribes = []; | ||
this.unsubscribeArchetypes = undefined; | ||
this.processDef = (userDef) => { | ||
return userDef.map((fil) => (isFilter(fil) ? fil : has(fil))); | ||
}; | ||
_this.matchArchetype = function (archetype) { | ||
var e_1, _a; | ||
var match = true; | ||
try { | ||
for (var _b = __values(_this.filter), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var filter = _c.value; | ||
switch (filter.kind) { | ||
case 'has': | ||
match = archetype.includes(filter.Component); | ||
break; | ||
case 'not': | ||
match = archetype.omits(filter.Component); | ||
break; | ||
case 'changed': | ||
match = archetype.includes(filter.Component); | ||
break; | ||
case 'any': | ||
match = filter.Components.some(function (Comp) { return archetype.includes(Comp); }); | ||
} | ||
if (!match) | ||
return; | ||
this.matchArchetype = (archetype) => { | ||
let match = true; | ||
for (const filter of this.filter) { | ||
switch (filter.kind) { | ||
case 'has': | ||
match = archetype.includes(filter.Component); | ||
break; | ||
case 'not': | ||
match = archetype.omits(filter.Component); | ||
break; | ||
case 'changed': | ||
match = archetype.includes(filter.Component); | ||
break; | ||
case 'any': | ||
match = filter.Components.some((Comp) => archetype.includes(Comp)); | ||
} | ||
if (!match) | ||
return; | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
_this.archetypes.push(archetype); | ||
logger_1.logger.debug("Query " + _this.toString() + " added Archetype " + archetype.id); | ||
archetype.on('entityRemoved', _this.handleEntityRemoved); | ||
archetype.on('entityAdded', _this.handleEntityAdded); | ||
this.archetypes.push(archetype); | ||
logger.debug(`Query ${this.toString()} added Archetype ${archetype.id}`); | ||
this.unsubscribes.push(archetype.subscribe('entityRemoved', this.handleEntityRemoved)); | ||
this.unsubscribes.push(archetype.subscribe('entityAdded', this.handleEntityAdded)); | ||
}; | ||
_this.reset = function () { | ||
_this.archetypes.length = 0; | ||
_this.filter = []; | ||
_this.game.archetypeManager.off('archetypeCreated', _this.matchArchetype); | ||
this.reset = () => { | ||
var _a; | ||
this.archetypes.length = 0; | ||
this.filter = []; | ||
(_a = this.unsubscribeArchetypes) === null || _a === void 0 ? void 0 : _a.call(this); | ||
}; | ||
// closure provides iterator properties | ||
_this.iterator = new QueryIterator_1.QueryIterator(_this, _this.game); | ||
_this.handleEntityAdded = function (entity) { | ||
_this.addToList(entity.id); | ||
this.iterator = new QueryIterator(this, this.game); | ||
this.handleEntityAdded = (entity) => { | ||
this.addToList(entity.id); | ||
}; | ||
_this.handleEntityRemoved = function (entityId) { | ||
_this.removeFromList(entityId); | ||
this.handleEntityRemoved = (entityId) => { | ||
this.removeFromList(entityId); | ||
}; | ||
_this.addToList = function (entityId) { | ||
_this.trackedEntities.push(entityId); | ||
var removedIndex = _this.removedThisFrame.indexOf(entityId); | ||
this.addToList = (entityId) => { | ||
this.trackedEntities.push(entityId); | ||
const removedIndex = this.removedThisFrame.indexOf(entityId); | ||
if (removedIndex !== -1) { | ||
// this was a transfer (removes happen first) | ||
_this.removedThisFrame.splice(removedIndex, 1); | ||
_this.changesThisFrame--; | ||
this.removedThisFrame.splice(removedIndex, 1); | ||
this.changesThisFrame--; | ||
} | ||
else { | ||
// only non-transfers count as adds | ||
_this.addedThisFrame.push(entityId); | ||
_this.changesThisFrame++; | ||
this.addedThisFrame.push(entityId); | ||
this.changesThisFrame++; | ||
} | ||
}; | ||
_this.removeFromList = function (entityId) { | ||
var index = _this.trackedEntities.indexOf(entityId); | ||
this.removeFromList = (entityId) => { | ||
const index = this.trackedEntities.indexOf(entityId); | ||
if (index === -1) | ||
return; | ||
_this.trackedEntities.splice(index, 1); | ||
_this.removedThisFrame.push(entityId); | ||
_this.changesThisFrame++; | ||
this.trackedEntities.splice(index, 1); | ||
this.removedThisFrame.push(entityId); | ||
this.changesThisFrame++; | ||
}; | ||
_this.resetStepTracking = function () { | ||
_this.addedThisFrame.length = 0; | ||
_this.removedThisFrame.length = 0; | ||
_this.changesThisFrame = 0; | ||
this.resetStepTracking = () => { | ||
this.addedThisFrame.length = 0; | ||
this.removedThisFrame.length = 0; | ||
this.changesThisFrame = 0; | ||
}; | ||
_this.processAddRemove = function () { | ||
if (_this.changesThisFrame) { | ||
_this.addedThisFrame.forEach(_this.emitAdded); | ||
_this.removedThisFrame.forEach(_this.emitRemoved); | ||
this.processAddRemove = () => { | ||
if (this.changesThisFrame) { | ||
this.addedThisFrame.forEach(this.emitAdded); | ||
this.removedThisFrame.forEach(this.emitRemoved); | ||
} | ||
}; | ||
_this.emitAdded = function (entityId) { | ||
logger_1.logger.debug("Entity " + entityId + " added to query " + _this.toString()); | ||
_this.emit('entityAdded', entityId); | ||
this.emitAdded = (entityId) => { | ||
logger.debug(`Entity ${entityId} added to query ${this.toString()}`); | ||
this.emit('entityAdded', entityId); | ||
}; | ||
_this.emitRemoved = function (entityId) { | ||
logger_1.logger.debug("Entity " + entityId + " removed from query " + _this.toString()); | ||
_this.emit('entityRemoved', entityId); | ||
this.emitRemoved = (entityId) => { | ||
logger.debug(`Entity ${entityId} removed from query ${this.toString()}`); | ||
this.emit('entityRemoved', entityId); | ||
}; | ||
_this.addedIterable = (_a = {}, | ||
_a[Symbol.iterator] = function () { return new AddedIterator(game, _this); }, | ||
_a); | ||
this.destroy = () => { | ||
this.reset(); | ||
this.unsubscribes.forEach((unsub) => unsub()); | ||
this.unsubscribes.length = 0; | ||
}; | ||
this.addedIterable = { | ||
[Symbol.iterator]: () => new AddedIterator(game, this), | ||
}; | ||
// when do we reset the frame-specific tracking? | ||
// right before we populate new values from this frame's operations. | ||
game.on('preApplyOperations', _this.resetStepTracking); | ||
this.unsubscribes.push(game.subscribe('preApplyOperations', this.resetStepTracking)); | ||
// after we apply operations and register all changes for the frame, | ||
// we do processing of final add/remove list | ||
game.on('stepComplete', _this.processAddRemove); | ||
return _this; | ||
this.unsubscribes.push(game.subscribe('stepComplete', this.processAddRemove)); | ||
} | ||
Query.prototype.initialize = function (def) { | ||
var e_2, _a; | ||
logger_1.logger.debug("Initializing Query " + this.toString()); | ||
initialize(def) { | ||
logger.debug(`Initializing Query ${this.toString()}`); | ||
this.filter = this.processDef(def); | ||
Object.values(this.game.archetypeManager.archetypes).forEach(this.matchArchetype); | ||
this.game.archetypeManager.on('archetypeCreated', this.matchArchetype); | ||
this.unsubscribeArchetypes = this.game.archetypeManager.subscribe('archetypeCreated', this.matchArchetype); | ||
// reset all tracking arrays | ||
@@ -158,27 +124,17 @@ this.trackedEntities.length = 0; | ||
this.changesThisFrame = 0; | ||
try { | ||
// bootstrap entities list - | ||
// TODO: optimize? | ||
for (var _b = __values(this), _c = _b.next(); !_c.done; _c = _b.next()) { | ||
var ent = _c.value; | ||
this.trackedEntities.push(ent.id); | ||
this.addedThisFrame.push(ent.id); | ||
this.emitAdded(ent.id); | ||
} | ||
// bootstrap entities list - | ||
// TODO: optimize? | ||
for (const ent of this) { | ||
this.trackedEntities.push(ent.id); | ||
this.addedThisFrame.push(ent.id); | ||
this.emitAdded(ent.id); | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (_c && !_c.done && (_a = _b.return)) _a.call(_b); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
}; | ||
Query.prototype[Symbol.iterator] = function () { | ||
} | ||
[Symbol.iterator]() { | ||
return this.iterator; | ||
}; | ||
Query.prototype.toString = function () { | ||
} | ||
toString() { | ||
return this.filter | ||
.map(function (filterItem) { | ||
if (filters_1.isFilter(filterItem)) { | ||
.map((filterItem) => { | ||
if (isFilter(filterItem)) { | ||
return filterItem.toString(); | ||
@@ -189,43 +145,21 @@ } | ||
.join(','); | ||
}; | ||
Object.defineProperty(Query.prototype, "archetypeIds", { | ||
get: function () { | ||
return this.archetypes.map(function (a) { return a.id; }); | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Query.prototype, "entities", { | ||
get: function () { | ||
return this.trackedEntities; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Query.prototype, "addedIds", { | ||
get: function () { | ||
return this.addedThisFrame; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Query.prototype, "added", { | ||
get: function () { | ||
return this.addedIterable; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(Query.prototype, "removedIds", { | ||
get: function () { | ||
return this.removedThisFrame; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return Query; | ||
}(events_1.EventEmitter)); | ||
exports.Query = Query; | ||
var AddedIterator = /** @class */ (function () { | ||
function AddedIterator(game, query) { | ||
} | ||
get archetypeIds() { | ||
return this.archetypes.map((a) => a.id); | ||
} | ||
get entities() { | ||
return this.trackedEntities; | ||
} | ||
get addedIds() { | ||
return this.addedThisFrame; | ||
} | ||
get added() { | ||
return this.addedIterable; | ||
} | ||
get removedIds() { | ||
return this.removedThisFrame; | ||
} | ||
} | ||
class AddedIterator { | ||
constructor(game, query) { | ||
this.game = game; | ||
@@ -239,3 +173,3 @@ this.query = query; | ||
} | ||
AddedIterator.prototype.next = function () { | ||
next() { | ||
if (this.index >= this.query.addedIds.length) { | ||
@@ -248,5 +182,4 @@ this.result.done = true; | ||
return this.result; | ||
}; | ||
return AddedIterator; | ||
}()); | ||
} | ||
} | ||
//# sourceMappingURL=Query.js.map |
export {}; |
@@ -1,37 +0,25 @@ | ||
"use strict"; | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var events_1 = require("events"); | ||
var ArchetypeManager_1 = require("./ArchetypeManager"); | ||
var Entity_1 = require("./Entity"); | ||
var filters_1 = require("./filters"); | ||
var Query_1 = require("./Query"); | ||
var componentFixtures_1 = require("./__tests__/componentFixtures"); | ||
var withA = 100; | ||
var withAB = 101; | ||
var withB = 102; | ||
var withC = 103; | ||
var withD = 104; | ||
var withAD = 105; | ||
describe('Query', function () { | ||
var game = null; | ||
import { ArchetypeManager } from './ArchetypeManager.js'; | ||
import { Entity } from './Entity.js'; | ||
import { not } from './filters.js'; | ||
import { Query } from './Query.js'; | ||
import { ComponentA, ComponentB, ComponentC, ComponentD, } from './__tests__/componentFixtures.js'; | ||
import { describe, it, beforeEach, expect, vi } from 'vitest'; | ||
import { EventSubscriber } from '@a-type/utils'; | ||
const withA = 100; | ||
const withAB = 101; | ||
const withB = 102; | ||
const withC = 103; | ||
const withD = 104; | ||
const withAD = 105; | ||
describe('Query', () => { | ||
let game = null; | ||
// bootstrapping | ||
function addEntity(eid, components) { | ||
game.archetypeManager.createEntity(eid); | ||
components.forEach(function (comp) { | ||
components.forEach((comp) => { | ||
game.archetypeManager.addComponent(eid, comp); | ||
}); | ||
} | ||
beforeEach(function () { | ||
var archetypeManager = new ArchetypeManager_1.ArchetypeManager({ | ||
beforeEach(() => { | ||
const archetypeManager = new ArchetypeManager({ | ||
componentManager: { | ||
@@ -41,31 +29,30 @@ componentTypes: { | ||
}, | ||
getTypeName: function () { return 'TEST MOCK'; }, | ||
getTypeName: () => 'TEST MOCK', | ||
}, | ||
entityPool: { | ||
acquire: function () { | ||
return new Entity_1.Entity(); | ||
acquire() { | ||
return new Entity(); | ||
}, | ||
release: function () { }, | ||
release() { }, | ||
}, | ||
}); | ||
game = new events_1.EventEmitter(); | ||
game = new EventSubscriber(); | ||
game.archetypeManager = archetypeManager; | ||
game.entityPool = { | ||
acquire: function () { | ||
return new Entity_1.Entity(); | ||
acquire() { | ||
return new Entity(); | ||
}, | ||
release: function () { }, | ||
release() { }, | ||
}; | ||
// bootstrap some testing archetypes | ||
addEntity(withA, [new componentFixtures_1.ComponentA()]); | ||
addEntity(withB, [new componentFixtures_1.ComponentB()]); | ||
addEntity(withAB, [new componentFixtures_1.ComponentA(), new componentFixtures_1.ComponentB()]); | ||
addEntity(withC, [new componentFixtures_1.ComponentC()]); | ||
addEntity(withD, [new componentFixtures_1.ComponentD()]); | ||
addEntity(withAD, [new componentFixtures_1.ComponentA(), new componentFixtures_1.ComponentD()]); | ||
addEntity(withA, [new ComponentA()]); | ||
addEntity(withB, [new ComponentB()]); | ||
addEntity(withAB, [new ComponentA(), new ComponentB()]); | ||
addEntity(withC, [new ComponentC()]); | ||
addEntity(withD, [new ComponentD()]); | ||
addEntity(withAD, [new ComponentA(), new ComponentD()]); | ||
}); | ||
it('registers Archetypes which match included components', function () { | ||
var e_1, _a; | ||
var query = new Query_1.Query(game); | ||
query.initialize([componentFixtures_1.ComponentA]); | ||
it('registers Archetypes which match included components', () => { | ||
const query = new Query(game); | ||
query.initialize([ComponentA]); | ||
expect.assertions(4); | ||
@@ -77,43 +64,21 @@ expect(query.archetypeIds).toEqual([ | ||
]); | ||
try { | ||
for (var query_1 = __values(query), query_1_1 = query_1.next(); !query_1_1.done; query_1_1 = query_1.next()) { | ||
var ent = query_1_1.value; | ||
expect(ent.get(componentFixtures_1.ComponentA)).not.toBe(null); | ||
} | ||
for (const ent of query) { | ||
expect(ent.get(ComponentA)).not.toBe(null); | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (query_1_1 && !query_1_1.done && (_a = query_1.return)) _a.call(query_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
}); | ||
it('registers Archetypes which omit excluded components', function () { | ||
var e_2, _a; | ||
var query = new Query_1.Query(game); | ||
query.initialize([componentFixtures_1.ComponentA, filters_1.not(componentFixtures_1.ComponentB)]); | ||
it('registers Archetypes which omit excluded components', () => { | ||
const query = new Query(game); | ||
query.initialize([ComponentA, not(ComponentB)]); | ||
expect.assertions(5); | ||
expect(query.archetypeIds).toEqual(['01000000000', '01001000000']); | ||
try { | ||
for (var query_2 = __values(query), query_2_1 = query_2.next(); !query_2_1.done; query_2_1 = query_2.next()) { | ||
var ent = query_2_1.value; | ||
expect(ent.get(componentFixtures_1.ComponentA)).not.toBe(null); | ||
expect(ent.get(componentFixtures_1.ComponentB)).toBe(null); | ||
} | ||
for (const ent of query) { | ||
expect(ent.get(ComponentA)).not.toBe(null); | ||
expect(ent.get(ComponentB)).toBe(null); | ||
} | ||
catch (e_2_1) { e_2 = { error: e_2_1 }; } | ||
finally { | ||
try { | ||
if (query_2_1 && !query_2_1.done && (_a = query_2.return)) _a.call(query_2); | ||
} | ||
finally { if (e_2) throw e_2.error; } | ||
} | ||
}); | ||
it('registers late-added Archetypes', function () { | ||
var e_3, _a; | ||
var query = new Query_1.Query(game); | ||
query.initialize([componentFixtures_1.ComponentB]); | ||
addEntity(200, [new componentFixtures_1.ComponentB(), new componentFixtures_1.ComponentD()]); | ||
addEntity(201, [new componentFixtures_1.ComponentC(), new componentFixtures_1.ComponentD()]); | ||
it('registers late-added Archetypes', () => { | ||
const query = new Query(game); | ||
query.initialize([ComponentB]); | ||
addEntity(200, [new ComponentB(), new ComponentD()]); | ||
addEntity(201, [new ComponentC(), new ComponentD()]); | ||
expect.assertions(4); | ||
@@ -125,23 +90,13 @@ expect(query.archetypeIds).toEqual([ | ||
]); | ||
try { | ||
for (var query_3 = __values(query), query_3_1 = query_3.next(); !query_3_1.done; query_3_1 = query_3.next()) { | ||
var ent = query_3_1.value; | ||
expect(ent.get(componentFixtures_1.ComponentB)).not.toBe(null); | ||
} | ||
for (const ent of query) { | ||
expect(ent.get(ComponentB)).not.toBe(null); | ||
} | ||
catch (e_3_1) { e_3 = { error: e_3_1 }; } | ||
finally { | ||
try { | ||
if (query_3_1 && !query_3_1.done && (_a = query_3.return)) _a.call(query_3); | ||
} | ||
finally { if (e_3) throw e_3.error; } | ||
} | ||
}); | ||
it('maintains a list of matching entities', function () { | ||
var onAdded = jest.fn(); | ||
var onRemoved = jest.fn(); | ||
var query = new Query_1.Query(game); | ||
query.on('entityAdded', onAdded); | ||
query.on('entityRemoved', onRemoved); | ||
query.initialize([componentFixtures_1.ComponentA]); | ||
it('maintains a list of matching entities', () => { | ||
const onAdded = vi.fn(); | ||
const onRemoved = vi.fn(); | ||
const query = new Query(game); | ||
query.subscribe('entityAdded', onAdded); | ||
query.subscribe('entityRemoved', onRemoved); | ||
query.initialize([ComponentA]); | ||
expect(query.entities).toEqual([withA, withAB, withAD]); | ||
@@ -157,3 +112,3 @@ expect(query.addedIds).toEqual([withA, withAB, withAD]); | ||
// simple add case | ||
game.archetypeManager.addComponent(withC, new componentFixtures_1.ComponentA()); | ||
game.archetypeManager.addComponent(withC, new ComponentA()); | ||
game.emit('stepComplete'); | ||
@@ -170,3 +125,3 @@ expect(query.entities).toEqual([withA, withAB, withAD, withC]); | ||
// simple remove case | ||
game.archetypeManager.removeComponent(withAD, componentFixtures_1.ComponentA.id); | ||
game.archetypeManager.removeComponent(withAD, ComponentA.id); | ||
game.emit('stepComplete'); | ||
@@ -183,3 +138,3 @@ expect(query.entities).toEqual([withA, withAB, withC]); | ||
// internal move archetype case | ||
game.archetypeManager.addComponent(withA, new componentFixtures_1.ComponentC()); | ||
game.archetypeManager.addComponent(withA, new ComponentC()); | ||
game.emit('stepComplete'); | ||
@@ -191,17 +146,17 @@ expect(query.entities).toEqual([withAB, withC, withA]); | ||
}); | ||
describe('events', function () { | ||
var query; | ||
var onAdded = jest.fn(); | ||
var onRemoved = jest.fn(); | ||
beforeEach(function () { | ||
query = new Query_1.Query(game); | ||
query.initialize([componentFixtures_1.ComponentA]); | ||
query.on('entityAdded', onAdded); | ||
query.on('entityRemoved', onRemoved); | ||
describe('events', () => { | ||
let query; | ||
const onAdded = vi.fn(); | ||
const onRemoved = vi.fn(); | ||
beforeEach(() => { | ||
query = new Query(game); | ||
query.initialize([ComponentA]); | ||
query.subscribe('entityAdded', onAdded); | ||
query.subscribe('entityRemoved', onRemoved); | ||
game.emit('preApplyOperations'); | ||
}); | ||
it('emits entityAdded events when an entity is added to matching Archetype', function () { | ||
addEntity(200, [new componentFixtures_1.ComponentA()]); | ||
addEntity(201, [new componentFixtures_1.ComponentA(), new componentFixtures_1.ComponentC()]); | ||
addEntity(202, [new componentFixtures_1.ComponentD()]); | ||
it('emits entityAdded events when an entity is added to matching Archetype', () => { | ||
addEntity(200, [new ComponentA()]); | ||
addEntity(201, [new ComponentA(), new ComponentC()]); | ||
addEntity(202, [new ComponentD()]); | ||
game.emit('stepComplete'); | ||
@@ -212,4 +167,4 @@ expect(onAdded).toHaveBeenCalledTimes(2); | ||
}); | ||
it('emits entityRemoved events when an entity is removed from matching Archetype', function () { | ||
game.archetypeManager.removeComponent(withAB, componentFixtures_1.ComponentA.id); | ||
it('emits entityRemoved events when an entity is removed from matching Archetype', () => { | ||
game.archetypeManager.removeComponent(withAB, ComponentA.id); | ||
game.emit('stepComplete'); | ||
@@ -219,4 +174,4 @@ expect(onRemoved).toHaveBeenCalledWith(withAB); | ||
}); | ||
it('does not emit added/removed when entity is moved between matching Archetypes', function () { | ||
game.archetypeManager.removeComponent(withAB, componentFixtures_1.ComponentB.id); | ||
it('does not emit added/removed when entity is moved between matching Archetypes', () => { | ||
game.archetypeManager.removeComponent(withAB, ComponentB.id); | ||
expect(onRemoved).not.toHaveBeenCalled(); | ||
@@ -223,0 +178,0 @@ expect(onAdded).not.toHaveBeenCalled(); |
@@ -1,13 +0,13 @@ | ||
import { ComponentType } from './Component'; | ||
import { Entity } from './Entity'; | ||
import { Any, Filter, Not } from './filters'; | ||
import { Game } from './Game'; | ||
import { Query, QueryComponentFilter } from './Query'; | ||
declare type FilterNots<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Not<any> ? never : CompUnion; | ||
declare type UnwrapAnys<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Any<any> ? never : CompUnion; | ||
declare type OnlyNots<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Not<infer C> ? C : never; | ||
declare type UnwrapFilters<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Filter<infer C> ? C : CompUnion; | ||
declare type DefiniteComponentsFromFilter<Fil extends QueryComponentFilter> = UnwrapFilters<UnwrapAnys<FilterNots<Fil[number]>>>; | ||
declare type OmittedComponentsFromFilter<Fil extends QueryComponentFilter> = OnlyNots<Fil[number]>; | ||
export declare type EntityImpostorFor<Q extends QueryComponentFilter> = Entity<DefiniteComponentsFromFilter<Q>, OmittedComponentsFromFilter<Q>>; | ||
import { ComponentType } from './Component.js'; | ||
import { Entity } from './Entity.js'; | ||
import { Any, Filter, Not } from './filters.js'; | ||
import { Game } from './Game.js'; | ||
import { Query, QueryComponentFilter } from './Query.js'; | ||
type FilterNots<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Not<any> ? never : CompUnion; | ||
type UnwrapAnys<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Any<any> ? never : CompUnion; | ||
type OnlyNots<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Not<infer C> ? C : never; | ||
type UnwrapFilters<CompUnion extends Filter<ComponentType<any>> | ComponentType<any>> = CompUnion extends Filter<infer C> ? C : CompUnion; | ||
type DefiniteComponentsFromFilter<Fil extends QueryComponentFilter> = UnwrapFilters<UnwrapAnys<FilterNots<Fil[number]>>>; | ||
type OmittedComponentsFromFilter<Fil extends QueryComponentFilter> = OnlyNots<Fil[number]>; | ||
export type EntityImpostorFor<Q extends QueryComponentFilter> = Entity<DefiniteComponentsFromFilter<Q>, OmittedComponentsFromFilter<Q>>; | ||
export declare class QueryIterator<Def extends QueryComponentFilter> implements Iterator<EntityImpostorFor<Def>> { | ||
@@ -14,0 +14,0 @@ private query; |
@@ -1,6 +0,3 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.QueryIterator = void 0; | ||
var QueryIterator = /** @class */ (function () { | ||
function QueryIterator(query, game) { | ||
export class QueryIterator { | ||
constructor(query, game) { | ||
this.query = query; | ||
@@ -14,16 +11,16 @@ this.game = game; | ||
}; | ||
this.changedFilters = query.filter.filter(function (f) { return f.kind === 'changed'; }); | ||
this.changedFilters = query.filter.filter((f) => f.kind === 'changed'); | ||
} | ||
QueryIterator.prototype.checkChangeFilter = function () { | ||
var _this = this; | ||
checkChangeFilter() { | ||
if (this.changedFilters.length === 0) | ||
return true; | ||
return this.changedFilters.some(function (filter) { | ||
_this.game.componentManager.wasChangedLastFrame(_this.result.value.get(filter.Component.prototype.constructor).id); | ||
return this.changedFilters.some((filter) => { | ||
this.game.componentManager.wasChangedLastFrame(this.result.value.get(filter.Component.prototype.constructor).id); | ||
}); | ||
}; | ||
QueryIterator.prototype.next = function () { | ||
} | ||
next() { | ||
while (this.archetypeIndex < this.query.archetypes.length) { | ||
if (!this.archetypeIterator) { | ||
this.archetypeIterator = this.query.archetypes[this.archetypeIndex][Symbol.iterator](); | ||
this.archetypeIterator = | ||
this.query.archetypes[this.archetypeIndex][Symbol.iterator](); | ||
} | ||
@@ -49,6 +46,4 @@ this.result = this.archetypeIterator.next(); | ||
return this.result; | ||
}; | ||
return QueryIterator; | ||
}()); | ||
exports.QueryIterator = QueryIterator; | ||
} | ||
} | ||
//# sourceMappingURL=QueryIterator.js.map |
@@ -1,3 +0,3 @@ | ||
import { Game } from './Game'; | ||
import { Query, QueryComponentFilter } from './Query'; | ||
import { Game } from './Game.js'; | ||
import { Query, QueryComponentFilter } from './Query.js'; | ||
export declare class QueryManager { | ||
@@ -4,0 +4,0 @@ private game; |
@@ -1,24 +0,18 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.QueryManager = void 0; | ||
var objectPool_1 = require("./internal/objectPool"); | ||
var Query_1 = require("./Query"); | ||
import { ObjectPool } from './internal/objectPool.js'; | ||
import { Query } from './Query.js'; | ||
// TODO: reuse queries with identical definitions! | ||
var QueryManager = /** @class */ (function () { | ||
function QueryManager(game) { | ||
var _this = this; | ||
export class QueryManager { | ||
constructor(game) { | ||
this.game = game; | ||
this.pool = new objectPool_1.ObjectPool(function () { return new Query_1.Query(_this.game); }); | ||
this.pool = new ObjectPool(() => new Query(this.game)); | ||
} | ||
QueryManager.prototype.create = function (userDef) { | ||
var query = this.pool.acquire(); | ||
create(userDef) { | ||
const query = this.pool.acquire(); | ||
query.initialize(userDef); | ||
return query; | ||
}; | ||
QueryManager.prototype.release = function (query) { | ||
} | ||
release(query) { | ||
this.pool.release(query); | ||
}; | ||
return QueryManager; | ||
}()); | ||
exports.QueryManager = QueryManager; | ||
} | ||
} | ||
//# sourceMappingURL=QueryManager.js.map |
@@ -1,2 +0,2 @@ | ||
import { Entity } from './Entity'; | ||
import { Entity } from './Entity.js'; | ||
/** | ||
@@ -12,3 +12,3 @@ * Manages "removed" Entities, stuck in limbo between being | ||
flush: (callback: (entity: Entity) => void) => void; | ||
get: (entityId: number) => Entity<import("./Component").ComponentType<any>, any>; | ||
get: (entityId: number) => Entity<import("./Component.js").ComponentType<any>, any>; | ||
} |
@@ -1,4 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.RemovedList = void 0; | ||
/** | ||
@@ -9,25 +6,22 @@ * Manages "removed" Entities, stuck in limbo between being | ||
*/ | ||
var RemovedList = /** @class */ (function () { | ||
function RemovedList() { | ||
var _this = this; | ||
export class RemovedList { | ||
constructor() { | ||
this._list = new Array(); | ||
this._lookup = new Array(); | ||
this.add = function (entity) { | ||
_this._lookup[entity.id] = _this._list.length; | ||
_this._list.push(entity); | ||
this.add = (entity) => { | ||
this._lookup[entity.id] = this._list.length; | ||
this._list.push(entity); | ||
}; | ||
this.flush = function (callback) { | ||
while (_this._list.length) { | ||
callback(_this._list.shift()); | ||
this.flush = (callback) => { | ||
while (this._list.length) { | ||
callback(this._list.shift()); | ||
} | ||
_this._lookup.length = 0; | ||
this._lookup.length = 0; | ||
}; | ||
this.get = function (entityId) { | ||
this.get = (entityId) => { | ||
var _a; | ||
return (_a = _this._list[_this._lookup[entityId]]) !== null && _a !== void 0 ? _a : null; | ||
return (_a = this._list[this._lookup[entityId]]) !== null && _a !== void 0 ? _a : null; | ||
}; | ||
} | ||
return RemovedList; | ||
}()); | ||
exports.RemovedList = RemovedList; | ||
} | ||
//# sourceMappingURL=RemovedList.js.map |
@@ -1,2 +0,2 @@ | ||
import { Poolable } from './internal/objectPool'; | ||
import { Poolable } from './internal/objectPool.js'; | ||
export declare class ResourceHandle<T = any> implements Poolable { | ||
@@ -3,0 +3,0 @@ private _promise; |
@@ -1,8 +0,4 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.ResourceHandle = void 0; | ||
var ResourceHandle = /** @class */ (function () { | ||
function ResourceHandle() { | ||
var _this = this; | ||
this._resolve = function () { | ||
export class ResourceHandle { | ||
constructor() { | ||
this._resolve = () => { | ||
throw new Error('Cannot resolve this resource yet'); | ||
@@ -12,36 +8,26 @@ }; | ||
this.__alive = false; | ||
this.resolve = function (value) { | ||
_this._resolve(value); | ||
_this._value = value; | ||
this.resolve = (value) => { | ||
this._resolve(value); | ||
this._value = value; | ||
}; | ||
this.reset = function () { | ||
_this._resolve = function () { | ||
this.reset = () => { | ||
this._resolve = () => { | ||
throw new Error('Cannot resolve this resource yet'); | ||
}; | ||
_this._promise = new Promise(function (resolve) { | ||
_this._resolve = resolve; | ||
this._promise = new Promise((resolve) => { | ||
this._resolve = resolve; | ||
}); | ||
_this._value = null; | ||
this._value = null; | ||
}; | ||
this._promise = new Promise(function (resolve) { | ||
_this._resolve = resolve; | ||
this._promise = new Promise((resolve) => { | ||
this._resolve = resolve; | ||
}); | ||
} | ||
Object.defineProperty(ResourceHandle.prototype, "value", { | ||
get: function () { | ||
return this._value; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
Object.defineProperty(ResourceHandle.prototype, "promise", { | ||
get: function () { | ||
return this._promise; | ||
}, | ||
enumerable: false, | ||
configurable: true | ||
}); | ||
return ResourceHandle; | ||
}()); | ||
exports.ResourceHandle = ResourceHandle; | ||
get value() { | ||
return this._value; | ||
} | ||
get promise() { | ||
return this._promise; | ||
} | ||
} | ||
//# sourceMappingURL=ResourceHandle.js.map |
@@ -0,0 +0,0 @@ export declare class Resources<ResourceMap extends Record<string, any>> { |
@@ -1,41 +0,35 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Resources = void 0; | ||
var objectPool_1 = require("./internal/objectPool"); | ||
var logger_1 = require("./logger"); | ||
var ResourceHandle_1 = require("./ResourceHandle"); | ||
var Resources = /** @class */ (function () { | ||
function Resources() { | ||
var _this = this; | ||
this.handlePool = new objectPool_1.ObjectPool(function () { return new ResourceHandle_1.ResourceHandle(); }); | ||
import { ObjectPool } from './internal/objectPool.js'; | ||
import { logger } from './logger.js'; | ||
import { ResourceHandle } from './ResourceHandle.js'; | ||
export class Resources { | ||
constructor() { | ||
this.handlePool = new ObjectPool(() => new ResourceHandle()); | ||
this.handles = new Map(); | ||
this.getOrCreateGlobalHandle = function (key) { | ||
var handle = _this.handles.get(key); | ||
this.getOrCreateGlobalHandle = (key) => { | ||
let handle = this.handles.get(key); | ||
if (!handle) { | ||
handle = _this.handlePool.acquire(); | ||
_this.handles.set(key, handle); | ||
handle = this.handlePool.acquire(); | ||
this.handles.set(key, handle); | ||
} | ||
return handle; | ||
}; | ||
this.load = function (key) { | ||
return _this.getOrCreateGlobalHandle(key).promise; | ||
this.load = (key) => { | ||
return this.getOrCreateGlobalHandle(key).promise; | ||
}; | ||
this.resolve = function (key, value) { | ||
_this.getOrCreateGlobalHandle(key).resolve(value); | ||
logger_1.logger.debug('Resolved resource', key); | ||
this.resolve = (key, value) => { | ||
this.getOrCreateGlobalHandle(key).resolve(value); | ||
logger.debug('Resolved resource', key); | ||
}; | ||
this.immediate = function (key) { | ||
return _this.getOrCreateGlobalHandle(key).value; | ||
this.immediate = (key) => { | ||
return this.getOrCreateGlobalHandle(key).value; | ||
}; | ||
this.remove = function (key) { | ||
var value = _this.handles.get(key); | ||
this.remove = (key) => { | ||
const value = this.handles.get(key); | ||
if (value) { | ||
_this.handlePool.release(value); | ||
_this.handles.delete(key); | ||
this.handlePool.release(value); | ||
this.handles.delete(key); | ||
} | ||
}; | ||
} | ||
return Resources; | ||
}()); | ||
exports.Resources = Resources; | ||
} | ||
//# sourceMappingURL=Resources.js.map |
@@ -1,4 +0,4 @@ | ||
import { Game } from './Game'; | ||
import { QueryComponentFilter } from './Query'; | ||
import { EntityImpostorFor } from './QueryIterator'; | ||
import { Game } from './Game.js'; | ||
import { QueryComponentFilter } from './Query.js'; | ||
import { EntityImpostorFor } from './QueryIterator.js'; | ||
export declare function makeSystem<Filter extends QueryComponentFilter>(filter: Filter, run: (entity: EntityImpostorFor<Filter>, game: Game) => void, phase?: 'step' | 'preStep' | 'postStep'): (game: Game) => () => void; |
@@ -1,43 +0,13 @@ | ||
"use strict"; | ||
var __values = (this && this.__values) || function(o) { | ||
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; | ||
if (m) return m.call(o); | ||
if (o && typeof o.length === "number") return { | ||
next: function () { | ||
if (o && i >= o.length) o = void 0; | ||
return { value: o && o[i++], done: !o }; | ||
} | ||
}; | ||
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.makeSystem = void 0; | ||
function makeSystem(filter, run, phase) { | ||
if (phase === void 0) { phase = 'step'; } | ||
export function makeSystem(filter, run, phase = 'step') { | ||
return function (game) { | ||
var query = game.queryManager.create(filter); | ||
const query = game.queryManager.create(filter); | ||
function onPhase() { | ||
var e_1, _a; | ||
var ent; | ||
try { | ||
for (var query_1 = __values(query), query_1_1 = query_1.next(); !query_1_1.done; query_1_1 = query_1.next()) { | ||
ent = query_1_1.value; | ||
run(ent, game); | ||
} | ||
let ent; | ||
for (ent of query) { | ||
run(ent, game); | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (query_1_1 && !query_1_1.done && (_a = query_1.return)) _a.call(query_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
} | ||
game.on(phase, onPhase); | ||
return function () { | ||
game.off(phase, onPhase); | ||
}; | ||
return game.subscribe(phase, onPhase); | ||
}; | ||
} | ||
exports.makeSystem = makeSystem; | ||
//# sourceMappingURL=System.js.map |
{ | ||
"name": "0g", | ||
"version": "0.0.9", | ||
"version": "0.1.0", | ||
"description": "", | ||
"type": "module", | ||
"exports": { | ||
".": { | ||
"import": "./dist/index.js", | ||
"types": "./dist/index.d.ts" | ||
}, | ||
"./input": { | ||
"import": "./dist/input/index.js", | ||
"types": "./dist/input/index.d.ts" | ||
} | ||
}, | ||
"publishConfig": { | ||
"access": "public" | ||
}, | ||
"files": [ | ||
"dist", | ||
"dist-esm" | ||
"dist/", | ||
"src/" | ||
], | ||
"main": "./dist/index.js", | ||
"module": "./dist-esm/index.js", | ||
"typings": "./dist-esm/index.d.ts", | ||
"scripts": { | ||
"test": "jest", | ||
"test:watch": "jest --watch --bail", | ||
"build:cjs": "tsc", | ||
"build:esm": "tsc -m es6 --outDir dist-esm", | ||
"build": "concurrently \"yarn build:cjs\" \"yarn build:esm\"", | ||
"dev:cjs": "tsc --watch", | ||
"dev:esm": "tsc -m es6 --outDir dist-esm --watch", | ||
"dev": "concurrently \"yarn dev:cjs\" \"yarn dev:esm\"", | ||
"prepublishOnly": "yarn build", | ||
"release": "npm publish --access public --registry https://registry.npmjs.org", | ||
"storybook": "start-storybook -p 6006", | ||
"storybook:build": "build-storybook -o docs/storybook", | ||
"typedoc": "typedoc --options typedoc.json" | ||
}, | ||
"repository": { | ||
@@ -42,32 +38,21 @@ "type": "git", | ||
"homepage": "https://github.com/a-type/0g#readme", | ||
"peerDependencies": {}, | ||
"devDependencies": { | ||
"@babel/core": "^7.10.5", | ||
"@babel/preset-env": "^7.10.4", | ||
"@babel/preset-react": "^7.10.4", | ||
"@babel/preset-typescript": "^7.10.4", | ||
"@testing-library/jest-dom": "^5.11.1", | ||
"@testing-library/react": "^10.4.7", | ||
"@types/jest": "^26.0.5", | ||
"@types/node": "^14.0.23", | ||
"@types/ramda": "^0.27.32", | ||
"@types/react": "^17.0.0", | ||
"@types/react-dom": "^17.0.0", | ||
"@types/shortid": "0.0.29", | ||
"@typescript-eslint/eslint-plugin": "^4.8.1", | ||
"@typescript-eslint/parser": "^4.8.1", | ||
"babel-loader": "^8.1.0", | ||
"concurrently": "^5.3.0", | ||
"eslint": "^7.13.0", | ||
"eslint-plugin-react": "^7.21.5", | ||
"eslint-plugin-react-hooks": "^4.2.0", | ||
"jest": "^26.6.3", | ||
"prettier": "^2.0.5", | ||
"typedoc": "0.17.0-3", | ||
"@types/shortid": "0.0.32", | ||
"jsdom": "^24.0.0", | ||
"typedoc": "0.25.13", | ||
"typedoc-plugin-internal-external": "^2.2.0", | ||
"typescript": "^4.1.2" | ||
"typescript": "5.4.5", | ||
"vite": "5.2.10", | ||
"vitest": "1.5.2" | ||
}, | ||
"dependencies": { | ||
"events": "^3.3.0" | ||
"@a-type/utils": "1.1.0", | ||
"mnemonist": "0.39.8", | ||
"shortid": "^2.2.16" | ||
}, | ||
"scripts": { | ||
"test": "vitest", | ||
"build": "tsc", | ||
"typedoc": "typedoc --options typedoc.json" | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
7
0
0
Yes
229017
3
139
4389
1
+ Added@a-type/utils@1.1.0
+ Addedmnemonist@0.39.8
+ Addedshortid@^2.2.16
+ Added@a-type/utils@1.1.0(transitive)
+ Addedmnemonist@0.39.8(transitive)
+ Addednanoid@3.3.8(transitive)
+ Addedobliterator@2.0.5(transitive)
+ Addedshortid@2.2.17(transitive)
- Removedevents@^3.3.0
- Removedevents@3.3.0(transitive)