silphius/app/engine/engine.js

201 lines
5.1 KiB
JavaScript
Raw Normal View History

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-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-12 19:35:51 -05:00
incoming = [];
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-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
};
this.connections = [];
this.connectedPlayers = new Map();
this.frame = 0;
this.last = Date.now();
class SilphiusServer extends Server {
accept(connection, packed) {
super.accept(connection, decode(packed));
}
transmit(connection, packet) {
super.transmit(connection, encode(packet));
}
}
this.server = new SilphiusServer();
this.server.addPacketListener((connection, packet) => {
this.accept(connection, packet);
});
}
2024-06-12 19:35:51 -05:00
accept(connection, packet) {
this.incoming.push([this.connectedPlayers.get(connection).entity, packet]);
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
}
for (const [{Controlled}, {payload, type}] of this.incoming) {
switch (type) {
case 'Action': {
if (payload.type in MOVE_MAP) {
Controlled[MOVE_MAP[payload.type]] = payload.value;
}
break;
}
default:
}
}
this.incoming = [];
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;
}
}