Socket
Socket
Sign inDemoInstall

0g

Package Overview
Dependencies
5
Maintainers
1
Versions
22
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.3.0 to 0.3.1

2

dist/ComponentManager.js

@@ -32,3 +32,3 @@ import { ComponentPool } from './ComponentPool.js';

this.onComponentChanged = (component) => {
this.game.enqueueOperation({
this.game.enqueuePhaseOperation({
op: 'markChanged',

@@ -35,0 +35,0 @@ componentId: component.$.id,

@@ -13,3 +13,2 @@ import { QueryManager } from './QueryManager.js';

import { type AssetLoaders, type BaseShape, type Globals } from './index.js';
import { EventSubscriber } from '@a-type/utils';
import { ComponentHandle } from './Component2.js';

@@ -21,5 +20,3 @@ export type GameConstants = {

export type GameEvents = {
preStep(): any;
step(): any;
postStep(): any;
[phase: `phase:${string}`]: any;
stepComplete(): any;

@@ -29,7 +26,9 @@ preApplyOperations(): any;

};
export declare class Game extends EventSubscriber<GameEvents> {
export declare class Game {
private events;
private _queryManager;
private _entityIds;
private _archetypeManager;
private _operationQueue;
private _stepOperationQueue;
private _phaseOperationQueue;
private _componentManager;

@@ -45,5 +44,6 @@ private _globals;

private _constants;
constructor({ assetLoaders, ignoreSystemsWarning, }?: {
constructor({ assetLoaders, ignoreSystemsWarning, phases, }?: {
assetLoaders?: AssetLoaders;
ignoreSystemsWarning?: boolean;
phases?: string[];
});

@@ -60,2 +60,3 @@ get entityIds(): IdManager;

get entityPool(): ObjectPool<Entity<ComponentHandle, any>>;
subscribe: <K extends keyof GameEvents>(event: K, listener: GameEvents[K]) => () => void;
/**

@@ -92,6 +93,8 @@ * Allocates a new entity id and enqueues an operation to create the entity at the next opportunity.

step: (delta: number) => void;
enqueueOperation: (operation: Operation) => void;
enqueuePhaseOperation: (operation: Operation) => void;
enqueueStepOperation: (operation: Operation) => void;
private destroyEntity;
private flushOperations;
private flushPhaseOperations;
private flushStepOperations;
private applyOperation;
}

@@ -12,11 +12,13 @@ import { QueryManager } from './QueryManager.js';

import { allSystems } from './System.js';
export class Game extends EventSubscriber {
constructor({ assetLoaders = {}, ignoreSystemsWarning, } = {}) {
super();
export class Game {
constructor({ assetLoaders = {}, ignoreSystemsWarning, phases, } = {}) {
this.events = new EventSubscriber();
this._entityIds = new IdManager((...msgs) => console.debug('Entity IDs:', ...msgs));
this._operationQueue = [];
// operations applied every step
this._stepOperationQueue = [];
// operations applied every phase
this._phaseOperationQueue = [];
this._globals = new Resources();
this._entityPool = new ObjectPool(() => new Entity(), (e) => e.reset());
this._removedList = new RemovedList();
// TODO: configurable?
this._phases = ['preStep', 'step', 'postStep'];

@@ -29,2 +31,8 @@ this._delta = 0;

};
this.subscribe = (event, listener) => {
if (event.startsWith('phase:') && !this._phases.includes(event.slice(6))) {
throw new Error(`Unknown phase: ${event.slice(6)}. Known phases: ${this._phases.join(', ')}. Add this phase to your phases array in the Game constructor if you want to use it.`);
}
return this.events.subscribe(event, listener);
};
/**

@@ -35,3 +43,3 @@ * Allocates a new entity id and enqueues an operation to create the entity at the next opportunity.

const id = this.entityIds.get();
this._operationQueue.push({
this.enqueueStepOperation({
op: 'createEntity',

@@ -46,3 +54,3 @@ entityId: id,

this.destroy = (id) => {
this._operationQueue.push({
this.enqueueStepOperation({
op: 'removeEntity',

@@ -57,3 +65,3 @@ entityId: id,

const entityId = typeof entity === 'number' ? entity : entity.id;
this._operationQueue.push({
this.enqueueStepOperation({
op: 'addComponent',

@@ -70,3 +78,3 @@ entityId,

const entityId = typeof entity === 'number' ? entity : entity.id;
this._operationQueue.push({
this.enqueueStepOperation({
op: 'removeComponent',

@@ -109,14 +117,18 @@ entityId,

this._delta = delta;
this._phases.forEach((phase) => {
this.emit(phase);
});
this.emit('destroyEntities');
for (const phase of this._phases) {
this.events.emit(`phase:${phase}`);
this.flushPhaseOperations();
}
this.events.emit('destroyEntities');
this._removedList.flush(this.destroyEntity);
this.emit('preApplyOperations');
this.flushOperations();
this.emit('stepComplete');
this.events.emit('preApplyOperations');
this.flushStepOperations();
this.events.emit('stepComplete');
};
this.enqueueOperation = (operation) => {
this._operationQueue.push(operation);
this.enqueuePhaseOperation = (operation) => {
this._phaseOperationQueue.push(operation);
};
this.enqueueStepOperation = (operation) => {
this._stepOperationQueue.push(operation);
};
this.destroyEntity = (entity) => {

@@ -129,7 +141,12 @@ entity.components.forEach((instance) => {

};
this.flushOperations = () => {
while (this._operationQueue.length) {
this.applyOperation(this._operationQueue.shift());
this.flushPhaseOperations = () => {
while (this._phaseOperationQueue.length) {
this.applyOperation(this._phaseOperationQueue.shift());
}
};
this.flushStepOperations = () => {
while (this._stepOperationQueue.length) {
this.applyOperation(this._stepOperationQueue.shift());
}
};
this.applyOperation = (operation) => {

@@ -168,2 +185,3 @@ let instance;

};
this._phases = phases !== null && phases !== void 0 ? phases : this._phases;
this._componentManager = new ComponentManager(this);

@@ -170,0 +188,0 @@ this._assets = new Assets(assetLoaders);

@@ -6,2 +6,4 @@ export type KeyboardKey = string;

private keysUp;
private _blockBrowserShortcuts;
set blockBrowserShortcuts(value: boolean);
constructor();

@@ -8,0 +10,0 @@ private handleKeyDown;

export class Keyboard {
set blockBrowserShortcuts(value) {
this._blockBrowserShortcuts = value;
}
constructor() {

@@ -6,4 +9,11 @@ this.keysPressed = new Set();

this.keysUp = new Set();
this._blockBrowserShortcuts = false;
this.handleKeyDown = (ev) => {
if (ev.target === document.body && ev.key !== 'F5' && ev.key !== 'F12') {
if (ev.target === document.body &&
(this._blockBrowserShortcuts ||
// allow F12
(ev.key !== 'F12' &&
// allow refresh shortcuts
ev.key !== 'F5' &&
!(ev.key === 'r' && (ev.ctrlKey || ev.metaKey))))) {
ev.preventDefault();

@@ -10,0 +20,0 @@ }

@@ -15,2 +15,3 @@ import { ArchetypeManager } from './ArchetypeManager.js';

describe('Query', () => {
let events;
let game = null;

@@ -37,3 +38,4 @@ // bootstrapping

});
game = new EventSubscriber();
events = new EventSubscriber();
game = events;
game.archetypeManager = archetypeManager;

@@ -103,3 +105,3 @@ game.entityPool = {

// reset frame tracking
game.emit('preApplyOperations');
events.emit('preApplyOperations');
onAdded.mockClear();

@@ -111,3 +113,3 @@ expect(query.entities).toEqual([withA, withAB, withAD]);

game.archetypeManager.addComponent(withC, ComponentA.create());
game.emit('stepComplete');
events.emit('stepComplete');
expect(query.entities).toEqual([withA, withAB, withAD, withC]);

@@ -117,3 +119,3 @@ expect(query.addedIds).toEqual([withC]);

expect(onAdded).toHaveBeenCalledTimes(1);
game.emit('preApplyOperations');
events.emit('preApplyOperations');
onAdded.mockClear();

@@ -125,3 +127,3 @@ expect(query.entities).toEqual([withA, withAB, withAD, withC]);

game.archetypeManager.removeComponent(withAD, ComponentA.id);
game.emit('stepComplete');
events.emit('stepComplete');
expect(query.entities).toEqual([withA, withAB, withC]);

@@ -131,3 +133,3 @@ expect(query.addedIds).toEqual([]);

expect(onRemoved).toHaveBeenCalledTimes(1);
game.emit('preApplyOperations');
events.emit('preApplyOperations');
onAdded.mockClear();

@@ -139,3 +141,3 @@ expect(query.entities).toEqual([withA, withAB, withC]);

game.archetypeManager.addComponent(withA, ComponentC.create());
game.emit('stepComplete');
events.emit('stepComplete');
expect(query.entities).toEqual([withAB, withC, withA]);

@@ -155,3 +157,3 @@ expect(query.addedIds).toEqual([]);

query.subscribe('entityRemoved', onRemoved);
game.emit('preApplyOperations');
events.emit('preApplyOperations');
});

@@ -162,3 +164,3 @@ it('emits entityAdded events when an entity is added to matching Archetype', () => {

addEntity(202, [ComponentD.create()]);
game.emit('stepComplete');
events.emit('stepComplete');
expect(onAdded).toHaveBeenCalledTimes(2);

@@ -170,3 +172,3 @@ expect(onAdded).toHaveBeenNthCalledWith(1, 200);

game.archetypeManager.removeComponent(withAB, ComponentA.id);
game.emit('stepComplete');
events.emit('stepComplete');
expect(onRemoved).toHaveBeenCalledWith(withAB);

@@ -173,0 +175,0 @@ expect(onAdded).not.toHaveBeenCalled();

@@ -5,4 +5,9 @@ import { Game } from './Game.js';

export declare const allSystems: ((game: Game) => void | (() => void))[];
export declare function system<Filter extends QueryComponentFilter>(filter: Filter, run: (entity: EntityImpostorFor<Filter>, game: Game) => void, phase?: 'step' | 'preStep' | 'postStep'): (game: Game) => () => void;
type SystemRunner<Filter extends QueryComponentFilter, Result> = (entity: EntityImpostorFor<Filter>, game: Game, previousResult: Result) => Result;
export declare function system<Filter extends QueryComponentFilter, Result = void>(filter: Filter, run: SystemRunner<Filter, Result>, { phase, initialResult, }?: {
phase?: 'step' | 'preStep' | 'postStep' | (string & {});
initialResult?: Result;
}): (game: Game) => () => void;
/** @deprecated - use system */
export declare const makeSystem: typeof system;
export {};
export const allSystems = new Array();
export function system(filter, run, phase = 'step') {
export function system(filter, run, { phase = 'step', initialResult = undefined, } = {}) {
function sys(game) {
const query = game.queryManager.create(filter);
let result;
const entityResults = new WeakMap();
function onPhase() {
var _a;
let ent;
for (ent of query) {
run(ent, game);
result = run(ent, game, (_a = entityResults.get(ent)) !== null && _a !== void 0 ? _a : initialResult);
entityResults.set(ent, result);
}
}
return game.subscribe(phase, onPhase);
return game.subscribe(`phase:${phase}`, onPhase);
}

@@ -13,0 +17,0 @@ allSystems.push(sys);

{
"name": "0g",
"version": "0.3.0",
"version": "0.3.1",
"description": "",

@@ -5,0 +5,0 @@ "type": "module",

@@ -60,3 +60,3 @@ import { ComponentPool } from './ComponentPool.js';

private onComponentChanged = (component: ComponentInstanceInternal) => {
this.game.enqueueOperation({
this.game.enqueuePhaseOperation({
op: 'markChanged',

@@ -63,0 +63,0 @@ componentId: component.$.id,

@@ -29,5 +29,3 @@ import { QueryManager } from './QueryManager.js';

export type GameEvents = {
preStep(): any;
step(): any;
postStep(): any;
[phase: `phase:${string}`]: any;
stepComplete(): any;

@@ -38,3 +36,4 @@ preApplyOperations(): any;

export class Game extends EventSubscriber<GameEvents> {
export class Game {
private events = new EventSubscriber<GameEvents>();
private _queryManager: QueryManager;

@@ -45,3 +44,6 @@ private _entityIds = new IdManager((...msgs) =>

private _archetypeManager: ArchetypeManager;
private _operationQueue: OperationQueue = [];
// operations applied every step
private _stepOperationQueue: OperationQueue = [];
// operations applied every phase
private _phaseOperationQueue: OperationQueue = [];
private _componentManager: ComponentManager;

@@ -57,4 +59,3 @@ private _globals = new Resources<Globals>();

// TODO: configurable?
private _phases = ['preStep', 'step', 'postStep'] as const;
private _phases = ['preStep', 'step', 'postStep'];

@@ -72,4 +73,9 @@ private _delta = 0;

ignoreSystemsWarning,
}: { assetLoaders?: AssetLoaders; ignoreSystemsWarning?: boolean } = {}) {
super();
phases,
}: {
assetLoaders?: AssetLoaders;
ignoreSystemsWarning?: boolean;
phases?: string[];
} = {}) {
this._phases = phases ?? this._phases;
this._componentManager = new ComponentManager(this);

@@ -122,2 +128,14 @@ this._assets = new Assets(assetLoaders);

subscribe = <K extends keyof GameEvents>(
event: K,
listener: GameEvents[K],
) => {
if (event.startsWith('phase:') && !this._phases.includes(event.slice(6))) {
throw new Error(
`Unknown phase: ${event.slice(6)}. Known phases: ${this._phases.join(', ')}. Add this phase to your phases array in the Game constructor if you want to use it.`,
);
}
return this.events.subscribe(event, listener);
};
/**

@@ -128,3 +146,3 @@ * Allocates a new entity id and enqueues an operation to create the entity at the next opportunity.

const id = this.entityIds.get();
this._operationQueue.push({
this.enqueueStepOperation({
op: 'createEntity',

@@ -140,3 +158,3 @@ entityId: id,

destroy = (id: number) => {
this._operationQueue.push({
this.enqueueStepOperation({
op: 'removeEntity',

@@ -156,3 +174,3 @@ entityId: id,

const entityId = typeof entity === 'number' ? entity : entity.id;
this._operationQueue.push({
this.enqueueStepOperation({
op: 'addComponent',

@@ -170,3 +188,3 @@ entityId,

const entityId = typeof entity === 'number' ? entity : entity.id;
this._operationQueue.push({
this.enqueueStepOperation({
op: 'removeComponent',

@@ -222,16 +240,21 @@ entityId,

this._delta = delta;
this._phases.forEach((phase) => {
this.emit(phase);
});
this.emit('destroyEntities');
for (const phase of this._phases) {
this.events.emit(`phase:${phase}`);
this.flushPhaseOperations();
}
this.events.emit('destroyEntities');
this._removedList.flush(this.destroyEntity);
this.emit('preApplyOperations');
this.flushOperations();
this.emit('stepComplete');
this.events.emit('preApplyOperations');
this.flushStepOperations();
this.events.emit('stepComplete');
};
enqueueOperation = (operation: Operation) => {
this._operationQueue.push(operation);
enqueuePhaseOperation = (operation: Operation) => {
this._phaseOperationQueue.push(operation);
};
enqueueStepOperation = (operation: Operation) => {
this._stepOperationQueue.push(operation);
};
private destroyEntity = (entity: Entity) => {

@@ -244,8 +267,14 @@ entity.components.forEach((instance) => {

private flushOperations = () => {
while (this._operationQueue.length) {
this.applyOperation(this._operationQueue.shift()!);
private flushPhaseOperations = () => {
while (this._phaseOperationQueue.length) {
this.applyOperation(this._phaseOperationQueue.shift()!);
}
};
private flushStepOperations = () => {
while (this._stepOperationQueue.length) {
this.applyOperation(this._stepOperationQueue.shift()!);
}
};
private applyOperation = (operation: Operation) => {

@@ -252,0 +281,0 @@ let instance: ComponentInstanceInternal | undefined;

@@ -8,2 +8,8 @@ export type KeyboardKey = string;

private _blockBrowserShortcuts = false;
set blockBrowserShortcuts(value: boolean) {
this._blockBrowserShortcuts = value;
}
constructor() {

@@ -15,3 +21,11 @@ window.addEventListener('keydown', this.handleKeyDown);

private handleKeyDown = (ev: KeyboardEvent) => {
if (ev.target === document.body && ev.key !== 'F5' && ev.key !== 'F12') {
if (
ev.target === document.body &&
(this._blockBrowserShortcuts ||
// allow F12
(ev.key !== 'F12' &&
// allow refresh shortcuts
ev.key !== 'F5' &&
!(ev.key === 'r' && (ev.ctrlKey || ev.metaKey))))
) {
ev.preventDefault();

@@ -18,0 +32,0 @@ }

@@ -24,2 +24,3 @@ import { ArchetypeManager } from './ArchetypeManager.js';

describe('Query', () => {
let events: EventSubscriber<any>;
let game: Game = null as any;

@@ -48,3 +49,4 @@

} as any);
game = new EventSubscriber() as any;
events = new EventSubscriber();
game = events as any;
(game as any).archetypeManager = archetypeManager;

@@ -121,3 +123,3 @@ (game as any).entityPool = {

// reset frame tracking
game.emit('preApplyOperations');
events.emit('preApplyOperations');
onAdded.mockClear();

@@ -131,3 +133,3 @@

game.archetypeManager.addComponent(withC, ComponentA.create());
game.emit('stepComplete');
events.emit('stepComplete');

@@ -139,3 +141,3 @@ expect(query.entities).toEqual([withA, withAB, withAD, withC]);

game.emit('preApplyOperations');
events.emit('preApplyOperations');
onAdded.mockClear();

@@ -149,3 +151,3 @@

game.archetypeManager.removeComponent(withAD, ComponentA.id);
game.emit('stepComplete');
events.emit('stepComplete');

@@ -157,3 +159,3 @@ expect(query.entities).toEqual([withA, withAB, withC]);

game.emit('preApplyOperations');
events.emit('preApplyOperations');
onAdded.mockClear();

@@ -167,3 +169,3 @@

game.archetypeManager.addComponent(withA, ComponentC.create());
game.emit('stepComplete');
events.emit('stepComplete');

@@ -186,3 +188,3 @@ expect(query.entities).toEqual([withAB, withC, withA]);

query.subscribe('entityRemoved', onRemoved);
game.emit('preApplyOperations');
events.emit('preApplyOperations');
});

@@ -194,3 +196,3 @@

addEntity(202, [ComponentD.create()]);
game.emit('stepComplete');
events.emit('stepComplete');
expect(onAdded).toHaveBeenCalledTimes(2);

@@ -203,3 +205,3 @@ expect(onAdded).toHaveBeenNthCalledWith(1, 200);

game.archetypeManager.removeComponent(withAB, ComponentA.id);
game.emit('stepComplete');
events.emit('stepComplete');
expect(onRemoved).toHaveBeenCalledWith(withAB);

@@ -206,0 +208,0 @@ expect(onAdded).not.toHaveBeenCalled();

@@ -7,9 +7,25 @@ import { Game } from './Game.js';

export function system<Filter extends QueryComponentFilter>(
type SystemRunner<Filter extends QueryComponentFilter, Result> = (
entity: EntityImpostorFor<Filter>,
game: Game,
previousResult: Result,
) => Result;
export function system<Filter extends QueryComponentFilter, Result = void>(
filter: Filter,
run: (entity: EntityImpostorFor<Filter>, game: Game) => void,
phase: 'step' | 'preStep' | 'postStep' = 'step',
run: SystemRunner<Filter, Result>,
{
phase = 'step',
initialResult = undefined,
}: {
// TS trick to show the default value in the signature
// but still allow any string
phase?: 'step' | 'preStep' | 'postStep' | (string & {});
initialResult?: Result;
} = {},
) {
function sys(game: Game) {
const query = game.queryManager.create(filter);
let result: Result;
const entityResults = new WeakMap<EntityImpostorFor<Filter>, Result>();

@@ -19,7 +35,8 @@ function onPhase() {

for (ent of query) {
run(ent, game);
result = run(ent, game, entityResults.get(ent) ?? initialResult!);
entityResults.set(ent, result);
}
}
return game.subscribe(phase, onPhase);
return game.subscribe(`phase:${phase}`, onPhase);
}

@@ -26,0 +43,0 @@

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

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc