Merge pull request 'Modernise & make fun' (#3) from asch/modernise into main
Reviewed-on: https://home.schmelczer.dev/git/git/andras/decla-red/pulls/3
This commit is contained in:
commit
5d854440ec
132 changed files with 11445 additions and 20695 deletions
|
|
@ -1,10 +0,0 @@
|
||||||
# Path to your oh-my-zsh installation.
|
|
||||||
export ZSH="/root/.oh-my-zsh"
|
|
||||||
|
|
||||||
# https://typewritten.dev/#/git_status_indicators
|
|
||||||
ZSH_THEME="typewritten"
|
|
||||||
|
|
||||||
# Which plugins would you like to load?
|
|
||||||
# plugins=(zsh-autosuggestions nvm git)
|
|
||||||
|
|
||||||
source $ZSH/oh-my-zsh.sh
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
ARG VARIANT="14-buster"
|
|
||||||
FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-${VARIANT}
|
|
||||||
|
|
||||||
RUN apt update && export DEBIAN_FRONTEND=noninteractive \
|
|
||||||
&& apt -y install --no-install-recommends git-lfs \
|
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
RUN git lfs install
|
|
||||||
|
|
||||||
RUN npm i && npm run init
|
|
||||||
|
|
||||||
ENV ZSH_CUSTOM /root/.oh-my-zsh/
|
|
||||||
RUN git clone https://github.com/reobin/typewritten.git $ZSH_CUSTOM/themes/typewritten
|
|
||||||
RUN ln -s "$ZSH_CUSTOM/themes/typewritten/typewritten.zsh-theme" "$ZSH_CUSTOM/themes/typewritten.zsh-theme"
|
|
||||||
RUN ln -s "$ZSH_CUSTOM/themes/typewritten/async.zsh" "$ZSH_CUSTOM/themes/async"
|
|
||||||
COPY .zshrc /root/.zshrc
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
{
|
|
||||||
"name": "Node.js & TypeScript",
|
|
||||||
"build": {
|
|
||||||
"dockerfile": "Dockerfile",
|
|
||||||
"args": {
|
|
||||||
"VARIANT": "14"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"terminal.integrated.shell.linux": "/bin/zsh",
|
|
||||||
"files.exclude": {
|
|
||||||
"**/node_modules": true,
|
|
||||||
"**/yarn.lock": true,
|
|
||||||
"**/dist": true,
|
|
||||||
"**/lib": true,
|
|
||||||
"**/.firebase": true
|
|
||||||
},
|
|
||||||
"editor.tabSize": 2,
|
|
||||||
"editor.detectIndentation": false,
|
|
||||||
"editor.formatOnSave": true,
|
|
||||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.fixAll.eslint": true
|
|
||||||
},
|
|
||||||
"eslint.validate": ["json"],
|
|
||||||
"markdown.extension.toc.levels": "2..4",
|
|
||||||
// <style>
|
|
||||||
"workbench.iconTheme": "material-icon-theme",
|
|
||||||
"workbench.colorTheme": "Community Material Theme Palenight High Contrast",
|
|
||||||
"editor.fontFamily": "'Fira Code'",
|
|
||||||
"editor.fontLigatures": true
|
|
||||||
// </style>
|
|
||||||
},
|
|
||||||
"extensions": [
|
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"yzhang.markdown-all-in-one",
|
|
||||||
"hediet.vscode-drawio",
|
|
||||||
"pkief.material-icon-theme",
|
|
||||||
"equinusocio.vsc-community-material-theme"
|
|
||||||
],
|
|
||||||
"workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached",
|
|
||||||
"workspaceFolder": "/workspace",
|
|
||||||
"mounts": [
|
|
||||||
"source=decla-red-root-node_modules-volume4,target=/workspace/node_modules,type=volume",
|
|
||||||
"source=decla-red-frontend-node_modules-volume4,target=/workspace/frontend/node_modules,type=volume",
|
|
||||||
"source=decla-red-backend-node_modules-volume4,target=/workspace/backend/node_modules,type=volume",
|
|
||||||
"source=decla-red-shared-node_modules-volume4,target=/workspace/shared/node_modules,type=volume"
|
|
||||||
],
|
|
||||||
"forwardPorts": [3000, 8080],
|
|
||||||
"postCreateCommand": "chown node:node ./**/node_modules && npm run build"
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
**/node_modules/**/*.js
|
|
||||||
node_modules/**/*.js
|
|
||||||
**/package-lock.json
|
|
||||||
package-lock.json
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
{
|
|
||||||
"root": true,
|
|
||||||
"env": {
|
|
||||||
"browser": true,
|
|
||||||
"es2020": true
|
|
||||||
},
|
|
||||||
"extends": [
|
|
||||||
"plugin:@typescript-eslint/recommended",
|
|
||||||
"prettier/@typescript-eslint",
|
|
||||||
"plugin:prettier/recommended"
|
|
||||||
],
|
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2020,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"plugins": ["unused-imports", "@typescript-eslint", "json-format", "prettier"],
|
|
||||||
"settings": {
|
|
||||||
"json/sort-package-json": true
|
|
||||||
},
|
|
||||||
"rules": {
|
|
||||||
"prettier/prettier": "error",
|
|
||||||
"no-unused-vars": "off",
|
|
||||||
"unused-imports/no-unused-imports-ts": "error",
|
|
||||||
"@typescript-eslint/no-unused-vars": [
|
|
||||||
"warn",
|
|
||||||
{
|
|
||||||
"argsIgnorePattern": "^_"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
|
||||||
"@typescript-eslint/explicit-module-boundary-types": "off",
|
|
||||||
"@typescript-eslint/no-non-null-assertion": "off",
|
|
||||||
"@typescript-eslint/no-empty-function": "off",
|
|
||||||
"@typescript-eslint/no-var-requires": "off"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -23,7 +23,7 @@ jobs:
|
||||||
- name: Setup Node
|
- name: Setup Node
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 14
|
node-version-file: .nvmrc
|
||||||
|
|
||||||
- name: Install dependencies
|
- name: Install dependencies
|
||||||
# No lockfiles are committed (see .gitignore), so use `npm install`.
|
# No lockfiles are committed (see .gitignore), so use `npm install`.
|
||||||
|
|
@ -32,6 +32,12 @@ jobs:
|
||||||
- name: Build (shared -> frontend -> backend)
|
- name: Build (shared -> frontend -> backend)
|
||||||
run: npm run build
|
run: npm run build
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: npm test
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npm run lint:check
|
||||||
|
|
||||||
- name: Deploy to host pages mount
|
- name: Deploy to host pages mount
|
||||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||||
uses: http://forgejo:3000/andras/ci-actions/deploy-pages@main
|
uses: http://forgejo:3000/andras/ci-actions/deploy-pages@main
|
||||||
|
|
|
||||||
1
.node-version
Normal file
1
.node-version
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
22
|
||||||
1
.nvmrc
Normal file
1
.nvmrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
22
|
||||||
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
|
@ -3,7 +3,7 @@
|
||||||
"Deserializable",
|
"Deserializable",
|
||||||
"Deserialization",
|
"Deserialization",
|
||||||
"Respawn",
|
"Respawn",
|
||||||
"decla",
|
"doppler",
|
||||||
"overridable",
|
"overridable",
|
||||||
"serializable"
|
"serializable"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
12
Dockerfile
12
Dockerfile
|
|
@ -1,13 +1,13 @@
|
||||||
# syntax=docker/dockerfile:1
|
# syntax=docker/dockerfile:1
|
||||||
|
|
||||||
# decla.red game server (the `declared-server` package).
|
# doppler game server (the `doppler-server` package).
|
||||||
# The frontend is a static site and is NOT built here — see .forgejo/workflows.
|
# The frontend is a static site and is NOT built here — see .forgejo/workflows.
|
||||||
|
|
||||||
# ---- Stage 1: build the shared lib, then bundle the server -------------------
|
# ---- Stage 1: build the shared lib, then bundle the server -------------------
|
||||||
# Node 14 matches the project toolchain (webpack 4 / TypeScript 4, see
|
# Node 22 (current LTS) matches the project toolchain (webpack 5 / TypeScript 6,
|
||||||
# .devcontainer). The full (non-slim) image carries the build tools that
|
# see .devcontainer). The full (non-slim) image carries the build tools that
|
||||||
# socket.io's optional native deps (bufferutil/utf-8-validate) compile against.
|
# socket.io's optional native deps (bufferutil/utf-8-validate) compile against.
|
||||||
FROM node:14-bullseye AS build
|
FROM node:22-bookworm AS build
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# `shared` is consumed by the backend as `file:../shared` and is bundled into
|
# `shared` is consumed by the backend as `file:../shared` and is bundled into
|
||||||
|
|
@ -28,7 +28,7 @@ RUN cd backend && npm run build
|
||||||
RUN cd backend && npm prune --production
|
RUN cd backend && npm prune --production
|
||||||
|
|
||||||
# ---- Stage 2: minimal runtime ----------------------------------------------
|
# ---- Stage 2: minimal runtime ----------------------------------------------
|
||||||
FROM node:14-bullseye-slim
|
FROM node:22-bookworm-slim
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
|
|
@ -46,5 +46,5 @@ HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
|
||||||
CMD node -e "require('http').get('http://localhost:3000/state',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"
|
CMD node -e "require('http').get('http://localhost:3000/state',r=>process.exit(r.statusCode===200?0:1)).on('error',()=>process.exit(1))"
|
||||||
|
|
||||||
ENTRYPOINT ["node", "dist/main.js"]
|
ENTRYPOINT ["node", "dist/main.js"]
|
||||||
# Override these to tune the server, e.g. `--name`, `--playerLimit`, `--worldSize`.
|
# Override these to tune the server, e.g. `--name`, `--playerLimit`, `--scoreLimit`.
|
||||||
CMD ["--port", "3000"]
|
CMD ["--port", "3000"]
|
||||||
|
|
|
||||||
10
README.md
10
README.md
|
|
@ -1,8 +1,8 @@
|
||||||
# [decla.red](https://decla.red)
|
# doppler
|
||||||
|
|
||||||
A 2-dimensional multiplayer game utilising ray tracing.
|
A 2-dimensional multiplayer game utilising ray tracing.
|
||||||
|
|
||||||
> **Available at [decla.red](https://decla.red).**
|
> **Available at [doppler.schmelczer.dev](https://doppler.schmelczer.dev).**
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||
|
|
@ -15,7 +15,7 @@ CI/CD runs on Forgejo Actions (`.forgejo/workflows/deploy.yml`). On a push to
|
||||||
`main` it:
|
`main` it:
|
||||||
|
|
||||||
- builds the static frontend and rsyncs `frontend/dist/` to the `/pages/declared`
|
- builds the static frontend and rsyncs `frontend/dist/` to the `/pages/declared`
|
||||||
mount on the runner host, and
|
mount on the runner host (the mount keeps its pre-rebrand name), and
|
||||||
- builds the server image from the root `Dockerfile` and pushes it to the Forgejo
|
- builds the server image from the root `Dockerfile` and pushes it to the Forgejo
|
||||||
container registry as `<registry>/<owner>/<repo>-server`.
|
container registry as `<registry>/<owner>/<repo>-server`.
|
||||||
|
|
||||||
|
|
@ -30,6 +30,6 @@ edit it to add or remove game-server origins.
|
||||||
Run the server image locally:
|
Run the server image locally:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
docker build -t declared-server .
|
docker build -t doppler-server .
|
||||||
docker run -p 3000:3000 declared-server --name "My server" --playerLimit 16
|
docker run -p 3000:3000 doppler-server --name "My server" --playerLimit 16
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
# Setup a decla.red server on a fresh debian/ubuntu machine
|
|
||||||
|
|
||||||
> The method was tested on Debian 10 DigitalOcean droplets.
|
|
||||||
|
|
||||||
- Copy the files from this directory to the target machine.
|
|
||||||
- Execute the following commands.
|
|
||||||
- ```sh
|
|
||||||
chmod +x setup.sh
|
|
||||||
./setup.sh serverX
|
|
||||||
```
|
|
||||||
|
|
||||||
> Where `serverX` is the serverX.decla.red subdomain pointing to the server.
|
|
||||||
|
|
||||||
- Optionally, change the arguments in [declared-servers.sh](declared-servers.sh).
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
[Unit]
|
|
||||||
Description=declared-server
|
|
||||||
|
|
||||||
Requires=basic.target network.target
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
ExecStart=/bin/sh /root/declared-servers.sh
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
NODE_ENV=production declared-server --port=3000 --name="Simonyi" --playerLimit=256 --npcCount=48 --scoreLimit=20000
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
user www-data;
|
|
||||||
worker_processes auto;
|
|
||||||
pid /run/nginx.pid;
|
|
||||||
|
|
||||||
events {
|
|
||||||
worker_connections 768;
|
|
||||||
}
|
|
||||||
|
|
||||||
http {
|
|
||||||
sendfile on;
|
|
||||||
tcp_nopush on;
|
|
||||||
tcp_nodelay on;
|
|
||||||
keepalive_timeout 65;
|
|
||||||
types_hash_max_size 2048;
|
|
||||||
server_tokens off;
|
|
||||||
|
|
||||||
include /etc/nginx/mime.types;
|
|
||||||
default_type application/octet-stream;
|
|
||||||
|
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
|
||||||
ssl_prefer_server_ciphers on;
|
|
||||||
|
|
||||||
access_log /var/log/nginx/access.log;
|
|
||||||
error_log /var/log/nginx/error.log;
|
|
||||||
|
|
||||||
map $http_upgrade $connection_upgrade {
|
|
||||||
default upgrade;
|
|
||||||
'' close;
|
|
||||||
}
|
|
||||||
|
|
||||||
server {
|
|
||||||
listen 443 ssl;
|
|
||||||
|
|
||||||
include /etc/letsencrypt/options-ssl-nginx.conf;
|
|
||||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
|
||||||
ssl_certificate /etc/letsencrypt/live/serverName.decla.red/fullchain.pem;
|
|
||||||
ssl_certificate_key /etc/letsencrypt/live/serverName.decla.red/privkey.pem;
|
|
||||||
|
|
||||||
server_name serverName.decla.red;
|
|
||||||
|
|
||||||
location / {
|
|
||||||
proxy_pass http://127.0.0.1:3000/;
|
|
||||||
proxy_http_version 1.1;
|
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
|
||||||
proxy_set_header Connection $connection_upgrade;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
if [ -z "$1" ]; then
|
|
||||||
echo "Please specify a domain" 1>&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
domain="$1"
|
|
||||||
|
|
||||||
apt install -y curl
|
|
||||||
curl -sL https://deb.nodesource.com/setup_15.x | bash -
|
|
||||||
apt update
|
|
||||||
apt install -y nodejs nginx certbot python3-certbot-nginx
|
|
||||||
npm i -g declared-server
|
|
||||||
|
|
||||||
certbot certonly --nginx -m schmelczerandras@gmail.com -d "$domain".decla.red --agree-tos --non-interactive
|
|
||||||
|
|
||||||
mv nginx.conf /etc/nginx/nginx.conf
|
|
||||||
sed -i "s/serverName/$domain/g" /etc/nginx/nginx.conf
|
|
||||||
nginx -s reload
|
|
||||||
|
|
||||||
chmod +x /root/declared-servers.sh
|
|
||||||
chown root:root /root/declared-servers.sh
|
|
||||||
cp declared-servers.service /etc/systemd/system/declared-servers.service
|
|
||||||
systemctl enable declared-servers.service
|
|
||||||
systemctl start declared-servers
|
|
||||||
|
|
@ -1,48 +1,43 @@
|
||||||
{
|
{
|
||||||
"name": "declared-server",
|
"name": "doppler-server",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"description": "Game server for decla.red",
|
"description": "Game server for doppler",
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
"author": "András Schmelczer <andras@schmelczer.dev> (https://schmelczer.dev/)",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"declared-server": "dist/main.js"
|
"doppler-server": "dist/main.js"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npx webpack --mode production",
|
"build": "npx webpack --mode production",
|
||||||
"start": "concurrently --kill-others-on-fail \"webpack --mode development -w\" \"nodemon --legacy-watch dist/main.js\"",
|
"dev": "concurrently --kill-others-on-fail \"webpack --mode development -w\" \"nodemon --legacy-watch dist/main.js\"",
|
||||||
"try-build": "npm run build && cd dist && node main.js && cd -"
|
"try-build": "npm run build && cd dist && node main.js && cd -"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/config": "0.0.36",
|
"cors": "^2.8.6",
|
||||||
"cors": "^2.8.5",
|
"express": "^5.2.1",
|
||||||
"express": "^4.17.1",
|
|
||||||
"gl-matrix": "3.3.0",
|
"gl-matrix": "3.3.0",
|
||||||
"minimist": "^1.2.5",
|
"minimist": "^1.2.8",
|
||||||
"socket.io": "^2.3.0",
|
"socket.io": "^4.8.3",
|
||||||
"socket.io-msgpack-parser": "^2.0.0"
|
"socket.io-msgpack-parser": "^3.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cors": "^2.8.7",
|
"@types/cors": "^2.8.19",
|
||||||
"@types/express": "^4.17.8",
|
"@types/express": "^5.0.6",
|
||||||
"@types/minimist": "^1.2.0",
|
"@types/minimist": "^1.2.5",
|
||||||
"@types/node": "^14.11.2",
|
"@types/node": "^22.0.0",
|
||||||
"@types/socket.io": "^2.1.11",
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
"clean-webpack-plugin": "^3.0.0",
|
"concurrently": "^10.0.3",
|
||||||
"concurrently": "^5.3.0",
|
"nodemon": "^3.1.14",
|
||||||
"file-loader": "^6.1.0",
|
|
||||||
"html-webpack-plugin": "^4.5.0",
|
|
||||||
"nodemon": "^2.0.4",
|
|
||||||
"raw-loader": "^4.0.1",
|
|
||||||
"resolve-url-loader": "^3.1.1",
|
|
||||||
"shared": "file:../shared",
|
"shared": "file:../shared",
|
||||||
"terser-webpack-plugin": "^2.3.5",
|
"terser-webpack-plugin": "^5.6.1",
|
||||||
"ts-config-webpack-plugin": "^2.0.0",
|
"ts-loader": "^9.6.0",
|
||||||
"ts-loader": "^8.0.3",
|
"typescript": "^6.0.3",
|
||||||
"typescript": "^4.0.3",
|
"webpack": "^5.107.2",
|
||||||
"webpack": "^4.44.2",
|
"webpack-cli": "^7.0.3",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-node-externals": "^3.0.0"
|
||||||
"webpack-dev-server": "^3.11.0",
|
|
||||||
"webpack-node-externals": "^2.5.2"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
backend/src/commands/announce.ts
Normal file
9
backend/src/commands/announce.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Command } from 'shared';
|
||||||
|
|
||||||
|
// Internal request from a game object (e.g. a keystone planet flipping) asking
|
||||||
|
// the GameServer to broadcast a one-off announcement to every connected client.
|
||||||
|
export class AnnounceCommand extends Command {
|
||||||
|
public constructor(public readonly text: string) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import { Command } from 'shared';
|
import { Command } from 'shared';
|
||||||
|
|
||||||
export class GeneratePointsCommand extends Command {
|
export class GeneratePointsCommand extends Command {
|
||||||
public constructor(public readonly decla: number, public readonly red: number) {
|
public constructor(
|
||||||
|
public readonly blue: number,
|
||||||
|
public readonly red: number,
|
||||||
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
import { vec2 } from 'gl-matrix';
|
import { vec2 } from 'gl-matrix';
|
||||||
import { Random, PlanetBase, hsl, settings } from 'shared';
|
import { Random, PlanetBase, hsl, settings, evaluateSdf } from 'shared';
|
||||||
import { LampPhysical } from './objects/lamp-physical';
|
import { LampPhysical } from './objects/lamp-physical';
|
||||||
import { PlanetPhysical } from './objects/planet-physical';
|
import { PlanetPhysical } from './objects/planet-physical';
|
||||||
import { PhysicalContainer } from './physics/containers/physical-container';
|
import { PhysicalContainer } from './physics/containers/physical-container';
|
||||||
import { evaluateSdf } from './physics/functions/evaluate-sdf';
|
|
||||||
import { Physical } from './physics/physicals/physical';
|
import { Physical } from './physics/physicals/physical';
|
||||||
|
|
||||||
export const createWorld = (objectContainer: PhysicalContainer, worldRadius: number) => {
|
export const createWorld = (objectContainer: PhysicalContainer) => {
|
||||||
const objects: Array<Physical> = [];
|
const objects: Array<Physical> = [];
|
||||||
const lights: Array<Physical> = [];
|
const lights: Array<Physical> = [];
|
||||||
|
|
||||||
for (let r = 0; r < worldRadius; r += settings.radiusSteps) {
|
for (let r = 0; r < settings.worldRadius; r += settings.radiusSteps) {
|
||||||
const circumference = 2 * Math.PI * r;
|
const circumference = 2 * Math.PI * r;
|
||||||
const stepCount = circumference * settings.objectsOnCircleLength;
|
const stepCount = circumference * settings.objectsOnCircleLength;
|
||||||
for (let rad = 0; rad < 2 * Math.PI; rad += (2 * Math.PI) / stepCount) {
|
for (let rad = 0; rad < 2 * Math.PI; rad += (2 * Math.PI) / stepCount) {
|
||||||
|
|
@ -45,13 +44,16 @@ export const createWorld = (objectContainer: PhysicalContainer, worldRadius: num
|
||||||
) {
|
) {
|
||||||
const planet =
|
const planet =
|
||||||
objects.length === 0
|
objects.length === 0
|
||||||
? new PlanetPhysical(
|
? // The first, central giant is the keystone "Heart": a named,
|
||||||
|
// always-contested focal objective the whole match orbits.
|
||||||
|
new PlanetPhysical(
|
||||||
PlanetBase.createPlanetVertices(
|
PlanetBase.createPlanetVertices(
|
||||||
position,
|
position,
|
||||||
Random.getRandomInRange(1600, 2400),
|
Random.getRandomInRange(1600, 2400),
|
||||||
Random.getRandomInRange(1600, 2400),
|
Random.getRandomInRange(1600, 2400),
|
||||||
Random.getRandomInRange(80, 300),
|
Random.getRandomInRange(80, 300),
|
||||||
),
|
),
|
||||||
|
true,
|
||||||
)
|
)
|
||||||
: new PlanetPhysical(
|
: new PlanetPhysical(
|
||||||
PlanetBase.createPlanetVertices(
|
PlanetBase.createPlanetVertices(
|
||||||
|
|
@ -67,8 +69,29 @@ export const createWorld = (objectContainer: PhysicalContainer, worldRadius: num
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.info('Generated planet count', objects.length);
|
console.info(`Generated ${objects.length} planets`);
|
||||||
console.info('Generated light count', lights.length);
|
console.info(`Generated ${lights.length} light`);
|
||||||
|
|
||||||
|
// Associate each lamp with its NEAREST planet, so a planet can repaint "its"
|
||||||
|
// lamps to the owning team's colour when it flips. Lamps are already placed by
|
||||||
|
// proximity during world-gen, so the nearest planet is the one whose capture
|
||||||
|
// they should advertise. Distances use the planet SDF (negative inside), which
|
||||||
|
// is exactly the "closest planet" metric we want.
|
||||||
|
const planets = objects.filter((o): o is PlanetPhysical => o instanceof PlanetPhysical);
|
||||||
|
lights
|
||||||
|
.filter((l): l is LampPhysical => l instanceof LampPhysical)
|
||||||
|
.forEach((lamp) => {
|
||||||
|
let nearest: PlanetPhysical | undefined;
|
||||||
|
let nearestDistance = Infinity;
|
||||||
|
planets.forEach((planet) => {
|
||||||
|
const distance = planet.distance(lamp.center);
|
||||||
|
if (distance < nearestDistance) {
|
||||||
|
nearestDistance = distance;
|
||||||
|
nearest = planet;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nearest?.addLamp(lamp);
|
||||||
|
});
|
||||||
|
|
||||||
[...objects, ...lights].forEach((o) => objectContainer.addObject(o));
|
[...objects, ...lights].forEach((o) => objectContainer.addObject(o));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue