react-encompass-ecs
Version:
Sync data from encompass-ecs to React
1 lines • 18.9 kB
Source Map (JSON)
{"version":3,"file":"react-encompass-ecs.mjs","sources":["../src/component.ts","../src/sync.ts","../node_modules/tslib/tslib.es6.js","../src/entity.tsx","../src/updator.ts"],"sourcesContent":["import { DrawComponent } from 'encompass-ecs';\n/** Marker component to indicate an entity is a candidate to be used in React */\nexport class ReactSyncComponent extends DrawComponent {}\n","import { Subject } from 'rxjs';\nimport { Renders, EntityRenderer, GeneralRenderer, Entity, WorldBuilder } from 'encompass-ecs';\nimport { produce } from 'immer';\nimport { ReactSyncComponent } from './component';\nimport { IEntityMap } from './entity';\n\nexport const updaterContext: Subject<boolean> = new Subject();\nexport class EntitySyncer {\n public entities: IEntityMap;\n /** trigger component update by flipping boolean value */\n\n private currentUpdaterValue: boolean = true;\n\n constructor(worldBuilder: WorldBuilder) {\n this.entities = {};\n const updateEntitiesStore = produce((draft, id, newEntity) => {\n draft[id] = newEntity;\n });\n const store = this; // tslint:disable-line no-this-assignment pass this from this class to temporary classes below\n\n @Renders(ReactSyncComponent)\n class ReactSyncRenderer extends EntityRenderer {\n // this got called on every entity on every render tick\n public render(currentEntity: Entity) {\n // put current entity into the resulting entity map, update the old one\n const id = currentEntity.get_component(ReactSyncComponent).entity_id;\n store.entities = updateEntitiesStore(store.entities, id, currentEntity);\n }\n }\n worldBuilder.add_renderer(ReactSyncRenderer);\n\n updaterContext.subscribe(currentValue => (store.currentUpdaterValue = currentValue));\n class ReactReRenderTriggerRenderer extends GeneralRenderer {\n public layer = 1;\n // this got called once every render tick\n public render() {\n updaterContext.next(!store.currentUpdaterValue);\n }\n }\n worldBuilder.add_renderer(ReactReRenderTriggerRenderer);\n }\n}\n","/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation. All rights reserved.\r\nLicensed under the Apache License, Version 2.0 (the \"License\"); you may not use\r\nthis file except in compliance with the License. You may obtain a copy of the\r\nLicense at http://www.apache.org/licenses/LICENSE-2.0\r\n\r\nTHIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r\nKIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED\r\nWARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,\r\nMERCHANTABLITY OR NON-INFRINGEMENT.\r\n\r\nSee the Apache Version 2.0 License for specific language governing permissions\r\nand limitations under the License.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n 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;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport function __exportStar(m, exports) {\r\n for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];\r\n}\r\n\r\nexport function __values(o) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator], i = 0;\r\n if (m) return m.call(o);\r\n return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n};\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];\r\n result.default = mod;\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n","import React, { useEffect, createContext, useContext, Context, useMemo } from 'react';\nimport { Component, Entity, EntityChecker, Type } from 'encompass-ecs';\nimport { GCOptimizedList } from 'encompass-gc-optimized-collections';\nimport { useImmer } from 'use-immer';\nimport { flatten, mapValues } from 'lodash';\n\nimport { useUpdate } from './updator';\nimport { ReactSyncComponent } from './component';\n\nexport interface IEntityMap {\n [name: string]: Entity;\n}\nexport interface IEntityResultMap {\n [name: string]: {\n [id: number]: Entity;\n };\n}\n\nexport const GameEntitiesContext = createContext<IEntityMap>({});\n\n/**\n * Select entity with provided components, return components inside entity\n * ```js\n * const { box } = useComponents({ box: [PositionComponent] });\n * const position = box ? box[0] : { x: 20, y: 20 };\n * ```\n * Above example return singleton component inside box, if you warp some component in array, it will return an array of that type of components (not supported now due to my TypeScript knowledge limitation)\n * \n * @param {boolean} [forceRender=false] reRender component on draw tick, only enable this when update you component 60 times per second is not costly\n */\nexport function useComponent<TComponent extends Component, T extends Type<TComponent> /* | Array<Type<TComponent>> */>(\n descriptions: { [name: string]: /* T[] */ Array<Type<TComponent>> },\n forceRender: boolean = false,\n context: Context<IEntityMap> = GameEntitiesContext,\n): {\n [name: string]: Array<\n Array</* T extends Array<Type<TComponent>> ? GCOptimizedList<Readonly<TComponent>> : */ Readonly<TComponent>>\n >;\n} {\n // prevent object passed in trigger reRender, assume that description won't change on runtime\n const [selectedEntities, setter] = useImmer<IEntityResultMap>({});\n const entities = useContext(context);\n useEffect(() => {\n // select entities that match the components description\n setter(draft => {\n for (const name of Object.keys(descriptions)) {\n for (const entity of Object.values(entities)) {\n const id = entity.get_component(ReactSyncComponent).entity_id;\n const components = descriptions[name];\n if (draft[name] === undefined) {\n draft[name] = {};\n }\n if (draft[name][id] !== entity && EntityChecker.check_entity(entity, flatten(components))) {\n draft[name][id] = entity;\n }\n }\n }\n });\n // only rerun this selection if entities changes\n }, [setter, entities]);\n const selectedComponents = useMemo(() => {\n const result = mapValues(selectedEntities, (entitiesWithSuchComponent, name) =>\n Object.values(entitiesWithSuchComponent).map(entity =>\n descriptions[name].map(component => {\n // if (Array.isArray(component)) {\n // component as Array<Type<TComponent>>;\n // return entity.get_components(component[0]);\n // }\n return entity.get_component(component);\n }),\n ),\n );\n // assign empty array, so you can xxx.map it easily in React\n for (const name of Object.keys(descriptions)) {\n if (!result[name]) {\n result[name] = [];\n }\n }\n return result;\n }, [selectedEntities]);\n useUpdate(forceRender);\n\n return selectedComponents;\n}\n\nexport function Provider(props: { children: React.ReactNode; entities: IEntityMap; context?: Context<IEntityMap> }) {\n const ProvidedContext = props.context || GameEntitiesContext;\n return <ProvidedContext.Provider value={props.entities}>{props.children}</ProvidedContext.Provider>;\n}\n","import { useState, useEffect } from 'react';\nimport { updaterContext } from './sync';\n\nexport function useUpdate(forceRender: boolean) {\n // force update component on component value change, since what we get till now is just a reference, it won't change despite of internal value changed by ecs engines\n const [, set] = useState(true);\n useEffect(() => {\n if (forceRender) {\n const subscription = updaterContext.subscribe(() => set(value => !value));\n return () => subscription.unsubscribe();\n }\n }, [forceRender]);\n}\n"],"names":["ReactSyncComponent","DrawComponent","updaterContext","Subject","EntitySyncer","constructor","worldBuilder","entities","updateEntitiesStore","produce","draft","id","newEntity","store","this","ReactSyncRenderer","render","currentEntity","get_component","entity_id","decorators","target","key","desc","d","c","arguments","length","r","Object","getOwnPropertyDescriptor","Reflect","decorate","i","defineProperty","Renders","add_renderer","subscribe","currentValue","currentUpdaterValue","next","GeneralRenderer","GameEntitiesContext","createContext","useComponent","descriptions","forceRender","context","useImmer","useContext","useEffect","setter","keys","const","name","values","entity","components","undefined","EntityChecker","check_entity","flatten","selectedComponents","useMemo","result","mapValues","selectedEntities","entitiesWithSuchComponent","map","component","useState","subscription","set","value","unsubscribe","useUpdate","Provider","props","React","children"],"mappings":"kXAEaA,0IAA2BC,GCI3BC,EAAmC,IAAIC,EACvCC,EAMXC,SAAYC,6BAF2B,OAGhCC,SAAW,OACVC,EAAsBC,WAASC,EAAOC,EAAIC,GAC9CF,EAAMC,GAAMC,IAERC,EAAQC,KAGRC,mJAEGC,gBAAOC,OAENN,EAAKM,EAAcC,cAAclB,GAAoBmB,UAC3DN,EAAMN,SAAWC,EAAoBK,EAAMN,SAAUI,EAAIM,UALvDF,EC+BV,SAA2BK,EAAYC,EAAQC,EAAKC,GAChD,IAA2HC,EAAvHC,EAAIC,UAAUC,OAAQC,EAAIH,EAAI,EAAIJ,EAAkB,OAATE,EAAgBA,EAAOM,OAAOC,yBAAyBT,EAAQC,GAAOC,EACrH,GAAuB,iBAAZQ,SAAoD,mBAArBA,QAAQC,SAAyBJ,EAAIG,QAAQC,SAASZ,EAAYC,EAAQC,EAAKC,QACpH,IAAK,IAAIU,EAAIb,EAAWO,OAAS,EAAGM,GAAK,EAAGA,KAAST,EAAIJ,EAAWa,MAAIL,GAAKH,EAAI,EAAID,EAAEI,GAAKH,EAAI,EAAID,EAAEH,EAAQC,EAAKM,GAAKJ,EAAEH,EAAQC,KAASM,GAChJ,OAAOH,EAAI,GAAKG,GAAKC,OAAOK,eAAeb,EAAQC,EAAKM,GAAIA,IDpC3DO,EAAQnC,IACHe,GAQNT,EAAa8B,aAAarB,GAE1Bb,EAAemC,mBAAUC,UAAiBzB,EAAM0B,oBAAsBD,IAQtEhC,EAAa8B,yBAPb/B,gDACiB,kGAERW,oBACUwB,MAAM3B,EAAM0B,yBAJYE,KEdlCC,EAAsBC,EAA0B,IAY7D,SAAgBC,EACdC,EACAC,EACAC,mBADuB,kBACQL,SAOIM,EAA2B,kBACxDzC,EAAW0C,EAAWF,GAC5BG,aAEEC,WAAOzC,OACA,UAAcmB,OAAOuB,KAAKP,uBAA1BQ,IAAMC,aACYzB,OAAO0B,OAAOhD,mBAAW,CAAzC8C,IAAMG,OACH7C,EAAK6C,EAAOtC,cAAclB,GAAoBmB,UAC9CsC,EAAaZ,EAAaS,QACZI,IAAhBhD,EAAM4C,KACR5C,EAAM4C,GAAQ,IAEZ5C,EAAM4C,GAAM3C,KAAQ6C,GAAUG,EAAcC,aAAaJ,EAAQK,EAAQJ,MAC3E/C,EAAM4C,GAAM3C,GAAM6C,OAMzB,CAACL,EAAQ5C,QACNuD,EAAqBC,qBACnBC,EAASC,EAAUC,WAAmBC,EAA2Bb,UACrEzB,OAAO0B,OAAOY,GAA2BC,aAAIZ,UAC3CX,EAAaS,GAAMc,aAAIC,UAKdb,EAAOtC,cAAcmD,eAKfxC,OAAOuB,KAAKP,mBAAe,CAAzCQ,IAAMC,OACJU,EAAOV,KACVU,EAAOV,GAAQ,WAGZU,GACN,CAACE,oBC5EoBpB,SAERwB,GAAS,MACzBpB,gBACMJ,EAAa,KACTyB,EAAerE,EAAemC,4BAAgBmC,WAAIC,UAAUA,+BACrDF,EAAaG,iBAE3B,CAAC5B,IDqEJ6B,CAAU7B,GAEHgB,WAGOc,EAASC,UAEhBC,iBADiBD,EAAM9B,SAAWL,GACjBkC,UAASH,MAAOI,EAAMtE,UAAWsE,EAAME"}