Skip to content

Instantly share code, notes, and snippets.

@mflux
Created October 4, 2017 18:50
Show Gist options
  • Save mflux/60e6393266c0168d555aa3d95ba35483 to your computer and use it in GitHub Desktop.
Save mflux/60e6393266c0168d555aa3d95ba35483 to your computer and use it in GitHub Desktop.
import R from 'ramda';
import * as Debug from './debug';
export function create(){
const events = {
componentCreations: [],
componentChanges: [],
componentDeletions: []
};
const update = handleStateChange( events );
const out = {
update,
componentCreated: ( filter ) => events.componentCreations.push( filter ),
componentChanged: ( filter ) => events.componentChanges.push( filter ),
componentDeleted: ( filter ) => events.componentDeletions.push( filter ),
bind: function( handlers ){
if( Array.isArray( handlers ) ){
bind( out, handlers );
}
else{
bindOne( out, handlers );
}
return out;
},
unbind: function( handlerId ){
Object.keys( events ).forEach( function( eventType ){
events[ eventType ] = events[ eventType ].filter( function( e ){
return e.handlerId !== handlerId;
});
});
}
};
return out;
}
export function bindOne( stateEvents, handler ){
const { type } = handler;
stateEvents[ type ]( handler );
}
export function bind( stateEvents, handlers ){
if( Array.isArray( handlers ) === false ){
bindOne( stateEvents, handlers );
return;
}
handlers.forEach( function( handler ){
bindOne( stateEvents, handler );
});
}
const handleStateChange = R.curry( function( events, states ){
// Debug.time('state change handler');
const { componentCreations, componentChanges, componentDeletions } = events;
const { oldState, gameState } = states;
const entities = gameState.entities;
const oldEntities = oldState.entities;
R.forEach( handleComponentCreations( entities, oldEntities ), componentCreations );
R.forEach( handleComponentChanges( entities, oldEntities ), componentChanges );
R.forEach( handleComponentDeletions( entities, oldEntities ), componentDeletions );
// Debug.timeEnd('state change handler');
});
const handleComponentCreations = R.curry( function( entities, oldEntities, filter ){
const componentName = filter.component;
const relevant = entitiesWithComponent( componentName, R.values( entities ) ).filter( hasRequiredComponents( filter ) );
function perform( entity ){
const oldEntity = oldEntities[ entity._id ];
if( oldEntity === undefined ){
filter.result( oldEntity, entity );
return;
}
if( entity[ componentName ] !== undefined && oldEntity[ componentName ] === undefined ){
filter.result( oldEntity, entity );
}
}
if( filter.specificId ){
perform( entities[ filter.specificId ] )
}
else{
relevant.forEach( perform );
}
});
const handleComponentDeletions = R.curry( function( entities, oldEntities, filter ){
const relevantOld = entitiesWithComponent( filter.component, R.values( oldEntities ) ).filter( hasRequiredComponents( filter ) );
function perform( oldEntity ){
const componentName = filter.component;
const entity = entities[ oldEntity._id ];
if( entity === undefined ){
filter.result( oldEntity, oldEntity );
return;
}
if( oldEntity[ componentName ] !== undefined && entity[ componentName ] === undefined ){
filter.result( oldEntity, entity );
}
}
if( filter.specificId ){
perform( oldEntities[ filter.specificId ] );
}
else{
relevantOld.forEach( perform );
}
});
const handleComponentChanges = R.curry( function( entities, oldEntities, filter ){
if( filter.check === undefined ){
console.warn('no check for handling component updates', JSON.stringify( filter, null, 2 ) );
return;
}
const relevant = filter.component === undefined ? R.values( entities ) : entitiesWithComponent( filter.component, R.values( entities ) ).filter( hasRequiredComponents( filter ) );
function perform( entity ){
const oldEntity = oldEntities[ entity._id ];
if( oldEntity === undefined ){
return;
}
const componentName = filter.component;
if( oldEntity[ componentName ] === undefined ){
return;
}
if( filter.check( oldEntity[ componentName ], entity[ componentName ] ) ){
filter.result( oldEntity, entity );
}
}
if( filter.specificId ){
perform( entities[ filter.specificId ] );
}
else{
relevant.forEach( perform );
}
});
function entitiesWithComponent( componentName, entities ){
return R.reject( ( entity ) => entity[ componentName ] === undefined, entities );
}
export const componentCheck = R.curry( function( componentKey, old, cur ){
return !R.equals( old[ componentKey ], cur[ componentKey ] );
});
const hasRequiredComponents = R.curry( function( filter, entity ){
if( filter.requireComponents !== undefined ){
const req = filter.requireComponents;
for( let i=0; i<req.length; i++ ){
const reqN = req[ i ];
if( entity[ reqN ] === undefined ){
return false;
}
}
}
return true;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment