2024-06-10 22:42:30 -05:00
|
|
|
import {
|
|
|
|
MOVE_MAP,
|
|
|
|
RESOLUTION,
|
|
|
|
TPS,
|
|
|
|
} from '@/constants.js';
|
2024-06-10 23:55:06 -05:00
|
|
|
import ControlMovement from '@/ecs-systems/control-movement.js';
|
|
|
|
import ApplyMomentum from '@/ecs-systems/apply-momentum.js';
|
|
|
|
import CalculateAabbs from '@/ecs-systems/calculate-aabbs.js';
|
2024-06-13 17:49:39 -05:00
|
|
|
import ClampPositions from '@/ecs-systems/clamp-positions.js';
|
2024-06-11 01:41:19 -05:00
|
|
|
import FollowCamera from '@/ecs-systems/follow-camera.js';
|
2024-06-10 23:55:06 -05:00
|
|
|
import UpdateSpatialHash from '@/ecs-systems/update-spatial-hash.js';
|
2024-06-12 14:31:12 -05:00
|
|
|
import RunAnimations from '@/ecs-systems/run-animations.js';
|
2024-06-12 19:35:51 -05:00
|
|
|
import ControlDirection from '@/ecs-systems/control-direction.js';
|
|
|
|
import SpriteDirection from '@/ecs-systems/sprite-direction.js';
|
2024-06-10 23:55:06 -05:00
|
|
|
import Ecs from '@/engine/ecs.js';
|
|
|
|
import {decode, encode} from '@/packets/index.js';
|
2024-06-10 22:42:30 -05:00
|
|
|
|
|
|
|
const players = {
|
|
|
|
0: {
|
2024-06-11 01:41:19 -05:00
|
|
|
Camera: {},
|
2024-06-10 22:42:30 -05:00
|
|
|
Controlled: {up: 0, right: 0, down: 0, left: 0},
|
2024-06-12 19:35:51 -05:00
|
|
|
Direction: {direction: 2},
|
2024-06-10 22:42:30 -05:00
|
|
|
Momentum: {},
|
2024-06-11 19:45:37 -05:00
|
|
|
Position: {x: 368, y: 368},
|
2024-06-10 22:42:30 -05:00
|
|
|
VisibleAabb: {},
|
2024-06-11 00:08:31 -05:00
|
|
|
World: {world: 1},
|
2024-06-12 14:31:12 -05:00
|
|
|
Sprite: {
|
2024-06-12 19:35:51 -05:00
|
|
|
animation: 'moving:down',
|
2024-06-12 14:31:12 -05:00
|
|
|
frame: 0,
|
|
|
|
frames: 8,
|
|
|
|
source: '/assets/dude.json',
|
2024-06-12 19:35:51 -05:00
|
|
|
speed: 0.115,
|
2024-06-12 14:31:12 -05:00
|
|
|
},
|
2024-06-10 22:42:30 -05:00
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
export default class Engine {
|
|
|
|
|
|
|
|
static Ecs = Ecs;
|
|
|
|
|
2024-06-13 01:26:01 -05:00
|
|
|
incomingActions = [];
|
2024-06-12 19:35:51 -05:00
|
|
|
|
2024-06-13 12:24:32 -05:00
|
|
|
connections = [];
|
|
|
|
|
|
|
|
connectedPlayers = new Map();
|
|
|
|
|
|
|
|
ecses = {};
|
|
|
|
|
|
|
|
frame = 0;
|
|
|
|
|
|
|
|
last = Date.now();
|
|
|
|
|
|
|
|
server;
|
|
|
|
|
2024-06-10 22:42:30 -05:00
|
|
|
constructor(Server) {
|
|
|
|
const ecs = new this.constructor.Ecs();
|
2024-06-12 13:19:16 -05:00
|
|
|
const layerSize = {x: Math.ceil(RESOLUTION.x / 4), y: Math.ceil(RESOLUTION.y / 4)};
|
2024-06-10 22:42:30 -05:00
|
|
|
ecs.create({
|
2024-06-11 02:24:45 -05:00
|
|
|
AreaSize: {x: RESOLUTION.x * 4, y: RESOLUTION.y * 4},
|
2024-06-12 13:19:16 -05:00
|
|
|
TileLayers: {
|
|
|
|
layers: [
|
|
|
|
{
|
|
|
|
data: (
|
|
|
|
Array(layerSize.x * layerSize.y)
|
|
|
|
.fill(0)
|
|
|
|
.map(() => 1 + Math.floor(Math.random() * 4))
|
|
|
|
),
|
|
|
|
size: layerSize,
|
|
|
|
}
|
|
|
|
],
|
|
|
|
},
|
2024-06-10 22:42:30 -05:00
|
|
|
});
|
|
|
|
ecs.addSystem(ControlMovement);
|
|
|
|
ecs.addSystem(ApplyMomentum);
|
2024-06-13 17:49:39 -05:00
|
|
|
ecs.addSystem(ClampPositions);
|
2024-06-11 01:41:19 -05:00
|
|
|
ecs.addSystem(FollowCamera);
|
2024-06-10 22:42:30 -05:00
|
|
|
ecs.addSystem(CalculateAabbs);
|
|
|
|
ecs.addSystem(UpdateSpatialHash);
|
2024-06-12 19:35:51 -05:00
|
|
|
ecs.addSystem(ControlDirection);
|
|
|
|
ecs.addSystem(SpriteDirection);
|
2024-06-12 14:31:12 -05:00
|
|
|
ecs.addSystem(RunAnimations);
|
2024-06-10 22:42:30 -05:00
|
|
|
this.ecses = {
|
2024-06-11 00:08:31 -05:00
|
|
|
1: ecs,
|
2024-06-10 22:42:30 -05:00
|
|
|
};
|
|
|
|
class SilphiusServer extends Server {
|
|
|
|
accept(connection, packed) {
|
|
|
|
super.accept(connection, decode(packed));
|
|
|
|
}
|
|
|
|
transmit(connection, packet) {
|
|
|
|
super.transmit(connection, encode(packet));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.server = new SilphiusServer();
|
2024-06-13 01:26:01 -05:00
|
|
|
this.server.addPacketListener('Action', (connection, payload) => {
|
|
|
|
this.incomingActions.push([this.connectedPlayers.get(connection).entity, payload]);
|
2024-06-10 22:42:30 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async connectPlayer(connection) {
|
|
|
|
this.connections.push(connection);
|
|
|
|
const entityJson = await this.loadPlayer(connection);
|
|
|
|
const ecs = this.ecses[entityJson.World.world];
|
|
|
|
const entity = ecs.create(entityJson);
|
|
|
|
this.connectedPlayers.set(
|
|
|
|
connection,
|
|
|
|
{
|
|
|
|
entity: ecs.get(entity),
|
|
|
|
memory: new Set(),
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
disconnectPlayer(connection) {
|
|
|
|
const {entity} = this.connectedPlayers.get(connection);
|
|
|
|
const ecs = this.ecses[entity.World.world];
|
|
|
|
players[0] = JSON.parse(JSON.stringify(entity.toJSON()));
|
|
|
|
ecs.destroy(entity.id);
|
|
|
|
this.connectedPlayers.delete(connection);
|
|
|
|
this.connections.splice(this.connections.indexOf(connection), 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
async load() {
|
|
|
|
}
|
|
|
|
|
|
|
|
async loadPlayer() {
|
|
|
|
return players[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
start() {
|
|
|
|
return setInterval(() => {
|
|
|
|
const elapsed = (Date.now() - this.last) / 1000;
|
|
|
|
this.last = Date.now();
|
|
|
|
this.tick(elapsed);
|
|
|
|
this.update(elapsed);
|
|
|
|
this.frame += 1;
|
|
|
|
}, 1000 / TPS);
|
|
|
|
}
|
|
|
|
|
|
|
|
tick(elapsed) {
|
|
|
|
for (const i in this.ecses) {
|
|
|
|
this.ecses[i].setClean();
|
2024-06-12 19:35:51 -05:00
|
|
|
}
|
2024-06-13 01:26:01 -05:00
|
|
|
for (const [{Controlled}, payload] of this.incomingActions) {
|
|
|
|
if (payload.type in MOVE_MAP) {
|
|
|
|
Controlled[MOVE_MAP[payload.type]] = payload.value;
|
2024-06-12 19:35:51 -05:00
|
|
|
}
|
|
|
|
}
|
2024-06-13 01:26:01 -05:00
|
|
|
this.incomingActions = [];
|
2024-06-12 19:35:51 -05:00
|
|
|
for (const i in this.ecses) {
|
2024-06-10 22:42:30 -05:00
|
|
|
this.ecses[i].tick(elapsed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
update(elapsed) {
|
|
|
|
for (const connection of this.connections) {
|
|
|
|
this.server.send(
|
|
|
|
connection,
|
|
|
|
{
|
|
|
|
type: 'Tick',
|
|
|
|
payload: {
|
|
|
|
ecs: this.updateFor(connection),
|
|
|
|
elapsed,
|
|
|
|
frame: this.frame,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
updateFor(connection) {
|
|
|
|
const update = {};
|
|
|
|
const {entity, memory} = this.connectedPlayers.get(connection);
|
2024-06-11 01:41:19 -05:00
|
|
|
const mainEntityId = entity.id;
|
2024-06-10 22:42:30 -05:00
|
|
|
const ecs = this.ecses[entity.World.world];
|
2024-06-11 02:10:08 -05:00
|
|
|
const nearby = ecs.system(UpdateSpatialHash).nearby(entity);
|
2024-06-12 13:19:16 -05:00
|
|
|
// Master entity.
|
|
|
|
nearby.add(ecs.get(1));
|
2024-06-10 22:42:30 -05:00
|
|
|
const lastMemory = new Set(memory.values());
|
|
|
|
for (const entity of nearby) {
|
|
|
|
const {id} = entity;
|
|
|
|
lastMemory.delete(id);
|
|
|
|
if (!memory.has(id)) {
|
|
|
|
update[id] = entity.toJSON();
|
2024-06-11 01:41:19 -05:00
|
|
|
if (mainEntityId === id) {
|
|
|
|
update[id].MainEntity = {};
|
|
|
|
}
|
2024-06-10 22:42:30 -05:00
|
|
|
}
|
|
|
|
else if (ecs.diff[id]) {
|
|
|
|
update[id] = ecs.diff[id];
|
|
|
|
}
|
|
|
|
memory.add(id);
|
|
|
|
}
|
|
|
|
for (const id of lastMemory) {
|
|
|
|
memory.delete(id);
|
|
|
|
update[id] = false;
|
|
|
|
}
|
|
|
|
return update;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|