chore: initial

This commit is contained in:
cha0s 2021-01-12 19:14:38 -06:00
parent b280b498a4
commit 6705608b5a
17 changed files with 1679 additions and 43 deletions

View File

@ -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",

View 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);
// }
// },
},
};

View File

@ -0,0 +1,5 @@
import Locate from './locate';
export default () => ({
Locate: Locate(),
});

View File

@ -0,0 +1,9 @@
import Locate from '../../packets/locate';
export default () => class ClientLocate extends Locate() {
// static respond() {
// return new super.constructor();
// }
};

View File

@ -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,
}),

View File

@ -0,0 +1,11 @@
import {Packet} from '@latus/socket';
export default () => class Join extends Packet {
static get data() {
return {
universe: 'string',
};
}
};

View File

@ -0,0 +1,3 @@
import {Packet} from '@latus/socket';
export default () => class Join extends Packet {};

View 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',
};
}
};

View File

@ -0,0 +1,5 @@
import Universe from './universe';
export default (latus) => ({
Universe: Universe(latus),
});

View 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);
}
}
};

View 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());

View File

@ -0,0 +1,5 @@
import Locate from './locate';
export default () => ({
Locate: Locate(),
});

View 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'});
}
};

View 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;

View File

@ -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],

View 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