From 28e5e9f56f99f63f4f01c31c3b314f20de0092fc Mon Sep 17 00:00:00 2001 From: cha0s Date: Wed, 10 Feb 2021 10:59:49 -0600 Subject: [PATCH] refactor: input --- app/src/react/components/play/index.jsx | 17 ++--- packages/core/src/traits/controllable.js | 97 ++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 11 deletions(-) diff --git a/app/src/react/components/play/index.jsx b/app/src/react/components/play/index.jsx index da5fc61..26f912c 100644 --- a/app/src/react/components/play/index.jsx +++ b/app/src/react/components/play/index.jsx @@ -1,6 +1,6 @@ import './index.scss'; -import {ActionRegistry, InputNormalizer} from '@avocado/input'; +import {InputNormalizer} from '@avocado/input'; import {setSelfEntity, useSelfEntity} from '@humus/core'; import {useDispatch} from '@latus/redux'; import {useSocket} from '@latus/socket'; @@ -26,23 +26,18 @@ const Play = () => { }; }, [dispatch, socket, uuid]); useEffect(() => { - if (!ref.current) { + if (!ref.current || !selfEntity) { return undefined; } const inputNormalizer = new InputNormalizer(); inputNormalizer.listen(window.document.body); - const actionRegistry = new ActionRegistry(); - actionRegistry.setActionTransformerFor('UseItem', (type) => ( - selfEntity && 'keyDown' === type ? selfEntity.activeSlotIndex : -1 + selfEntity.listenForInput(inputNormalizer); + selfEntity.actionRegistry.setTransformerFor('UseItem', (type) => ( + 'keyDown' === type ? selfEntity.activeSlotIndex : -1 )); - actionRegistry.listen(inputNormalizer); const inputHandle = setInterval(() => { - const inputStream = actionRegistry.drain(); + const inputStream = selfEntity.drainInput(); if (inputStream.length > 0) { - // Inject input. - if (selfEntity) { - selfEntity.inputStream = inputStream; - } const sending = inputStream.filter(({action}) => { if (action.match(/^HotbarSlot(\d)/)) { return false; diff --git a/packages/core/src/traits/controllable.js b/packages/core/src/traits/controllable.js index 1a18b89..50a3d22 100644 --- a/packages/core/src/traits/controllable.js +++ b/packages/core/src/traits/controllable.js @@ -2,6 +2,7 @@ import { TickingPromise, } from '@avocado/core'; import {Vector} from '@avocado/math'; +import {ActionRegistry} from '@avocado/input'; import {Trait} from '@avocado/traits'; import { compose, @@ -18,15 +19,85 @@ const decorate = compose( // Input handling. export default () => class Controllable extends decorate(Trait) { + #actionRegistry; + #itemPromise; #itemUseRequest = -1; + #queued = []; + constructor() { super(); this.on('controllableMovementChanged', this.updateAnimation, this); } + get actionRegistry() { + return this.#actionRegistry; + } + + static defaultParams() { + return { + actions: { + HotbarSlot0: [ + {type: 'key', index: '1'}, + ], + HotbarSlot1: [ + {type: 'key', index: '2'}, + ], + HotbarSlot2: [ + {type: 'key', index: '3'}, + ], + HotbarSlot3: [ + {type: 'key', index: '4'}, + ], + HotbarSlot4: [ + {type: 'key', index: '5'}, + ], + HotbarSlot5: [ + {type: 'key', index: '6'}, + ], + HotbarSlot6: [ + {type: 'key', index: '7'}, + ], + HotbarSlot7: [ + {type: 'key', index: '8'}, + ], + HotbarSlot8: [ + {type: 'key', index: '9'}, + ], + HotbarSlot9: [ + {type: 'key', index: '0'}, + ], + HotbarSlotNext: [ + {type: 'key', index: 'WheelDown'}, + ], + HotbarSlotPrevious: [ + {type: 'key', index: 'WheelUp'}, + ], + MoveUp: [ + {type: 'key', index: 'w'}, + ], + MoveLeft: [ + {type: 'key', index: 'a'}, + ], + MoveDown: [ + {type: 'key', index: 's'}, + ], + MoveRight: [ + {type: 'key', index: 'd'}, + ], + UseItem: [ + {type: 'key', index: 'ArrowLeft'}, + {type: 'button', index: 0}, + ], + Interact: [ + {type: 'key', index: 'e'}, + ], + }, + }; + } + static dependencies() { return [ 'Animated', @@ -36,6 +107,10 @@ export default () => class Controllable extends decorate(Trait) { ]; } + destroy() { + this.#actionRegistry.stopListening(); + } + set inputStream(inputStream) { for (let i = 0; i < inputStream.length; i++) { const {action, value} = inputStream[i]; @@ -76,9 +151,31 @@ export default () => class Controllable extends decorate(Trait) { async load(json) { await super.load(json); this.entity.on('isMobileChanged', this.updateAnimation, this); + this.#actionRegistry = new ActionRegistry(this.params.actions); + } + + methods() { + return { + + drainInput: () => { + const drained = this.#queued; + this.#queued = []; + return drained; + }, + + listenForInput: (inputNormalizer) => { + this.#actionRegistry.listen(inputNormalizer); + }, + + }; } tick(elapsed) { + if ('client' === process.env.SIDE) { + const drained = this.#actionRegistry.drain(); + this.inputStream = drained; + this.#queued.push(...drained); + } if (-1 !== this.#itemUseRequest && !this.#itemPromise) { this.#itemPromise = this.entity.useItemInSlot(this.#itemUseRequest); Promise.resolve(this.#itemPromise).then(() => {