Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# top-most EditorConfig file
root = true

## 4 space indentation
[*.{js,jsx,ts,tsx}]
indent_style = space
indent_size = 2
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ worlds
*.swp

.turbo

bun.lockb

8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ Need to install global cargo packages: `cargo install cargo-watch` and `cargo in

`yarn dev`


## Running just one app

```
bunx turbo dev --filter=web-client...
```


# Deploying

The server lives on my raspberry pi. The whole app can be deployed by running `make deploy-pi` when on the same network as the pi.
Expand Down
1 change: 1 addition & 0 deletions apps/server/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export class DBManager implements IDbManager {
throw new Error("DB_URL not defined");
}
const client = await MongoClient.connect(DB_URL);
console.log("Database Connected");
return new DBManager(client);
}

Expand Down
52 changes: 10 additions & 42 deletions apps/server/worldManager.ts → apps/server/game-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@ import {
IChunkReader,
ICreateGameOptions,
IGameData,
IGameMetadata,
ISerializedGame,
ISocketMessageType,
SocketMessage,
TerrainGenerator,
Vector2D,
WorldModule,
} from "@craft/engine";
import { ServerGame } from "./serverGame.js";
import Websocket from "ws";
import { ServerGame } from "./server-game.js";
import { IDbManager } from "./db.js";
import { SocketInterface } from "./server.js";

export class RamChunkReader implements IChunkReader {
private chunkMap = new Map<string, Chunk>();
Expand All @@ -40,45 +37,16 @@ export class RamChunkReader implements IChunkReader {
}
}

export class GameManager {
private games: Map<string, ServerGame> = new Map();
export interface IGameService {
getWorld(gameId: string): Promise<ServerGame | null>;
getAllWorlds(): Promise<IGameMetadata[]>;
createGame(options: ICreateGameOptions): Promise<ServerGame>;
}

constructor(private dbManager: IDbManager) {
SocketInterface.listenForConnection((ws: Websocket) => {
SocketInterface.listenTo(ws, (message) => {
this.handleSocketMessage(message, ws)
.then(() => void 0)
.catch((e) => {
console.log("Error handling socket message", message, e);
});
});
});
}
export class GameService implements IGameService {
private games: Map<string, ServerGame> = new Map();

async handleSocketMessage(message: SocketMessage, ws: Websocket) {
if (message.isType(ISocketMessageType.joinWorld)) {
const { worldId, myUid } = message.data;
const world = await this.getWorld(worldId);
if (!world) {
return;
}
// this function sends a welcome message to the client
world.addSocket(myUid, ws);
} else if (message.isType(ISocketMessageType.newWorld)) {
const payload = message.data;
const world = await this.createGame(payload);
console.log("Create Id: ", world.gameId);
world.addSocket(payload.myUid, ws);
} else if (message.isType(ISocketMessageType.saveWorld)) {
const payload = message.data;
const world = this.games.get(payload.worldId);
if (!world) {
console.log("That world doesn't exist", payload);
return;
}
await this.dbManager.saveGame(world.serialize());
}
}
constructor(private dbManager: IDbManager) {}

async getWorld(gameId: string): Promise<ServerGame | null> {
const world = this.games.get(gameId);
Expand Down
9 changes: 9 additions & 0 deletions apps/server/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { WorldModule } from "@craft/engine";
import { DBManager } from "./db";
import { startServer } from "./server";
import { GameService } from "./game-service";

const db = await DBManager.makeClient();
await WorldModule.load();
const gameService = new GameService(db);
startServer(gameService);
10 changes: 0 additions & 10 deletions apps/server/nodemon.json

This file was deleted.

16 changes: 7 additions & 9 deletions apps/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node --experimental-modules --experimental-wasm-modules -r dotenv/config ./dist/server.js",
"build": "tsc -b",
"dev:build": "tsc -b -w --preserveWatchOutput",
"nodemon": "nodemon",
"buildAndRun": "yarn build && yarn start",
"dev": "npm-run-all --parallel nodemon dev:build",
"start": "bun run index.ts",
"start:watch": "bun --watch run index.ts",
"dev": "npm-run-all --parallel start:watch typecheck",
"debug": "bun --watch run --inspect index.ts",
"typecheck": "tsc -w",
"clean": "rm -rf ./dist",
"lint": "eslint --ext .ts ."
},
Expand All @@ -25,10 +24,9 @@
"@types/express": "^4.17.7",
"@types/mongodb": "^4.0.7",
"@types/ws": "^8.5.3",
"dotenv": "^16.1.4",
"bun-types": "^1.0.1",
"eslint": "^8.42.0",
"nodemon": "1.19.1",
"npm-run-all": "^4.1.5",
"typescript": "^4.9.5"
"typescript": "^5.2.2"
}
}
130 changes: 0 additions & 130 deletions apps/server/players.ts

This file was deleted.

50 changes: 50 additions & 0 deletions apps/server/server-game.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import WebSocket from "ws";
import {
EmptyController,
Game,
GameAction,
MapArray,
GameController,
EntityHolder,
World,
IGameData,
} from "@craft/engine";

export class ServerGame extends Game {
public actionMap: MapArray<WebSocket, GameAction> = new MapArray();

public controller: GameController = new EmptyController(this);

static async make(gameData: IGameData): Promise<ServerGame> {
console.log("Making server game", gameData);
const entityHolder = new EntityHolder(gameData.data?.entities);

// Remove all players since none are connected yet
entityHolder.removeAllPlayers();

const world = await World.make(gameData.chunkReader, gameData.data?.world);

const game = new ServerGame(entityHolder, world, gameData);

return game;
}

constructor(entities: EntityHolder, world: World, gameData: IGameData) {
super(entities, world, gameData);
}

onGameAction(_action: GameAction): void {
// NO-OP
}

update(_delta: number): void {
// Send the initial state diff to all clients
// This state diff has no client sent actions so it should
// only be passive things (An entity spawning)
// if (this.stateDiff.hasData()) {
// this.clients.sendMessageToAll(
// new SocketMessage(ISocketMessageType.gameDiff, this.stateDiff.get())
// );
// }
}
}
Loading