diff --git a/.gitignore b/.gitignore index ea76762..fc482fb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ dist node_modules .vscode /isolate-0x*-v8-*.log +# /resource/*.*.json \ No newline at end of file diff --git a/client/app.js b/client/app.js index 9b36abf..a357457 100644 --- a/client/app.js +++ b/client/app.js @@ -7,15 +7,14 @@ import {Stage} from '@avocado/graphics'; import {ActionRegistry, InputPacket} from '@avocado/input'; import {Vector} from '@avocado/math'; import {SocketClient} from '@avocado/net/client/socket'; -import {BundlePacket, SocketIoParser} from '@avocado/net'; -import {Synchronizer} from '@avocado/state'; +import {BundlePacket, ClientSynchronizer, SocketIoParser} from '@avocado/net'; import {clearAnimation, setAnimation} from '@avocado/timing'; import {World} from '@avocado/physics/matter/world'; import {Room, RoomView} from '@avocado/topdown'; // 1st party. import {augmentParserWithThroughput} from '../common/parser-throughput'; import {SelfEntityPacket} from '../common/packets/self-entity.packet'; -import {WorldTime} from '../common/world-time'; +import {WorldTime} from '../common/world-time.synchronized'; import {CycleTracker} from './cycle-tracker'; import {showMessage} from './overlay'; @@ -102,10 +101,8 @@ export class App extends decorate(class {}) { this.room.world.stepTime = config.simulationFrequency; // State synchronization. this.state = undefined; - this.synchronizer = new Synchronizer([ - this.room, - this.worldTime, - ]); + this.synchronizer = new ClientSynchronizer(); + this.synchronizer.addSynchronized(this.worldTime); } applyLighting() { @@ -275,14 +272,12 @@ export class App extends decorate(class {}) { this.hasReceivedState = true; } if (packet instanceof BundlePacket) { - for (let i = 0; i < packet.data.length; i++) { - this.onPacket(packet.data[i]); - } + return this.synchronizer.acceptPackets(packet.data); } if (packet instanceof SelfEntityPacket) { this.selfEntityUuid = packet.data; } - this.synchronizer.acceptPacket(packet); + this.synchronizer.acceptPackets([packet]); } onPointerDown(event) { diff --git a/client/ui/menu/inventory.js b/client/ui/menu/inventory.js index 1433836..3a4e99c 100644 --- a/client/ui/menu/inventory.js +++ b/client/ui/menu/inventory.js @@ -35,7 +35,7 @@ const decorate = compose( `), ); -const InventoryComponent = ({worldTime}) => { +const InventoryComponent = () => { const bagSlots = []; for (let i = 0; i < 40; ++i) { bagSlots.push(); diff --git a/client/ui/menu/world-time.js b/client/ui/menu/world-time.js index 0974123..f3ef808 100644 --- a/client/ui/menu/world-time.js +++ b/client/ui/menu/world-time.js @@ -4,7 +4,7 @@ import React, {useEffect, useState} from 'react'; import {compose} from '@avocado/core'; import contempo from 'contempo'; // 1st party. -import {WorldTime} from '../../../common/world-time'; +import {WorldTime} from '../../../common/world-time.synchronized'; const decorate = compose( contempo(` diff --git a/common/world-time.packet.js b/common/world-time.packet.js index fa17555..0925f2e 100644 --- a/common/world-time.packet.js +++ b/common/world-time.packet.js @@ -1,11 +1,15 @@ -import {Packet} from '@avocado/net'; +import {SynchronizedUpdatePacket} from '@avocado/net'; -export class WorldTimePacket extends Packet { +export class WorldTimePacket extends SynchronizedUpdatePacket { static get schema() { + const superSchema = super.schema; return { - ...super.schema, - data: 'uint16', + ...superSchema, + data: { + ...superSchema.data, + hour: 'uint16', + }, }; } diff --git a/common/world-time.js b/common/world-time.synchronized.js similarity index 61% rename from common/world-time.js rename to common/world-time.synchronized.js index f3fab37..a11dfd4 100644 --- a/common/world-time.js +++ b/common/world-time.synchronized.js @@ -1,5 +1,5 @@ import {compose} from '@avocado/core'; -import {Synchronized} from '@avocado/state'; +import {SynchronizedMixin} from '@avocado/net'; import {Ticker} from '@avocado/timing'; import {WorldTimePacket} from './world-time.packet'; @@ -7,12 +7,12 @@ import {WorldTimePacket} from './world-time.packet'; const MAGIC_TO_FIT_HOUR_INTO_USHORT = 2730; const decorate = compose( - Synchronized, + SynchronizedMixin, ); export class WorldTime extends decorate(class {}) { - constructor() { + constructor(json) { super(); this._hour = 0; this._isUpdateReady = true; @@ -21,14 +21,22 @@ export class WorldTime extends decorate(class {}) { this.ticker.on('tick', () => { this._isUpdateReady = true; }); + if ('undefined' !== typeof json) { + this.fromJSON(json); + } } acceptPacket(packet) { if (packet instanceof WorldTimePacket) { - this._hour = packet.data / MAGIC_TO_FIT_HOUR_INTO_USHORT; + this.fromNetwork(packet.data.hour); } } + cleanPackets() { + super.cleanPackets(); + this._isUpdateReady = false; + } + static format(time) { const rawHour = (time + 12) % 12; const hour = Math.floor(0 === Math.floor(rawHour) ? 12 : rawHour); @@ -41,6 +49,16 @@ export class WorldTime extends decorate(class {}) { } } + fromJSON(json) { + if (json.hour) { + this._hour = this.fromNetwork(json.hour); + } + } + + fromNetwork(hour) { + this._hour = hour / MAGIC_TO_FIT_HOUR_INTO_USHORT; + } + get hour() { return this._hour; } @@ -49,17 +67,13 @@ export class WorldTime extends decorate(class {}) { this._hour = hour; } - packetsForUpdate(force) { - const updates = []; - if (force || this._isUpdateReady) { - updates.push(new WorldTimePacket( - (this._hour * MAGIC_TO_FIT_HOUR_INTO_USHORT) >> 0 - )); + packets(informed) { + if (!this._isUpdateReady) { + return; } - if (!force) { - this._isUpdateReady = false; - } - return updates; + return new WorldTimePacket({ + hour: this.toNetwork(), + }); } secondsPerHour() { @@ -72,4 +86,14 @@ export class WorldTime extends decorate(class {}) { this.ticker.tick(elapsed); } + toNetwork() { + return (this._hour * MAGIC_TO_FIT_HOUR_INTO_USHORT) >> 0; + } + + toJSON() { + return { + hour: this.toNetwork(), + } + } + } diff --git a/package.json b/package.json index 6105dc0..afbf847 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,6 @@ "@avocado/physics": "1.x", "@avocado/resource": "1.x", "@avocado/sound": "1.x", - "@avocado/state": "1.x", "@avocado/timing": "1.x", "@avocado/topdown": "1.x", "classnames": "2.2.6", diff --git a/register-synchronizeds.js b/register-synchronizeds.js new file mode 100644 index 0000000..e69de29 diff --git a/resource/base-test.entity.json b/resource/base-test.entity.json deleted file mode 100644 index 63978f6..0000000 --- a/resource/base-test.entity.json +++ /dev/null @@ -1 +0,0 @@ -{"traits": {"existent": {"state": {"isTicking": false, "name": "Base"}}}} \ No newline at end of file diff --git a/resource/extension-test.entity.json b/resource/extension-test.entity.json deleted file mode 100644 index 69c3a64..0000000 --- a/resource/extension-test.entity.json +++ /dev/null @@ -1 +0,0 @@ -{"base": "/base-test.entity.json", "traits": {"existent": {"state": {"name": "Extension"}}}} \ No newline at end of file diff --git a/resource/hoe.entity.json b/resource/hoe.entity.json new file mode 100644 index 0000000..bbe03f4 --- /dev/null +++ b/resource/hoe.entity.json @@ -0,0 +1 @@ +{"traits":{"existent":{},"item":{"params":{"itemActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"useTool"},{"type":"invoke","args":[]}]}]},"slotImages":{"default":"/hoe.png"}}},"tool":{"params":{"condition":{"type":"condition","operator":"contains","operands":[{"type":"literal","value":[1,2,3,4]},{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"tileAt"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"target"}]}]}]}]},"actions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"setTileAt"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"target"}]},{"type":"literal","value":6}]}]}]},"target":{"type":"projection","distance":1,"length":1,"width":1}}}}} \ No newline at end of file diff --git a/resource/kitty-fire.room.json b/resource/kitty-fire.room.json index 4b3d86a..7e083d4 100644 --- a/resource/kitty-fire.room.json +++ b/resource/kitty-fire.room.json @@ -1 +1 @@ -{"size":[384,384],"layers":[{"entities":[{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":352,"y":908}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":1204,"y":240}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":320,"y":444}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":732,"y":856}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":900,"y":516}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":532,"y":1272}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":368,"y":840}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":512,"y":1328}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":1288,"y":220}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":544,"y":976}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":420,"y":1072}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":412,"y":388}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":1008,"y":1124}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":512,"y":1188}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":736,"y":1316}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":248,"y":636}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":1068,"y":1180}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":1076,"y":812}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":984,"y":1228}}}},{"uri":"/flower-barrel.entity.json","traits":{"positioned":{"state":{"x":1116,"y":376}}}},{"uri":"/mama-kitty-spawner.entity.json","traits":{"positioned":{"state":{"x":968,"y":1152}}}},{"uri":"/mama-kitty-spawner.entity.json","traits":{"positioned":{"state":{"x":404,"y":948}}}},{"uri":"/mama-kitty-spawner.entity.json","traits":{"positioned":{"state":{"x":672,"y":1116}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":712,"y":320}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":712,"y":1096}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":1144,"y":704}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":416,"y":212}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":528,"y":780}}}},{"uri":"/blue-fire.entity.json","traits":{"positioned":{"state":{"x":436,"y":992}}}}],"tiles":{"size":[24,24],"data":[1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4,1,2,3,4]},"tilesetUri":"/tileset.json"}]} \ No newline at end of file +{"size":[384,384],"layers":[{"entities":[{"uri":"/mama-kitty-spawner.entity.json","traits":{"positioned":{"state":{"x":980,"y":1164}}}},{"uri":"/mama-kitty-spawner.entity.json","traits":{"positioned":{"state":{"x":1028,"y":1112}}}},{"uri":"/mama-kitty-spawner.entity.json","traits":{"positioned":{"state":{"x":208,"y":1312}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":312,"y":376}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":592,"y":1248}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":572,"y":780}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":352,"y":1328}}}},{"uri":"/fire.entity.json","traits":{"positioned":{"state":{"x":1204,"y":1176}}}}],"tiles":{"size":[24,24],"data":[6,5,1,3,3,2,2,4,4,1,2,3,1,3,6,4,5,1,2,5,4,1,4,2,4,4,2,4,4,3,5,3,1,1,5,2,2,5,2,3,2,1,3,2,4,4,3,3,4,4,4,3,4,6,2,4,6,1,5,2,6,5,4,6,3,3,2,2,2,2,3,6,6,1,3,1,1,4,6,5,3,1,1,4,2,4,4,5,3,6,5,5,5,4,5,1,3,1,4,4,5,3,3,5,3,3,3,3,2,4,4,4,3,6,2,2,5,4,3,6,5,5,5,4,3,2,4,1,4,3,3,4,6,6,3,6,2,3,5,6,3,2,3,5,6,4,3,2,3,6,6,3,1,4,4,3,2,3,1,1,2,3,1,3,3,6,1,3,5,4,4,4,1,3,1,3,2,6,1,1,3,2,4,2,2,2,6,5,2,4,1,1,1,6,1,1,4,1,6,6,1,2,3,6,3,6,3,2,4,2,3,5,3,2,5,4,4,2,5,6,2,1,2,3,2,2,3,1,3,2,2,1,5,2,6,1,5,3,2,4,1,6,1,4,1,1,2,6,1,4,1,2,3,5,1,3,2,3,2,3,5,2,6,1,4,3,4,6,1,5,2,2,5,5,3,3,4,2,5,5,6,4,3,2,4,2,5,1,2,4,1,5,4,2,2,5,4,2,4,2,1,5,2,2,2,1,2,3,4,5,2,6,1,3,6,5,4,3,1,1,2,2,2,2,2,3,3,1,3,6,4,2,5,1,4,1,3,1,6,4,4,6,2,3,3,3,5,3,4,2,1,6,6,3,1,6,6,4,5,1,2,5,2,3,3,5,6,2,1,6,5,6,3,3,3,5,5,4,5,1,2,2,1,3,2,1,3,6,1,2,3,4,2,3,3,2,4,5,2,4,4,2,5,3,6,6,4,3,1,2,3,4,2,2,5,3,4,6,1,1,3,6,3,3,2,3,1,3,3,2,5,1,6,4,4,4,6,3,5,5,5,4,2,3,6,4,3,6,4,3,6,1,4,6,2,4,2,6,6,5,6,2,2,1,4,4,4,3,5,2,3,4,6,5,3,2,6,6,5,1,3,2,5,4,1,1,5,3,4,6,1,6,3,2,2,1,1,3,5,1,1,5,1,4,5,1,4,2,3,1,5,2,3,6,4,6,3,3,4,4,6,1,4,5,5,2,2,4,5,2,1,4,3,1,1,4,4,4,1,1,3,2,1,6,1,4,3,3,2,3,2,2,2,4,5,5,1,3,2,1,3,4,4,2,2,1,2,4,5,2,2,2,2,4,5,3]},"tilesetUri":"/tileset.json"}]} \ No newline at end of file diff --git a/resource/kitty.entity.json b/resource/kitty.entity.json index 71b67f2..9f9a9b3 100644 --- a/resource/kitty.entity.json +++ b/resource/kitty.entity.json @@ -1 +1 @@ -{"traits":{"alive":{},"animated":{"params":{"animations":{"idle":{"offset":[0,-3],"uri":"/kitty.animation.json"}}}},"audible":{"params":{"sounds":{"deathSound":{"uri":"/ded.sound.json"}}}},"behaved":{"params":{"routines":{"type":"routines","routines":{"initial":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"moveFor"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.25},{"type":"literal","value":2.5},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":false}},{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":1},{"type":"literal","value":4},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0},{"type":"literal","value":3}]}]}},{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.5},{"type":"literal","value":3},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":true}}]}}}}}},"collider":{},"directional":{"params":{"directionCount":4},"state":{"direction":2}},"emitter":{},"existent":{"state":{"name":"Kitty"}},"visible":{"state":{"visibleScale":[1,1]}},"layered":{},"listed":{},"mobile":{"state":{"speed":40}},"physical":{},"positioned":{},"roomed":{},"shaped":{"params":{"shape":{"type":"rectangle","position":[0,0],"size":[8,4]}}},"vulnerable":{}}} \ No newline at end of file +{"traits":{"alive":{},"animated":{"params":{"animations":{"idle":{"offset":[0,-3],"uri":"/kitty.animation.json"}}}},"audible":{"params":{"sounds":{"deathSound":{"uri":"/ded.sound.json"}}}},"behaved":{"params":{"routines":{"type":"routines","routines":{"initial":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0},{"type":"literal","value":3}]}]}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"moveFor"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"Vector"},{"type":"key","key":"fromDirection"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.25},{"type":"literal","value":2.5},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":false}},{"type":"traversal","steps":[{"type":"key","key":"Timing"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":1},{"type":"literal","value":4},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0},{"type":"literal","value":3}]}]}},{"type":"traversal","steps":[{"type":"key","key":"Timing"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.5},{"type":"literal","value":3},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":true}}]}}}}}},"collider":{},"directional":{"params":{"directionCount":4},"state":{"direction":2}},"emitter":{},"existent":{"state":{"name":"Kitty"}},"visible":{"state":{"visibleScale":[1,1]}},"layered":{},"listed":{},"mobile":{"state":{"speed":40}},"physical":{},"positioned":{},"roomed":{},"shaped":{"params":{"shape":{"type":"rectangle","position":[0,0],"size":[8,4]}}},"vulnerable":{}}} \ No newline at end of file diff --git a/resource/mama-kitty-spawner.entity.json b/resource/mama-kitty-spawner.entity.json index 647b3a7..0c79480 100644 --- a/resource/mama-kitty-spawner.entity.json +++ b/resource/mama-kitty-spawner.entity.json @@ -1 +1 @@ -{"traits":{"behaved":{"params":{"routines":{"type":"routines","routines":{"initial":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"}],"value":{"type":"literal","value":{"traits":{"positioned":{"state":{}}}}}},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"},{"type":"key","key":"traits"},{"type":"key","key":"positioned"},{"type":"key","key":"state"},{"type":"key","key":"x"}],"value":{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"multiply"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":100},{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"sub"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"room"},{"type":"key","key":"width"}]},{"type":"literal","value":100}]}]}]}]},{"type":"literal","value":4}]}]}},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"},{"type":"key","key":"traits"},{"type":"key","key":"positioned"},{"type":"key","key":"state"},{"type":"key","key":"y"}],"value":{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"multiply"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":100},{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"sub"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"room"},{"type":"key","key":"height"}]},{"type":"literal","value":100}]}]}]}]},{"type":"literal","value":4}]}]}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"spawn"},{"type":"invoke","args":[{"type":"literal","value":"mama"},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"}]}]}]}]}}}}}},"existent":{"state":{"name":"Mama spawner"}},"layered":{},"listed":{},"roomed":{},"spawner":{"params":{"spawns":{"mama":{"uri":"/mama-kitty.entity.json"}}},"state":{"maxSpawns":2}}}} \ No newline at end of file +{"traits":{"behaved":{"params":{"routines":{"type":"routines","routines":{"initial":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"spawnAt"},{"type":"invoke","args":[{"type":"literal","value":"mama"},{"type":"traversal","steps":[{"type":"key","key":"Utility"},{"type":"key","key":"makeArray"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":100},{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"sub"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"room"},{"type":"key","key":"width"}]},{"type":"literal","value":100}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":100},{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"sub"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"room"},{"type":"key","key":"height"}]},{"type":"literal","value":100}]}]}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"}]}]}]}]}}}}}},"existent":{"state":{"name":"Mama spawner"}},"layered":{},"listed":{},"roomed":{},"spawner":{"params":{"spawns":{"mama":{"uri":"/mama-kitty.entity.json"}}},"state":{"maxSpawns":2}}}} \ No newline at end of file diff --git a/resource/mama-kitty.entity.json b/resource/mama-kitty.entity.json index 9c3acb8..8f2b007 100644 --- a/resource/mama-kitty.entity.json +++ b/resource/mama-kitty.entity.json @@ -1 +1 @@ -{"traits":{"alive":{"params":{"deathActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"playSound"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"deathSound"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"killAllChildren"},{"type":"invoke","args":[]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"transition"},{"type":"invoke","args":[{"type":"literal","value":{"opacity":0,"visibleScaleX":0.3,"visibleScaleY":3}},{"type":"literal","value":0.2}]}]}]}},"state":{"life":500,"maxLife":500}},"animated":{"params":{"animations":{"idle":{"offset":[0,-8],"uri":"/kitty.animation.json"}}}},"audible":{"params":{"sounds":{"deathSound":{"uri":"/ded.sound.json"}}}},"behaved":{"params":{"routines":{"type":"routines","routines":{"initial":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"moveFor"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.25},{"type":"literal","value":2.5},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":false}},{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":1},{"type":"literal","value":4},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0},{"type":"literal","value":3}]}]}},{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.5},{"type":"literal","value":3},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":true}},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"}],"value":{"type":"literal","value":{"traits":{"positioned":{"state":{}}}}}},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"},{"type":"key","key":"traits"},{"type":"key","key":"positioned"},{"type":"key","key":"state"},{"type":"key","key":"x"}],"value":{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"multiply"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"x"}]},{"type":"literal","value":4}]}]}},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"},{"type":"key","key":"traits"},{"type":"key","key":"positioned"},{"type":"key","key":"state"},{"type":"key","key":"y"}],"value":{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"multiply"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"y"}]},{"type":"literal","value":4}]}]}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"spawn"},{"type":"invoke","args":[{"type":"literal","value":"kitteh"},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"}]}]}]}]}}}}}},"collider":{},"directional":{"params":{"directionCount":4},"state":{"direction":2}},"emitter":{},"existent":{"state":{"name":"Mama Kitty"}},"visible":{"state":{"visibleScale":[2,2]}},"layered":{},"listed":{},"mobile":{"state":{"speed":40}},"physical":{},"positioned":{},"roomed":{},"shaped":{"params":{"shape":{"type":"rectangle","position":[0,0],"size":[16,8]}}},"vulnerable":{},"spawner":{"params":{"spawns":{"kitteh":{"uri":"/kitty.entity.json"}}},"state":{"maxSpawns":10}}}} \ No newline at end of file +{"traits":{"alive":{"params":{"deathActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"playSound"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"deathSound"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"killAllChildren"},{"type":"invoke","args":[]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"transition"},{"type":"invoke","args":[{"type":"literal","value":{"opacity":0,"visibleScaleX":0.3,"visibleScaleY":3}},{"type":"literal","value":0.2}]}]}]}},"state":{"life":500,"maxLife":500}},"animated":{"params":{"animations":{"idle":{"offset":[0,-8],"uri":"/kitty.animation.json"}}}},"audible":{"params":{"sounds":{"deathSound":{"uri":"/ded.sound.json"}}}},"behaved":{"params":{"routines":{"type":"routines","routines":{"initial":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0},{"type":"literal","value":3}]}]}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"moveFor"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"Vector"},{"type":"key","key":"fromDirection"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.25},{"type":"literal","value":2.5},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":false}},{"type":"traversal","steps":[{"type":"key","key":"Timing"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":1},{"type":"literal","value":4},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0},{"type":"literal","value":3}]}]}},{"type":"traversal","steps":[{"type":"key","key":"Timing"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"randomNumber"},{"type":"invoke","args":[{"type":"literal","value":0.5},{"type":"literal","value":3},{"type":"literal","value":false}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isAnimating"}],"value":{"type":"literal","value":true}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"spawnAt"},{"type":"invoke","args":[{"type":"literal","value":"kitteh"},{"type":"traversal","steps":[{"type":"key","key":"Utility"},{"type":"key","key":"makeArray"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"x"}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"y"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"json"}]}]}]}]}}}}}},"collider":{},"directional":{"params":{"directionCount":4},"state":{"direction":2}},"emitter":{},"existent":{"state":{"name":"Mama Kitty"}},"visible":{"state":{"visibleScale":[2,2]}},"layered":{},"listed":{},"mobile":{"state":{"speed":40}},"physical":{},"positioned":{},"roomed":{},"shaped":{"params":{"shape":{"type":"rectangle","position":[0,0],"size":[16,8]}}},"vulnerable":{},"spawner":{"params":{"spawns":{"kitteh":{"uri":"/kitty.entity.json"}}},"state":{"maxSpawns":10}}}} \ No newline at end of file diff --git a/resource/potion.entity.json b/resource/potion.entity.json index ed2a55c..52ca5b2 100644 --- a/resource/potion.entity.json +++ b/resource/potion.entity.json @@ -1 +1 @@ -{"traits":{"damaging":{"params":{"damageSpecs":[{"affinity":0,"lock":0,"power":-50,"variance":0.1}]}},"existent":{},"item":{"params":{"itemActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"user"},{"type":"key","key":"takeDamageFrom"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"item"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"decrementQuantity"},{"type":"invoke","args":[]}]},{"type":"traversal","steps":[{"type":"key","key":"global"},{"type":"key","key":"wait"},{"type":"invoke","args":[{"type":"literal","value":0.5}]}]}]},"slotImages":{"default":"/potion.png"}}}}} \ No newline at end of file +{"traits":{"damaging":{"params":{"damageSpecs":[{"affinity":0,"lock":0,"power":-50,"variance":0.1}]}},"existent":{},"item":{"params":{"cooldown":0.5,"itemActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"takeDamageFrom"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"item"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"decrementQuantity"},{"type":"invoke","args":[{"type":"literal","value":1}]}]}]},"slotImages":{"default":"/potion.png"}}}}} \ No newline at end of file diff --git a/resource/rock-projectile.entity.json b/resource/rock-projectile.entity.json new file mode 100644 index 0000000..18345fe --- /dev/null +++ b/resource/rock-projectile.entity.json @@ -0,0 +1 @@ +{"traits":{"behaved":{"params":{"routines":{"type":"routines","routines":{"initial":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"setDoesNotCollideWith"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"wielder"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"setPosition"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"position"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isVisible"}],"value":{"type":"literal","value":true}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"direction"}]}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"moveFor"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"Vector"},{"type":"key","key":"fromDirection"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"direction"}]}]}]},{"type":"literal","value":0.5}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"destroy"},{"type":"invoke","args":[]}]}]}},"reflect":{"type":"routine","routine":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isColliding"}],"value":{"type":"literal","value":false}},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"isDamaging"}],"value":{"type":"literal","value":false}},{"type":"traversal","steps":[{"type":"key","key":"Flow"},{"type":"key","key":"parallel"},{"type":"invoke","args":[{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"transition"},{"type":"invoke","args":[{"type":"literal","value":{"opacity":0,"speed":0}},{"type":"literal","value":0.2}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"moveFor"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"Vector"},{"type":"key","key":"sub"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"position"}]},{"type":"traversal","steps":[{"type":"key","key":"obstacle"},{"type":"key","key":"position"}]}]}]},{"type":"literal","value":0.2}]}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"destroy"},{"type":"invoke","args":[]}]}]}}}}},"state":{"isBehaving":false}},"collider":{"params":{"collisionStartActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"context"},{"type":"key","key":"add"},{"type":"invoke","args":[{"type":"literal","value":"obstacle"},{"type":"traversal","steps":[{"type":"key","key":"other"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"entity"},{"type":"key","key":"currentRoutine"}],"value":{"type":"literal","value":"reflect"}}]},"isSensor":true}},"damaging":{"params":{"damageSpecs":[{"affinity":0,"knockback":500,"lock":1,"power":50,"variance":0.1}]}},"directional":{"params":{"directionCount":4}},"existent":{"state":{"name":"Rock (projectile)"}},"layered":{},"listed":{},"mobile":{"state":{"speed":200}},"physical":{},"pictured":{"params":{"images":{"initial":{"offset":[0,0],"size":[12,12],"uri":"/rock.png"}}}},"positioned":{},"roomed":{},"shaped":{"params":{"shape":{"type":"rectangle","position":[0,0],"size":[12,12]}}},"visible":{"state":{"isVisible":false}}}} \ No newline at end of file diff --git a/resource/rock.entity.json b/resource/rock.entity.json index 9a20387..a4fc1bb 100644 --- a/resource/rock.entity.json +++ b/resource/rock.entity.json @@ -1 +1 @@ -{"traits":{"collider":{"params":{"isSensor":true}},"damaging":{"params":{"damageSpecs":[{"affinity":0,"lock":0.25,"power":50,"variance":0.1}]}},"directional":{"params":{"directionCount":4}},"existent":{"state":{"name":"Rock"}},"item":{"params":{"itemActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"setDoesNotDamage"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"user"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"user"},{"type":"key","key":"list"},{"type":"key","key":"addEntity"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"item"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"setPosition"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"user"},{"type":"key","key":"position"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"direction"}],"value":{"type":"traversal","steps":[{"type":"key","key":"user"},{"type":"key","key":"direction"}]}},{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"moveFor"},{"type":"invoke","args":[{"type":"literal","value":0.5}]}]},{"type":"traversal","steps":[{"type":"key","key":"user"},{"type":"key","key":"list"},{"type":"key","key":"removeEntity"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"item"}]}]}]}]},"slotImages":{"default":"/rock.png"}}},"layered":{},"listed":{},"mobile":{"state":{"speed":200}},"physical":{},"pictured":{"params":{"images":{"initial":{"offset":[0,0],"size":[12,12],"uri":"/rock.png"}}}},"positioned":{},"roomed":{},"shaped":{"params":{"shape":{"type":"rectangle","position":[0,0],"size":[12,12]}}},"visible":{}}} \ No newline at end of file +{"traits":{"collider":{"params":{"isSensor":true}},"existent":{"state":{"name":"Rock"}},"item":{"params":{"cooldown":0.33,"itemActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"context"},{"type":"key","key":"add"},{"type":"invoke","args":[{"type":"literal","value":"projectile"},{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"spawn"},{"type":"invoke","args":[{"type":"literal","value":"rock"}]}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"projectile"},{"type":"key","key":"context"},{"type":"key","key":"add"},{"type":"invoke","args":[{"type":"literal","value":"wielder"},{"type":"traversal","steps":[{"type":"key","key":"wielder"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"projectile"},{"type":"key","key":"isBehaving"}],"value":{"type":"literal","value":true}}]},"slotImages":{"default":"/rock.png"}}},"layered":{},"listed":{},"magnetic":{},"mobile":{},"physical":{},"pictured":{"params":{"images":{"initial":{"offset":[0,0],"size":[12,12],"uri":"/rock.png"}}}},"positioned":{},"roomed":{},"shaped":{"params":{"shape":{"type":"rectangle","position":[0,0],"size":[12,12]}}},"spawner":{"params":{"spawns":{"rock":{"uri":"/rock-projectile.entity.json"}}}},"visible":{}}} \ No newline at end of file diff --git a/resource/tomato-plant.entity.json b/resource/tomato-plant.entity.json new file mode 100644 index 0000000..611d713 --- /dev/null +++ b/resource/tomato-plant.entity.json @@ -0,0 +1 @@ +{"traits":{"existent":{"state":{"name":"Tomato plant"}},"layered":{},"listed":{},"pictured":{"params":{"images":{"initial":{"offset":[0,0],"size":[16,16],"uri":"/tomato-stage-0.png"},"stage-1":{"offset":[0,3],"size":[16,16],"uri":"/tomato-stage-1.png"},"stage-2":{"offset":[0,3],"size":[16,16],"uri":"/tomato-stage-2.png"},"stage-3":{"offset":[0,3],"size":[16,16],"uri":"/tomato-stage-3.png"},"stage-4":{"offset":[0,3],"size":[16,16],"uri":"/tomato-stage-4.png"}}}},"plant":{"params":{"stageSpecs":{"0":{"growAt":2,"image":"initial"},"1":{"growAt":4,"image":"stage-1"},"2":{"growAt":6,"image":"stage-2"},"3":{"growAt":8,"image":"stage-3"},"4":{"image":"stage-4"}}}},"positioned":{},"roomed":{},"tile-entity":{},"visible":{}}} \ No newline at end of file diff --git a/resource/tomato-seeds.entity.json b/resource/tomato-seeds.entity.json new file mode 100644 index 0000000..a8b8879 --- /dev/null +++ b/resource/tomato-seeds.entity.json @@ -0,0 +1 @@ +{"traits":{"existent":{},"item":{"params":{"itemActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"useTool"},{"type":"invoke","args":[]}]}]},"slotImages":{"default":"/seeds.png"}}},"spawner":{"params":{"spawns":{"tomato-plant":{"uri":"/tomato-plant.entity.json"}}}},"tool":{"params":{"condition":{"type":"condition","operator":"and","operands":[{"type":"condition","operator":"is","operands":[{"type":"literal","value":7},{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"tileAt"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"target"}]}]}]}]},{"type":"condition","operator":"is","operands":[{"type":"literal","value":false},{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"hasTileEntityWithUriAt"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"target"}]},{"type":"literal","value":"/tomato-plant.entity.json"}]}]}]}]},"actions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"spawnAt"},{"type":"invoke","args":[{"type":"literal","value":"tomato-plant"},{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"Vector"},{"type":"key","key":"add"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"Vector"},{"type":"key","key":"mul"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"target"}]},{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"tileset"},{"type":"key","key":"tileSize"}]}]}]},{"type":"traversal","steps":[{"type":"key","key":"Math"},{"type":"key","key":"Vector"},{"type":"key","key":"scale"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"tileset"},{"type":"key","key":"tileSize"}]},{"type":"literal","value":0.5}]}]}]}]}]}]}]},"target":{"type":"projection","distance":-1,"length":3,"width":3}}}}} \ No newline at end of file diff --git a/resource/watering-can.entity.json b/resource/watering-can.entity.json new file mode 100644 index 0000000..7605109 --- /dev/null +++ b/resource/watering-can.entity.json @@ -0,0 +1 @@ +{"traits":{"existent":{},"item":{"params":{"itemActions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"item"},{"type":"key","key":"useTool"},{"type":"invoke","args":[]}]}]},"slotImages":{"default":"/watering-can.png"}}},"tool":{"params":{"condition":{"type":"condition","operator":"is","operands":[{"type":"literal","value":6},{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"tileAt"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"target"}]}]}]}]},"actions":{"type":"actions","traversals":[{"type":"traversal","steps":[{"type":"key","key":"wielder"},{"type":"key","key":"layer"},{"type":"key","key":"setTileAt"},{"type":"invoke","args":[{"type":"traversal","steps":[{"type":"key","key":"target"}]},{"type":"literal","value":7}]}]}]},"target":{"type":"projection","distance":1,"length":1,"width":1}}}}} \ No newline at end of file diff --git a/server/fixtures/kitty-fire.room.js b/server/fixtures/kitty-fire.room.js index 7116b95..252dd95 100644 --- a/server/fixtures/kitty-fire.room.js +++ b/server/fixtures/kitty-fire.room.js @@ -61,20 +61,20 @@ export function kittyFireJSON() { roomJSON.layers[0].entities.push(positionedEntityJSON(uri, position)); } - for (let i = 0; i < 20; ++i) { - addEntityWithRandomPosition('/rock.entity.json'); - } - for (let i = 0; i < 20; ++i) { - addEntityWithRandomPosition('/flower-barrel.entity.json'); - } + // for (let i = 0; i < 20; ++i) { + // addEntityWithRandomPosition('/rock.entity.json'); + // } + // for (let i = 0; i < 20; ++i) { + // addEntityWithRandomPosition('/flower-barrel.entity.json'); + // } for (let i = 0; i < 3; ++i) { addEntityWithRandomPosition('/mama-kitty-spawner.entity.json'); } for (let i = 0; i < 5; ++i) { addEntityWithRandomPosition('/fire.entity.json'); } - for (let i = 0; i < 1; ++i) { - addEntityWithRandomPosition('/blue-fire.entity.json'); - } + // for (let i = 0; i < 1; ++i) { + // addEntityWithRandomPosition('/blue-fire.entity.json'); + // } return roomJSON; } diff --git a/server/game.js b/server/game.js index 4f3109e..0ca3073 100644 --- a/server/game.js +++ b/server/game.js @@ -5,12 +5,11 @@ import {performance} from 'perf_hooks'; // 2nd party. import {InputPacket} from '@avocado/input'; import {World} from '@avocado/physics/matter/world'; -import {Synchronizer} from '@avocado/state'; import {Ticker} from '@avocado/timing'; import {Room} from '@avocado/topdown'; // 1st party. import {SelfEntityPacket} from '../common/packets/self-entity.packet'; -import {WorldTime} from '../common/world-time'; +import {WorldTime} from '../common/world-time.synchronized'; import {createEntityForConnection} from './create-entity-for-connection'; // Create game. export default class Game { @@ -22,7 +21,6 @@ export default class Game { Room.load('/kitty-fire.room.json').then((room) => { room.world = new World(); room.world.stepTime = config.simulationInterval; - this.synchronizer.addChild(room); this.room = room; }); // World time. Start at 10 am for testing. @@ -31,9 +29,6 @@ export default class Game { // Entity tracking. this.informables = []; // State synchronization. - this.synchronizer = new Synchronizer([ - this.worldTime, - ]); this.informTicker = new Ticker(config.informInterval); this.informTicker.on('tick', this.inform, this); // Simulation. @@ -62,14 +57,14 @@ export default class Game { this.informables.splice(index, 1); } }); + // Sync world time. + entity.addSynchronized(this.worldTime); // Add entity to room. if (this.room) { this.room.addEntityToLayer(entity, 0); } // Initial information. - const packets = this.synchronizer.packetsForUpdate(true); - packets.unshift(new SelfEntityPacket(entity.numericUid)); - entity.inform(packets); + entity.inform(); // Listen for events. socket.on('packet', this.createPacketListener(socket)); socket.on('disconnect', this.createDisconnectionListener(socket)); @@ -110,12 +105,12 @@ export default class Game { } inform() { - const packets = this.synchronizer.packetsForUpdate(); // Inform entities of the new state. for (let i = 0; i < this.informables.length; ++i) { - const entity = this.informables[i]; - entity.inform(packets); + this.informables[i].inform(); } + // Clean packets. + this.worldTime.cleanPackets(); } readConfig() { diff --git a/server/traits/informed.trait.js b/server/traits/informed.trait.js index d58bcec..49dd796 100644 --- a/server/traits/informed.trait.js +++ b/server/traits/informed.trait.js @@ -6,8 +6,7 @@ import immutablediff from 'immutablediff'; import {compose} from '@avocado/core'; import {EntityCreatePacket, EntityPacket, EntityRemovePacket, Trait} from '@avocado/entity'; import {Rectangle, Vector} from '@avocado/math'; -import {BundlePacket} from '@avocado/net'; -import {Synchronizer} from '@avocado/state'; +import {BundlePacket, ServerSynchronizer} from '@avocado/net'; const decorate = compose( ); @@ -22,6 +21,7 @@ export class Informed extends decorate(Trait) { super(entity, params, state); this.seenEntities = []; this._socket = undefined; + this._synchronizer = new ServerSynchronizer(); } destroy() { @@ -29,6 +29,7 @@ export class Informed extends decorate(Trait) { delete this._socket.entity; delete this._socket; } + this._synchronizer.destroy(); } get areaToInform() { @@ -62,6 +63,44 @@ export class Informed extends decorate(Trait) { }); } + filter(packets) { + packets = packets.filter((packet) => { + return !(packet instanceof EntityPacket); + }); + // // Filter invisible entities. + // packets = this.filterInvisibleEntityPackets(packets); + // // Reduce entities by range. + // const [ + // inRangeEntities, + // outOfRangeEntities, + // visibleEntities, + // ] = this.reducePacketEntitiesByRange(packets); + + // // TODO? Upgrade seen entity packets that are out of range to entity + // // remembers. + + // // Filter the out of range entity updates. + // packets = this.filterOutOfRangeEntityPackets( + // packets, + // outOfRangeEntities + // ); + // // Deduplicate entity creates. + // packets = this.deduplicateEntityCreatePackets(packets); + // // Filter known creates. + // packets = this.filterKnownEntityCreatePackets(packets); + // // Inject create packets. + // packets = this.injectEntityCreatePackets(packets, visibleEntities); + // // Inject removes for any previously seen entity that isn't visible + // // anymore. + // packets = this.injectEntityRemovePackets(packets, visibleEntities); + // // "See" entities. + // this.markEntitiesSeen(visibleEntities); + // // Unsee any removed entities. + // this.markEntitiesUnseen(packets); + + return packets; + } + filterInvisibleEntityPackets(packets) { return packets.filter((packet) => { const entity = packet.entity; @@ -262,46 +301,34 @@ export class Informed extends decorate(Trait) { methods() { return { - inform: (packets) => { - if (0 === packets.length) { + inform: () => { + const payload = this._synchronizer.packetsFor(this.entity); + // const payload = []; + // for (let i = 0; i < this._willWatch.length; i++) { + // const packets = this._willWatch[i].packets(this.entity); + // for (let j = 0; j < packets.length; j++) { + // payload.push(packets[j]); + // } + // } + // for (let i = 0; i < this._watching.length; i++) { + // const packets = this._watching[i].packets(this.entity); + // for (let j = 0; j < packets.length; j++) { + // payload.push(packets[j]); + // } + // } + // for (let i = 0; i < this._willWatch.length; i++) { + // this._watching.push(this._willWatch[i]); + // } + // this._willWatch = []; + // // Clean all packets. + // for (let i = 0; i < this._watching.length; i++) { + // this._watching[i].cleanPackets(); + // } + if (0 === payload.length) { return; } - - // TODO: filter packets that are only delivered to self entity. - - // Filter invisible entities. - packets = this.filterInvisibleEntityPackets(packets); - // Reduce entities by range. - const [ - inRangeEntities, - outOfRangeEntities, - visibleEntities, - ] = this.reducePacketEntitiesByRange(packets); - - // TODO? Upgrade seen entity packets that are out of range to entity - // remembers. - - // Filter the out of range entity updates. - packets = this.filterOutOfRangeEntityPackets( - packets, - outOfRangeEntities - ); - // Deduplicate entity creates. - packets = this.deduplicateEntityCreatePackets(packets); - // Filter known creates. - packets = this.filterKnownEntityCreatePackets(packets); - // Inject create packets. - packets = this.injectEntityCreatePackets(packets, visibleEntities); - // Inject removes for any previously seen entity that isn't visible - // anymore. - packets = this.injectEntityRemovePackets(packets, visibleEntities); - // "See" entities. - this.markEntitiesSeen(visibleEntities); - // Unsee any removed entities. - this.markEntitiesUnseen(packets); - // Ship it! if (this._socket) { - this._socket.send(new BundlePacket(packets)); + this._socket.send(new BundlePacket(payload)); } }, @@ -310,7 +337,15 @@ export class Informed extends decorate(Trait) { this.entity.areaToInform, entity.visibleAabb ); - } + }, + + addSynchronized: (synchronized) => { + this._synchronizer.addSynchronized(synchronized); + }, + + removeSynchronized: (synchronized) => { + this._synchronizer.removeSynchronized(synchronized); + }, }; } diff --git a/webpack.client.config.js b/webpack.client.config.js index 2adbc38..c89ded5 100644 --- a/webpack.client.config.js +++ b/webpack.client.config.js @@ -9,6 +9,7 @@ config.entry = { client: [ '@babel/polyfill', 'register-packets', + 'register-synchronizeds', 'register-traits', '@avocado/behavior/item/initialize', path.join(__dirname, 'client', 'index.js'), @@ -46,6 +47,9 @@ config.module.rules[1].use.options.paths.push( config.module.rules[2].use.options.paths.push( path.resolve(__dirname, 'client'), ); +config.module.rules[3].use.options.paths.push( + path.resolve(__dirname, 'client'), +); config.node = { fs: 'empty', path: 'empty', diff --git a/webpack.common.config.js b/webpack.common.config.js index dba6c61..0f79910 100644 --- a/webpack.common.config.js +++ b/webpack.common.config.js @@ -37,6 +37,22 @@ const config = { }, }, }, + { + test: /register-synchronizeds\.js$/, + use: { + loader: './defgen', + options: { + paths: [ + path.resolve(__dirname, 'common'), + ], + registrar: { + function: 'registerSynchronized', + module: '@avocado/net', + }, + type: 'synchronized', + }, + }, + }, { test: /register-traits\.js$/, use: { @@ -64,8 +80,9 @@ const config = { plugins: [], resolve: { alias: { - 'register-packets': path.resolve(__dirname, 'register-packets'), - 'register-traits': path.resolve(__dirname, 'register-traits'), + 'register-packets': path.join(__dirname, 'register-packets'), + 'register-synchronizeds': path.join(__dirname, 'register-synchronizeds'), + 'register-traits': path.join(__dirname, 'register-traits'), }, modules: [path.resolve(__dirname, 'node_modules')], }, diff --git a/webpack.server.config.js b/webpack.server.config.js index 94d9398..f84fbcc 100644 --- a/webpack.server.config.js +++ b/webpack.server.config.js @@ -12,6 +12,7 @@ config.entry = { 'source-map-support/register', '@babel/polyfill', path.join(__dirname, 'register-packets.js'), + path.join(__dirname, 'register-synchronizeds.js'), '@avocado/behavior/item/initialize', path.join(__dirname, 'server', 'index.js'), ], @@ -34,6 +35,9 @@ config.module.rules[1].use.options.paths.push( config.module.rules[2].use.options.paths.push( path.resolve(__dirname, 'server'), ); +config.module.rules[3].use.options.paths.push( + path.resolve(__dirname, 'server'), +); const nodeArgs = ['--preserve-symlinks']; if (process.argv.find((arg) => '--prof' === arg)) { nodeArgs.push('--prof');