Skip to content

Commit

Permalink
Merge pull request #62 from cardano-scaling/pi/dedicated
Browse files Browse the repository at this point in the history
Pi/dedicated
  • Loading branch information
Quantumplation authored Nov 14, 2024
2 parents 8ef1be6 + e9e7714 commit 9cfab0a
Show file tree
Hide file tree
Showing 19 changed files with 620 additions and 214 deletions.
67 changes: 17 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,50 +1,17 @@
# React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.

Currently, two official plugins are available:

- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh

## Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:

- Configure the top-level `parserOptions` property like this:

```js
export default tseslint.config({
languageOptions: {
// other options...
parserOptions: {
project: ['./tsconfig.node.json', './tsconfig.app.json'],
tsconfigRootDir: import.meta.dirname,
},
},
})
```

- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
- Optionally add `...tseslint.configs.stylisticTypeChecked`
- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:

```js
// eslint.config.js
import react from 'eslint-plugin-react'

export default tseslint.config({
// Set the react version
settings: { react: { version: '18.3' } },
plugins: {
// Add the react plugin
react,
},
rules: {
// other rules...
// Enable its recommended rules
...react.configs.recommended.rules,
...react.configs['jsx-runtime'].rules,
},
})
```
# Hydra Doom

This repository contains the parts of the hydra doom project that are written in javascript, including the frontend UI, the dedicated backend server, and the AI agents.

## UI

To run the UI, set `VITE_SERVER_URL` in your environment to point to a hydra-control-plane API URL, then run `yarn dev`

## Dedicated Server

To run the dedicated server, switch to the `dedicated` directory, then run `yarn`, and then `npx tsx dedicated.ts`.

You can also build a docker image with `docker build -f ./dedicated/Dockerfile .`

## AI Agent

TBD
1 change: 1 addition & 0 deletions dedicated/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
22 changes: 22 additions & 0 deletions dedicated/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
FROM node:20-alpine AS base

RUN apk add

WORKDIR /usr/src/app
RUN --mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=yarn.lock,target=yarn.lock \
yarn install --frozen-lockfile
USER node

WORKDIR /usr/src
COPY ./dedicated ./app
COPY ./dedicated/tsconfig.docker.json ./app/tsconfig.json
COPY ./src/utils/hydra-multiplayer.ts ./app/utils/hydra-multiplayer.ts
COPY ./src/utils/hydra.ts ./app/utils/hydra.ts
COPY ./websockets-doom.js ./websockets-doom.js
COPY ./public/ ./public/


WORKDIR /usr/src/app
EXPOSE 3000
CMD npx -y tsx dedicated.ts
119 changes: 119 additions & 0 deletions dedicated/dedicated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Run as a node process to run a dedicated doom server

import { readFile } from "node:fs/promises";
import { HydraMultiplayer } from "utils/hydra-multiplayer";
import { Lucid, toHex, fromHex } from "lucid-cardano";
import * as bech32 from "bech32-buffer";
import * as ed25519 from "@noble/ed25519";
import { blake2b } from "@noble/hashes/blake2b";

let done = false;
const lucid = await Lucid.new(undefined, "Preprod");
const adminKeyFile = process.env.ADMIN_KEY_FILE ?? "admin.sk";
const adminKey = JSON.parse((await readFile(adminKeyFile)).toString());
const privateKeyBytes = adminKey.cborHex.slice(4);
const sessionKeyBech32 = bech32.encode("ed25519_sk", fromHex(privateKeyBytes));

const publicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);
const publicKeyHashBytes = blake2b(publicKeyBytes, { dkLen: 224 / 8 });
const publicKeyHashHex = toHex(publicKeyHashBytes);
const keys = {
sessionKeyBech32,
privateKeyBytes,
privateKeyHex: toHex(privateKeyBytes),
publicKeyBytes,
publicKeyHex: toHex(publicKeyBytes),
publicKeyHashBytes,
publicKeyHashHex,
address: lucid.utils.credentialToAddress({
type: "Key",
hash: publicKeyHashHex,
}),
};
console.log("Address: ", keys.address);

const { default: createModule } = await import("../websockets-doom.js");
const module = await createModule({
locateFile: (path, scripts) => {
console.log(scripts + "public/" + path);
return scripts + "public/" + path;
},
noInitialRun: true,
preRun: function (mod: any) {
const files = ["freedoom2.wad", "default.cfg", "Cardano.wad"];
files.forEach((file) => {
mod.FS!.createPreloadedFile("/", file, "../public/" + file, true, true);
});
},
canvas: null as any,
print: (text: string) => {
console.log("stdout:", text);
},
printErr: (text: string) => {
console.error("stderr:", text);
},
onExit: () => {
console.log("Game exited");
done = true;
},
});
global.Module = module;
global.HydraMultiplayer = new HydraMultiplayer(
keys,
"http://localhost:4001",
module,
);

global.gameStarted = () => {
// TODO: Hit localhost to record game start
};
global.playerConnected = () => {
// TODO: Hit localhost to record a player joined
// NOTE: might need to ignore ourselves joining, so we don't inflate the player metrics
};
global.playerDisconnected = () => {
// TODO: Hit localhost to record a player disconnected
};
global.kill = (_killer, _victim) => {
// TODO: map from player idx to ephemeral key
// TODO: Hit localhost to record a kill
};
global.suicide = (_player) => {
// TODO: Hit localhist to record a kill
};

// TODO: check for a pending game and run cleanup

const args = [
"-server",
"-deathmatch",
"-iwad",
"freedoom2.wad",
"-file",
"Cardano.wad",
"-drone",
"-nodraw",
"-nomouse",
"-nograbmouse",
"-nogui",
"-nomusic",
"-nosound",
"-config",
"default.cfg",
];
try {
module.callMain(args);
} catch (e) {
console.error(e);
}

// TODO: hit localhost to record the server is online

while (!done) {
await new Promise((resolve) => setTimeout(resolve, 1000));
}

// TODO: record the game as ended
// TODO: also decrement metrics by the number of players?

process.exit(0);
14 changes: 14 additions & 0 deletions dedicated/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "dedicated-doom",
"type": "module",
"module": "ES2022",
"target": "ES2022",
"dependencies": {
"@noble/ed25519": "^2.1.0",
"@noble/hashes": "^1.5.0",
"bech32-buffer": "^0.2.1",
"lucid-cardano": "^0.10.7",
"prom-client": "^15.1.3",
"readline": "^1.3.0"
}
}
11 changes: 11 additions & 0 deletions dedicated/tsconfig.docker.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"module": "ES2022",
"target": "ES2022",
"paths": {
"utils/*": ["./utils/*"]
}
},
"files": ["dedicated.ts"],
"references": []
}
11 changes: 11 additions & 0 deletions dedicated/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"compilerOptions": {
"module": "ES2022",
"target": "ES2022",
"paths": {
"utils/*": ["../src/utils/*"]
}
},
"files": ["dedicated.ts"],
"references": []
}
Loading

0 comments on commit 9cfab0a

Please sign in to comment.