Merge branch 'main' of github.com:openfrontio/OpenFrontIO into feature/eslint

This commit is contained in:
BeGj
2025-03-07 16:52:42 +00:00
13 changed files with 3215 additions and 19463 deletions
+15
View File
@@ -0,0 +1,15 @@
node_modules
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode
Makefile
helm-charts
.env
.editorconfig
.idea
coverage*
+6 -6
View File
@@ -8,14 +8,14 @@ jobs:
uses: actions/checkout@v4
with:
submodules: false
- name: Setup node
uses: actions/setup-node@v4
- name: Setup bun
uses: oven-sh/setup-bun@v2
with:
node-version: 20
- name: Setup npm
run: npm install
bun-version: 1.2.4
- name: install packages
run: bun install
- name: Build
run: npm run build-prod
run: bun run build-prod
- uses: actions/upload-artifact@v4
with:
path: out/index.html
+4 -5
View File
@@ -10,9 +10,8 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- uses: oven-sh/setup-bun@v2
with:
node-version: "20"
cache: "npm"
- run: npm ci
- run: npx prettier --check .
bun-version: 1.2.4
- run: bun i
- run: bunx prettier --check .
-16
View File
@@ -1,16 +0,0 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "Launch Program",
"skipFiles": ["<node_internals>/**"],
"program": "${workspaceFolder}/src/server/GameManager.ts",
"outFiles": ["${workspaceFolder}/**/*.js"]
}
]
}
+4 -4
View File
@@ -1,5 +1,5 @@
# Use an official Node runtime as the base image
FROM node:18
FROM oven/bun:1
# Add environment variable
ARG GAME_ENV=prod
@@ -13,18 +13,18 @@ RUN apt-get update && apt-get install -y nginx supervisor git && \
WORKDIR /usr/src/app
# Copy package.json and package-lock.json
COPY package*.json ./
COPY package.json bun.lock ./
# Install dependencies while bypassing Husky hooks
ENV HUSKY=0
ENV NPM_CONFIG_IGNORE_SCRIPTS=1
RUN mkdir -p .git && npm install --include=dev
RUN mkdir -p .git && bun install --include=dev
# Copy the rest of the application code
COPY . .
# Build the client-side application
RUN npm run build-prod
RUN bun run build-prod
ENV NODE_ENV=production
+6 -7
View File
@@ -24,8 +24,7 @@ This is a fork/rewrite of WarFront.io. Credit to https://github.com/WarFrontIO.
## 📋 Prerequisites
- [Node.js](https://nodejs.org/) (v16.x or higher)
- [npm](https://www.npmjs.com/) (v8.x or higher)
- [Bun.js](https://bun.sh/) (v1.2.4 or higher)
- A modern web browser (Chrome, Firefox, Edge, etc.)
## 🚀 Installation
@@ -40,7 +39,7 @@ This is a fork/rewrite of WarFront.io. Credit to https://github.com/WarFrontIO.
2. **Install dependencies**
```bash
npm install
bun i
```
## 🎮 Running the Game
@@ -50,7 +49,7 @@ This is a fork/rewrite of WarFront.io. Credit to https://github.com/WarFrontIO.
Run both the client and server in development mode with live reloading:
```bash
npm run dev
bun run dev
```
This will:
@@ -64,7 +63,7 @@ This will:
To run just the client with hot reloading:
```bash
npm run start:client
bun run start:client
```
### Server Only
@@ -72,7 +71,7 @@ npm run start:client
To run just the server with development settings:
```bash
npm run start:server-dev
bun run start:server-dev
```
## 🛠️ Development Tools
@@ -80,7 +79,7 @@ npm run start:server-dev
- **Format code**:
```bash
npm run format
bun run format
```
- **Lint code**:
+3083
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -0,0 +1,8 @@
services:
openfront:
build: .
ports:
- "80:80"
- "443:443"
env_file:
- .env
-19364
View File
File diff suppressed because it is too large Load Diff
+6 -6
View File
@@ -1,14 +1,14 @@
{
"name": "openfront-client",
"scripts": {
"build-map": "node --loader ts-node/esm --experimental-specifier-resolution=node src/scripts/TerrainMapGenerator.ts",
"build-map": "bun src/scripts/TerrainMapGenerator.ts",
"build-dev": "webpack --config webpack.config.js --mode development",
"build-prod": "webpack --config webpack.config.js --mode production",
"start:client": "webpack serve --open --node-env development",
"start:server": "node --loader ts-node/esm --experimental-specifier-resolution=node src/server/Server.ts",
"start:server-dev": "cross-env GAME_ENV=dev node --loader ts-node/esm --experimental-specifier-resolution=node src/server/Server.ts",
"dev": "cross-env GAME_ENV=dev concurrently \"npm run start:client\" \"npm run start:server-dev\"",
"tunnel": "npm run build-prod && npm run start:server",
"start:server": "bun src/server/Server.ts",
"start:server-dev": "cross-env GAME_ENV=dev bun src/server/Server.ts",
"dev": "cross-env GAME_ENV=dev concurrently \"bun run start:client\" \"bun run start:server-dev\"",
"tunnel": "bun run build-prod && bun run start:server",
"test": "jest",
"format": "prettier --ignore-unknown --write .",
"lint": "eslint",
@@ -30,7 +30,7 @@
"@types/jest": "^29.5.12",
"@types/jquery": "^3.5.31",
"@types/mocha": "^10.0.7",
"@types/node": "^22.10.2",
"@types/bun": "latest",
"@types/pg": "^8.11.11",
"@types/sinon": "^17.0.3",
"@types/systeminformation": "^3.23.1",
+57 -29
View File
@@ -24,7 +24,9 @@ import {
CancelAttackIntentEvent,
SendAllianceReplyIntentEvent,
} from "../../Transport";
import { unsafeHTML } from "lit/directives/unsafe-html.js";
import { unsafeHTML, UnsafeHTMLDirective } from "lit/directives/unsafe-html.js";
import { DirectiveResult } from "lit/directive.js";
import { onlyImages, sanitize } from "../../../core/Util";
import { GameView, PlayerView } from "../../../core/game/GameView";
import { renderTroops } from "../../Utils";
@@ -46,6 +48,7 @@ interface Event {
// lower number: lower on the display
priority?: number;
duration?: Tick;
focusID?: number;
}
@customElement("events-display")
@@ -218,6 +221,7 @@ export class EventsDisplay extends LitElement implements Layer {
),
priority: 0,
duration: 150,
focusID: update.requestorID,
});
}
@@ -238,6 +242,7 @@ export class EventsDisplay extends LitElement implements Layer {
type: update.accepted ? MessageType.SUCCESS : MessageType.ERROR,
highlight: true,
createdAt: this.game.ticks(),
focusID: update.request.recipientID,
});
}
@@ -254,6 +259,7 @@ export class EventsDisplay extends LitElement implements Layer {
type: MessageType.ERROR,
highlight: true,
createdAt: this.game.ticks(),
focusID: update.betrayedID,
});
} else if (betrayed === myPlayer) {
this.addEvent({
@@ -261,6 +267,7 @@ export class EventsDisplay extends LitElement implements Layer {
type: MessageType.ERROR,
highlight: true,
createdAt: this.game.ticks(),
focusID: update.traitorID,
});
}
}
@@ -283,6 +290,7 @@ export class EventsDisplay extends LitElement implements Layer {
type: MessageType.WARN,
highlight: true,
createdAt: this.game.ticks(),
focusID: otherID,
});
}
@@ -298,6 +306,7 @@ export class EventsDisplay extends LitElement implements Layer {
type: MessageType.INFO,
highlight: true,
createdAt: this.game.ticks(),
focusID: event.targetID,
});
}
@@ -307,6 +316,12 @@ export class EventsDisplay extends LitElement implements Layer {
this.eventBus.emit(new CancelAttackIntentEvent(myPlayer.id(), id));
}
emitGoToPlayerEvent(attackerID: number) {
const attacker = this.game.playerBySmallID(attackerID) as PlayerView;
if (!attacker) return;
this.eventBus.emit(new GoToPlayerEvent(attacker));
}
onEmojiMessageEvent(update: EmojiUpdate) {
const myPlayer = this.game.playerByClientID(this.clientID);
if (!myPlayer) return;
@@ -326,6 +341,7 @@ export class EventsDisplay extends LitElement implements Layer {
type: MessageType.INFO,
highlight: true,
createdAt: this.game.ticks(),
focusID: update.emoji.senderID,
});
} else if (sender === myPlayer && recipient !== AllPlayers) {
this.addEvent({
@@ -336,6 +352,7 @@ export class EventsDisplay extends LitElement implements Layer {
type: MessageType.INFO,
highlight: true,
createdAt: this.game.ticks(),
focusID: recipient.smallID(),
});
}
}
@@ -355,6 +372,14 @@ export class EventsDisplay extends LitElement implements Layer {
}
}
private getEventDescription(
event: Event,
): string | DirectiveResult<typeof UnsafeHTMLDirective> {
return event.unsafeDescription
? unsafeHTML(onlyImages(event.description))
: event.description;
}
private renderAttacks() {
if (
this.incomingAttacks.length === 0 &&
@@ -370,25 +395,18 @@ export class EventsDisplay extends LitElement implements Layer {
<td class="lg:p-3 p-1 text-left text-red-400">
${this.incomingAttacks.map(
(attack) => html`
<div class="ml-2">
<button
class="ml-2"
@click=${() =>
this.emitGoToPlayerEvent(attack.attackerID)}
>
${renderTroops(attack.troops)}
${(
this.game.playerBySmallID(
attack.attackerID,
) as PlayerView
)?.name()}
<button
class="inline-block px-2 text-white rounded text-sm cursor-pointer transition-colors duration-300 bg-blue-500 hover:bg-blue-600 btn-gray"
@click=${() => {
const attacker = this.game.playerBySmallID(
attack.attackerID,
) as PlayerView;
this.eventBus.emit(new GoToPlayerEvent(attacker));
}}
>
Focus
</button>
</div>
</button>
`,
)}
</td>
@@ -401,22 +419,26 @@ export class EventsDisplay extends LitElement implements Layer {
<td class="lg:p-3 p-1 text-left text-blue-400">
${this.outgoingAttacks.map(
(attack) => html`
<div class="ml-2">
<button
class="ml-2"
@click=${() => this.emitGoToPlayerEvent(attack.targetID)}
>
${renderTroops(attack.troops)}
${(
this.game.playerBySmallID(attack.targetID) as PlayerView
)?.name()}
${!attack.retreating
? html`<button
${attack.retreating ? "disabled" : ""}
@click=${() => {
this.emitCancelAttackIntent(attack.id);
}}
>
</button>`
: "(retreating...)"}
</div>
</button>
${!attack.retreating
? html`<button
${attack.retreating ? "disabled" : ""}
@click=${() => {
this.emitCancelAttackIntent(attack.id);
}}
>
</button>`
: "(retreating...)"}
`,
)}
</td>
@@ -491,9 +513,15 @@ export class EventsDisplay extends LitElement implements Layer {
)}"
>
<td class="lg:p-3 p-1 text-left">
${event.unsafeDescription
? unsafeHTML(onlyImages(event.description))
: event.description}
${event.focusID
? html`<button
@click=${() => {
this.emitGoToPlayerEvent(event.focusID);
}}
>
${this.getEventDescription(event)}
</button>`
: this.getEventDescription(event)}
${event.buttons
? html`
<div class="flex flex-wrap gap-1.5 mt-1">
+25 -25
View File
@@ -283,32 +283,32 @@ export class AttackExecution implements Execution {
}
private handleDeadDefender() {
if (this.target.isPlayer() && this.target.numTilesOwned() < 100) {
const gold = this.target.gold();
this.mg.displayMessage(
`Conquered ${this.target.displayName()} received ${renderNumber(
gold,
)} gold`,
MessageType.SUCCESS,
this._owner.id(),
);
this.target.removeGold(gold);
this._owner.addGold(gold);
if (!(this.target.isPlayer() && this.target.numTilesOwned() < 100)) return;
for (let i = 0; i < 10; i++) {
for (const tile of this.target.tiles()) {
const borders = this.mg
.neighbors(tile)
.some((t) => this.mg.owner(t) == this._owner);
if (borders) {
this._owner.conquer(tile);
} else {
for (const neighbor of this.mg.neighbors(tile)) {
const no = this.mg.owner(neighbor);
if (no.isPlayer() && no != this.target) {
this.mg.player(no.id()).conquer(tile);
break;
}
const gold = this.target.gold();
this.mg.displayMessage(
`Conquered ${this.target.displayName()} received ${renderNumber(
gold,
)} gold`,
MessageType.SUCCESS,
this._owner.id(),
);
this.target.removeGold(gold);
this._owner.addGold(gold);
for (let i = 0; i < 10; i++) {
for (const tile of this.target.tiles()) {
const borders = this.mg
.neighbors(tile)
.some((t) => this.mg.owner(t) == this._owner);
if (borders) {
this._owner.conquer(tile);
} else {
for (const neighbor of this.mg.neighbors(tile)) {
const no = this.mg.owner(neighbor);
if (no.isPlayer() && no != this.target) {
this.mg.player(no.id()).conquer(tile);
break;
}
}
}
+1 -1
View File
@@ -14,7 +14,7 @@ stderr_logfile=/dev/stderr
stderr_logfile_maxbytes=0
[program:node]
command=npm run start:server
command=bun run start:server
directory=/usr/src/app
autostart=true
autorestart=true