holy fuck we actually got somewhere

This commit is contained in:
Elizabeth Hunt 2023-08-23 19:44:59 -06:00
parent d64ffb5016
commit dec7b614d8
Signed by: simponic
GPG Key ID: 52B3774857EB24B1
20 changed files with 346 additions and 133 deletions

View File

@ -1,4 +1,5 @@
import { Game } from "@engine/Game"; import { Game } from "@engine/Game";
import { Entity } from "@engine/entities";
import { Grid } from "@engine/structures"; import { Grid } from "@engine/structures";
import { import {
WallBounds, WallBounds,
@ -7,67 +8,116 @@ import {
Physics, Physics,
Input, Input,
Collision, Collision,
MessageQueueProvider,
MessagePublisher,
NetworkUpdate, NetworkUpdate,
} from "@engine/systems"; } from "@engine/systems";
import {
type MessageQueueProvider,
type MessagePublisher,
type MessageProcessor,
type Message,
type EntityAddBody,
MessageType,
} from "@engine/network";
import { stringify, parse } from "@engine/utils";
class ClientMessageProcessor implements MessageProcessor {
private game: Game;
constructor(game: Game) {
this.game = game;
}
public process(message: Message) {
switch (message.type) {
case MessageType.NEW_ENTITY:
const entityAddBody = message.body as unknown as EntityAddBody;
this.game.addEntity(
Entity.from(entityAddBody.entityName, entityAddBody.args),
);
break;
}
console.log(message);
}
}
class ClientSocketMessageQueueProvider implements MessageQueueProvider { class ClientSocketMessageQueueProvider implements MessageQueueProvider {
private socket: WebSocket; private socket: WebSocket;
private messages: any[]; private messages: Message[];
constructor(socket: WebSocket) { constructor(socket: WebSocket) {
this.socket = socket; this.socket = socket;
this.messages = []; this.messages = [];
this.socket.addEventListener("message", (e) => { this.socket.addEventListener("message", (e) => {
console.log(e); const message = parse<Message>(e.data);
this.messages.push(message);
}); });
} }
getNewMessages() { public getNewMessages() {
return this.messages; return this.messages;
} }
clearMessages() { public clearMessages() {
this.messages = []; this.messages = [];
} }
} }
class ClientSocketMessagePublisher implements MessagePublisher { class ClientSocketMessagePublisher implements MessagePublisher {
private socket: WebSocket; private socket: WebSocket;
private messages: any[]; private messages: Message[];
constructor(socket: WebSocket) { constructor(socket: WebSocket) {
this.socket = socket; this.socket = socket;
this.messages = []; this.messages = [];
this.socket.addEventListener("message", (e) => {
console.log(e);
});
} }
addMessage(_message: any) {} public addMessage(message: Message) {
this.messages.push(message);
}
publish() {} public publish() {
this.messages.forEach((message: Message) =>
this.socket.send(stringify(message)),
);
}
} }
export class JumpStorm { export class JumpStorm {
private game: Game; private game: Game;
private clientId: string;
constructor(ctx: CanvasRenderingContext2D) { constructor(game: Game) {
this.game = new Game(); this.game = game;
}
const socket = new WebSocket("ws://localhost:8080"); public async init(
setInterval(() => socket.send(JSON.stringify({ x: 1 })), 1_000); ctx: CanvasRenderingContext2D,
const clientSocketMessageQueueProvider = httpMethod: string,
new ClientSocketMessageQueueProvider(socket); wsMethod: string,
const clientSocketMessagePublisher = new ClientSocketMessagePublisher( host: string,
socket ) {
); await fetch(`${httpMethod}://${host}/assign`)
.then((resp) => {
if (resp.ok) {
return resp.text();
}
throw resp;
})
.then((cookie) => {
this.clientId = cookie;
});
const grid = new Grid(); const grid = new Grid();
const socket = new WebSocket(`${wsMethod}://${host}/game`);
const clientSocketMessageQueueProvider =
new ClientSocketMessageQueueProvider(socket);
const clientSocketMessagePublisher = new ClientSocketMessagePublisher(
socket,
);
const clientMessageProcessor = new ClientMessageProcessor(this.game);
[ [
this.createInputSystem(), this.createInputSystem(),
new FacingDirection(), new FacingDirection(),
@ -76,7 +126,8 @@ export class JumpStorm {
new WallBounds(ctx.canvas.width), new WallBounds(ctx.canvas.width),
new NetworkUpdate( new NetworkUpdate(
clientSocketMessageQueueProvider, clientSocketMessageQueueProvider,
clientSocketMessagePublisher clientSocketMessagePublisher,
clientMessageProcessor,
), ),
new Render(ctx), new Render(ctx),
].forEach((system) => this.game.addSystem(system)); ].forEach((system) => this.game.addSystem(system));
@ -93,7 +144,7 @@ export class JumpStorm {
} }
private createInputSystem(): Input { private createInputSystem(): Input {
const inputSystem = new Input(); const inputSystem = new Input(this.clientId);
window.addEventListener("keydown", (e) => { window.addEventListener("keydown", (e) => {
if (!e.repeat) { if (!e.repeat) {

View File

@ -1,6 +1,7 @@
<script lang="ts"> <script lang="ts">
import { onMount } from "svelte"; import { onMount } from "svelte";
import { loadAssets } from "@engine/config"; import { loadAssets } from "@engine/config";
import { Game } from "@engine/Game";
import { JumpStorm } from "../JumpStorm"; import { JumpStorm } from "../JumpStorm";
let canvas: HTMLCanvasElement; let canvas: HTMLCanvasElement;
@ -9,16 +10,18 @@
export let width: number; export let width: number;
export let height: number; export let height: number;
let jumpStorm: JumpStorm; onMount(async () => {
onMount(() => {
ctx = canvas.getContext("2d"); ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false;
loadAssets().then(() => { await loadAssets();
jumpStorm = new JumpStorm(ctx);
jumpStorm.play(); const game = new Game();
}); const jumpStorm = new JumpStorm(game);
const url = new URL(document.location);
await jumpStorm.init(ctx, "http", "ws", url.host + "/api");
jumpStorm.play();
}); });
</script> </script>

View File

@ -1,5 +1,5 @@
{ {
"extends": "@tsconfig/svelte/tsconfig.json", "extends": ["@tsconfig/svelte/tsconfig.json", "../tsconfig.engine.json"],
"compilerOptions": { "compilerOptions": {
"target": "ESNext", "target": "ESNext",
"useDefineForClassFields": true, "useDefineForClassFields": true,
@ -24,8 +24,5 @@
"src/**/*.js", "src/**/*.js",
"src/**/*.svelte" "src/**/*.svelte"
], ],
"paths": {
"@engine/*": ["../engine/*"]
},
"references": [{ "path": "./tsconfig.node.json" }] "references": [{ "path": "./tsconfig.node.json" }]
} }

View File

@ -4,6 +4,16 @@ import { fileURLToPath, URL } from "node:url";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig({ export default defineConfig({
server: {
proxy: {
"/api": {
target: "http://localhost:8080",
ws: true,
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
},
cors: true,
plugins: [svelte()], plugins: [svelte()],
resolve: { resolve: {
alias: { alias: {

View File

@ -60,7 +60,7 @@ export class Game {
return this.systems.get(name); return this.systems.get(name);
} }
public doGameLoop = (timeStamp: number) => { public doGameLoop(timeStamp: number) {
if (!this.running) { if (!this.running) {
return; return;
} }
@ -86,5 +86,5 @@ export class Game {
this.systemOrder.forEach((systemName) => { this.systemOrder.forEach((systemName) => {
this.systems.get(systemName)?.update(dt, this); this.systems.get(systemName)?.update(dt, this);
}); });
}; }
} }

View File

@ -2,13 +2,15 @@ import { Component, ComponentNames, Velocity } from ".";
export class Control extends Component { export class Control extends Component {
public controlVelocityComponent: Velocity; public controlVelocityComponent: Velocity;
public controllableBy: string;
constructor( constructor(
controllableBy: string,
controlVelocityComponent: Velocity = new Velocity(), controlVelocityComponent: Velocity = new Velocity(),
controllableBy: string
) { ) {
super(ComponentNames.Control); super(ComponentNames.Control);
this.controllableBy = controllableBy;
this.controlVelocityComponent = controlVelocityComponent; this.controlVelocityComponent = controlVelocityComponent;
} }
} }

View File

@ -14,7 +14,7 @@ export namespace KeyConstants {
// value -> [key] from KeyActions // value -> [key] from KeyActions
export const ActionKeys: Map<Action, string[]> = Object.keys( export const ActionKeys: Map<Action, string[]> = Object.keys(
KeyActions KeyActions,
).reduce((acc: Map<Action, string[]>, key) => { ).reduce((acc: Map<Action, string[]>, key) => {
const action = KeyActions[key]; const action = KeyActions[key];
@ -42,6 +42,4 @@ export namespace Miscellaneous {
export const DEFAULT_GRID_WIDTH = 30; export const DEFAULT_GRID_WIDTH = 30;
export const DEFAULT_GRID_HEIGHT = 30; export const DEFAULT_GRID_HEIGHT = 30;
export const SERVER_TICK_RATE = 5 / 100;
} }

View File

@ -1,10 +1,13 @@
import { EntityNames, Player } from ".";
import type { Component } from "../components"; import type { Component } from "../components";
export abstract class Entity { export abstract class Entity {
public readonly id: string; public id: string;
public readonly components: Map<string, Component>; public components: Map<string, Component>;
public name: string;
constructor(id: string = crypto.randomUUID()) { constructor(name: string, id: string = crypto.randomUUID()) {
this.name = name;
this.id = id; this.id = id;
this.components = new Map(); this.components = new Map();
} }
@ -27,4 +30,13 @@ export abstract class Entity {
public hasComponent(name: string): boolean { public hasComponent(name: string): boolean {
return this.components.has(name); return this.components.has(name);
} }
static from(entityName: string, args: any): Entity {
switch (entityName) {
case EntityNames.Player:
return new Player(args.playerId);
default:
throw new Error(".from() Entity type not implemented: " + entityName);
}
}
} }

View File

@ -1,7 +1,7 @@
import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config"; import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config";
import { BoundingBox, Sprite } from "../components"; import { BoundingBox, Sprite } from "../components";
import { TopCollidable } from "../components/TopCollidable"; import { TopCollidable } from "../components/TopCollidable";
import { Entity } from "../entities"; import { Entity, EntityNames } from "../entities";
export class Floor extends Entity { export class Floor extends Entity {
private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( private static spriteSpec: SpriteSpec = SPRITE_SPECS.get(
@ -9,7 +9,7 @@ export class Floor extends Entity {
) as SpriteSpec; ) as SpriteSpec;
constructor(width: number) { constructor(width: number) {
super(); super(EntityNames.Floor);
this.addComponent( this.addComponent(
new Sprite( new Sprite(

View File

@ -1,4 +1,4 @@
import { Entity } from "."; import { Entity, EntityNames } from ".";
import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config"; import { IMAGES, SPRITE_SPECS, Sprites, type SpriteSpec } from "../config";
import { import {
Jump, Jump,
@ -21,11 +21,11 @@ export class Player extends Entity {
private static MOI: number = 100; private static MOI: number = 100;
private static spriteSpec: SpriteSpec = SPRITE_SPECS.get( private static spriteSpec: SpriteSpec = SPRITE_SPECS.get(
Sprites.COFFEE Sprites.COFFEE,
) as SpriteSpec; ) as SpriteSpec;
constructor() { constructor(playerId: string) {
super(); super(EntityNames.Player);
this.addComponent( this.addComponent(
new BoundingBox( new BoundingBox(
@ -34,12 +34,12 @@ export class Player extends Entity {
y: 100, y: 100,
}, },
{ width: Player.spriteSpec.width, height: Player.spriteSpec.height }, { width: Player.spriteSpec.width, height: Player.spriteSpec.height },
0 0,
) ),
); );
this.addComponent( this.addComponent(
new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }) new Velocity({ dCartesian: { dx: 0, dy: 0 }, dTheta: 0 }),
); );
this.addComponent(new Mass(Player.MASS)); this.addComponent(new Mass(Player.MASS));
@ -48,7 +48,7 @@ export class Player extends Entity {
this.addComponent(new Gravity()); this.addComponent(new Gravity());
this.addComponent(new Jump()); this.addComponent(new Jump());
this.addComponent(new Control()); this.addComponent(new Control(playerId));
this.addComponent(new Collide()); this.addComponent(new Collide());
this.addComponent(new WallBounded()); this.addComponent(new WallBounded());
@ -64,8 +64,8 @@ export class Player extends Entity {
{ x: 0, y: 0 }, { x: 0, y: 0 },
{ width: Player.spriteSpec.width, height: Player.spriteSpec.height }, { width: Player.spriteSpec.width, height: Player.spriteSpec.height },
Player.spriteSpec.msPerFrame, Player.spriteSpec.msPerFrame,
Player.spriteSpec.frames Player.spriteSpec.frames,
) ),
); );
this.addComponent(new FacingDirection(leftSprite, rightSprite)); this.addComponent(new FacingDirection(leftSprite, rightSprite));

View File

@ -1,3 +1,4 @@
export * from "./Entity"; export * from "./Entity";
export * from "./Floor"; export * from "./Floor";
export * from "./Player"; export * from "./Player";
export * from "./names";

4
engine/entities/names.ts Normal file
View File

@ -0,0 +1,4 @@
export namespace EntityNames {
export const Player = "Player";
export const Floor = "Floor";
}

29
engine/network/index.ts Normal file
View File

@ -0,0 +1,29 @@
export enum MessageType {
NEW_ENTITY = "NEW_ENTITY",
REMOVE_ENTITY = "REMOVE_ENTITY",
UPDATE_ENTITY = "UPDATE_ENTITY",
}
export type EntityAddBody = {
entityName: string;
args: any;
};
export type Message = {
type: MessageType;
body: any;
};
export interface MessageQueueProvider {
getNewMessages(): Message[];
clearMessages(): void;
}
export interface MessagePublisher {
addMessage(message: Message): void;
publish(): void;
}
export interface MessageProcessor {
process(message: Message): void;
}

View File

@ -12,12 +12,14 @@ import { Action } from "../interfaces";
import { System, SystemNames } from "."; import { System, SystemNames } from ".";
export class Input extends System { export class Input extends System {
public clientId: string;
private keys: Set<string>; private keys: Set<string>;
private actionTimeStamps: Map<Action, number>; private actionTimeStamps: Map<Action, number>;
constructor() { constructor(clientId: string) {
super(SystemNames.Input); super(SystemNames.Input);
this.clientId = clientId;
this.keys = new Set<string>(); this.keys = new Set<string>();
this.actionTimeStamps = new Map<Action, number>(); this.actionTimeStamps = new Map<Action, number>();
} }
@ -42,6 +44,7 @@ export class Input extends System {
const controlComponent = entity.getComponent<Control>( const controlComponent = entity.getComponent<Control>(
ComponentNames.Control, ComponentNames.Control,
); );
if (controlComponent.controllableBy != this.clientId) return;
if (this.hasSomeKey(KeyConstants.ActionKeys.get(Action.MOVE_RIGHT))) { if (this.hasSomeKey(KeyConstants.ActionKeys.get(Action.MOVE_RIGHT))) {
controlComponent.controlVelocityComponent.velocity.dCartesian.dx += controlComponent.controlVelocityComponent.velocity.dCartesian.dx +=

View File

@ -1,43 +1,44 @@
import { System, SystemNames } from "."; import { System, SystemNames } from ".";
import { Game } from "../Game"; import { Game } from "../Game";
import { ComponentNames, NetworkUpdateable } from "../components"; import { ComponentNames, NetworkUpdateable } from "../components";
import {
export interface MessageQueueProvider { type MessageQueueProvider,
getNewMessages(): any[]; type MessagePublisher,
clearMessages(): void; type MessageProcessor,
} } from "../network";
export interface MessagePublisher {
addMessage(message: any): void;
publish(): void;
}
export class NetworkUpdate extends System { export class NetworkUpdate extends System {
private queueProvider: MessageQueueProvider; private queueProvider: MessageQueueProvider;
private publisher: MessagePublisher; private publisher: MessagePublisher;
private messageProcessor: MessageProcessor;
constructor( constructor(
queueProvider: MessageQueueProvider, queueProvider: MessageQueueProvider,
publisher: MessagePublisher publisher: MessagePublisher,
messageProcessor: MessageProcessor,
) { ) {
super(SystemNames.NetworkUpdate); super(SystemNames.NetworkUpdate);
this.queueProvider = queueProvider; this.queueProvider = queueProvider;
this.publisher = publisher; this.publisher = publisher;
this.messageProcessor = messageProcessor;
} }
public update(_dt: number, game: Game) { public update(_dt: number, game: Game) {
const messages = this.queueProvider.getNewMessages(); this.queueProvider
if (messages.length) console.log(messages); .getNewMessages()
.forEach((message) => this.messageProcessor.process(message));
this.queueProvider.clearMessages(); this.queueProvider.clearMessages();
game.forEachEntityWithComponent( game.forEachEntityWithComponent(
ComponentNames.NetworkUpdateable, ComponentNames.NetworkUpdateable,
(entity) => { (entity) => {
const networkUpdateComponent = entity.getComponent<NetworkUpdateable>( const networkUpdateComponent = entity.getComponent<NetworkUpdateable>(
ComponentNames.NetworkUpdateable ComponentNames.NetworkUpdateable,
); );
} },
); );
this.publisher.publish();
} }
} }

27
engine/utils/coding.ts Normal file
View File

@ -0,0 +1,27 @@
const replacer = (_key: any, value: any) => {
if (value instanceof Map) {
return {
dataType: "Map",
value: Array.from(value.entries()),
};
} else {
return value;
}
};
const reviver = (_key: any, value: any) => {
if (typeof value === "object" && value !== null) {
if (value.dataType === "Map") {
return new Map(value.value);
}
}
return value;
};
export const stringify = (obj: any) => {
return JSON.stringify(obj, replacer);
};
export const parse = <T>(str: string) => {
return JSON.parse(str, reviver) as unknown as T;
};

View File

@ -1,3 +1,4 @@
export * from "./rotateVector"; export * from "./rotateVector";
export * from "./dotProduct"; export * from "./dotProduct";
export * from "./clamp"; export * from "./clamp";
export * from "./coding";

View File

@ -1,109 +1,179 @@
import { Game } from "@engine/Game"; import { Game } from "@engine/Game";
import { Floor, Player } from "@engine/entities"; import { EntityNames, Player } from "@engine/entities";
import { WallBounds, Physics, Collision, NetworkUpdate } from "@engine/systems";
import { import {
WallBounds, type MessageQueueProvider,
Physics, type MessagePublisher,
Collision, MessageType,
NetworkUpdate, type MessageProcessor,
MessageQueueProvider, type Message,
MessagePublisher, } from "@engine/network";
} from "@engine/systems"; import { stringify, parse } from "@engine/utils";
import { Grid } from "@engine/structures"; import { Grid } from "@engine/structures";
import { Miscellaneous } from "@engine/config"; import { Miscellaneous } from "@engine/config";
import { Server } from "bun"; import { Server } from "bun";
const SERVER_PORT = 8080;
const SERVER_TICK_RATE = (1 / 100) * 1000;
const GAME_TOPIC = "game";
type SessionData = { sessionId: string };
interface ServerMessage extends Message {
sessionData: SessionData;
}
class ServerSocketMessageReceiver implements MessageQueueProvider { class ServerSocketMessageReceiver implements MessageQueueProvider {
private messages: any[]; private messages: ServerMessage[];
constructor() { constructor() {
this.messages = []; this.messages = [];
} }
addMessage(message: any) { public addMessage(message: ServerMessage) {
this.messages.push(message); this.messages.push(message);
} }
getNewMessages() { public getNewMessages() {
return this.messages; return this.messages;
} }
clearMessages() { public clearMessages() {
this.messages = []; this.messages = [];
} }
} }
class ServerSocketMessagePublisher implements MessagePublisher { class ServerMessageProcessor implements MessageProcessor {
private server: Server; constructor() {}
private messages: any[];
public process(_message: ServerMessage) {}
}
class ServerSocketMessagePublisher implements MessagePublisher {
private server?: Server;
private messages: Message[];
constructor(server?: Server) {
if (server) {
this.server = server;
}
constructor(server: Server) {
this.server = server;
this.messages = []; this.messages = [];
} }
addMessage(_message: any) {} public setServer(server: Server) {
this.server = server;
}
publish() {} public addMessage(message: Message) {
this.messages.push(message);
}
public publish() {
this.messages.forEach(
(message) => this.server?.publish(GAME_TOPIC, stringify(message)),
);
this.messages = [];
}
} }
const game = new Game(); const game = new Game();
const messageReceiver = new ServerSocketMessageReceiver(); const messageReceiver = new ServerSocketMessageReceiver();
const messagePublisher = new ServerSocketMessagePublisher();
const messageProcessor = new ServerMessageProcessor();
const sessionControllableEntities: Map<string, Set<string>> = new Map();
const server = Bun.serve<{ sessionId: string }>({ const server = Bun.serve<SessionData>({
port: 8080, port: SERVER_PORT,
fetch: async (req, server): Promise<string> => { fetch: async (req, server): Promise<Response> => {
const sessionId = crypto.randomUUID(); const url = new URL(req.url);
server.upgrade(req, { const headers = new Headers();
headers: { headers.set("Access-Control-Allow-Origin", "*");
"Set-Cookie": `SessionId=${sessionId}`,
},
data: {
sessionId,
},
});
return sessionId; if (url.pathname == "/assign") {
const sessionId = crypto.randomUUID();
headers.set("Set-Cookie", `SessionId=${sessionId};`);
return new Response(sessionId, { headers });
}
const cookie = req.headers.get("cookie");
if (!cookie) {
return new Response("No session", { headers, status: 401 });
}
const sessionId = cookie.split(";").at(0)!.split("SessionId=").at(1);
if (url.pathname == "/game") {
headers.set(
"Set-Cookie",
`SessionId=${sessionId}; HttpOnly; SameSite=Strict;`,
);
server.upgrade(req, {
headers,
data: {
sessionId,
},
});
return new Response("upgraded", { headers });
}
if (url.pathname == "/me") {
return new Response(sessionId, { headers });
}
return new Response("Not found", { headers, status: 404 });
}, },
websocket: { websocket: {
open(ws) { open(ws) {
const { sessionId } = ws.data; const { sessionId } = ws.data;
if (sessionControllableEntities.has(sessionId)) { if (sessionControllableEntities.has(sessionId)) {
// no need to add player
return; return;
} }
const player = new Player(); const player = new Player(sessionId);
game.addEntity(player); game.addEntity(player);
sessionControllableEntities.set(sessionId, new Set(player.id)); sessionControllableEntities.set(sessionId, new Set(player.id));
messagePublisher.addMessage({
type: MessageType.NEW_ENTITY,
body: {
entityName: EntityNames.Player,
args: { playerId: sessionId },
},
});
ws.subscribe(GAME_TOPIC);
}, },
message(ws, message) { message(ws, message) {
console.log(JSON.parse(message)); if (typeof message == "string") {
messageReceiver.addMessage(message); const receivedMessage = parse<ServerMessage>(message);
receivedMessage.sessionData = ws.data;
messageReceiver.addMessage(receivedMessage);
}
}, },
close(ws) {}, close(_ws) {},
}, },
}); });
const messagePublisher = new ServerSocketMessagePublisher(server); messagePublisher.setServer(server);
[ [
new Physics(), new Physics(),
new Collision(new Grid()), new Collision(new Grid()),
new WallBounds(Miscellaneous.WIDTH), new WallBounds(Miscellaneous.WIDTH),
new NetworkUpdate(messageReceiver, messagePublisher), new NetworkUpdate(messageReceiver, messagePublisher, messageProcessor),
].forEach((system) => game.addSystem(system)); ].forEach((system) => game.addSystem(system));
[new Floor(160), new Player()].forEach((entity) => game.addEntity(entity));
game.start(); game.start();
setInterval(() => { setInterval(() => {
game.doGameLoop(performance.now()); game.doGameLoop(performance.now());
}, Miscellaneous.SERVER_TICK_RATE); }, SERVER_TICK_RATE);
const sessionControllableEntities: Map<string, Set<string>> = new Map();
console.log(`Listening on ${server.hostname}:${server.port}`); console.log(`Listening on ${server.hostname}:${server.port}`);

View File

@ -1,4 +1,5 @@
{ {
"extends": "../tsconfig.engine.json",
"compilerOptions": { "compilerOptions": {
// add Bun type definitions // add Bun type definitions
"types": ["bun-types"], "types": ["bun-types"],
@ -21,18 +22,6 @@
// best practices // best practices
"strict": true, "strict": true,
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"skipLibCheck": true, "skipLibCheck": true
// engine path
"paths": {
"@engine/*": ["../engine/*"],
"@engine/components": ["../engine/components"],
"@engine/config": ["../engine/config"],
"@engine/entities": ["../engine/entities"],
"@engine/interfaces": ["../engine/interfaces"],
"@engine/structures": ["../engine/structures"],
"@engine/systems": ["../engine/systems"],
"@engine/utils": ["../engine/utils"],
}
} }
} }

15
tsconfig.engine.json Normal file
View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"paths": {
"@engine/*": ["./engine/*"],
"@engine/components": ["./engine/components"],
"@engine/config": ["./engine/config"],
"@engine/entities": ["./engine/entities"],
"@engine/interfaces": ["./engine/interfaces"],
"@engine/structures": ["./engine/structures"],
"@engine/systems": ["./engine/systems"],
"@engine/utils": ["./engine/utils"],
"@engine/network": ["./engine/network"]
}
}
}