Compare commits
41 Commits
324123df14
...
8527be39fb
Author | SHA1 | Date | |
---|---|---|---|
|
8527be39fb | ||
|
9cfb06f66c | ||
|
7c976ad8c0 | ||
|
88fa01c920 | ||
|
7bafc4702a | ||
|
e540d98c46 | ||
|
5aa17441a1 | ||
|
bfe9e427b9 | ||
|
51edbec463 | ||
|
d82c33338e | ||
|
0c234de26d | ||
|
b773f44c31 | ||
|
dfc190048f | ||
|
8589589d2b | ||
|
5f279bf549 | ||
|
477b76acd5 | ||
|
e3d0cc2477 | ||
|
9dec5d15a3 | ||
|
88055be00a | ||
|
7a1e08bc1a | ||
|
5de530077f | ||
|
6b3136a0b5 | ||
|
aaa78c99c5 | ||
|
d55c35ca33 | ||
|
bcb4115fa0 | ||
|
04fd533811 | ||
|
9262e7b1a8 | ||
|
500ada03ff | ||
|
3df5266ba3 | ||
|
21f8864b1b | ||
|
3fffb49e24 | ||
|
c21e6982ac | ||
|
607fbe9d9e | ||
|
050664a826 | ||
|
8ae9daa9ba | ||
|
6526989db6 | ||
|
85b0e59907 | ||
|
4c9635ec83 | ||
|
ff52066e71 | ||
|
de6465df5b | ||
|
eca9bc631e |
|
@ -2,19 +2,22 @@ import fastCall from './fast-call.js';
|
|||
|
||||
export default class EventEmitter {
|
||||
$$listeners = {};
|
||||
addListener(type, listener) {
|
||||
addListener(type, listener, options = {}) {
|
||||
if (!this.$$listeners[type]) {
|
||||
this.$$listeners[type] = new Set();
|
||||
this.$$listeners[type] = new Map();
|
||||
}
|
||||
this.$$listeners[type].add(listener);
|
||||
this.$$listeners[type].set(listener, options);
|
||||
}
|
||||
invoke(type, ...args) {
|
||||
const listeners = this.$$listeners[type];
|
||||
if (!listeners) {
|
||||
return;
|
||||
}
|
||||
for (const listener of listeners) {
|
||||
for (const [listener, options] of listeners) {
|
||||
fastCall(listener, undefined, args);
|
||||
if (options.once) {
|
||||
listeners.delete(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
removeListener(type, listener) {
|
||||
|
|
|
@ -53,6 +53,23 @@ export const HALF_PI = Math.PI / 2;
|
|||
export const TAU = Math.PI * 2;
|
||||
export const PI_180 = Math.PI / 180;
|
||||
|
||||
export function aabbFromPoints(points) {
|
||||
let x0 = Infinity, x1 = -Infinity, y0 = Infinity, y1 = -Infinity;
|
||||
for (const point of points) {
|
||||
const {x, y} = point;
|
||||
if (x < x0) x0 = x;
|
||||
if (x > x1) x1 = x;
|
||||
if (y < y0) y0 = y;
|
||||
if (y > y1) y1 = y;
|
||||
}
|
||||
return {
|
||||
x0: x0 > x1 ? x1 : x0,
|
||||
x1: x0 > x1 ? x0 : x1,
|
||||
y0: y0 > y1 ? y1 : y0,
|
||||
y1: y0 > y1 ? y0 : y1,
|
||||
};
|
||||
}
|
||||
|
||||
export function bresenham({x: x1, y: y1}, {x: x2, y: y2}) {
|
||||
const points = [];
|
||||
let x; let y; let px; let py; let xe; let ye;
|
||||
|
|
|
@ -48,7 +48,7 @@ export default class Script {
|
|||
static async registerScriptsModule() {
|
||||
const {default: scripts} = await import('./scripts.js');
|
||||
for (const path in scripts) {
|
||||
Script.register(path, scripts[path]);
|
||||
this.register(path, scripts[path]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ export default function addKeyListener(target, listener) {
|
|||
delete keyUpDelays[key];
|
||||
delete keysDown[key];
|
||||
listener({event, type: 'keyUp', payload: key});
|
||||
}, 20);
|
||||
}, 5);
|
||||
}
|
||||
window.addEventListener('blur', onBlur);
|
||||
window.addEventListener('keyup', onKeyUp);
|
||||
|
|
|
@ -1,52 +1,37 @@
|
|||
import {useCallback, useState} from 'react';
|
||||
import {useEffect} from 'react';
|
||||
import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
|
||||
import 'react-tabs/style/react-tabs.css';
|
||||
|
||||
import {useClient} from '@/react/context/client.js';
|
||||
import {useEcsTick} from '@/react/context/ecs.js';
|
||||
import {useMainEntity} from '@/react/context/main-entity.js';
|
||||
|
||||
import styles from './devtools.module.css';
|
||||
|
||||
import Tiles from './devtools/tiles.jsx';
|
||||
import TabComponents from './devtools/components.js';
|
||||
|
||||
export default function Devtools({
|
||||
eventsChannel,
|
||||
}) {
|
||||
const client = useClient();
|
||||
const mainEntityRef = useMainEntity();
|
||||
const [mainEntityJson, setMainEntityJson] = useState('');
|
||||
const onEcsTick = useCallback((payload, ecs) => {
|
||||
if (!mainEntityRef.current) {
|
||||
return;
|
||||
useEffect(() => {
|
||||
if (import.meta.hot) {
|
||||
const updating = new Set(TabComponents.map(([path]) => path));
|
||||
import.meta.hot.on('vite:afterUpdate', ({updates}) => {
|
||||
if (updates.some(({path}) => updating.has(path))) {
|
||||
import.meta.hot.invalidate();
|
||||
}
|
||||
});
|
||||
}
|
||||
setMainEntityJson(JSON.stringify(ecs.get(mainEntityRef.current), null, 2));
|
||||
}, [mainEntityRef]);
|
||||
useEcsTick(onEcsTick);
|
||||
}, []);
|
||||
return (
|
||||
<div className={styles.devtools}>
|
||||
<Tabs>
|
||||
<TabList>
|
||||
<Tab>Dashboard</Tab>
|
||||
<Tab>Tiles</Tab>
|
||||
{TabComponents.map(([path, {displayName}]) => <Tab key={path}>{displayName}</Tab>)}
|
||||
</TabList>
|
||||
<TabPanel>
|
||||
<div className={styles.dashboard}>
|
||||
<form>
|
||||
<div className={styles.engineBar}>
|
||||
<div>{Math.round(client.rtt * 100) / 100}rtt</div>
|
||||
<div>{Math.round(((client.throughput.down * 8) / 1024) * 10) / 10}kb/s down</div>
|
||||
<div>{Math.round(((client.throughput.up * 8) / 1024) * 10) / 10}kb/s up</div>
|
||||
</div>
|
||||
</form>
|
||||
<pre><code><small>{mainEntityJson}</small></code></pre>
|
||||
</div>
|
||||
</TabPanel>
|
||||
<TabPanel>
|
||||
<Tiles
|
||||
eventsChannel={eventsChannel}
|
||||
/>
|
||||
</TabPanel>
|
||||
{TabComponents.map(([path, TabComponent]) => (
|
||||
<TabPanel key={path}>
|
||||
<TabComponent
|
||||
eventsChannel={eventsChannel}
|
||||
/>
|
||||
</TabPanel>
|
||||
))}
|
||||
</Tabs>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
.engineBar {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px 0;
|
||||
}
|
||||
|
||||
.devtools {
|
||||
background-color: #444444;
|
||||
color: white;
|
||||
font-size: 24px;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.devtools form {
|
||||
&, & * {
|
||||
font-size: 100%;
|
||||
}
|
||||
label {
|
||||
font-weight: bold;
|
||||
:first-child {
|
||||
|
@ -35,6 +33,24 @@
|
|||
> :global(.react-tabs__tab-panel) {
|
||||
overflow-y: auto;
|
||||
}
|
||||
:global(.react-tabs__tab) {
|
||||
button {
|
||||
background: transparent;
|
||||
border: none;
|
||||
border-radius: 1em;
|
||||
cursor: pointer;
|
||||
left: 0.25em;
|
||||
padding: 0 0.125em;
|
||||
position: relative;
|
||||
visibility: hidden;
|
||||
&:hover {
|
||||
background-color: #ffffff33;
|
||||
}
|
||||
}
|
||||
&:hover button {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
:global(.react-tabs__tab--selected) {
|
||||
background-color: #00000022;
|
||||
color: #ffffff;
|
||||
|
@ -43,10 +59,3 @@
|
|||
background-color: #00000044;
|
||||
}
|
||||
}
|
||||
|
||||
.dashboard {
|
||||
margin: 16px;
|
||||
pre {
|
||||
user-select: text;
|
||||
}
|
||||
}
|
||||
|
|
7
app/react/components/devtools/components.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
const entries = Object.entries(
|
||||
import.meta.glob('./*.jsx', {eager: true}),
|
||||
);
|
||||
|
||||
export default entries
|
||||
.filter(([, M]) => M.default)
|
||||
.map(([path, M]) => ([new URL(path, import.meta.url).pathname, M.default]));
|
34
app/react/components/devtools/dashboard.jsx
Normal file
|
@ -0,0 +1,34 @@
|
|||
import {useClient} from '@/react/context/client.js';
|
||||
import {useDebug} from '@/react/context/debug.js';
|
||||
|
||||
import styles from './dashboard.module.css';
|
||||
|
||||
function Dashboard() {
|
||||
const client = useClient();
|
||||
const [debug, setDebug] = useDebug();
|
||||
return (
|
||||
<div className={styles.dashboard}>
|
||||
<form>
|
||||
<div className={styles.engineBar}>
|
||||
<div>{Math.round(client.rtt * 100) / 100}rtt</div>
|
||||
<div>{Math.round(((client.throughput.down * 8) / 1024) * 10) / 10}kb/s down</div>
|
||||
<div>{Math.round(((client.throughput.up * 8) / 1024) * 10) / 10}kb/s up</div>
|
||||
</div>
|
||||
<label>
|
||||
Disable ambient light
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={debug.disableAmbientLight}
|
||||
onChange={() => {
|
||||
setDebug({...debug, disableAmbientLight: !debug.disableAmbientLight});
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Dashboard.displayName = 'Dashboard';
|
||||
|
||||
export default Dashboard;
|
12
app/react/components/devtools/dashboard.module.css
Normal file
|
@ -0,0 +1,12 @@
|
|||
.dashboard {
|
||||
margin: 16px;
|
||||
pre {
|
||||
user-select: text;
|
||||
}
|
||||
}
|
||||
|
||||
.engineBar {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
margin-bottom: 16px 0;
|
||||
}
|
192
app/react/components/devtools/entities.jsx
Normal file
|
@ -0,0 +1,192 @@
|
|||
import {Map} from 'immutable';
|
||||
import {useCallback, useEffect, useState} from 'react';
|
||||
import {Tab, Tabs, TabList, TabPanel} from 'react-tabs';
|
||||
|
||||
import {useClient} from '@/react/context/client.js';
|
||||
import {useEcs, useEcsTick} from '@/react/context/ecs.js';
|
||||
|
||||
import styles from './entities.module.css';
|
||||
|
||||
const entityJsonPaths = Object.keys(import.meta.glob('%/**/*.entity.json'));
|
||||
|
||||
function entityLabel(entity) {
|
||||
let label = `${entity.id}`;
|
||||
const {Label, Player} = entity;
|
||||
if (1 === entity.id) {
|
||||
label = 'Master';
|
||||
}
|
||||
if (Player) {
|
||||
label = `Player (${Player.id})`;
|
||||
}
|
||||
if (Label) {
|
||||
label = Label.label;
|
||||
}
|
||||
return label;
|
||||
}
|
||||
|
||||
function Entities({eventsChannel}) {
|
||||
const client = useClient();
|
||||
const ecsRef = useEcs();
|
||||
const [activeEntity, setActiveEntity] = useState('1');
|
||||
const [creatingEntityPath, setCreatingEntityPath] = useState(entityJsonPaths[0]);
|
||||
const [entities, setEntities] = useState(Map());
|
||||
const onEcsTick = useCallback((payload, ecs) => {
|
||||
setEntities((entities) => {
|
||||
return entities.withMutations((entities) => {
|
||||
if (0 === entities.size) {
|
||||
for (const id in ecs.$$entities) {
|
||||
const entity = ecs.get(id);
|
||||
entities.set(id, entityLabel(entity));
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (const id in payload) {
|
||||
const update = payload[id];
|
||||
if (false === update) {
|
||||
entities.delete(id);
|
||||
}
|
||||
else {
|
||||
const entity = ecs.get(id);
|
||||
entities.set(id, entityLabel(entity));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}, []);
|
||||
useEcsTick(onEcsTick);
|
||||
const list = Array.from(entities.keys())
|
||||
.toSorted(new Intl.Collator(undefined, {numeric: true, sensitivity: 'base'}).compare);
|
||||
useEffect(() => {
|
||||
if (!ecsRef.current) {
|
||||
return;
|
||||
}
|
||||
const master = ecsRef.current.get(1);
|
||||
if (!master) {
|
||||
return;
|
||||
}
|
||||
const {TileLayers} = master;
|
||||
const {size, tileSize} = TileLayers.layer(0);
|
||||
function onClick({x, y}, {shiftKey}) {
|
||||
const at = {
|
||||
x: shiftKey ? Math.floor(x / tileSize.x) * tileSize.x + (tileSize.x / 2) : x,
|
||||
y: shiftKey ? Math.floor(y / tileSize.y) * tileSize.y + (tileSize.y / 2) : y,
|
||||
};
|
||||
if (at.x < 0 || at.y < 0 || at.x >= size.x || at.y >= size.y) {
|
||||
return;
|
||||
}
|
||||
const entity = ecsRef.current.get(activeEntity);
|
||||
if (!entity.Position) {
|
||||
return;
|
||||
}
|
||||
client.send({
|
||||
type: 'AdminAction',
|
||||
payload: {
|
||||
type: 'moveEntity',
|
||||
value: {
|
||||
id: activeEntity,
|
||||
at,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
eventsChannel.addListener('click', onClick);
|
||||
return () => {
|
||||
eventsChannel.removeListener('click', onClick);
|
||||
};
|
||||
}, [activeEntity, client, ecsRef, eventsChannel]);
|
||||
const options = [];
|
||||
const tabLabels = [];
|
||||
const tabPanels = [];
|
||||
for (const id of list) {
|
||||
const label = entities.get(id);
|
||||
tabLabels.push(
|
||||
<Tab key={id}>
|
||||
{label}
|
||||
<button
|
||||
onClick={(event) => {
|
||||
client.send({
|
||||
type: 'AdminAction',
|
||||
payload: {
|
||||
type: 'destroyEntity',
|
||||
value: {
|
||||
id,
|
||||
},
|
||||
},
|
||||
});
|
||||
event.preventDefault();
|
||||
}}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</Tab>
|
||||
);
|
||||
tabPanels.push(
|
||||
<TabPanel key={id}>
|
||||
{id}
|
||||
</TabPanel>
|
||||
);
|
||||
options.push(
|
||||
<option
|
||||
key={id}
|
||||
value={id}
|
||||
>
|
||||
{label}
|
||||
</option>);
|
||||
}
|
||||
return (
|
||||
<div className={styles.entities}>
|
||||
<form>
|
||||
<div
|
||||
className={styles.createEntity}
|
||||
>
|
||||
<button
|
||||
onClick={async (event) => {
|
||||
event.preventDefault();
|
||||
const {payload} = await client.request({
|
||||
type: 'AdminAction',
|
||||
payload: {
|
||||
type: 'createEntity',
|
||||
value: {
|
||||
path: creatingEntityPath,
|
||||
},
|
||||
},
|
||||
});
|
||||
setActiveEntity(`${payload.id}`);
|
||||
}}
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<select
|
||||
onChange={(event) => {
|
||||
setCreatingEntityPath(event.target.value);
|
||||
}}
|
||||
value={creatingEntityPath}
|
||||
>
|
||||
{entityJsonPaths.map((path) => (
|
||||
<option key={path} value={path}>{path}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div
|
||||
className={styles.activeEntity}
|
||||
>
|
||||
<Tabs
|
||||
onSelect={(index) => {
|
||||
setActiveEntity(list[index]);
|
||||
}}
|
||||
selectedIndex={list.indexOf(activeEntity)}
|
||||
>
|
||||
<TabList>
|
||||
{tabLabels}
|
||||
</TabList>
|
||||
{tabPanels}
|
||||
</Tabs>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Entities.displayName = 'Entities';
|
||||
|
||||
export default Entities;
|
7
app/react/components/devtools/entities.module.css
Normal file
|
@ -0,0 +1,7 @@
|
|||
.activeEntity {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.createEntity {
|
||||
display: flex;
|
||||
}
|
|
@ -6,7 +6,7 @@ import useRect from '@/react/hooks/use-rect.js';
|
|||
|
||||
import styles from './tiles.module.css';
|
||||
|
||||
export default function Tiles({eventsChannel}) {
|
||||
function Tiles({eventsChannel}) {
|
||||
const client = useClient();
|
||||
const wrapperRef = useRef();
|
||||
const imageRef = useRef();
|
||||
|
@ -228,4 +228,8 @@ export default function Tiles({eventsChannel}) {
|
|||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Tiles.displayName = 'Tiles';
|
||||
|
||||
export default Tiles;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.tiles {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
image-rendering: pixelated;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,8 @@
|
|||
calc(-50% + (1px * var(--offsetY)) + var(--positionY))
|
||||
;
|
||||
user-select: none;
|
||||
will-change: color, scale, opacity, translate, transform;
|
||||
/** quality degradation... */
|
||||
/* will-change: color, scale, opacity, translate, transform; */
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import {Emitter} from '@/lib/particles.js';
|
||||
import Script from '@/lib/script.js';
|
||||
import createEcs from '@/silphius/server/create/ecs.js';
|
||||
|
||||
import ClientEcs from './client-ecs.js';
|
||||
|
@ -28,7 +29,9 @@ addEventListener('message', (particle) => {
|
|||
.onEnd(() => {});
|
||||
});
|
||||
|
||||
postMessage(null);
|
||||
Script.registerScriptsModule().then(() => {
|
||||
postMessage(null);
|
||||
});
|
||||
|
||||
let last = performance.now();
|
||||
function tick(now) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import {Container, useApp} from '@pixi/react';
|
||||
import {useCallback, useState} from 'react';
|
||||
|
||||
import {useDebug} from '@/react/context/debug.js';
|
||||
import {useEcsTick} from '@/react/context/ecs.js';
|
||||
import {useMainEntity} from '@/react/context/main-entity.js';
|
||||
|
||||
|
@ -12,6 +13,7 @@ import Water from './water.jsx';
|
|||
|
||||
export default function Ecs({monopolizers, particleWorker}) {
|
||||
const app = useApp();
|
||||
const [debug] = useDebug();
|
||||
const mainEntityRef = useMainEntity();
|
||||
const [layers, setLayers] = useState([]);
|
||||
const [projected, setProjected] = useState([]);
|
||||
|
@ -104,7 +106,7 @@ export default function Ecs({monopolizers, particleWorker}) {
|
|||
}
|
||||
}
|
||||
// 7 - 19 day
|
||||
if (hour >= 7 && hour < 19) {
|
||||
if (debug.disableAmbientLight || hour >= 7 && hour < 19) {
|
||||
brightness = 1;
|
||||
color = 0xffffff;
|
||||
}
|
||||
|
@ -132,7 +134,7 @@ export default function Ecs({monopolizers, particleWorker}) {
|
|||
: projected;
|
||||
});
|
||||
}
|
||||
}, [app.ambientLight, mainEntityRef]);
|
||||
}, [app.ambientLight, debug, mainEntityRef]);
|
||||
useEcsTick(onEcsTick);
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -60,7 +60,7 @@ export default function Entities({monopolizers, particleWorker}) {
|
|||
}, []);
|
||||
useEffect(() => {
|
||||
for (const key in entities.current) {
|
||||
entities.current[key].setDebug(debug);
|
||||
entities.current[key].setDebug(debug.info);
|
||||
}
|
||||
}, [debug]);
|
||||
usePacket('EcsChange', () => {
|
||||
|
|
|
@ -198,7 +198,7 @@ function Ui({disconnected}) {
|
|||
event.preventDefault();
|
||||
}
|
||||
if ('keyDown' === type) {
|
||||
setDebug((debug) => !debug);
|
||||
setDebug(({...debug}) => ({...debug, info: !debug.info}));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -611,6 +611,7 @@ function Ui({disconnected}) {
|
|||
devEventsChannel.invoke(
|
||||
'click',
|
||||
where,
|
||||
event,
|
||||
);
|
||||
}
|
||||
else if (!isInventoryOpen) {
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
import {useCallback, useEffect, useRef, useState} from 'react';
|
||||
import {useOutletContext, useParams} from 'react-router-dom';
|
||||
|
||||
import ClientEcs from '@/react/components/client-ecs.js';
|
||||
import Ui from '@/react/components/ui.jsx';
|
||||
import AssetsContext from '@/react/context/assets.js';
|
||||
import ClientContext from '@/react/context/client.js';
|
||||
import DebugContext from '@/react/context/debug.js';
|
||||
import EcsContext from '@/react/context/ecs.js';
|
||||
import MainEntityContext from '@/react/context/main-entity.js';
|
||||
|
||||
import ClientEcs from '@/react/components/client-ecs.js';
|
||||
import Components from '@/silphius/ecs/components/index.js';
|
||||
import Systems from '@/silphius/ecs/systems/index.js';
|
||||
|
||||
export default function PlaySpecific() {
|
||||
const Client = useOutletContext();
|
||||
const assetsTuple = useState({});
|
||||
const [client, setClient] = useState();
|
||||
const mainEntityRef = useRef();
|
||||
const debugTuple = useState(false);
|
||||
const [Components, setComponents] = useState();
|
||||
const [Systems, setSystems] = useState();
|
||||
const debugTuple = useState({
|
||||
disableAmbientLight: false,
|
||||
info: false,
|
||||
});
|
||||
const reconnectionBackoff = useRef(0);
|
||||
const ecsRef = useRef();
|
||||
const [disconnected, setDisconnected] = useState(false);
|
||||
const params = useParams();
|
||||
const [type, url] = params['*'].split('/');
|
||||
useEffect(() => {
|
||||
if (!Client || !Components || !Systems) {
|
||||
if (!Client) {
|
||||
return;
|
||||
}
|
||||
const client = new Client();
|
||||
|
@ -36,7 +38,7 @@ export default function PlaySpecific() {
|
|||
return () => {
|
||||
client.disconnect();
|
||||
};
|
||||
}, [Client, Components, Systems, url]);
|
||||
}, [Client, url]);
|
||||
// Sneakily use beforeunload to snag some time to save.
|
||||
useEffect(() => {
|
||||
if ('local' !== type) {
|
||||
|
@ -60,16 +62,7 @@ export default function PlaySpecific() {
|
|||
}
|
||||
ecsRef.current = new ClientEcsPerf({Components, Systems});
|
||||
mainEntityRef.current = undefined;
|
||||
}, [ecsRef, Components, Systems]);
|
||||
useEffect(() => {
|
||||
async function setEcsStuff() {
|
||||
const {default: Components} = await import('@/silphius/ecs/components/index.js');
|
||||
const {default: Systems} = await import('@/silphius/ecs/systems/index.js');
|
||||
setComponents(Components);
|
||||
setSystems(Systems);
|
||||
}
|
||||
setEcsStuff();
|
||||
});
|
||||
}, [ecsRef]);
|
||||
useEffect(() => {
|
||||
refreshEcs();
|
||||
}, [refreshEcs]);
|
||||
|
|
|
@ -4,6 +4,9 @@ export default class LocalClient extends Client {
|
|||
server = null;
|
||||
async connect() {
|
||||
await super.connect();
|
||||
if (!this.connected) {
|
||||
return;
|
||||
}
|
||||
this.server = new Worker(
|
||||
new URL('../server/worker.js', import.meta.url),
|
||||
{type: 'module'},
|
||||
|
@ -19,7 +22,9 @@ export default class LocalClient extends Client {
|
|||
}
|
||||
disconnect() {
|
||||
super.disconnect();
|
||||
this.server.postMessage(0);
|
||||
if (this.server) {
|
||||
this.server.postMessage(0);
|
||||
}
|
||||
}
|
||||
transmit(packed) {
|
||||
this.server.postMessage(packed);
|
||||
|
|
|
@ -4,6 +4,9 @@ export default class RemoteClient extends Client {
|
|||
socket = null;
|
||||
async connect(host) {
|
||||
await super.connect();
|
||||
if (!this.connected) {
|
||||
return;
|
||||
}
|
||||
this.socket = new WebSocket(`//${host}/silphius`);
|
||||
this.socket.binaryType = 'arraybuffer';
|
||||
this.socket.addEventListener('message', (event) => {
|
||||
|
|
|
@ -40,7 +40,7 @@ export default class Component {
|
|||
const {
|
||||
constructor: Schema,
|
||||
specification: {concrete: {properties}},
|
||||
} = this.constructor.schema;
|
||||
} = this.schema;
|
||||
const defaults = {};
|
||||
for (const key in properties) {
|
||||
defaults[key] = ((key) => () => Schema.defaultValue(properties[key]))(key);
|
||||
|
@ -83,9 +83,9 @@ export default class Component {
|
|||
}
|
||||
|
||||
deserialize(entityId, view, offset) {
|
||||
const {properties} = this.constructor.schema.specification.concrete;
|
||||
const {properties} = this.schema.specification.concrete;
|
||||
const instance = this.get(entityId);
|
||||
const deserialized = this.constructor.schema.deserialize(view, offset);
|
||||
const deserialized = this.schema.deserialize(view, offset);
|
||||
for (const key in properties) {
|
||||
instance[key] = deserialized[key];
|
||||
}
|
||||
|
@ -107,18 +107,6 @@ export default class Component {
|
|||
}
|
||||
}
|
||||
|
||||
static filterDefaults(instance) {
|
||||
const {properties} = this.schema.specification.concrete;
|
||||
const Schema = this.schema.constructor;
|
||||
const json = {};
|
||||
for (const key in properties) {
|
||||
if (key in instance && instance[key] !== Schema.defaultValue(properties[key])) {
|
||||
json[key] = instance[key];
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
get(entityId) {
|
||||
return this.instances[entityId];
|
||||
}
|
||||
|
@ -129,7 +117,8 @@ export default class Component {
|
|||
|
||||
instanceFromSchema() {
|
||||
const Component = this;
|
||||
const {concrete} = Component.constructor.schema.specification;
|
||||
const {concrete} = Component.schema.specification;
|
||||
const setContext = {ecs: this.ecs};
|
||||
const Instance = class {
|
||||
$$entity = 0;
|
||||
destroy() {}
|
||||
|
@ -137,7 +126,7 @@ export default class Component {
|
|||
const {properties} = concrete;
|
||||
for (const key in values) {
|
||||
if (properties[key]?.$.set) {
|
||||
properties[key].$.set(Component, this, `$$${key}`, values[key]);
|
||||
properties[key].$.set(this, `$$${key}`, values[key], setContext);
|
||||
}
|
||||
else {
|
||||
this[`$$${key}`] = values[key];
|
||||
|
@ -145,7 +134,7 @@ export default class Component {
|
|||
}
|
||||
for (const key in defaults) {
|
||||
if (properties[key]?.$.set) {
|
||||
properties[key].$.set(Component, this, `$$${key}`, defaults[key]);
|
||||
properties[key].$.set(this, `$$${key}`, defaults[key], setContext);
|
||||
}
|
||||
else {
|
||||
this[`$$${key}`] = defaults[key];
|
||||
|
@ -180,7 +169,7 @@ export default class Component {
|
|||
for (const key in values) {
|
||||
if (properties[key]) {
|
||||
if (properties[key]?.$.set) {
|
||||
properties[key].$.set(Component, this, `$$${key}`, values[key]);
|
||||
properties[key].$.set(this, `$$${key}`, values[key], setContext);
|
||||
}
|
||||
else {
|
||||
this[`$$${key}`] = values[key];
|
||||
|
@ -209,7 +198,7 @@ export default class Component {
|
|||
set: function set(value) {
|
||||
if (this[`$$${key}`] !== value) {
|
||||
if (concrete.properties[key]?.$.set) {
|
||||
concrete.properties[key].$.set(Component, this, `$$${key}`, value);
|
||||
concrete.properties[key].$.set(this, `$$${key}`, value, setContext);
|
||||
}
|
||||
else {
|
||||
this[`$$${key}`] = value;
|
||||
|
@ -235,22 +224,24 @@ export default class Component {
|
|||
return {...original, ...update};
|
||||
}
|
||||
|
||||
static get schema() {
|
||||
get schema() {
|
||||
if (!this.$$schema) {
|
||||
this.$$schema = new Schema({
|
||||
type: 'object',
|
||||
properties: this.properties,
|
||||
});
|
||||
this.$$schema = new Schema(
|
||||
{
|
||||
type: 'object',
|
||||
properties: this.constructor.properties,
|
||||
},
|
||||
);
|
||||
}
|
||||
return this.$$schema;
|
||||
}
|
||||
|
||||
serialize(entityId, view, offset) {
|
||||
this.constructor.schema.serialize(this.get(entityId), view, offset);
|
||||
this.schema.serialize(this.get(entityId), view, offset);
|
||||
}
|
||||
|
||||
sizeOf(entityId) {
|
||||
return this.constructor.schema.sizeOf(this.get(entityId));
|
||||
return this.schema.sizeOf(this.get(entityId));
|
||||
}
|
||||
|
||||
updateMany(entities) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {aabbFromPoints, distance, intersects, transform} from '@/lib/math.js';
|
||||
import Component from '@/silphius/ecs/component.js';
|
||||
import {distance, intersects, transform} from '@/lib/math.js';
|
||||
|
||||
import vector2d from './helpers/vector-2d';
|
||||
|
||||
|
@ -32,7 +32,7 @@ export default class Collider extends Component {
|
|||
}
|
||||
return aabbs;
|
||||
}
|
||||
checkCollision(other) {
|
||||
checkCollision(other, {runScripts}) {
|
||||
if (!this.isColliding || !other.isColliding) {
|
||||
return;
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ export default class Collider extends Component {
|
|||
if (0 === activeIntersections.size) {
|
||||
return;
|
||||
}
|
||||
this.endIntersections(other, intersections);
|
||||
this.endIntersections(other, intersections, {runScripts});
|
||||
return;
|
||||
}
|
||||
for (const intersection of intersections) {
|
||||
|
@ -75,7 +75,7 @@ export default class Collider extends Component {
|
|||
}
|
||||
}
|
||||
if (!hasMatchingIntersection) {
|
||||
if (this.collisionStartScript) {
|
||||
if (runScripts && this.collisionStartScript) {
|
||||
const script = this.collisionStartScript.clone();
|
||||
script.locals.entity = thisEntity;
|
||||
script.locals.other = otherEntity;
|
||||
|
@ -85,7 +85,7 @@ export default class Collider extends Component {
|
|||
ecs.addDestructionDependency(otherEntity.id, promise);
|
||||
ecs.addDestructionDependency(thisEntity.id, promise);
|
||||
}
|
||||
if (other.collisionStartScript) {
|
||||
if (runScripts && other.collisionStartScript) {
|
||||
const script = other.collisionStartScript.clone();
|
||||
script.locals.entity = otherEntity;
|
||||
script.locals.other = thisEntity;
|
||||
|
@ -99,37 +99,10 @@ export default class Collider extends Component {
|
|||
}
|
||||
// undo restricted movement
|
||||
if (!body.unstoppable && otherBody.impassable) {
|
||||
const j = this.bodies.indexOf(body);
|
||||
const oj = other.bodies.indexOf(otherBody);
|
||||
const aabb = this.$$aabbs[j];
|
||||
const otherAabb = other.aabbs[oj];
|
||||
const {Position} = thisEntity;
|
||||
if (!intersects(
|
||||
{
|
||||
x0: aabb.x0 + Position.lastX,
|
||||
x1: aabb.x1 + Position.lastX,
|
||||
y0: aabb.y0 + Position.y,
|
||||
y1: aabb.y1 + Position.y,
|
||||
},
|
||||
otherAabb,
|
||||
)) {
|
||||
Position.x = Position.lastX
|
||||
}
|
||||
else if (!intersects(
|
||||
{
|
||||
x0: aabb.x0 + Position.x,
|
||||
x1: aabb.x1 + Position.x,
|
||||
y0: aabb.y0 + Position.lastY,
|
||||
y1: aabb.y1 + Position.lastY,
|
||||
},
|
||||
otherAabb,
|
||||
)) {
|
||||
Position.y = Position.lastY
|
||||
}
|
||||
else {
|
||||
Position.x = Position.lastX
|
||||
Position.y = Position.lastY
|
||||
}
|
||||
this.revertPosition(
|
||||
this.$$aabbs[this.bodies.indexOf(body)],
|
||||
other.aabbs[other.bodies.indexOf(otherBody)],
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +125,7 @@ export default class Collider extends Component {
|
|||
}
|
||||
this.$$intersections.clear();
|
||||
}
|
||||
endIntersections(other, intersections) {
|
||||
endIntersections(other, intersections, {runScripts}) {
|
||||
const otherEntity = ecs.get(other.entity);
|
||||
const thisEntity = ecs.get(this.entity);
|
||||
for (const intersection of intersections) {
|
||||
|
@ -160,7 +133,7 @@ export default class Collider extends Component {
|
|||
intersection.entity.bodies[intersection.i],
|
||||
intersection.other.bodies[intersection.j],
|
||||
];
|
||||
if (this.collisionEndScript) {
|
||||
if (runScripts && this.collisionEndScript) {
|
||||
const script = this.collisionEndScript.clone();
|
||||
script.locals.other = otherEntity;
|
||||
script.locals.pair = [body, otherBody];
|
||||
|
@ -169,7 +142,7 @@ export default class Collider extends Component {
|
|||
ecs.addDestructionDependency(thisEntity.id, promise);
|
||||
ecs.addDestructionDependency(otherEntity.id, promise);
|
||||
}
|
||||
if (other.collisionEndScript) {
|
||||
if (runScripts && other.collisionEndScript) {
|
||||
const script = other.collisionEndScript.clone();
|
||||
script.locals.other = thisEntity;
|
||||
script.locals.pair = [otherBody, body];
|
||||
|
@ -228,30 +201,53 @@ export default class Collider extends Component {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
revertPosition(aabb, otherAabb) {
|
||||
const {Position} = ecs.get(this.entity);
|
||||
const {lastX, lastY} = Position;
|
||||
const {x, y} = Position;
|
||||
if (intersects(
|
||||
{
|
||||
x0: aabb.x0 + lastX,
|
||||
x1: aabb.x1 + lastX,
|
||||
y0: aabb.y0 + y,
|
||||
y1: aabb.y1 + y,
|
||||
},
|
||||
otherAabb,
|
||||
)) {
|
||||
Position.y = lastY;
|
||||
Position.lastY = lastY;
|
||||
}
|
||||
if (intersects(
|
||||
{
|
||||
x0: aabb.x0 + x,
|
||||
x1: aabb.x1 + x,
|
||||
y0: aabb.y0 + lastY,
|
||||
y1: aabb.y1 + lastY,
|
||||
},
|
||||
otherAabb,
|
||||
)) {
|
||||
Position.x = lastX;
|
||||
Position.lastX = lastX;
|
||||
}
|
||||
}
|
||||
updateAabbs() {
|
||||
this.$$aabb = {x0: Infinity, x1: -Infinity, y0: Infinity, y1: -Infinity};
|
||||
this.$$aabbs = [];
|
||||
const {bodies} = this;
|
||||
const {Direction: {direction = 0} = {}} = ecs.get(this.entity) || {};
|
||||
let {Direction: {direction = 0} = {}} = ecs.get(this.entity) || {};
|
||||
if (!this.rotatesCollision) {
|
||||
direction = 0;
|
||||
}
|
||||
for (const body of bodies) {
|
||||
let x0 = Infinity, x1 = -Infinity, y0 = Infinity, y1 = -Infinity;
|
||||
for (const point of transform(body.points, {rotation: direction})) {
|
||||
const points = transform(body.points, {rotation: direction});
|
||||
this.$$aabbs.push(aabbFromPoints(points));
|
||||
for (const point of points) {
|
||||
const {x, y} = point;
|
||||
if (x < x0) x0 = x;
|
||||
if (x < this.$$aabb.x0) this.$$aabb.x0 = x;
|
||||
if (x > x1) x1 = x;
|
||||
if (x > this.$$aabb.x1) this.$$aabb.x1 = x;
|
||||
if (y < y0) y0 = y;
|
||||
if (y < this.$$aabb.y0) this.$$aabb.y0 = y;
|
||||
if (y > y1) y1 = y;
|
||||
if (y > this.$$aabb.y1) this.$$aabb.y1 = y;
|
||||
}
|
||||
this.$$aabbs.push({
|
||||
x0: x0 > x1 ? x1 : x0,
|
||||
x1: x0 > x1 ? x0 : x1,
|
||||
y0: y0 > y1 ? y1 : y0,
|
||||
y1: y0 > y1 ? y0 : y1,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -259,8 +255,8 @@ export default class Collider extends Component {
|
|||
load(instance) {
|
||||
for (const i in instance.bodies) {
|
||||
instance.bodies[i] = {
|
||||
...this.constructor.schema.constructor.defaultValue(
|
||||
this.constructor.schema.specification.concrete.properties.bodies.concrete.subtype,
|
||||
...this.schema.constructor.defaultValue(
|
||||
this.schema.specification.concrete.properties.bodies.concrete.subtype,
|
||||
),
|
||||
...instance.bodies[i],
|
||||
};
|
||||
|
@ -292,5 +288,6 @@ export default class Collider extends Component {
|
|||
collisionEndScript: {type: 'script'},
|
||||
collisionStartScript: {type: 'script'},
|
||||
isColliding: {defaultValue: 1, type: 'uint8'},
|
||||
rotatesCollision: {defaultValue: 1, type: 'uint8'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -17,12 +17,6 @@ export default class Forces extends Component {
|
|||
applyImpulse({x, y}) {
|
||||
this.$$impulseX += x;
|
||||
this.$$impulseY += y;
|
||||
ecs.markChange(this.entity, {
|
||||
Forces: {
|
||||
impulseX: this.$$impulseX,
|
||||
impulseY: this.$$impulseY,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
7
app/silphius/ecs/components/label.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
import Component from '@/silphius/ecs/component.js';
|
||||
|
||||
export default class Label extends Component {
|
||||
static properties = {
|
||||
label: {type: 'string'},
|
||||
};
|
||||
}
|
|
@ -48,4 +48,7 @@ export default class Player extends Component {
|
|||
}
|
||||
};
|
||||
}
|
||||
static properties = {
|
||||
id: {type: 'string'},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -31,6 +31,10 @@ export default class Position extends Component {
|
|||
}
|
||||
};
|
||||
}
|
||||
load(instance) {
|
||||
instance.lastX = instance.$$x;
|
||||
instance.lastY = instance.$$y;
|
||||
}
|
||||
static properties = {
|
||||
x: {type: 'float32'},
|
||||
y: {type: 'float32'},
|
||||
|
|
|
@ -103,6 +103,10 @@ class LayerProxy {
|
|||
? this.Component.ecs.readJson(this.layer.source)
|
||||
: {};
|
||||
}
|
||||
get size() {
|
||||
const {area, tileSize} = this;
|
||||
return {x: area.x * tileSize.x, y: area.y * tileSize.y};
|
||||
}
|
||||
get source() {
|
||||
return this.layer.source;
|
||||
}
|
||||
|
|
|
@ -283,29 +283,7 @@ export default class Ecs {
|
|||
}
|
||||
|
||||
static deserialize(ecs, view) {
|
||||
const componentNames = Object.keys(ecs.Components);
|
||||
const {entities, systems} = decoder.decode(view.buffer);
|
||||
for (const system of systems) {
|
||||
const System = ecs.system(system);
|
||||
if (System) {
|
||||
System.active = true;
|
||||
}
|
||||
}
|
||||
const specifics = [];
|
||||
let max = 1;
|
||||
for (const id in entities) {
|
||||
max = Math.max(max, parseInt(id));
|
||||
specifics.push([
|
||||
parseInt(id),
|
||||
Object.fromEntries(
|
||||
Object.entries(entities[id])
|
||||
.filter(([componentName]) => componentNames.includes(componentName)),
|
||||
),
|
||||
]);
|
||||
}
|
||||
ecs.$$caret = max + 1;
|
||||
ecs.createManySpecific(specifics);
|
||||
return ecs;
|
||||
return ecs.fromJSON(decoder.decode(view.buffer));
|
||||
}
|
||||
|
||||
destroy(entityId) {
|
||||
|
@ -358,6 +336,32 @@ export default class Ecs {
|
|||
return ids;
|
||||
}
|
||||
|
||||
fromJSON(json) {
|
||||
const componentNames = Object.keys(this.Components);
|
||||
const {entities, systems} = json;
|
||||
for (const system of systems) {
|
||||
const System = this.system(system);
|
||||
if (System) {
|
||||
System.active = true;
|
||||
}
|
||||
}
|
||||
const specifics = [];
|
||||
let max = 1;
|
||||
for (const id in entities) {
|
||||
max = Math.max(max, parseInt(id));
|
||||
specifics.push([
|
||||
parseInt(id),
|
||||
Object.fromEntries(
|
||||
Object.entries(entities[id])
|
||||
.filter(([componentName]) => componentNames.includes(componentName)),
|
||||
),
|
||||
]);
|
||||
}
|
||||
this.$$caret = max + 1;
|
||||
this.createManySpecific(specifics);
|
||||
return this;
|
||||
}
|
||||
|
||||
get(entityId) {
|
||||
return this.$$entities[entityId];
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ export default class EntityFactory {
|
|||
let size = 0;
|
||||
for (const componentName of this.constructor.componentNames) {
|
||||
const instance = Components[componentName];
|
||||
size += 2 + 4 + instance.constructor.schema.sizeOf(instance.get(this.id));
|
||||
size += 2 + 4 + instance.schema.sizeOf(instance.get(this.id));
|
||||
}
|
||||
// ID + # of components.
|
||||
return size + 4 + 2;
|
||||
|
|
|
@ -7,16 +7,11 @@ export default function () {
|
|||
json: (value) => {
|
||||
return value ? value.path : '';
|
||||
},
|
||||
set: (Component, receiver, key, value) => {
|
||||
set: (receiver, key, value, {ecs}) => {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
receiver[key] = Component.ecs.readScript(
|
||||
value,
|
||||
{
|
||||
ecs: Component.ecs,
|
||||
},
|
||||
);
|
||||
receiver[key] = ecs.readScript(value, {ecs});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ export default class Schema {
|
|||
}
|
||||
|
||||
serialize(source, view, offset = 0) {
|
||||
this.constructor.serialize(source, view, offset, this.specification);
|
||||
return this.constructor.serialize(source, view, offset, this.specification);
|
||||
}
|
||||
|
||||
static sizeOf(instance, {$, concrete}) {
|
||||
|
|
|
@ -2,6 +2,24 @@ import {System} from '@/silphius/ecs/index.js';
|
|||
|
||||
export default class Colliders extends System {
|
||||
|
||||
predict(entity) {
|
||||
if (!entity.Collider) {
|
||||
return;
|
||||
}
|
||||
const within = this.ecs.system('MaintainColliderHash').collisions(entity);
|
||||
for (const other of within) {
|
||||
if (entity === other || !other.Collider) {
|
||||
continue;
|
||||
}
|
||||
entity.Collider.checkCollision(other.Collider, {runScripts: false});
|
||||
}
|
||||
for (const [other, intersections] of entity.Collider.$$intersections) {
|
||||
if (!within.has(this.ecs.get(other.entity))) {
|
||||
entity.Collider.endIntersections(other, intersections, {runScripts: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static get priority() {
|
||||
return {
|
||||
after: 'MaintainColliderHash',
|
||||
|
@ -29,11 +47,11 @@ export default class Colliders extends System {
|
|||
continue;
|
||||
}
|
||||
checked.get(other).add(entity);
|
||||
entity.Collider.checkCollision(other.Collider);
|
||||
entity.Collider.checkCollision(other.Collider, {runScripts: true});
|
||||
}
|
||||
for (const [other, intersections] of entity.Collider.$$intersections) {
|
||||
if (!within.has(this.ecs.get(other.entity))) {
|
||||
entity.Collider.endIntersections(other, intersections);
|
||||
entity.Collider.endIntersections(other, intersections, {runScripts: true});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,14 +23,14 @@ export default class IntegratePhysics extends System {
|
|||
if (!Forces || !Position) {
|
||||
return;
|
||||
}
|
||||
Position.lastX = Position.$$x;
|
||||
Position.lastY = Position.$$y;
|
||||
const xd = elapsed * (Forces.$$impulseX + Forces.$$forceX);
|
||||
if (xd) {
|
||||
Position.lastX = Position.$$x;
|
||||
Position.x = Position.$$x + xd;
|
||||
}
|
||||
const yd = elapsed * (Forces.$$impulseY + Forces.$$forceY);;
|
||||
if (yd) {
|
||||
Position.lastY = Position.$$y;
|
||||
Position.y = Position.$$y + yd;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,10 +28,10 @@ export default class ResetForces extends System {
|
|||
return;
|
||||
}
|
||||
if (Forces.$$impulseX) {
|
||||
Forces.impulseX = 0;
|
||||
Forces.$$impulseX = 0;
|
||||
}
|
||||
if (Forces.$$impulseY) {
|
||||
Forces.impulseY = 0;
|
||||
Forces.$$impulseY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
68
app/silphius/ecs/systems/tile-collision.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
import {aabbFromPoints, intersects} from '@/lib/math.js';
|
||||
import {System} from '@/silphius/ecs/index.js';
|
||||
|
||||
export default class TileCollision extends System {
|
||||
|
||||
predict(entity) {
|
||||
this.tickSingle(entity);
|
||||
}
|
||||
|
||||
static get priority() {
|
||||
return {
|
||||
after: 'Colliders',
|
||||
};
|
||||
}
|
||||
|
||||
tick() {
|
||||
for (const entity of this.ecs.changed(['Position'])) {
|
||||
this.tickSingle(entity);
|
||||
}
|
||||
}
|
||||
|
||||
tickSingle(entity) {
|
||||
if (!entity.Collider) {
|
||||
return;
|
||||
}
|
||||
const master = this.ecs.get(1);
|
||||
const {TileLayers} = master;
|
||||
const {tileSize} = TileLayers.layer(0);
|
||||
const {$$aabbs, aabb, aabbs, bodies} = entity.Collider;
|
||||
const tx0 = Math.floor(aabb.x0 / tileSize.x);
|
||||
const tx1 = Math.floor(aabb.x1 / tileSize.x);
|
||||
const ty0 = Math.floor(aabb.y0 / tileSize.y);
|
||||
const ty1 = Math.floor(aabb.y1 / tileSize.y);
|
||||
for (const i in aabbs) {
|
||||
if (bodies[i].unstoppable) {
|
||||
continue;
|
||||
}
|
||||
const aabb = aabbs[i];
|
||||
for (let x = tx0; x <= tx1; ++x) {
|
||||
for (let y = ty0; y <= ty1; ++y) {
|
||||
for (let j = 0; j < TileLayers.layers.length; ++j) {
|
||||
const layer = TileLayers.layer(j);
|
||||
const {collision} = layer.sourceJson.meta;
|
||||
if (!collision) {
|
||||
return;
|
||||
}
|
||||
const otherBodies = collision[layer.tile({x, y})];
|
||||
if (!otherBodies) {
|
||||
continue;
|
||||
}
|
||||
for (const k in otherBodies) {
|
||||
const otherAabb = aabbFromPoints(otherBodies[k].points);
|
||||
otherAabb.x0 += x * tileSize.x + (tileSize.x / 2);
|
||||
otherAabb.x1 += x * tileSize.x + (tileSize.x / 2);
|
||||
otherAabb.y0 += y * tileSize.y + (tileSize.y / 2);
|
||||
otherAabb.y1 += y * tileSize.y + (tileSize.y / 2);
|
||||
// todo accuracy
|
||||
if (intersects(aabb, otherAabb)) {
|
||||
entity.Collider.revertPosition($$aabbs[i], otherAabb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,12 @@
|
|||
import {CLIENT_LATENCY, CLIENT_INTERPOLATION, CLIENT_PREDICTION} from '@/lib/constants.js';
|
||||
import EventEmitter from '@/lib/event-emitter.js';
|
||||
import {withResolvers} from '@/lib/promise.js';
|
||||
import {decode, encode} from '@/silphius/net/packets/index.js';
|
||||
|
||||
import {Flow} from './constants.js';
|
||||
|
||||
export default class Client {
|
||||
connected = true;
|
||||
emitter = new EventEmitter();
|
||||
interpolator = null;
|
||||
predictor = null;
|
||||
|
@ -70,6 +72,7 @@ export default class Client {
|
|||
}
|
||||
});
|
||||
}
|
||||
this.connected = true;
|
||||
}
|
||||
disconnect() {
|
||||
if (CLIENT_INTERPOLATION) {
|
||||
|
@ -80,6 +83,7 @@ export default class Client {
|
|||
this.predictor?.terminate();
|
||||
this.predictor = null;
|
||||
}
|
||||
this.connected = false;
|
||||
}
|
||||
receive(packed) {
|
||||
this.throughput.$$down += packed.byteLength;
|
||||
|
@ -97,6 +101,25 @@ export default class Client {
|
|||
removePacketListener(type, listener) {
|
||||
this.emitter.removeListener(type, listener);
|
||||
}
|
||||
async request(packet) {
|
||||
// needs crypto strength
|
||||
const id = Math.random();
|
||||
const request = {
|
||||
type: 'Request',
|
||||
payload: {id, request: packet},
|
||||
}
|
||||
this.send(request);
|
||||
const {promise, resolve} = withResolvers();
|
||||
const listenForId = (payload) => {
|
||||
if (id !== payload.id) {
|
||||
return;
|
||||
}
|
||||
this.emitter.removeListener(listenForId);
|
||||
resolve(payload.response);
|
||||
}
|
||||
this.emitter.addListener('Response', listenForId);
|
||||
return promise;
|
||||
}
|
||||
send(packet) {
|
||||
const transmitOrPredict = () => {
|
||||
if (CLIENT_PREDICTION) {
|
||||
|
|
|
@ -15,12 +15,4 @@ export default class Packet {
|
|||
return new DataView(encoder.bytes.buffer, 0, encoder.pos);
|
||||
}
|
||||
|
||||
static pack(payload) {
|
||||
return payload;
|
||||
}
|
||||
|
||||
static unpack(packed) {
|
||||
return packed;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,34 +1,3 @@
|
|||
import Packet from '@/silphius/net/packet.js';
|
||||
|
||||
const WIRE_MAP = {
|
||||
'moveUp': 0,
|
||||
'moveRight': 1,
|
||||
'moveDown': 2,
|
||||
'moveLeft': 3,
|
||||
'use': 4,
|
||||
'changeSlot': 5,
|
||||
'interact': 6,
|
||||
};
|
||||
Object.entries(WIRE_MAP)
|
||||
.forEach(([k, v]) => {
|
||||
WIRE_MAP[v] = k;
|
||||
});
|
||||
|
||||
export default class Action extends Packet {
|
||||
|
||||
static pack(payload) {
|
||||
return super.pack({
|
||||
type: WIRE_MAP[payload.type],
|
||||
value: payload.value,
|
||||
});
|
||||
}
|
||||
|
||||
static unpack(packed) {
|
||||
const unpacked = super.unpack(packed);
|
||||
return {
|
||||
type: WIRE_MAP[unpacked.type],
|
||||
value: unpacked.value,
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
export default class Action extends Packet {}
|
||||
|
|
3
app/silphius/net/packets/admin-action-response.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Packet from '@/silphius/net/packet.js';
|
||||
|
||||
export default class AdminActionResponse extends Packet {}
|
|
@ -1,14 +1,14 @@
|
|||
import gather from '@/lib/gather.js';
|
||||
|
||||
const Gathered = gather(import.meta.glob('./*.js', {eager: true, import: 'default'}));
|
||||
const Packets = gather(import.meta.glob('./*.js', {eager: true, import: 'default'}));
|
||||
|
||||
const typeToId = new Map(Object.entries(Gathered).map(([type], id) => [type, id]));
|
||||
const idToType = new Map(Object.entries(Gathered).map(([type], id) => [id, type]));
|
||||
const typeToId = new Map(Object.entries(Packets).map(([type], id) => [type, id]));
|
||||
const idToType = new Map(Object.entries(Packets).map(([type], id) => [id, type]));
|
||||
|
||||
export function decode(packed) {
|
||||
const view = ArrayBuffer.isView(packed) ? packed : new DataView(packed);
|
||||
const type = idToType.get(view.getUint16(0, true));
|
||||
const Packet = Gathered[type];
|
||||
const Packet = Packets[type];
|
||||
return {
|
||||
type,
|
||||
payload: Packet.decode(view),
|
||||
|
@ -16,7 +16,7 @@ export function decode(packed) {
|
|||
}
|
||||
|
||||
export function encode(packet) {
|
||||
const encoded = Gathered[packet.type].encode(packet.payload);
|
||||
const encoded = Packets[packet.type].encode(packet.payload);
|
||||
encoded.setUint16(0, typeToId.get(packet.type), true);
|
||||
return encoded;
|
||||
}
|
||||
|
|
3
app/silphius/net/packets/request.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Packet from '@/silphius/net/packet.js';
|
||||
|
||||
export default class Request extends Packet {}
|
3
app/silphius/net/packets/response.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import Packet from '@/silphius/net/packet.js';
|
||||
|
||||
export default class Response extends Packet {}
|
|
@ -19,6 +19,7 @@ const Action = {
|
|||
|
||||
const actions = new Map();
|
||||
let ecs = new PredictionEcs({Components, Systems});
|
||||
ecs.system('MaintainColliderHash').active = true;
|
||||
let mainEntityId = 0;
|
||||
|
||||
function applyClientActions(elapsed) {
|
||||
|
@ -64,7 +65,9 @@ function applyClientActions(elapsed) {
|
|||
continue;
|
||||
}
|
||||
}
|
||||
ecs.predict(main, action.stop - action.start);
|
||||
const actionElapsed = action.stop - action.start;
|
||||
ecs.tick(actionElapsed)
|
||||
ecs.predict(main, actionElapsed);
|
||||
}
|
||||
for (const id of finished) {
|
||||
actions.delete(id);
|
||||
|
|
|
@ -26,6 +26,7 @@ export default function createEcs(Ecs) {
|
|||
'Interactions',
|
||||
'InventoryCloser',
|
||||
'KillPerishable',
|
||||
'TileCollision',
|
||||
];
|
||||
defaultSystems.forEach((defaultSystem) => {
|
||||
const System = ecs.system(defaultSystem);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import data from './homestead.json';
|
||||
import layers from './homestead.json';
|
||||
|
||||
function animal() {
|
||||
return {
|
||||
|
@ -23,25 +23,17 @@ function animal() {
|
|||
}
|
||||
|
||||
function createMaster() {
|
||||
const area = {x: 100, y: 60};
|
||||
const area = {x: 25, y: 25};
|
||||
return {
|
||||
AreaSize: {x: area.x * 16, y: area.y * 16},
|
||||
Ticking: {},
|
||||
TileLayers: {
|
||||
layers: [
|
||||
{
|
||||
area,
|
||||
data,
|
||||
source: '/resources/tileset.sprite.json',
|
||||
tileSize: {x: 16, y: 16},
|
||||
},
|
||||
{
|
||||
area,
|
||||
data: Array(area.x * area.y).fill(0),
|
||||
source: '/resources/tileset.sprite.json',
|
||||
tileSize: {x: 16, y: 16},
|
||||
},
|
||||
],
|
||||
layers: layers.map((data) => ({
|
||||
area,
|
||||
data,
|
||||
source: '/resources/tileset/homestead.sprite.json',
|
||||
tileSize: {x: 16, y: 16},
|
||||
})),
|
||||
},
|
||||
Time: {},
|
||||
Water: {water: {}},
|
||||
|
|
|
@ -13,6 +13,7 @@ export default function createPlayer(id) {
|
|||
],
|
||||
},
|
||||
],
|
||||
rotatesCollision: 0,
|
||||
},
|
||||
Controlled: {},
|
||||
Direction: {},
|
||||
|
|
|
@ -106,14 +106,21 @@ export default class Engine {
|
|||
if (!this.incomingActions.has(connection)) {
|
||||
this.incomingActions.set(connection, []);
|
||||
}
|
||||
this.incomingActions.get(connection).push(payload);
|
||||
this.incomingActions.get(connection).push({payload});
|
||||
});
|
||||
this.server.addPacketListener('AdminAction', (connection, payload) => {
|
||||
// check...
|
||||
if (!this.incomingActions.has(connection)) {
|
||||
this.incomingActions.set(connection, []);
|
||||
}
|
||||
this.incomingActions.get(connection).push(payload);
|
||||
this.incomingActions.get(connection).push({payload});
|
||||
});
|
||||
this.server.addPacketListener('Request', (connection, payload) => {
|
||||
if (!this.incomingActions.has(connection)) {
|
||||
this.incomingActions.set(connection, []);
|
||||
}
|
||||
const {request} = payload;
|
||||
this.incomingActions.get(connection).push({payload: request.payload, respondTo: payload.id});
|
||||
});
|
||||
this.server.addPacketListener('Heartbeat', (connection) => {
|
||||
const playerData = this.connectedPlayers.get(connection);
|
||||
|
@ -158,7 +165,7 @@ export default class Engine {
|
|||
Wielder,
|
||||
} = entity;
|
||||
const ecs = this.ecses[Ecs.path];
|
||||
for (const payload of payloads) {
|
||||
for (const {payload, respondTo} of payloads) {
|
||||
switch (payload.type) {
|
||||
case 'chat': {
|
||||
if (payload.value.startsWith('/')) {
|
||||
|
@ -173,7 +180,7 @@ export default class Engine {
|
|||
{
|
||||
type: 'Download',
|
||||
payload: {
|
||||
data: TileLayers.layer(0).data,
|
||||
data: TileLayers.layers.map((_, i) => TileLayers.layer(i).data),
|
||||
filename: 'tiles.json',
|
||||
},
|
||||
},
|
||||
|
@ -195,6 +202,29 @@ export default class Engine {
|
|||
});
|
||||
break;
|
||||
}
|
||||
case 'createEntity': {
|
||||
const {path} = payload.value;
|
||||
const id = ecs.create({$$extends: path});
|
||||
if (respondTo) {
|
||||
this.server.send(
|
||||
connection,
|
||||
{
|
||||
type: 'Response',
|
||||
payload: {
|
||||
id: respondTo,
|
||||
response: {type: 'AdminActionResponse', payload: {id}},
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case 'destroyEntity': {
|
||||
const {id} = payload.value;
|
||||
ecs.destroy(parseInt(id));
|
||||
break;
|
||||
}
|
||||
case 'paint': {
|
||||
const {TileLayers} = ecs.get(1);
|
||||
const {brush, layer: paintLayer, stamp} = payload.value;
|
||||
|
@ -213,6 +243,15 @@ export default class Engine {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case 'moveEntity': {
|
||||
const {at: {x, y}, id} = payload.value;
|
||||
const entity = ecs.get(id);
|
||||
if (entity.Position) {
|
||||
entity.Position.x = x;
|
||||
entity.Position.y = y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'moveUp':
|
||||
case 'moveRight':
|
||||
case 'moveDown':
|
||||
|
|
|
@ -128,7 +128,7 @@ if (import.meta.hot) {
|
|||
await engine.saveEcs('homesteads/0', homestead);
|
||||
resolve();
|
||||
});
|
||||
import.meta.hot.accept('./create/town.js', async ({default: createTown}) => {
|
||||
import.meta.hot.accept('./create/town.js', async ({default: createTown}) => {
|
||||
const {promise, resolve} = withResolvers();
|
||||
promises.push(promise);
|
||||
await before.promise;
|
||||
|
|
752
package-lock.json
generated
|
@ -26,6 +26,7 @@
|
|||
"cross-env": "^7.0.3",
|
||||
"express": "^4.19.2",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"immutable": "^5.0.2",
|
||||
"isbot": "^4.1.0",
|
||||
"kefir": "^3.8.8",
|
||||
"morgan": "^1.10.0",
|
||||
|
@ -36,7 +37,7 @@
|
|||
"remark-mdx": "^3.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"simplex-noise": "^4.0.1",
|
||||
"sylvite": "^1.0.3",
|
||||
"sylvite": "^1.0.6",
|
||||
"unified": "^11.0.5",
|
||||
"unist-util-visit-parents": "^6.0.1",
|
||||
"ws": "^8.18.0"
|
||||
|
@ -62,6 +63,7 @@
|
|||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"image-size": "^1.1.1",
|
||||
"jimp": "^1.6.0",
|
||||
"playwright": "^1.47.0",
|
||||
"postcss": "^8.4.38",
|
||||
"storybook": "^8.1.6",
|
||||
|
@ -2989,6 +2991,430 @@
|
|||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/core": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/core/-/core-1.6.0.tgz",
|
||||
"integrity": "sha512-EQQlKU3s9QfdJqiSrZWNTxBs3rKXgO2W+GxNXDtwchF3a4IqxDheFX1ti+Env9hdJXDiYLp2jTRjlxhPthsk8w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/file-ops": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"await-to-js": "^3.0.0",
|
||||
"exif-parser": "^0.1.12",
|
||||
"file-type": "^16.0.0",
|
||||
"mime": "3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/core/node_modules/mime": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
|
||||
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/diff": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/diff/-/diff-1.6.0.tgz",
|
||||
"integrity": "sha512-+yUAQ5gvRC5D1WHYxjBHZI7JBRusGGSLf8AmPRPCenTzh4PA+wZ1xv2+cYqQwTfQHU5tXYOhA0xDytfHUf1Zyw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/plugin-resize": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"pixelmatch": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/file-ops": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/file-ops/-/file-ops-1.6.0.tgz",
|
||||
"integrity": "sha512-Dx/bVDmgnRe1AlniRpCKrGRm5YvGmUwbDzt+MAkgmLGf+jvBT75hmMEZ003n9HQI/aPnm/YKnXjg/hOpzNCpHQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/js-bmp": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/js-bmp/-/js-bmp-1.6.0.tgz",
|
||||
"integrity": "sha512-FU6Q5PC/e3yzLyBDXupR3SnL3htU7S3KEs4e6rjDP6gNEOXRFsWs6YD3hXuXd50jd8ummy+q2WSwuGkr8wi+Gw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"bmp-ts": "^1.0.9"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/js-gif": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/js-gif/-/js-gif-1.6.0.tgz",
|
||||
"integrity": "sha512-N9CZPHOrJTsAUoWkWZstLPpwT5AwJ0wge+47+ix3++SdSL/H2QzyMqxbcDYNFe4MoI5MIhATfb0/dl/wmX221g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"gifwrap": "^0.10.1",
|
||||
"omggif": "^1.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/js-jpeg": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/js-jpeg/-/js-jpeg-1.6.0.tgz",
|
||||
"integrity": "sha512-6vgFDqeusblf5Pok6B2DUiMXplH8RhIKAryj1yn+007SIAQ0khM1Uptxmpku/0MfbClx2r7pnJv9gWpAEJdMVA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"jpeg-js": "^0.4.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/js-png": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/js-png/-/js-png-1.6.0.tgz",
|
||||
"integrity": "sha512-AbQHScy3hDDgMRNfG0tPjL88AV6qKAILGReIa3ATpW5QFjBKpisvUaOqhzJ7Reic1oawx3Riyv152gaPfqsBVg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"pngjs": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/js-tiff": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/js-tiff/-/js-tiff-1.6.0.tgz",
|
||||
"integrity": "sha512-zhReR8/7KO+adijj3h0ZQUOiun3mXUv79zYEAKvE0O+rP7EhgtKvWJOZfRzdZSNv0Pu1rKtgM72qgtwe2tFvyw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"utif2": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-blit": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-1.6.0.tgz",
|
||||
"integrity": "sha512-M+uRWl1csi7qilnSK8uxK4RJMSuVeBiO1AY0+7APnfUbQNZm6hCe0CCFv1Iyw1D/Dhb8ph8fQgm5mwM0eSxgVA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-blur": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-1.6.0.tgz",
|
||||
"integrity": "sha512-zrM7iic1OTwUCb0g/rN5y+UnmdEsT3IfuCXCJJNs8SZzP0MkZ1eTvuwK9ZidCuMo4+J3xkzCidRwYXB5CyGZTw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/utils": "1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-circle": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-1.6.0.tgz",
|
||||
"integrity": "sha512-xt1Gp+LtdMKAXfDp3HNaG30SPZW6AQ7dtAtTnoRKorRi+5yCJjKqXRgkewS5bvj8DEh87Ko1ydJfzqS3P2tdWw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-color": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-1.6.0.tgz",
|
||||
"integrity": "sha512-J5q8IVCpkBsxIXM+45XOXTrsyfblyMZg3a9eAo0P7VPH4+CrvyNQwaYatbAIamSIN1YzxmO3DkIZXzRjFSz1SA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"tinycolor2": "^1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-contain": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-1.6.0.tgz",
|
||||
"integrity": "sha512-oN/n+Vdq/Qg9bB4yOBOxtY9IPAtEfES8J1n9Ddx+XhGBYT1/QTU/JYkGaAkIGoPnyYvmLEDqMz2SGihqlpqfzQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/plugin-blit": "1.6.0",
|
||||
"@jimp/plugin-resize": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-cover": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-1.6.0.tgz",
|
||||
"integrity": "sha512-Iow0h6yqSC269YUJ8HC3Q/MpCi2V55sMlbkkTTx4zPvd8mWZlC0ykrNDeAy9IJegrQ7v5E99rJwmQu25lygKLA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/plugin-crop": "1.6.0",
|
||||
"@jimp/plugin-resize": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-crop": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-1.6.0.tgz",
|
||||
"integrity": "sha512-KqZkEhvs+21USdySCUDI+GFa393eDIzbi1smBqkUPTE+pRwSWMAf01D5OC3ZWB+xZsNla93BDS9iCkLHA8wang==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-displace": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-1.6.0.tgz",
|
||||
"integrity": "sha512-4Y10X9qwr5F+Bo5ME356XSACEF55485j5nGdiyJ9hYzjQP9nGgxNJaZ4SAOqpd+k5sFaIeD7SQ0Occ26uIng5Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-dither": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-1.6.0.tgz",
|
||||
"integrity": "sha512-600d1RxY0pKwgyU0tgMahLNKsqEcxGdbgXadCiVCoGd6V6glyCvkNrnnwC0n5aJ56Htkj88PToSdF88tNVZEEQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-fisheye": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-1.6.0.tgz",
|
||||
"integrity": "sha512-E5QHKWSCBFtpgZarlmN3Q6+rTQxjirFqo44ohoTjzYVrDI6B6beXNnPIThJgPr0Y9GwfzgyarKvQuQuqCnnfbA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-flip": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-1.6.0.tgz",
|
||||
"integrity": "sha512-/+rJVDuBIVOgwoyVkBjUFHtP+wmW0r+r5OQ2GpatQofToPVbJw1DdYWXlwviSx7hvixTWLKVgRWQ5Dw862emDg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-hash": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-hash/-/plugin-hash-1.6.0.tgz",
|
||||
"integrity": "sha512-wWzl0kTpDJgYVbZdajTf+4NBSKvmI3bRI8q6EH9CVeIHps9VWVsUvEyb7rpbcwVLWYuzDtP2R0lTT6WeBNQH9Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/js-bmp": "1.6.0",
|
||||
"@jimp/js-jpeg": "1.6.0",
|
||||
"@jimp/js-png": "1.6.0",
|
||||
"@jimp/js-tiff": "1.6.0",
|
||||
"@jimp/plugin-color": "1.6.0",
|
||||
"@jimp/plugin-resize": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"any-base": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-mask": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-1.6.0.tgz",
|
||||
"integrity": "sha512-Cwy7ExSJMZszvkad8NV8o/Z92X2kFUFM8mcDAhNVxU0Q6tA0op2UKRJY51eoK8r6eds/qak3FQkXakvNabdLnA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-print": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-1.6.0.tgz",
|
||||
"integrity": "sha512-zarTIJi8fjoGMSI/M3Xh5yY9T65p03XJmPsuNet19K/Q7mwRU6EV2pfj+28++2PV2NJ+htDF5uecAlnGyxFN2A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/js-jpeg": "1.6.0",
|
||||
"@jimp/js-png": "1.6.0",
|
||||
"@jimp/plugin-blit": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"parse-bmfont-ascii": "^1.0.6",
|
||||
"parse-bmfont-binary": "^1.0.6",
|
||||
"parse-bmfont-xml": "^1.1.6",
|
||||
"simple-xml-to-json": "^1.2.2",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-quantize": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-quantize/-/plugin-quantize-1.6.0.tgz",
|
||||
"integrity": "sha512-EmzZ/s9StYQwbpG6rUGBCisc3f64JIhSH+ncTJd+iFGtGo0YvSeMdAd+zqgiHpfZoOL54dNavZNjF4otK+mvlg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"image-q": "^4.0.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-resize": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-1.6.0.tgz",
|
||||
"integrity": "sha512-uSUD1mqXN9i1SGSz5ov3keRZ7S9L32/mAQG08wUwZiEi5FpbV0K8A8l1zkazAIZi9IJzLlTauRNU41Mi8IF9fA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-rotate": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-1.6.0.tgz",
|
||||
"integrity": "sha512-JagdjBLnUZGSG4xjCLkIpQOZZ3Mjbg8aGCCi4G69qR+OjNpOeGI7N2EQlfK/WE8BEHOW5vdjSyglNqcYbQBWRw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/plugin-crop": "1.6.0",
|
||||
"@jimp/plugin-resize": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/plugin-threshold": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-1.6.0.tgz",
|
||||
"integrity": "sha512-M59m5dzLoHOVWdM41O8z9SyySzcDn43xHseOH0HavjsfQsT56GGCC4QzU1banJidbUrePhzoEdS42uFE8Fei8w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/plugin-color": "1.6.0",
|
||||
"@jimp/plugin-hash": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/types": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/types/-/types-1.6.0.tgz",
|
||||
"integrity": "sha512-7UfRsiKo5GZTAATxm2qQ7jqmUXP0DxTArztllTcYdyw6Xi5oT4RaoXynVtCD4UyLK5gJgkZJcwonoijrhYFKfg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@jimp/utils": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-1.6.0.tgz",
|
||||
"integrity": "sha512-gqFTGEosKbOkYF/WFj26jMHOI5OH2jeP1MmC/zbK6BF6VJBf8rIC5898dPfSzZEbSA0wbbV5slbntWVc5PKLFA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/types": "1.6.0",
|
||||
"tinycolor2": "^1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@joshwooding/vite-plugin-react-docgen-typescript": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/@joshwooding/vite-plugin-react-docgen-typescript/-/vite-plugin-react-docgen-typescript-0.3.1.tgz",
|
||||
|
@ -5747,6 +6173,12 @@
|
|||
"@testing-library/dom": ">=7.21.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@tokenizer/token": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
||||
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/acorn": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
|
||||
|
@ -7013,6 +7445,12 @@
|
|||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/any-base": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz",
|
||||
"integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/anymatch": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
|
@ -7294,6 +7732,15 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/await-to-js": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/await-to-js/-/await-to-js-3.0.0.tgz",
|
||||
"integrity": "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/axe-core": {
|
||||
"version": "4.10.0",
|
||||
"resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz",
|
||||
|
@ -7454,6 +7901,12 @@
|
|||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bmp-ts": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/bmp-ts/-/bmp-ts-1.0.9.tgz",
|
||||
"integrity": "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.2",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz",
|
||||
|
@ -10063,6 +10516,12 @@
|
|||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/exif-parser": {
|
||||
"version": "0.1.12",
|
||||
"resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz",
|
||||
"integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/exit-hook": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz",
|
||||
|
@ -10235,6 +10694,23 @@
|
|||
"node": "^10.12.0 || >=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/file-type": {
|
||||
"version": "16.5.4",
|
||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
|
||||
"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"readable-web-to-node-stream": "^3.0.0",
|
||||
"strtok3": "^6.2.4",
|
||||
"token-types": "^4.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/file-type?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/filesize": {
|
||||
"version": "10.1.6",
|
||||
"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz",
|
||||
|
@ -10601,6 +11077,16 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gifwrap": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.10.1.tgz",
|
||||
"integrity": "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"image-q": "^4.0.0",
|
||||
"omggif": "^1.0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/giget": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/giget/-/giget-1.2.3.tgz",
|
||||
|
@ -11056,6 +11542,21 @@
|
|||
"node": ">= 4"
|
||||
}
|
||||
},
|
||||
"node_modules/image-q": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz",
|
||||
"integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "16.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/image-q/node_modules/@types/node": {
|
||||
"version": "16.9.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz",
|
||||
"integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/image-size": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.1.1.tgz",
|
||||
|
@ -11071,6 +11572,11 @@
|
|||
"node": ">=16.x"
|
||||
}
|
||||
},
|
||||
"node_modules/immutable": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz",
|
||||
"integrity": "sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw=="
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -11826,6 +12332,50 @@
|
|||
"integrity": "sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/jimp": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/jimp/-/jimp-1.6.0.tgz",
|
||||
"integrity": "sha512-YcwCHw1kiqEeI5xRpDlPPBGL2EOpBKLwO4yIBJcXWHPj5PnA5urGq0jbyhM5KoNpypQ6VboSoxc9D8HyfvngSg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jimp/core": "1.6.0",
|
||||
"@jimp/diff": "1.6.0",
|
||||
"@jimp/js-bmp": "1.6.0",
|
||||
"@jimp/js-gif": "1.6.0",
|
||||
"@jimp/js-jpeg": "1.6.0",
|
||||
"@jimp/js-png": "1.6.0",
|
||||
"@jimp/js-tiff": "1.6.0",
|
||||
"@jimp/plugin-blit": "1.6.0",
|
||||
"@jimp/plugin-blur": "1.6.0",
|
||||
"@jimp/plugin-circle": "1.6.0",
|
||||
"@jimp/plugin-color": "1.6.0",
|
||||
"@jimp/plugin-contain": "1.6.0",
|
||||
"@jimp/plugin-cover": "1.6.0",
|
||||
"@jimp/plugin-crop": "1.6.0",
|
||||
"@jimp/plugin-displace": "1.6.0",
|
||||
"@jimp/plugin-dither": "1.6.0",
|
||||
"@jimp/plugin-fisheye": "1.6.0",
|
||||
"@jimp/plugin-flip": "1.6.0",
|
||||
"@jimp/plugin-hash": "1.6.0",
|
||||
"@jimp/plugin-mask": "1.6.0",
|
||||
"@jimp/plugin-print": "1.6.0",
|
||||
"@jimp/plugin-quantize": "1.6.0",
|
||||
"@jimp/plugin-resize": "1.6.0",
|
||||
"@jimp/plugin-rotate": "1.6.0",
|
||||
"@jimp/plugin-threshold": "1.6.0",
|
||||
"@jimp/types": "1.6.0",
|
||||
"@jimp/utils": "1.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/jpeg-js": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz",
|
||||
"integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
|
@ -15873,6 +16423,12 @@
|
|||
"integrity": "sha512-zuHHiGTYTA1sYJ/wZN+t5HKZaH23i4yI1HMwbuXm24Nid7Dv0KcuRlKoNKS9UNfAVSBlnGLcuQrnOKWOZoEGaw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/omggif": {
|
||||
"version": "1.0.10",
|
||||
"resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz",
|
||||
"integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
|
@ -16046,6 +16602,28 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-bmfont-ascii": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz",
|
||||
"integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/parse-bmfont-binary": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz",
|
||||
"integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/parse-bmfont-xml": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.6.tgz",
|
||||
"integrity": "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"xml-parse-from-string": "^1.0.0",
|
||||
"xml2js": "^0.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-entities": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
|
||||
|
@ -16196,6 +16774,19 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/peek-readable": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
|
||||
"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/peek-stream": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/peek-stream/-/peek-stream-1.1.3.tgz",
|
||||
|
@ -16260,6 +16851,27 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/pixelmatch": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-5.3.0.tgz",
|
||||
"integrity": "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"pngjs": "^6.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"pixelmatch": "bin/pixelmatch"
|
||||
}
|
||||
},
|
||||
"node_modules/pixelmatch/node_modules/pngjs": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz",
|
||||
"integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pixi.js": {
|
||||
"version": "7.4.2",
|
||||
"resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-7.4.2.tgz",
|
||||
|
@ -16406,6 +17018,15 @@
|
|||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/pngjs": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz",
|
||||
"integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=14.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/polished": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/polished/-/polished-4.3.1.tgz",
|
||||
|
@ -17049,6 +17670,22 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-web-to-node-stream": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz",
|
||||
"integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"readable-stream": "^3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
|
@ -18238,6 +18875,12 @@
|
|||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/sax": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz",
|
||||
"integrity": "sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
|
@ -18414,6 +19057,15 @@
|
|||
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/simple-xml-to-json": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/simple-xml-to-json/-/simple-xml-to-json-1.2.3.tgz",
|
||||
"integrity": "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=20.12.2"
|
||||
}
|
||||
},
|
||||
"node_modules/simplex-noise": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/simplex-noise/-/simplex-noise-4.0.3.tgz",
|
||||
|
@ -18957,6 +19609,23 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/strtok3": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
|
||||
"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@tokenizer/token": "^0.3.0",
|
||||
"peek-readable": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/style-to-object": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz",
|
||||
|
@ -18991,9 +19660,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/sylvite": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/sylvite/-/sylvite-1.0.3.tgz",
|
||||
"integrity": "sha512-/2hURIj84fmKd2XtX9IAm3VShBDPWnLHEQrMzocG0q3ic1aW3yaYQKKQ3+FnWcFkMqapWv8ySFhyDo6sz2TZbw==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/sylvite/-/sylvite-1.0.6.tgz",
|
||||
"integrity": "sha512-aJ43Elol6QPUsL+eg9SewQjesY/x/UtsggEX0pvsDPcwnhvf8afx5rwSkLTXrbufBA/y4YurT4VqWBrIZNKDtg==",
|
||||
"dependencies": {
|
||||
"tapable": "^2.2.1",
|
||||
"vite-plugin-restart": "^0.4.1"
|
||||
|
@ -19336,6 +20005,12 @@
|
|||
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tinycolor2": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
|
||||
"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/tinypool": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.1.tgz",
|
||||
|
@ -19391,6 +20066,23 @@
|
|||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/token-types": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
|
||||
"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@tokenizer/token": "^0.3.0",
|
||||
"ieee754": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/Borewit"
|
||||
}
|
||||
},
|
||||
"node_modules/toml": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz",
|
||||
|
@ -20072,6 +20764,21 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/utif2": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/utif2/-/utif2-4.1.0.tgz",
|
||||
"integrity": "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"pako": "^1.0.11"
|
||||
}
|
||||
},
|
||||
"node_modules/utif2/node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/util": {
|
||||
"version": "0.12.5",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz",
|
||||
|
@ -21307,6 +22014,34 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml-parse-from-string": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz",
|
||||
"integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/xml2js": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz",
|
||||
"integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"sax": ">=0.6.0",
|
||||
"xmlbuilder": "~11.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xmlbuilder": {
|
||||
"version": "11.0.1",
|
||||
"resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz",
|
||||
"integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
|
@ -21414,6 +22149,15 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.23.8",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
||||
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"node_modules/zwitch": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
"cross-env": "^7.0.3",
|
||||
"express": "^4.19.2",
|
||||
"idb-keyval": "^6.2.1",
|
||||
"immutable": "^5.0.2",
|
||||
"isbot": "^4.1.0",
|
||||
"kefir": "^3.8.8",
|
||||
"morgan": "^1.10.0",
|
||||
|
@ -42,7 +43,7 @@
|
|||
"remark-mdx": "^3.0.1",
|
||||
"remark-parse": "^11.0.0",
|
||||
"simplex-noise": "^4.0.1",
|
||||
"sylvite": "^1.0.3",
|
||||
"sylvite": "^1.0.6",
|
||||
"unified": "^11.0.5",
|
||||
"unist-util-visit-parents": "^6.0.1",
|
||||
"ws": "^8.18.0"
|
||||
|
@ -68,6 +69,7 @@
|
|||
"eslint-plugin-react": "^7.33.2",
|
||||
"eslint-plugin-react-hooks": "^4.6.0",
|
||||
"image-size": "^1.1.1",
|
||||
"jimp": "^1.6.0",
|
||||
"playwright": "^1.47.0",
|
||||
"postcss": "^8.4.38",
|
||||
"storybook": "^8.1.6",
|
||||
|
@ -78,4 +80,4 @@
|
|||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
23
resources/ambient/construction/fence-h-l.entity.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"Collider": {
|
||||
"bodies": [
|
||||
{
|
||||
"impassable": 1,
|
||||
"points": [
|
||||
{"x": -8, "y": -1},
|
||||
{"x": 8, "y": -1},
|
||||
{"x": -8, "y": 1},
|
||||
{"x": 8, "y": 1}
|
||||
],
|
||||
"unstoppable": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Label": {"label": "Fence - Horizontal Left"},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorY": 0.9,
|
||||
"source": "/resources/ambient/construction/fence-h-l.sprite.json"
|
||||
},
|
||||
"VisibleAabb": {}
|
||||
}
|
BIN
resources/ambient/construction/fence-h-l.normals.png
Normal file
After Width: | Height: | Size: 121 B |
BIN
resources/ambient/construction/fence-h-l.png
Normal file
After Width: | Height: | Size: 861 B |
31
resources/ambient/construction/fence-h-l.sprite.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-l.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
31
resources/ambient/construction/fence-h-l.sprite.normals.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-l.normals.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
23
resources/ambient/construction/fence-h-lm.entity.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"Collider": {
|
||||
"bodies": [
|
||||
{
|
||||
"impassable": 1,
|
||||
"points": [
|
||||
{"x": -8, "y": -1},
|
||||
{"x": 8, "y": -1},
|
||||
{"x": -8, "y": 1},
|
||||
{"x": 8, "y": 1}
|
||||
],
|
||||
"unstoppable": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Label": {"label": "Fence - Horizontal LeftMiddle"},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorY": 0.9,
|
||||
"source": "/resources/ambient/construction/fence-h-lm.sprite.json"
|
||||
},
|
||||
"VisibleAabb": {}
|
||||
}
|
BIN
resources/ambient/construction/fence-h-lm.normals.png
Normal file
After Width: | Height: | Size: 121 B |
BIN
resources/ambient/construction/fence-h-lm.png
Normal file
After Width: | Height: | Size: 906 B |
31
resources/ambient/construction/fence-h-lm.sprite.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-lm.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-lm.normals.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
23
resources/ambient/construction/fence-h-m.entity.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"Collider": {
|
||||
"bodies": [
|
||||
{
|
||||
"impassable": 1,
|
||||
"points": [
|
||||
{"x": -8, "y": -1},
|
||||
{"x": 8, "y": -1},
|
||||
{"x": -8, "y": 1},
|
||||
{"x": 8, "y": 1}
|
||||
],
|
||||
"unstoppable": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Label": {"label": "Fence - Horizontal Middle"},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorY": 0.9,
|
||||
"source": "/resources/ambient/construction/fence-h-m.sprite.json"
|
||||
},
|
||||
"VisibleAabb": {}
|
||||
}
|
BIN
resources/ambient/construction/fence-h-m.normals.png
Normal file
After Width: | Height: | Size: 121 B |
BIN
resources/ambient/construction/fence-h-m.png
Normal file
After Width: | Height: | Size: 620 B |
31
resources/ambient/construction/fence-h-m.sprite.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-m.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
31
resources/ambient/construction/fence-h-m.sprite.normals.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-m.normals.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
23
resources/ambient/construction/fence-h-r.entity.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"Collider": {
|
||||
"bodies": [
|
||||
{
|
||||
"impassable": 1,
|
||||
"points": [
|
||||
{"x": -8, "y": -1},
|
||||
{"x": 8, "y": -1},
|
||||
{"x": -8, "y": 1},
|
||||
{"x": 8, "y": 1}
|
||||
],
|
||||
"unstoppable": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Label": {"label": "Fence - Horizontal Right"},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorY": 0.9,
|
||||
"source": "/resources/ambient/construction/fence-h-r.sprite.json"
|
||||
},
|
||||
"VisibleAabb": {}
|
||||
}
|
BIN
resources/ambient/construction/fence-h-r.normals.png
Normal file
After Width: | Height: | Size: 121 B |
BIN
resources/ambient/construction/fence-h-r.png
Normal file
After Width: | Height: | Size: 859 B |
31
resources/ambient/construction/fence-h-r.sprite.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-r.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
31
resources/ambient/construction/fence-h-r.sprite.normals.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-r.normals.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
23
resources/ambient/construction/fence-h-rm.entity.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"Collider": {
|
||||
"bodies": [
|
||||
{
|
||||
"impassable": 1,
|
||||
"points": [
|
||||
{"x": -8, "y": -1},
|
||||
{"x": 8, "y": -1},
|
||||
{"x": -8, "y": 1},
|
||||
{"x": 8, "y": 1}
|
||||
],
|
||||
"unstoppable": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
"Label": {"label": "Fence - Horizontal RightMiddle"},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorY": 0.9,
|
||||
"source": "/resources/ambient/construction/fence-h-rm.sprite.json"
|
||||
},
|
||||
"VisibleAabb": {}
|
||||
}
|
BIN
resources/ambient/construction/fence-h-rm.normals.png
Normal file
After Width: | Height: | Size: 121 B |
BIN
resources/ambient/construction/fence-h-rm.png
Normal file
After Width: | Height: | Size: 906 B |
31
resources/ambient/construction/fence-h-rm.sprite.json
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-rm.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 16,
|
||||
"h": 32
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./fence-h-rm.normals.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 16,
|
||||
"h": 32
|
||||
}
|
||||
}
|
||||
}
|
9
resources/ambient/shrub.entity.json
Normal file
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"Label": {"label": "Shrub"},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorY": 0.7,
|
||||
"source": "/resources/ambient/shrub.sprite.json"
|
||||
},
|
||||
"VisibleAabb": {}
|
||||
}
|
|
@ -4,7 +4,7 @@ export default function*({ecs, projected}) {
|
|||
const filtered = [];
|
||||
for (const position of projected) {
|
||||
if (
|
||||
[1, 2, 3, 4, 6].includes(layer0.tile(position))
|
||||
[224, 225, 226, 227, 242, 243, 244, 245].includes(layer0.tile(position))
|
||||
&& ![7].includes(layer1.tile(position))
|
||||
) {
|
||||
filtered.push(position);
|
||||
|
|
35
resources/shit-shack/shit-shack.entity.json
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"Collider": {
|
||||
"bodies": [
|
||||
{
|
||||
"impassable": 1,
|
||||
"points": [
|
||||
{
|
||||
"x": -40,
|
||||
"y": -40
|
||||
},
|
||||
{
|
||||
"x": 40,
|
||||
"y": -20
|
||||
},
|
||||
{
|
||||
"x": -40,
|
||||
"y": 20
|
||||
},
|
||||
{
|
||||
"x": 40,
|
||||
"y": 20
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.8,
|
||||
"source": "/resources/shit-shack/shit-shack.sprite.json"
|
||||
},
|
||||
"Ticking": {},
|
||||
"VisibleAabb": {}
|
||||
}
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 299 B |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 5.0 KiB |
|
@ -4,18 +4,18 @@
|
|||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 110,
|
||||
"h": 102
|
||||
"w": 88,
|
||||
"h": 115
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 110,
|
||||
"h": 102
|
||||
"w": 88,
|
||||
"h": 115
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 110,
|
||||
"h": 102
|
||||
"w": 88,
|
||||
"h": 115
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -24,8 +24,8 @@
|
|||
"image": "./shit-shack.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 110,
|
||||
"h": 102
|
||||
"w": 88,
|
||||
"h": 115
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1 +1,31 @@
|
|||
{"frames":{"":{"frame":{"x":0,"y":0,"w":110,"h":102},"spriteSourceSize":{"x":0,"y":0,"w":110,"h":102},"sourceSize":{"w":110,"h":102}}},"meta":{"format":"RGBA8888","image":"./shit-shack.normals.png","scale":1,"size":{"w":110,"h":102}}}
|
||||
{
|
||||
"frames": {
|
||||
"": {
|
||||
"frame": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 88,
|
||||
"h": 115
|
||||
},
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 88,
|
||||
"h": 115
|
||||
},
|
||||
"sourceSize": {
|
||||
"w": 88,
|
||||
"h": 115
|
||||
}
|
||||
}
|
||||
},
|
||||
"meta": {
|
||||
"format": "RGBA8888",
|
||||
"image": "./shit-shack.normals.png",
|
||||
"scale": 1,
|
||||
"size": {
|
||||
"w": 88,
|
||||
"h": 115
|
||||
}
|
||||
}
|
||||
}
|
BIN
resources/tileset/homestead.normals.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
resources/tileset/homestead.png
Executable file
After Width: | Height: | Size: 68 KiB |
14819
resources/tileset/homestead.sprite.json
Normal file
14269
resources/tileset/homestead.sprite.normals.json
Normal file
|
@ -30,6 +30,7 @@
|
|||
"source": "/resources/tomato/tomato.item.json"
|
||||
},
|
||||
"Magnetic": {},
|
||||
"Position": {},
|
||||
"Sprite": {
|
||||
"anchorX": 0.5,
|
||||
"anchorY": 0.5,
|
||||
|
|
|
@ -59,6 +59,9 @@ export default defineConfig(hooks.call('sylvite:viteConfig', {
|
|||
},
|
||||
server: {
|
||||
host: true,
|
||||
hmr: {
|
||||
port: 3101,
|
||||
},
|
||||
...(!isInsecure && {
|
||||
https: {
|
||||
key: readFileSync(httpsKey),
|
||||
|
|