85 lines
2.6 KiB
TypeScript
85 lines
2.6 KiB
TypeScript
import { mts } from "../../common/mod.ts";
|
|
import { log_from, v2, Vec2 } from "../../common/utils.ts";
|
|
import { CompDisplay, sys_render_world } from "../components/display.ts";
|
|
import { CompPos, sys_find_free_pos } from "../components/world.ts";
|
|
import { CompId, Engine, Entity } from "../engine.ts";
|
|
import { ClientInterface } from "../network.ts";
|
|
const log = log_from(import.meta);
|
|
|
|
export class Session {
|
|
client;
|
|
engine;
|
|
entity;
|
|
|
|
constructor(client: ClientInterface, engine: Engine, entity: Entity) {
|
|
this.client = client;
|
|
this.engine = engine;
|
|
this.entity = entity;
|
|
}
|
|
|
|
static init(client: ClientInterface, engine: Engine) {
|
|
const spawn_pos = engine.run(sys_find_free_pos(v2(0, 0)));
|
|
const entity = engine.run(sys_spawn_player(spawn_pos));
|
|
const self = new Session(client, engine, entity);
|
|
return self;
|
|
}
|
|
|
|
async start() {
|
|
try {
|
|
for await (const input of this.client.inputs.iter()) {
|
|
if (input.kind !== "request_display") log("Received", input);
|
|
|
|
if (input.kind === "ping") this.client.outputs.send({ kind: "ping_response", content: input.content });
|
|
if (input.kind === "request_display") this.send_display(input.content.width, input.content.height);
|
|
if (input.kind === "input") this.handle_input(input);
|
|
if (input.kind === "exit") break;
|
|
}
|
|
} catch (error) {
|
|
console.error("Session loop failed, ", error);
|
|
}
|
|
this.engine.delete(this.entity.get_force(CompId).id);
|
|
}
|
|
|
|
handle_input(input: mts.MsgInput) {
|
|
if (input.content.control === "up") this.move(v2(0, 1));
|
|
if (input.content.control === "down") this.move(v2(0, -1));
|
|
if (input.content.control === "left") this.move(v2(-1, 0));
|
|
if (input.content.control === "right") this.move(v2(1, 0));
|
|
}
|
|
|
|
send_display(width: number, height: number) {
|
|
const raw = this.engine.run(sys_render_world(this.entity.get_force(CompPos).pos, v2(width, height)));
|
|
this.client.outputs.send({ kind: "display", content: { raw } });
|
|
}
|
|
|
|
move(direction: Vec2) {
|
|
const pos = this.entity.get_force(CompPos);
|
|
pos.move_collide(this.engine, direction);
|
|
const player = this.entity.get_force(CompPlayer);
|
|
const display = this.entity.get_force(CompDisplay);
|
|
if (direction.x() > 0) player.direction = Dir.Right, display.update("P/");
|
|
if (direction.x() < 0) player.direction = Dir.Left, display.update("\\P");
|
|
}
|
|
}
|
|
|
|
export function sys_spawn_player(position: Vec2) {
|
|
return (engine: Engine) => {
|
|
return engine.spawn((entity) =>
|
|
entity.insert(
|
|
new CompPlayer(),
|
|
new CompPos(entity, position),
|
|
new CompDisplay("\\P"),
|
|
)
|
|
);
|
|
};
|
|
}
|
|
|
|
enum Dir {
|
|
Left,
|
|
Right,
|
|
}
|
|
|
|
export class CompPlayer {
|
|
life = 10;
|
|
direction = Dir.Left;
|
|
}
|