chore: initial
This commit is contained in:
parent
b280b498a4
commit
6705608b5a
|
@ -16,14 +16,24 @@
|
|||
"watch": "NODE_PATH=./node_modules webpack --watch --mode development"
|
||||
},
|
||||
"files": [
|
||||
"client.js",
|
||||
"client.js.map",
|
||||
"index.js",
|
||||
"index.js.map",
|
||||
"server.js",
|
||||
"server.js.map",
|
||||
"test.js",
|
||||
"test.js.map"
|
||||
],
|
||||
"dependencies": {
|
||||
"@avocado/math": "^2.0.0",
|
||||
"@avocado/resource": "^2.0.0",
|
||||
"@avocado/traits": "^2.0.0",
|
||||
"@latus/core": "^2.0.0",
|
||||
"@latus/redux": "^2.0.0",
|
||||
"debug": "4.3.1"
|
||||
"@latus/socket": "^2.0.0",
|
||||
"debug": "4.3.1",
|
||||
"glob": "^7.1.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@neutrinojs/airbnb-base": "^9.4.0",
|
||||
|
@ -34,7 +44,6 @@
|
|||
"chai": "4.2.0",
|
||||
"eslint": "^7",
|
||||
"eslint-import-resolver-webpack": "0.13.0",
|
||||
"glob": "7.1.6",
|
||||
"mocha": "^8",
|
||||
"neutrino": "^9.4.0",
|
||||
"source-map-support": "0.5.19",
|
||||
|
|
16
packages/universe/src/client/index.js
Normal file
16
packages/universe/src/client/index.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
// import {join} from 'path';
|
||||
|
||||
// import {Resource} from '@avocado/resource';
|
||||
|
||||
import Packets from './packets';
|
||||
|
||||
export default {
|
||||
hooks: {
|
||||
'@latus/socket/packets': Packets,
|
||||
// '@latus/core/started': async ({config: {'@humus/universe/client': {uuid}}}) => {
|
||||
// if (uuid) {
|
||||
// Resource.root = join('/', 'universe', uuid);
|
||||
// }
|
||||
// },
|
||||
},
|
||||
};
|
5
packages/universe/src/client/packets/index.js
Normal file
5
packages/universe/src/client/packets/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Locate from './locate';
|
||||
|
||||
export default () => ({
|
||||
Locate: Locate(),
|
||||
});
|
9
packages/universe/src/client/packets/locate.js
Normal file
9
packages/universe/src/client/packets/locate.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Locate from '../../packets/locate';
|
||||
|
||||
export default () => class ClientLocate extends Locate() {
|
||||
|
||||
// static respond() {
|
||||
// return new super.constructor();
|
||||
// }
|
||||
|
||||
};
|
|
@ -1,9 +1,11 @@
|
|||
import Resources from './resources';
|
||||
import {universes} from './state';
|
||||
|
||||
export * from './state';
|
||||
|
||||
export default {
|
||||
hooks: {
|
||||
'@avocado/resource/resources': Resources,
|
||||
'@latus/redux/slices': () => ({
|
||||
universes,
|
||||
}),
|
||||
|
|
11
packages/universe/src/packets/join.js
Normal file
11
packages/universe/src/packets/join.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import {Packet} from '@latus/socket';
|
||||
|
||||
export default () => class Join extends Packet {
|
||||
|
||||
static get data() {
|
||||
return {
|
||||
universe: 'string',
|
||||
};
|
||||
}
|
||||
|
||||
};
|
3
packages/universe/src/packets/leave.js
Normal file
3
packages/universe/src/packets/leave.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
import {Packet} from '@latus/socket';
|
||||
|
||||
export default () => class Join extends Packet {};
|
18
packages/universe/src/packets/locate.js
Normal file
18
packages/universe/src/packets/locate.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
import {Vector} from '@avocado/math';
|
||||
import {compose} from '@latus/core';
|
||||
import {Packet} from '@latus/socket';
|
||||
|
||||
const decorate = compose(
|
||||
Vector.Packer('position'),
|
||||
);
|
||||
|
||||
export default () => class Locate extends decorate(Packet) {
|
||||
|
||||
static get data() {
|
||||
return {
|
||||
...this.data,
|
||||
room: 'string',
|
||||
};
|
||||
}
|
||||
|
||||
};
|
5
packages/universe/src/resources/index.js
Normal file
5
packages/universe/src/resources/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Universe from './universe';
|
||||
|
||||
export default (latus) => ({
|
||||
Universe: Universe(latus),
|
||||
});
|
100
packages/universe/src/resources/universe.js
Normal file
100
packages/universe/src/resources/universe.js
Normal file
|
@ -0,0 +1,100 @@
|
|||
import {dirname, join} from 'path';
|
||||
|
||||
import {promisify} from 'util';
|
||||
|
||||
import {resource, JsonResource} from '@avocado/resource';
|
||||
import glob from 'glob';
|
||||
|
||||
const pglob = promisify(glob);
|
||||
|
||||
export default (latus) => class Universe extends JsonResource {
|
||||
|
||||
#mainLoopHandle = null;
|
||||
|
||||
#rooms = {};
|
||||
|
||||
#roomsFlat = [];
|
||||
|
||||
#tps;
|
||||
|
||||
constructor({rooms = {}, tps = 60} = {}) {
|
||||
super();
|
||||
Object.entries(rooms).forEach(([uri, room]) => {
|
||||
this.addRoom(uri, room);
|
||||
});
|
||||
this.#tps = tps;
|
||||
}
|
||||
|
||||
addRoom(uri, room) {
|
||||
this.#rooms[uri] = room;
|
||||
this.#roomsFlat.push(room);
|
||||
}
|
||||
|
||||
static async extendJson(json) {
|
||||
const uri = json.extends;
|
||||
const extended = await super.extendJson(json);
|
||||
const {fromResourceType: {Room}} = resource(latus);
|
||||
if (uri) {
|
||||
const universePath = dirname(uri);
|
||||
extended.rooms = Object.fromEntries(
|
||||
await Promise.all(
|
||||
(
|
||||
await pglob(
|
||||
'**/*.room.json',
|
||||
{
|
||||
cwd: join(process.cwd(), this.root, universePath),
|
||||
},
|
||||
)
|
||||
)
|
||||
.map(async (roomUri) => [
|
||||
roomUri,
|
||||
await Room.load({extends: join(universePath, roomUri)}),
|
||||
]),
|
||||
),
|
||||
);
|
||||
}
|
||||
return extended;
|
||||
}
|
||||
|
||||
static async load(json = {}) {
|
||||
if (!json.extends) {
|
||||
throw new Error('Universe::extendJSON needs a URI');
|
||||
}
|
||||
return super.load(json);
|
||||
}
|
||||
|
||||
room(uri) {
|
||||
return this.#rooms[uri];
|
||||
}
|
||||
|
||||
start() {
|
||||
if (!this.#mainLoopHandle) {
|
||||
// eslint-disable-next-line no-eval
|
||||
const {performance} = eval('require')('perf_hooks');
|
||||
let lastTime = performance.now();
|
||||
this.#mainLoopHandle = setInterval(
|
||||
() => {
|
||||
const now = performance.now();
|
||||
const elapsed = (now - lastTime) / 1000;
|
||||
lastTime = now;
|
||||
this.tick(elapsed);
|
||||
},
|
||||
1000 / this.#tps,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
stop() {
|
||||
if (this.#mainLoopHandle) {
|
||||
clearInterval(this.#mainLoopHandle);
|
||||
this.#mainLoopHandle = null;
|
||||
}
|
||||
}
|
||||
|
||||
tick(elapsed) {
|
||||
for (let i = 0; i < this.#roomsFlat.length; i++) {
|
||||
this.#roomsFlat[i].tick(elapsed);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
41
packages/universe/src/server/index.js
Normal file
41
packages/universe/src/server/index.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
// import fs from 'fs';
|
||||
// import {join} from 'path';
|
||||
// import {promisify} from 'util';
|
||||
|
||||
import {resource} from '@avocado/resource';
|
||||
|
||||
import Packets from './packets';
|
||||
|
||||
// const access = promisify(fs.access).bind(fs);
|
||||
|
||||
export default {
|
||||
hooks: {
|
||||
'@latus/core/up': async (latus) => {
|
||||
const {config: {'@humus/universe': {running}}} = latus;
|
||||
if (!running) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const {fromResourceType: {Universe}} = resource(latus);
|
||||
const universe = await Universe.load({extends: `/universe/${running}/index.universe.json`});
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
latus.config['%universe'] = universe;
|
||||
universe.start();
|
||||
console.log(`Universe ${running} up and running!`);
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`Couldn't run universe '${running}': ${error.stack}`);
|
||||
}
|
||||
},
|
||||
'@latus/http/plugins': (req, {config: {'@humus/universe': {uuid}}}) => ({
|
||||
'@humus/universe/client': {uuid},
|
||||
}),
|
||||
'@latus/socket/packets': Packets,
|
||||
},
|
||||
};
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
process.stdout.write('\n');
|
||||
});
|
||||
|
||||
process.on('SIGINT', () => process.exit());
|
5
packages/universe/src/server/packets/index.js
Normal file
5
packages/universe/src/server/packets/index.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
import Locate from './locate';
|
||||
|
||||
export default () => ({
|
||||
Locate: Locate(),
|
||||
});
|
11
packages/universe/src/server/packets/locate.js
Normal file
11
packages/universe/src/server/packets/locate.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import {ValidationError} from '@latus/socket';
|
||||
|
||||
import Locate from '../../packets/locate';
|
||||
|
||||
export default () => class ServerLocate extends Locate() {
|
||||
|
||||
static validate() {
|
||||
throw new ValidationError({code: 500, reason: 'protocol'});
|
||||
}
|
||||
|
||||
};
|
54
packages/universe/src/state/universe.js
Normal file
54
packages/universe/src/state/universe.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
import {resource} from '@avocado/resource';
|
||||
import {
|
||||
createAsyncThunk,
|
||||
createSelector,
|
||||
createSlice,
|
||||
} from '@latus/redux';
|
||||
import {
|
||||
socket,
|
||||
} from '@latus/socket/client';
|
||||
|
||||
export const universeSelector = ({universe}) => universe;
|
||||
|
||||
export const roomSelector = createSelector(
|
||||
[universeSelector],
|
||||
({room}) => room,
|
||||
);
|
||||
|
||||
export const playUniverse = createAsyncThunk(
|
||||
'humus/universe/play',
|
||||
async (uuid, {extra: latus}) => {
|
||||
const {data: {room, selfEntityUuid}} = await socket(latus).send(['Join', uuid]);
|
||||
const {fromResourceType: {Room}} = resource(latus);
|
||||
return {
|
||||
room: await Room.load(room),
|
||||
selfEntityUuid,
|
||||
};
|
||||
},
|
||||
);
|
||||
|
||||
const slice = createSlice({
|
||||
name: 'humus/universe',
|
||||
initialState: {
|
||||
online: [],
|
||||
room: null,
|
||||
selfEntityUuid: -1,
|
||||
},
|
||||
/* eslint-disable no-param-reassign */
|
||||
extraReducers: {
|
||||
[playUniverse.fulfilled]: (state, {payload: {room, selfEntityUuid}}) => {
|
||||
state.room = room;
|
||||
state.selfEntityUuid = selfEntityUuid;
|
||||
},
|
||||
},
|
||||
reducers: {
|
||||
},
|
||||
/* eslint-enable no-param-reassign */
|
||||
});
|
||||
|
||||
slice.reducer.subscription = slice.reducer;
|
||||
|
||||
// export const {
|
||||
// } = slice.actions;
|
||||
|
||||
export default slice.reducer;
|
|
@ -3,7 +3,7 @@ import {
|
|||
createSlice,
|
||||
} from '@latus/redux';
|
||||
|
||||
export const universesSelector = (state) => state.universes;
|
||||
export const universesSelector = ({universes}) => universes;
|
||||
|
||||
export const universesByLocalitySelector = createSelector(
|
||||
[universesSelector, (_, isLocal) => isLocal],
|
||||
|
|
11
packages/universe/src/traits/universed.js
Normal file
11
packages/universe/src/traits/universed.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
import {Trait} from '@avocado/traits';
|
||||
|
||||
export default class Universed extends Trait {
|
||||
|
||||
static defaultState() {
|
||||
return {
|
||||
in: '/rooms/town.room.json',
|
||||
};
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user