This commit is contained in:
Matthieu Jolimaitre 2024-04-09 02:05:02 +02:00
commit 28b026a614
17 changed files with 895 additions and 0 deletions

153
server/engine.ts Normal file
View file

@ -0,0 +1,153 @@
import { assertEquals } from "https://deno.land/std@0.221.0/assert/mod.ts";
import { chunks, enumerate, log_from, Prototyped, range, Vec2 } from "../common/utils.ts";
import { ClientInterface } from "./network.ts";
import { Session } from "./entities/player.ts";
import { ClassMap } from "../common/utils.ts";
import { maybe } from "../common/utils.ts";
const log = log_from(import.meta);
export class WorldEntity {
display;
world;
identifier;
position;
compontents;
constructor(world: World, identifier: number, display: string, position: Vec2, ...components: Prototyped[]) {
this.display = display;
this.world = world;
this.identifier = identifier;
this.position = position;
this.compontents = new ClassMap();
for (const c of components) this.compontents.insert(c);
}
}
export class World {
next_id;
entities;
constructor() {
this.next_id = 0;
this.entities = new Map<number, WorldEntity>();
}
spawn_entity(display: string, pos: Vec2) {
const entity = new WorldEntity(this, this.next_id++, display, pos);
this.entities.set(entity.identifier, entity);
return entity;
}
async spawn_structure(file_path: string, origin: Vec2) {
const content = await Deno.readTextFile(file_path);
let count = 0;
for (const [y, line] of enumerate(content.split("\n"))) {
for (const [x, chars] of enumerate(chunks(line, 2))) {
const display = chars[0] + chars[1];
if (display === " ") continue;
this.spawn_entity(display, origin.add(new Vec2(x, y)));
count += 1;
}
}
log("Spawned", count, "tiles from", file_path);
}
render(center: Vec2, size: Vec2) {
const radius = size.scale(0.5);
const result = Array.from(range(0, size.y())).map(() => Array.from(range(0, size.x())).map(() => " "));
const top_left = center.sub(radius);
const bottom_right = center.add(radius);
for (const entity of this.entities.values()) {
if (!entity.position.inside(top_left, bottom_right)) continue;
const local_pos = entity.position.sub(top_left);
result[local_pos.y()][local_pos.x()] = entity.display;
}
return result.map((line) => line.join("")).toReversed().join("\n");
}
move_collide(entity_id: number, displacement: Vec2) {
let result = false;
const entity = this.get_entity(entity_id);
if (entity === undefined) return result;
for (const step of displacement_steps(entity.position, displacement)) {
const collision = this.get_entity_at(step);
if (collision !== undefined) return result;
entity.position = step;
result = true;
}
return result;
}
get_entity(entity_id: number) {
return this.entities.get(entity_id);
}
*get_entities_at(pos: Vec2) {
for (const entity of this.entities.values()) if (entity.position.overlaps(pos)) yield entity;
}
get_entity_at(pos: Vec2) {
return maybe([...this.get_entities_at(pos)][0]);
}
*get_entities_in_range(min: Vec2, max: Vec2) {
for (const entity of this.entities.values()) if (entity.position.inside(min, max)) yield entity;
}
get_entity_in_range(min: Vec2, max: Vec2) {
return maybe([...this.get_entities_in_range(min, max)][0]);
}
kill(entity_id: number) {
this.entities.delete(entity_id);
}
}
export class Engine {
world;
constructor(world: World) {
this.world = world;
}
async start() {
log("Started engine.");
}
add_session(client: ClientInterface) {
const player_entity = this.world.spawn_entity("`/", new Vec2(0, 0));
const session = new Session(client, this.world, player_entity);
session.spin();
}
}
function* displacement_steps(position: Vec2, displacement: Vec2) {
let pos = position;
let left = displacement;
while (left.len() >= 1) {
if (left.x() >= 1) {
pos = pos.add(new Vec2(1, 0));
left = left.sub(new Vec2(1, 0));
}
if (left.x() <= -1) {
pos = pos.add(new Vec2(-1, 0));
left = left.sub(new Vec2(-1, 0));
}
if (left.y() >= 1) {
pos = pos.add(new Vec2(0, 1));
left = left.sub(new Vec2(0, 1));
}
if (left.y() <= -1) {
pos = pos.add(new Vec2(0, -1));
left = left.sub(new Vec2(0, -1));
}
yield pos;
}
}
Deno.test("test_displacement", () => {
assertEquals(
[...displacement_steps(new Vec2(1, 1), new Vec2(4, 6))],
[new Vec2(2, 2), new Vec2(3, 3), new Vec2(4, 4), new Vec2(5, 5), new Vec2(5, 6), new Vec2(5, 7)],
);
});