feat: inventory ops
This commit is contained in:
parent
997ef691ca
commit
9d9f94a7cc
|
@ -121,7 +121,7 @@ class ItemProxy {
|
||||||
|
|
||||||
export default class Inventory extends Component {
|
export default class Inventory extends Component {
|
||||||
async updateMany(entities) {
|
async updateMany(entities) {
|
||||||
for (const [id, {cleared, given, qtyUpdated, swapped}] of entities) {
|
for (const [id, {cleared, distributed, given, qtyUpdated, swapped}] of entities) {
|
||||||
const instance = this.get(id);
|
const instance = this.get(id);
|
||||||
const {$$items, slots} = instance;
|
const {$$items, slots} = instance;
|
||||||
if (cleared) {
|
if (cleared) {
|
||||||
|
@ -173,6 +173,7 @@ export default class Inventory extends Component {
|
||||||
instanceFromSchema() {
|
instanceFromSchema() {
|
||||||
const Instance = super.instanceFromSchema();
|
const Instance = super.instanceFromSchema();
|
||||||
const Component = this;
|
const Component = this;
|
||||||
|
const {ecs} = Component;
|
||||||
return class InventoryInstance extends Instance {
|
return class InventoryInstance extends Instance {
|
||||||
$$items = {};
|
$$items = {};
|
||||||
clear(slot) {
|
clear(slot) {
|
||||||
|
@ -180,6 +181,56 @@ export default class Inventory extends Component {
|
||||||
delete this.slots[slot];
|
delete this.slots[slot];
|
||||||
delete this.$$items[slot];
|
delete this.$$items[slot];
|
||||||
}
|
}
|
||||||
|
async distribute(slot, potentialDestinations) {
|
||||||
|
const {slots} = this;
|
||||||
|
if (!slots[slot]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const destinations = [];
|
||||||
|
const given = [];
|
||||||
|
const updated = [];
|
||||||
|
for (const [entityId, destination] of potentialDestinations) {
|
||||||
|
const {Inventory} = ecs.get(entityId);
|
||||||
|
const {slots} = Inventory;
|
||||||
|
if (!slots[destination]) {
|
||||||
|
slots[destination] = {
|
||||||
|
qty: 0,
|
||||||
|
source: slots[slot].source,
|
||||||
|
};
|
||||||
|
this.$$items[destination] = new ItemProxy(Component, this, destination);
|
||||||
|
await this.$$items[destination].load(slots[destination].source);
|
||||||
|
destinations.push([entityId, destination]);
|
||||||
|
given.push([entityId, destination]);
|
||||||
|
}
|
||||||
|
else if (slots[slot].source === slots[destination].source) {
|
||||||
|
destinations.push([entityId, destination]);
|
||||||
|
updated.push([entityId, destination, slots[destination].qty]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const {qty} = slots[slot];
|
||||||
|
slots[slot].qty = 0;
|
||||||
|
for (let i = 0; i < qty; ++i) {
|
||||||
|
const [entityId, destination] = destinations[i % destinations.length];
|
||||||
|
const {Inventory} = ecs.get(entityId);
|
||||||
|
const {slots} = Inventory;
|
||||||
|
slots[destination].qty += 1;
|
||||||
|
}
|
||||||
|
if (!destinations.find(([entityId, destination]) => {
|
||||||
|
return entityId == this.entity && destination === slot;
|
||||||
|
})) {
|
||||||
|
this.clear(slot);
|
||||||
|
}
|
||||||
|
for (const [entityId, destination] of given) {
|
||||||
|
const {Inventory} = ecs.get(entityId);
|
||||||
|
const {slots} = Inventory;
|
||||||
|
Component.markChange(entityId, 'given', {[destination]: {qty: slots[destination].qty, source: slots[destination].source}});
|
||||||
|
}
|
||||||
|
for (const [entityId, destination, qty] of updated) {
|
||||||
|
const {Inventory} = ecs.get(entityId);
|
||||||
|
const {slots} = Inventory;
|
||||||
|
Component.markChange(entityId, 'qtyUpdated', {[destination]: slots[destination].qty - qty});
|
||||||
|
}
|
||||||
|
}
|
||||||
item(slot) {
|
item(slot) {
|
||||||
return this.$$items[slot];
|
return this.$$items[slot];
|
||||||
}
|
}
|
||||||
|
@ -265,7 +316,7 @@ export default class Inventory extends Component {
|
||||||
value: {
|
value: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
quantity: {type: 'uint16'},
|
qty: {type: 'uint16'},
|
||||||
source: {type: 'string'},
|
source: {type: 'string'},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -11,6 +11,8 @@ export default function Grid({
|
||||||
highlighted,
|
highlighted,
|
||||||
label,
|
label,
|
||||||
onSlotMouseDown,
|
onSlotMouseDown,
|
||||||
|
onSlotMouseMove,
|
||||||
|
onSlotMouseUp,
|
||||||
slots,
|
slots,
|
||||||
}) {
|
}) {
|
||||||
const Slots = slots.map((slot, i) => (
|
const Slots = slots.map((slot, i) => (
|
||||||
|
@ -28,10 +30,15 @@ export default function Grid({
|
||||||
<Slot
|
<Slot
|
||||||
icon={slot?.icon}
|
icon={slot?.icon}
|
||||||
onMouseDown={(event) => {
|
onMouseDown={(event) => {
|
||||||
onSlotMouseDown(i)
|
onSlotMouseDown?.(i, event)
|
||||||
|
event.stopPropagation();
|
||||||
|
}}
|
||||||
|
onMouseMove={(event) => {
|
||||||
|
onSlotMouseMove?.(i, event)
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}}
|
}}
|
||||||
onMouseUp={(event) => {
|
onMouseUp={(event) => {
|
||||||
|
onSlotMouseUp?.(i, event)
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
}}
|
}}
|
||||||
onDragStart={(event) => {
|
onDragStart={(event) => {
|
||||||
|
|
|
@ -10,10 +10,9 @@ import Grid from './grid.jsx';
|
||||||
*/
|
*/
|
||||||
function Hotbar({
|
function Hotbar({
|
||||||
active,
|
active,
|
||||||
highlighted,
|
|
||||||
hotbarIsHidden,
|
hotbarIsHidden,
|
||||||
onSlotMouseDown,
|
|
||||||
slots,
|
slots,
|
||||||
|
...rest
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
@ -35,10 +34,9 @@ function Hotbar({
|
||||||
active={active}
|
active={active}
|
||||||
color="rgba(02, 02, 57, 0.6)"
|
color="rgba(02, 02, 57, 0.6)"
|
||||||
columns={10}
|
columns={10}
|
||||||
highlighted={highlighted}
|
|
||||||
label={slots[active] && slots[active].label}
|
label={slots[active] && slots[active].label}
|
||||||
onSlotMouseDown={onSlotMouseDown}
|
|
||||||
slots={slots}
|
slots={slots}
|
||||||
|
{...rest}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,6 +11,7 @@ export default function Slot({
|
||||||
onDragStart,
|
onDragStart,
|
||||||
onDrop,
|
onDrop,
|
||||||
onMouseDown,
|
onMouseDown,
|
||||||
|
onMouseMove,
|
||||||
onMouseUp,
|
onMouseUp,
|
||||||
qty = 1,
|
qty = 1,
|
||||||
}) {
|
}) {
|
||||||
|
@ -27,6 +28,7 @@ export default function Slot({
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}}
|
}}
|
||||||
onMouseDown={onMouseDown}
|
onMouseDown={onMouseDown}
|
||||||
|
onMouseMove={onMouseMove}
|
||||||
onMouseUp={onMouseUp}
|
onMouseUp={onMouseUp}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
|
@ -45,6 +45,8 @@ function Ui({disconnected}) {
|
||||||
const ecsRef = useEcs();
|
const ecsRef = useEcs();
|
||||||
const [showDisconnected, setShowDisconnected] = useState(false);
|
const [showDisconnected, setShowDisconnected] = useState(false);
|
||||||
const [bufferSlot, setBufferSlot] = useState();
|
const [bufferSlot, setBufferSlot] = useState();
|
||||||
|
const hadBufferSlot = useRef();
|
||||||
|
const distributing = useRef(new Map());
|
||||||
const [devtoolsIsOpen, setDevtoolsIsOpen] = useState(false);
|
const [devtoolsIsOpen, setDevtoolsIsOpen] = useState(false);
|
||||||
const ratio = (RESOLUTION.x * (devtoolsIsOpen ? 2 : 1)) / RESOLUTION.y;
|
const ratio = (RESOLUTION.x * (devtoolsIsOpen ? 2 : 1)) / RESOLUTION.y;
|
||||||
const [camera, setCamera] = useState({x: 0, y: 0});
|
const [camera, setCamera] = useState({x: 0, y: 0});
|
||||||
|
@ -223,7 +225,7 @@ function Ui({disconnected}) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [client, keepHotbarOpen, setDebug]);
|
}, [client, keepHotbarOpen, mainEntityRef, setDebug]);
|
||||||
const onEcsChangePacket = useCallback(() => {
|
const onEcsChangePacket = useCallback(() => {
|
||||||
mainEntityRef.current = undefined;
|
mainEntityRef.current = undefined;
|
||||||
monopolizers.current = [];
|
monopolizers.current = [];
|
||||||
|
@ -390,7 +392,7 @@ function Ui({disconnected}) {
|
||||||
mainEntityRef,
|
mainEntityRef,
|
||||||
scale,
|
scale,
|
||||||
]);
|
]);
|
||||||
const hotbarOnSlotMouseDown = useCallback((i) => {
|
const hotbarOnSlotMouseDown = useCallback((i, event) => {
|
||||||
keepHotbarOpen();
|
keepHotbarOpen();
|
||||||
if (trading) {
|
if (trading) {
|
||||||
const index = losing.indexOf(i + 1);
|
const index = losing.indexOf(i + 1);
|
||||||
|
@ -403,12 +405,77 @@ function Ui({disconnected}) {
|
||||||
setLosing([...losing]);
|
setLosing([...losing]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
client.send({
|
hadBufferSlot.current = bufferSlot;
|
||||||
type: 'Action',
|
switch (event.button) {
|
||||||
payload: {type: 'swapSlots', value: [0, mainEntityRef.current, i + 1]},
|
case 0:
|
||||||
});
|
if (bufferSlot) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
client.send({
|
||||||
|
type: 'Action',
|
||||||
|
payload: {type: 'swapSlots', value: [0, mainEntityRef.current, i + 1]},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
client.send({
|
||||||
|
type: 'Action',
|
||||||
|
payload: {
|
||||||
|
type: 'distribute',
|
||||||
|
value: [
|
||||||
|
i + 1,
|
||||||
|
[
|
||||||
|
[mainEntityRef.current, 0],
|
||||||
|
[mainEntityRef.current, i + 1],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [client, keepHotbarOpen, losing, mainEntityRef, trading]);
|
}, [bufferSlot, client, keepHotbarOpen, losing, mainEntityRef, trading]);
|
||||||
|
const hotbarOnSlotMouseMove = useCallback((i) => {
|
||||||
|
if (hadBufferSlot.current) {
|
||||||
|
distributing.current.set([mainEntityRef.current, i + 1].join(':'), true);
|
||||||
|
}
|
||||||
|
}, [mainEntityRef]);
|
||||||
|
const hotbarOnSlotMouseUp = useCallback((i, event) => {
|
||||||
|
keepHotbarOpen();
|
||||||
|
if (trading) {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (event.button) {
|
||||||
|
case 0:
|
||||||
|
if (distributing.current.size > 0) {
|
||||||
|
client.send({
|
||||||
|
type: 'Action',
|
||||||
|
payload: {
|
||||||
|
type: 'distribute',
|
||||||
|
value: [
|
||||||
|
0,
|
||||||
|
Array.from(distributing.current.keys()).map((idAndSlot) => idAndSlot.split(':')),
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
distributing.current.clear();
|
||||||
|
}
|
||||||
|
else if (hadBufferSlot.current) {
|
||||||
|
client.send({
|
||||||
|
type: 'Action',
|
||||||
|
payload: {type: 'swapSlots', value: [0, mainEntityRef.current, i + 1]},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
hadBufferSlot.current = undefined;
|
||||||
|
}, [client, keepHotbarOpen, mainEntityRef, trading]);
|
||||||
const bagOnSlotMouseDown = useCallback((i) => {
|
const bagOnSlotMouseDown = useCallback((i) => {
|
||||||
if (trading) {
|
if (trading) {
|
||||||
const index = losing.indexOf(i + 11);
|
const index = losing.indexOf(i + 11);
|
||||||
|
@ -574,6 +641,8 @@ function Ui({disconnected}) {
|
||||||
highlighted={trading && losing.filter((i) => i < 11).map((i) => i - 1)}
|
highlighted={trading && losing.filter((i) => i < 11).map((i) => i - 1)}
|
||||||
hotbarIsHidden={hotbarIsHidden}
|
hotbarIsHidden={hotbarIsHidden}
|
||||||
onSlotMouseDown={hotbarOnSlotMouseDown}
|
onSlotMouseDown={hotbarOnSlotMouseDown}
|
||||||
|
onSlotMouseMove={hotbarOnSlotMouseMove}
|
||||||
|
onSlotMouseUp={hotbarOnSlotMouseUp}
|
||||||
slots={hotbarSlots}
|
slots={hotbarSlots}
|
||||||
/>
|
/>
|
||||||
<Bag
|
<Bag
|
||||||
|
|
|
@ -260,6 +260,13 @@ export default class Engine {
|
||||||
Wallet.gold += earn;
|
Wallet.gold += earn;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'distribute': {
|
||||||
|
if (!Controlled.locked) {
|
||||||
|
const [slot, destinations] = payload.value;
|
||||||
|
Inventory.distribute(slot, destinations);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case 'swapSlots': {
|
case 'swapSlots': {
|
||||||
if (!Controlled.locked) {
|
if (!Controlled.locked) {
|
||||||
const [l, other, r] = payload.value;
|
const [l, other, r] = payload.value;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user