diff --git a/package-lock.json b/package-lock.json index 1f6cd8a0f..4d4ab10e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/preset-typescript": "^7.24.7", + "@bufbuild/protobuf": "^2.10.2", "@datastructures-js/priority-queue": "^6.3.3", "@eslint/compat": "^1.2.7", "@eslint/js": "^9.21.0", @@ -105,6 +106,7 @@ "style-loader": "^4.0.0", "tailwindcss": "^3.4.17", "ts-loader": "^9.5.2", + "ts-proto": "^2.8.3", "tsconfig-paths": "^4.2.0", "tsx": "^4.17.0", "typescript": "^5.7.2", @@ -1049,7 +1051,6 @@ "integrity": "sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.27.1", @@ -2803,6 +2804,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@bufbuild/protobuf": { + "version": "2.10.2", + "resolved": "https://registry.npmjs.org/@bufbuild/protobuf/-/protobuf-2.10.2.tgz", + "integrity": "sha512-uFsRXwIGyu+r6AMdz+XijIIZJYpoWeYzILt5yZ2d3mCjQrWUTVpVD9WL/jZAbvp+Ed04rOhrsk7FiTcEDseB5A==", + "dev": true, + "license": "(Apache-2.0 AND BSD-3-Clause)" + }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", @@ -2922,7 +2930,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -2946,7 +2953,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -5101,7 +5107,6 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=8.0.0" } @@ -6420,6 +6425,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=10" } @@ -6436,6 +6442,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">=10" } @@ -6452,6 +6459,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6468,6 +6476,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6484,6 +6493,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6500,6 +6510,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6516,6 +6527,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">=10" } @@ -6532,6 +6544,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -6548,6 +6561,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -6564,6 +6578,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">=10" } @@ -6599,6 +6614,7 @@ "integrity": "sha512-u1iIVZV9Q0jxY+yM2vw/hZGDNudsN85bBpTqzAQ9rzkxW9D+e3aEM4Han+ow518gSewkXgjmEK0BD79ZcNVgPw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@swc/counter": "^0.1.3" } @@ -7253,7 +7269,6 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.32.tgz", "integrity": "sha512-3jigKqgSjsH6gYZv2nEsqdXfZqIFGAV36XYYjf9KGZ3PSG+IhLecqPnI310RvjutyMwifE2hhhNEklOUrvx/wA==", "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -7488,7 +7503,6 @@ "integrity": "sha512-4O3idHxhyzjClSMJ0a29AcoK0+YwnEqzI6oz3vlRf3xw0zbzt15MzXwItOlnr5nIth6zlY2RENLsOPvhyrKAQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.34.1", "@typescript-eslint/types": "8.34.1", @@ -8259,7 +8273,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -8318,7 +8331,6 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -8884,7 +8896,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001718", "electron-to-chromium": "^1.5.160", @@ -9063,7 +9074,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "node-addon-api": "^7.0.0", "prebuild-install": "^7.1.1" @@ -9079,13 +9089,25 @@ "dev": true, "license": "MIT" }, + "node_modules/case-anything": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/case-anything/-/case-anything-2.1.13.tgz", + "integrity": "sha512-zlOQ80VrQ2Ue+ymH5OuM/DlDq64mEm+B9UTdHULv5osUMD6HalNTblf2b1u/m6QecjsnOkBpqVZ+XPwIVsy7Ng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.13" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, "node_modules/chai": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", @@ -9690,7 +9712,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -10278,7 +10299,6 @@ "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", "dev": true, "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -10739,6 +10759,29 @@ "url": "https://dotenvx.com" } }, + "node_modules/dprint-node": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/dprint-node/-/dprint-node-1.0.8.tgz", + "integrity": "sha512-iVKnUtYfGrYcW1ZAlfR/F59cUVL8QIhWoBJoSjkkdua/dkWIgjZfiLMeTjiB06X0ZLkQ0M2C1VbUj/CxkIf1zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^1.0.3" + } + }, + "node_modules/dprint-node/node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -11021,7 +11064,6 @@ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -11191,7 +11233,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -11550,7 +11591,6 @@ "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "license": "MIT", - "peer": true, "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -12451,7 +12491,6 @@ "integrity": "sha512-QSf1yjtSAsmf7rYBV7XX86uua4W/vkhIt0xNXKbsi2foEeW7vjJQz4bhnpL3xH+l1ryl1680uNv968Z+X6jSYg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", @@ -14981,7 +15020,6 @@ "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", @@ -16695,7 +16733,6 @@ "integrity": "sha512-dyuThzncsgEgJZnvd/A/5x6IkUERbK+phXqUQrI+0C6WE+8xqGH5VChRTLecemhgZF0kQ+gZOM3tJTX9937xpg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@pixi/colord": "^2.9.6", "@types/css-font-loading-module": "^0.0.12", @@ -16753,7 +16790,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -17092,7 +17128,6 @@ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -18362,7 +18397,6 @@ "integrity": "sha512-TOgRcwFPbfGtpqvZw+hyqJDvqfapr1qUlOizROIk4bBLjlsjlB00Pg6wMFXNtJRpu+eCZuVOaLatG7M8105kAw==", "dev": true, "license": "BSD-3-Clause", - "peer": true, "dependencies": { "@sinonjs/commons": "^3.0.1", "@sinonjs/fake-timers": "^13.0.5", @@ -19075,7 +19109,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -19307,7 +19340,6 @@ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -19495,7 +19527,6 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -19549,6 +19580,42 @@ "node": ">=0.3.1" } }, + "node_modules/ts-poet": { + "version": "6.12.0", + "resolved": "https://registry.npmjs.org/ts-poet/-/ts-poet-6.12.0.tgz", + "integrity": "sha512-xo+iRNMWqyvXpFTaOAvLPA5QAWO6TZrSUs5s4Odaya3epqofBu/fMLHEWl8jPmjhA0s9sgj9sNvF1BmaQlmQkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dprint-node": "^1.0.8" + } + }, + "node_modules/ts-proto": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/ts-proto/-/ts-proto-2.8.3.tgz", + "integrity": "sha512-TdXInqG+61pj/TvORqITWjvjTTsL1EZxwX49iEj89+xFAcqPT8tjChpAGQXzfcF4MJwvNiuoCEbBOKqVf3ds3g==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0", + "case-anything": "^2.1.13", + "ts-poet": "^6.12.0", + "ts-proto-descriptors": "2.0.0" + }, + "bin": { + "protoc-gen-ts_proto": "protoc-gen-ts_proto" + } + }, + "node_modules/ts-proto-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-proto-descriptors/-/ts-proto-descriptors-2.0.0.tgz", + "integrity": "sha512-wHcTH3xIv11jxgkX5OyCSFfw27agpInAd6yh89hKG6zqIXnjW9SYqSER2CVQxdPj4czeOhGagNvZBEbJPy7qkw==", + "dev": true, + "license": "ISC", + "dependencies": { + "@bufbuild/protobuf": "^2.0.0" + } + }, "node_modules/tsconfig-paths": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", @@ -19578,8 +19645,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/tsx": { "version": "4.20.3", @@ -19668,7 +19734,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -19963,7 +20028,6 @@ "integrity": "sha512-QaNKAvGCDRh3wW1dsDjeMdDXwZm2vqq3zn6Pvq4rHOEOGSaUMgOOjG2Y9ZbIGzpfkJk9ZYTHpDqgDfeBDcnLaw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -20013,7 +20077,6 @@ "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", @@ -20097,7 +20160,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -20213,7 +20275,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -20306,7 +20367,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", diff --git a/package.json b/package.json index 9e93c8b16..069ff1671 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "lint": "eslint", "lint:fix": "eslint --fix", "prepare": "husky", - "gen-maps": "cd map-generator && go run . && npm run format" + "gen-maps": "cd map-generator && go run . && npm run format", + "gen-proto": "npx protoc --plugin=./node_modules/.bin/protoc-gen-ts_proto --ts_proto_out=. src/core/game/GameUpdates.proto --ts_proto_opt=unrecognizedEnum=false" }, "lint-staged": { "**/*": [ @@ -30,6 +31,7 @@ "@babel/core": "^7.25.2", "@babel/preset-env": "^7.25.3", "@babel/preset-typescript": "^7.24.7", + "@bufbuild/protobuf": "^2.10.2", "@datastructures-js/priority-queue": "^6.3.3", "@eslint/compat": "^1.2.7", "@eslint/js": "^9.21.0", @@ -92,6 +94,7 @@ "style-loader": "^4.0.0", "tailwindcss": "^3.4.17", "ts-loader": "^9.5.2", + "ts-proto": "^2.8.3", "tsconfig-paths": "^4.2.0", "tsx": "^4.17.0", "typescript": "^5.7.2", diff --git a/src/client/ClientGameRunner.ts b/src/client/ClientGameRunner.ts index 5089b6be2..844a054c3 100644 --- a/src/client/ClientGameRunner.ts +++ b/src/client/ClientGameRunner.ts @@ -1,6 +1,7 @@ import { translateText } from "../client/Utils"; import { EventBus } from "../core/EventBus"; import { + AllPlayersStats, ClientID, GameID, GameRecord, @@ -8,18 +9,19 @@ import { PlayerCosmeticRefs, PlayerRecord, ServerMessage, + Winner, } from "../core/Schemas"; import { createPartialGameRecord, replacer } from "../core/Util"; import { ServerConfig } from "../core/configuration/Config"; import { getConfig } from "../core/configuration/ConfigLoader"; -import { PlayerActions, UnitType } from "../core/game/Game"; +import { PlayerActions } from "../core/game/Game"; import { TileRef } from "../core/game/GameMap"; import { GameMapLoader } from "../core/game/GameMapLoader"; import { ErrorUpdate, GameUpdateType, GameUpdateViewData, - HashUpdate, + UnitType, WinUpdate, } from "../core/game/GameUpdates"; import { GameView, PlayerView } from "../core/game/GameView"; @@ -241,18 +243,20 @@ export class ClientGameRunner { if (this.myPlayer === null) { return; } + const stats = JSON.parse(update.stats) as AllPlayersStats; const players: PlayerRecord[] = [ { persistentID: getPersistentID(), username: this.lobby.playerName, clientID: this.lobby.clientID, - stats: update.allPlayersStats[this.lobby.clientID], + stats: stats[this.lobby.clientID], }, ]; if (this.lobby.gameStartInfo === undefined) { throw new Error("missing gameStartInfo"); } + const winner = JSON.parse(update.winner) as Winner; const record = createPartialGameRecord( this.lobby.gameStartInfo.gameID, this.lobby.gameStartInfo.config, @@ -261,7 +265,7 @@ export class ClientGameRunner { [], startTime(), Date.now(), - update.winner, + winner, this.lobby.gameStartInfo.lobbyCreatedAt, ); endGame(record); @@ -310,8 +314,10 @@ export class ClientGameRunner { return; } this.transport.turnComplete(); - gu.updates[GameUpdateType.Hash].forEach((hu: HashUpdate) => { - this.eventBus.emit(new SendHashEvent(hu.tick, hu.hash)); + gu.updates[GameUpdateType.Hash].updates.forEach((update) => { + this.eventBus.emit( + new SendHashEvent(update.hash!.tick, update.hash!.hash), + ); }); this.gameView.update(gu); this.renderer.tick(); @@ -324,7 +330,7 @@ export class ClientGameRunner { // Reset tick delay for next measurement this.currentTickDelay = undefined; - if (gu.updates[GameUpdateType.Win].length > 0) { + if (gu.updates[GameUpdateType.Win]?.updates.length > 0) { this.saveGame(gu.updates[GameUpdateType.Win][0]); } }); diff --git a/src/client/HostLobbyModal.ts b/src/client/HostLobbyModal.ts index 5d94324e9..6115f8845 100644 --- a/src/client/HostLobbyModal.ts +++ b/src/client/HostLobbyModal.ts @@ -12,9 +12,9 @@ import { HumansVsNations, Quads, Trios, - UnitType, mapCategories, } from "../core/game/Game"; +import { UnitType } from "../core/game/GameUpdates"; import { UserSettings } from "../core/game/UserSettings"; import { ClientInfo, diff --git a/src/client/InputHandler.ts b/src/client/InputHandler.ts index cf70215d9..9b23b7ae7 100644 --- a/src/client/InputHandler.ts +++ b/src/client/InputHandler.ts @@ -1,5 +1,5 @@ import { EventBus, GameEvent } from "../core/EventBus"; -import { UnitType } from "../core/game/Game"; +import { UnitType } from "../core/game/GameUpdates"; import { UnitView } from "../core/game/GameView"; import { UserSettings } from "../core/game/UserSettings"; import { UIState } from "./graphics/UIState"; diff --git a/src/client/SinglePlayerModal.ts b/src/client/SinglePlayerModal.ts index 9c51bf905..696a0369f 100644 --- a/src/client/SinglePlayerModal.ts +++ b/src/client/SinglePlayerModal.ts @@ -12,9 +12,9 @@ import { HumansVsNations, Quads, Trios, - UnitType, mapCategories, } from "../core/game/Game"; +import { UnitType } from "../core/game/GameUpdates"; import { UserSettings } from "../core/game/UserSettings"; import { TeamCountConfig } from "../core/Schemas"; import { generateID } from "../core/Util"; diff --git a/src/client/Transport.ts b/src/client/Transport.ts index 8c94d215f..b04ab955e 100644 --- a/src/client/Transport.ts +++ b/src/client/Transport.ts @@ -1,14 +1,8 @@ import { z } from "zod"; import { EventBus, GameEvent } from "../core/EventBus"; -import { - AllPlayers, - GameType, - Gold, - PlayerID, - Tick, - UnitType, -} from "../core/game/Game"; +import { AllPlayers, GameType, Gold, PlayerID, Tick } from "../core/game/Game"; import { TileRef } from "../core/game/GameMap"; +import { UnitType } from "../core/game/GameUpdates"; import { PlayerView } from "../core/game/GameView"; import { AllPlayersStats, diff --git a/src/client/Utils.ts b/src/client/Utils.ts index a842a42af..c19bcf276 100644 --- a/src/client/Utils.ts +++ b/src/client/Utils.ts @@ -1,5 +1,5 @@ import IntlMessageFormat from "intl-messageformat"; -import { MessageType } from "../core/game/Game"; +import { MessageType } from "../core/game/GameUpdates"; import { LangSelector } from "./LangSelector"; export function renderDuration(totalSeconds: number): string { diff --git a/src/client/components/LobbyTeamView.ts b/src/client/components/LobbyTeamView.ts index 711d9790c..c2a31a4a7 100644 --- a/src/client/components/LobbyTeamView.ts +++ b/src/client/components/LobbyTeamView.ts @@ -8,11 +8,11 @@ import { GameMode, HumansVsNations, PlayerInfo, - PlayerType, Quads, Team, Trios, } from "../../core/game/Game"; +import { PlayerType } from "../../core/game/GameUpdates"; import { assignTeamsLobbyPreview } from "../../core/game/TeamAssignment"; import { ClientInfo, TeamCountConfig } from "../../core/Schemas"; import { translateText } from "../Utils"; diff --git a/src/client/graphics/NameBoxCalculator.ts b/src/client/graphics/NameBoxCalculator.ts index 67f21916c..5d9195a1f 100644 --- a/src/client/graphics/NameBoxCalculator.ts +++ b/src/client/graphics/NameBoxCalculator.ts @@ -1,4 +1,5 @@ -import { Cell, Game, NameViewData, Player } from "../../core/game/Game"; +import { Cell, Game, Player } from "../../core/game/Game"; +import { NameViewData } from "../../core/game/GameUpdates"; import { calculateBoundingBox } from "../../core/Util"; export interface Point { diff --git a/src/client/graphics/PlayerIcons.ts b/src/client/graphics/PlayerIcons.ts index 8c2510827..830878c06 100644 --- a/src/client/graphics/PlayerIcons.ts +++ b/src/client/graphics/PlayerIcons.ts @@ -11,7 +11,7 @@ import nukeWhiteIcon from "../../../resources/images/NukeIconWhite.svg"; import questionMarkIcon from "../../../resources/images/QuestionMarkIcon.svg"; import targetIcon from "../../../resources/images/TargetIcon.svg"; import traitorIcon from "../../../resources/images/TraitorIcon.svg"; -import { AllPlayers, nukeTypes } from "../../core/game/Game"; +import { nukeTypes } from "../../core/game/Game"; import { GameView, PlayerView } from "../../core/game/GameView"; export type PlayerIconId = @@ -114,15 +114,14 @@ export function getPlayerIcons( .outgoingEmojis() .filter( (emoji) => - emoji.recipientID === AllPlayers || - emoji.recipientID === myPlayer?.smallID(), + emoji.allPlayers ?? emoji.recipientId === myPlayer?.smallID(), ); if (emojis.length > 0) { icons.push({ id: "emoji", kind: "emoji", - text: emojis[0].message, + text: emojis[0].emoji, }); } } diff --git a/src/client/graphics/SpriteLoader.ts b/src/client/graphics/SpriteLoader.ts index 29d5b7791..a0d93e348 100644 --- a/src/client/graphics/SpriteLoader.ts +++ b/src/client/graphics/SpriteLoader.ts @@ -10,7 +10,7 @@ import trainEngineSprite from "../../../resources/sprites/trainEngine.png"; import transportShipSprite from "../../../resources/sprites/transportship.png"; import warshipSprite from "../../../resources/sprites/warship.png"; import { Theme } from "../../core/configuration/Config"; -import { TrainType, UnitType } from "../../core/game/Game"; +import { TrainType, UnitType } from "../../core/game/GameUpdates"; import { UnitView } from "../../core/game/GameView"; // Can't reuse TrainType because "loaded" is not a type, just an attribute diff --git a/src/client/graphics/UIState.ts b/src/client/graphics/UIState.ts index 01c4a60cb..cded8d990 100644 --- a/src/client/graphics/UIState.ts +++ b/src/client/graphics/UIState.ts @@ -1,4 +1,4 @@ -import { UnitType } from "../../core/game/Game"; +import { UnitType } from "../../core/game/GameUpdates"; export interface UIState { attackRatio: number; diff --git a/src/client/graphics/fx/ConquestFx.ts b/src/client/graphics/fx/ConquestFx.ts index 7fa8d0690..f97b189a4 100644 --- a/src/client/graphics/fx/ConquestFx.ts +++ b/src/client/graphics/fx/ConquestFx.ts @@ -1,5 +1,5 @@ import { ConquestUpdate } from "../../../core/game/GameUpdates"; -import { GameView } from "../../../core/game/GameView"; +import { GameView, PlayerView } from "../../../core/game/GameView"; import { renderNumber } from "../../Utils"; import { AnimatedSpriteLoader } from "../AnimatedSpriteLoader"; import { Fx, FxType } from "./Fx"; @@ -17,7 +17,7 @@ export function conquestFxFactory( game: GameView, ): Fx[] { const conquestFx: Fx[] = []; - const conquered = game.player(conquest.conqueredId); + const conquered = game.playerBySmallID(conquest.conqueredId) as PlayerView; const x = conquered.nameLocation().x; const y = conquered.nameLocation().y; diff --git a/src/client/graphics/layers/AlertFrame.ts b/src/client/graphics/layers/AlertFrame.ts index 407cd81ff..7b86a4e87 100644 --- a/src/client/graphics/layers/AlertFrame.ts +++ b/src/client/graphics/layers/AlertFrame.ts @@ -108,8 +108,8 @@ export class AlertFrame extends LitElement implements Layer { // Check for BrokeAllianceUpdate events this.game .updatesSinceLastTick() - ?.[GameUpdateType.BrokeAlliance]?.forEach((update) => { - this.onBrokeAllianceUpdate(update as BrokeAllianceUpdate); + ?.[GameUpdateType.BrokeAlliance]?.updates.forEach((update) => { + this.onBrokeAllianceUpdate(update.brokeAlliance!); }); // Check for new incoming attacks @@ -125,7 +125,7 @@ export class AlertFrame extends LitElement implements Layer { const myPlayer = this.game.myPlayer(); if (!myPlayer) return; - const betrayed = this.game.playerBySmallID(update.betrayedID); + const betrayed = this.game.playerBySmallID(update.betrayedId); // Only trigger alert if the current player is the betrayed one if (betrayed === myPlayer) { @@ -154,8 +154,8 @@ export class AlertFrame extends LitElement implements Layer { // Track when we attack other players (not terra nullius) for (const attack of outgoingAttacks) { // Only track attacks on players (targetID !== 0 means it's a player, not unclaimed land) - if (attack.targetID !== 0 && !attack.retreating) { - const existingTick = this.outgoingAttackTicks.get(attack.targetID); + if (attack.targetId !== 0 && !attack.retreating) { + const existingTick = this.outgoingAttackTicks.get(attack.targetId); // Only update timestamp if: // 1. This is a new attack (not in map yet), OR @@ -164,7 +164,7 @@ export class AlertFrame extends LitElement implements Layer { existingTick === undefined || currentTick - existingTick >= RETALIATION_WINDOW_TICKS ) { - this.outgoingAttackTicks.set(attack.targetID, currentTick); + this.outgoingAttackTicks.set(attack.targetId, currentTick); } } } @@ -199,7 +199,7 @@ export class AlertFrame extends LitElement implements Layer { // Only alert for non-retreating attacks if (!attack.retreating && !this.seenAttackIds.has(attack.id)) { // Check if this is a retaliation (we attacked them recently) - const ourAttackTick = this.outgoingAttackTicks.get(attack.attackerID); + const ourAttackTick = this.outgoingAttackTicks.get(attack.attackerId); const isRetaliation = ourAttackTick !== undefined && currentTick - ourAttackTick < RETALIATION_WINDOW_TICKS; diff --git a/src/client/graphics/layers/BuildMenu.ts b/src/client/graphics/layers/BuildMenu.ts index 46adc3367..86353746f 100644 --- a/src/client/graphics/layers/BuildMenu.ts +++ b/src/client/graphics/layers/BuildMenu.ts @@ -13,13 +13,9 @@ import samlauncherIcon from "../../../../resources/images/SamLauncherIconWhite.s import shieldIcon from "../../../../resources/images/ShieldIconWhite.svg"; import { translateText } from "../../../client/Utils"; import { EventBus } from "../../../core/EventBus"; -import { - BuildableUnit, - Gold, - PlayerActions, - UnitType, -} from "../../../core/game/Game"; +import { BuildableUnit, Gold, PlayerActions } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; +import { UnitType } from "../../../core/game/GameUpdates"; import { GameView } from "../../../core/game/GameView"; import { CloseViewEvent, diff --git a/src/client/graphics/layers/ChatDisplay.ts b/src/client/graphics/layers/ChatDisplay.ts index 941b08551..90b14c1d9 100644 --- a/src/client/graphics/layers/ChatDisplay.ts +++ b/src/client/graphics/layers/ChatDisplay.ts @@ -3,10 +3,10 @@ import { customElement, state } from "lit/decorators.js"; import { DirectiveResult } from "lit/directive.js"; import { unsafeHTML, UnsafeHTMLDirective } from "lit/directives/unsafe-html.js"; import { EventBus } from "../../../core/EventBus"; -import { MessageType } from "../../../core/game/Game"; import { DisplayMessageUpdate, GameUpdateType, + MessageType, } from "../../../core/game/GameUpdates"; import { GameView } from "../../../core/game/GameView"; import { onlyImages } from "../../../core/Util"; @@ -57,8 +57,8 @@ export class ChatDisplay extends LitElement implements Layer { if (event.messageType !== MessageType.CHAT) return; const myPlayer = this.game.myPlayer(); if ( - event.playerID !== null && - (!myPlayer || myPlayer.smallID() !== event.playerID) + event.playerId !== null && + (!myPlayer || myPlayer.smallID() !== event.playerId) ) { return; } @@ -76,31 +76,26 @@ export class ChatDisplay extends LitElement implements Layer { tick() { // this.active = true; const updates = this.game.updatesSinceLastTick(); - if (updates === null) return; - const messages = updates[GameUpdateType.DisplayEvent] as - | DisplayMessageUpdate[] - | undefined; - - if (messages) { - for (const msg of messages) { - if (msg.messageType === MessageType.CHAT) { - const myPlayer = this.game.myPlayer(); - if ( - msg.playerID !== null && - (!myPlayer || myPlayer.smallID() !== msg.playerID) - ) { - continue; - } - - this.chatEvents = [ - ...this.chatEvents, - { - description: msg.message, - unsafeDescription: true, - createdAt: this.game.ticks(), - }, - ]; + for (const update of updates?.[GameUpdateType.DisplayEvent]?.updates ?? + []) { + const msg = update.displayMessage!; + if (msg.messageType === MessageType.CHAT) { + const myPlayer = this.game.myPlayer(); + if ( + msg.playerId !== null && + (!myPlayer || myPlayer.smallID() !== msg.playerId) + ) { + continue; } + + this.chatEvents = [ + ...this.chatEvents, + { + description: msg.message, + unsafeDescription: true, + createdAt: this.game.ticks(), + }, + ]; } } diff --git a/src/client/graphics/layers/ChatModal.ts b/src/client/graphics/layers/ChatModal.ts index 64023e66f..f0694ec1c 100644 --- a/src/client/graphics/layers/ChatModal.ts +++ b/src/client/graphics/layers/ChatModal.ts @@ -1,7 +1,7 @@ import { LitElement, html } from "lit"; import { customElement, query } from "lit/decorators.js"; -import { PlayerType } from "../../../core/game/Game"; +import { PlayerType } from "../../../core/game/GameUpdates"; import { GameView, PlayerView } from "../../../core/game/GameView"; import quickChatData from "../../../../resources/QuickChat.json"; diff --git a/src/client/graphics/layers/EventsDisplay.ts b/src/client/graphics/layers/EventsDisplay.ts index 98b32a0c8..b5381b51f 100644 --- a/src/client/graphics/layers/EventsDisplay.ts +++ b/src/client/graphics/layers/EventsDisplay.ts @@ -8,15 +8,7 @@ import donateGoldIcon from "../../../../resources/images/DonateGoldIconWhite.svg import nukeIcon from "../../../../resources/images/NukeIconWhite.svg"; import swordIcon from "../../../../resources/images/SwordIconWhite.svg"; import { EventBus } from "../../../core/EventBus"; -import { - AllPlayers, - getMessageCategory, - MessageCategory, - MessageType, - PlayerType, - Tick, - UnitType, -} from "../../../core/game/Game"; +import { AllPlayers, getMessageCategory, Tick } from "../../../core/game/Game"; import { AllianceExpiredUpdate, AllianceRequestReplyUpdate, @@ -27,8 +19,12 @@ import { DisplayMessageUpdate, EmojiUpdate, GameUpdateType, + MessageCategory, + MessageType, + PlayerType, TargetPlayerUpdate, UnitIncomingUpdate, + UnitType, } from "../../../core/game/GameUpdates"; import { CancelAttackIntentEvent, @@ -96,7 +92,7 @@ export class EventsDisplay extends LitElement implements Layer { [MessageCategory.NUKE, false], [MessageCategory.TRADE, false], [MessageCategory.ALLIANCE, false], - [MessageCategory.CHAT, false], + [MessageCategory.CHAT_CATEGORY, false], ]); @query(".events-container") @@ -228,7 +224,7 @@ export class EventsDisplay extends LitElement implements Layer { const updates = this.game.updatesSinceLastTick(); if (updates) { for (const [ut, fn] of this.updateMap) { - updates[ut]?.forEach(fn as (event: unknown) => void); + updates[ut]?.updates.forEach(fn as (event: unknown) => void); } } @@ -253,17 +249,17 @@ export class EventsDisplay extends LitElement implements Layer { // Update attacks this.incomingAttacks = myPlayer.incomingAttacks().filter((a) => { - const t = (this.game.playerBySmallID(a.attackerID) as PlayerView).type(); + const t = (this.game.playerBySmallID(a.attackerId) as PlayerView).type(); return t !== PlayerType.Bot; }); this.outgoingAttacks = myPlayer .outgoingAttacks() - .filter((a) => a.targetID !== 0); + .filter((a) => a.targetId !== 0); this.outgoingLandAttacks = myPlayer .outgoingAttacks() - .filter((a) => a.targetID === 0); + .filter((a) => a.targetId === 0); this.outgoingBoats = myPlayer .units() @@ -362,15 +358,15 @@ export class EventsDisplay extends LitElement implements Layer { onDisplayMessageEvent(event: DisplayMessageUpdate) { const myPlayer = this.game.myPlayer(); if ( - event.playerID !== null && - (!myPlayer || myPlayer.smallID() !== event.playerID) + event.playerId !== null && + (!myPlayer || myPlayer.smallID() !== event.playerId) ) { return; } if (event.goldAmount !== undefined) { - const hasChanged = this.latestGoldAmount !== event.goldAmount; - this.latestGoldAmount = event.goldAmount; + const hasChanged = this.latestGoldAmount !== BigInt(event.goldAmount); + this.latestGoldAmount = BigInt(event.goldAmount); if (this.goldAmountTimeoutId !== null) { clearTimeout(this.goldAmountTimeoutId); @@ -408,9 +404,9 @@ export class EventsDisplay extends LitElement implements Layer { onDisplayChatEvent(event: DisplayChatMessageUpdate) { const myPlayer = this.game.myPlayer(); if ( - event.playerID === null || + event.playerId === null || !myPlayer || - myPlayer.smallID() !== event.playerID + myPlayer.smallID() !== event.playerId ) { return; } @@ -452,15 +448,15 @@ export class EventsDisplay extends LitElement implements Layer { onAllianceRequestEvent(update: AllianceRequestUpdate) { const myPlayer = this.game.myPlayer(); - if (!myPlayer || update.recipientID !== myPlayer.smallID()) { + if (!myPlayer || update.recipientId !== myPlayer.smallID()) { return; } const requestor = this.game.playerBySmallID( - update.requestorID, + update.requestorId, ) as PlayerView; const recipient = this.game.playerBySmallID( - update.recipientID, + update.recipientId, ) as PlayerView; this.addEvent({ @@ -500,7 +496,7 @@ export class EventsDisplay extends LitElement implements Layer { // Recipient sent a separate request, so they became allied without the recipient responding. return requestor.isAlliedWith(recipient); }, - focusID: update.requestorID, + focusID: update.requestorId, }); } @@ -510,25 +506,25 @@ export class EventsDisplay extends LitElement implements Layer { return; } // myPlayer can deny alliances without clicking on the button - if (update.request.recipientID === myPlayer.smallID()) { + if (update.request!.recipientId === myPlayer.smallID()) { // Remove alliance requests whose requestors are the same as the reply's requestor // Noop unless the request was denied through other means (e.g attacking the requestor) this.events = this.events.filter( (event) => !( event.type === MessageType.ALLIANCE_REQUEST && - event.focusID === update.request.requestorID + event.focusID === update.request!.requestorId ), ); this.requestUpdate(); return; } - if (update.request.requestorID !== myPlayer.smallID()) { + if (update.request!.requestorId !== myPlayer.smallID()) { return; } const recipient = this.game.playerBySmallID( - update.request.recipientID, + update.request!.recipientId, ) as PlayerView; this.addEvent({ description: translateText("events_display.alliance_request_status", { @@ -542,7 +538,7 @@ export class EventsDisplay extends LitElement implements Layer { : MessageType.ALLIANCE_REJECTED, highlight: true, createdAt: this.game.ticks(), - focusID: update.request.recipientID, + focusID: update.request!.recipientId, }); } @@ -550,8 +546,8 @@ export class EventsDisplay extends LitElement implements Layer { const myPlayer = this.game.myPlayer(); if (!myPlayer) return; - const betrayed = this.game.playerBySmallID(update.betrayedID) as PlayerView; - const traitor = this.game.playerBySmallID(update.traitorID) as PlayerView; + const betrayed = this.game.playerBySmallID(update.betrayedId) as PlayerView; + const traitor = this.game.playerBySmallID(update.traitorId) as PlayerView; if (betrayed.isDisconnected()) return; // Do not send the message if betraying a disconnected player @@ -579,7 +575,7 @@ export class EventsDisplay extends LitElement implements Layer { type: MessageType.ALLIANCE_BROKEN, highlight: true, createdAt: this.game.ticks(), - focusID: update.betrayedID, + focusID: update.betrayedId, }); } else if (betrayed === myPlayer) { const buttons = [ @@ -597,7 +593,7 @@ export class EventsDisplay extends LitElement implements Layer { type: MessageType.ALLIANCE_BROKEN, highlight: true, createdAt: this.game.ticks(), - focusID: update.traitorID, + focusID: update.traitorId, buttons, }); } @@ -608,10 +604,10 @@ export class EventsDisplay extends LitElement implements Layer { if (!myPlayer) return; const otherID = - update.player1ID === myPlayer.smallID() - ? update.player2ID - : update.player2ID === myPlayer.smallID() - ? update.player1ID + update.player1Id === myPlayer.smallID() + ? update.player2Id + : update.player2Id === myPlayer.smallID() + ? update.player1Id : null; if (otherID === null) return; const other = this.game.playerBySmallID(otherID) as PlayerView; @@ -629,11 +625,11 @@ export class EventsDisplay extends LitElement implements Layer { } onTargetPlayerEvent(event: TargetPlayerUpdate) { - const other = this.game.playerBySmallID(event.playerID) as PlayerView; + const other = this.game.playerBySmallID(event.playerId) as PlayerView; const myPlayer = this.game.myPlayer() as PlayerView; if (!myPlayer || !myPlayer.isFriendly(other)) return; - const target = this.game.playerBySmallID(event.targetID) as PlayerView; + const target = this.game.playerBySmallID(event.targetId) as PlayerView; this.addEvent({ description: translateText("events_display.attack_request", { @@ -643,7 +639,7 @@ export class EventsDisplay extends LitElement implements Layer { type: MessageType.ATTACK_REQUEST, highlight: true, createdAt: this.game.ticks(), - focusID: event.targetID, + focusID: event.targetId, }); } @@ -677,28 +673,27 @@ export class EventsDisplay extends LitElement implements Layer { const myPlayer = this.game.myPlayer(); if (!myPlayer) return; - const recipient = - update.emoji.recipientID === AllPlayers - ? AllPlayers - : this.game.playerBySmallID(update.emoji.recipientID); + const recipient = update.emoji!.allPlayers + ? AllPlayers + : this.game.playerBySmallID(update.emoji!.recipientId!); const sender = this.game.playerBySmallID( - update.emoji.senderID, + update.emoji!.senderId, ) as PlayerView; if (recipient === myPlayer) { this.addEvent({ - description: `${sender.displayName()}: ${update.emoji.message}`, + description: `${sender.displayName()}: ${update.emoji!.emoji}`, unsafeDescription: true, type: MessageType.CHAT, highlight: true, createdAt: this.game.ticks(), - focusID: update.emoji.senderID, + focusID: update.emoji!.senderId, }); } else if (sender === myPlayer && recipient !== AllPlayers) { this.addEvent({ description: translateText("events_display.sent_emoji", { name: (recipient as PlayerView).displayName(), - emoji: update.emoji.message, + emoji: update.emoji!.emoji, }), unsafeDescription: true, type: MessageType.CHAT, @@ -712,11 +707,11 @@ export class EventsDisplay extends LitElement implements Layer { onUnitIncomingEvent(event: UnitIncomingUpdate) { const myPlayer = this.game.myPlayer(); - if (!myPlayer || myPlayer.smallID() !== event.playerID) { + if (!myPlayer || myPlayer.smallID() !== event.playerId) { return; } - const unitView = this.game.unit(event.unitID); + const unitView = this.game.unit(event.unitId); this.addEvent({ description: event.message, @@ -737,27 +732,27 @@ export class EventsDisplay extends LitElement implements Layer { } private async attackWarningOnClick(attack: AttackUpdate) { - const playerView = this.game.playerBySmallID(attack.attackerID); + const playerView = this.game.playerBySmallID(attack.attackerId); if (playerView !== undefined) { if (playerView instanceof PlayerView) { const averagePosition = await playerView.attackAveragePosition( - attack.attackerID, + attack.attackerId, attack.id, ); if (averagePosition === null) { - this.emitGoToPlayerEvent(attack.attackerID); + this.emitGoToPlayerEvent(attack.attackerId); } else { this.emitGoToPositionEvent(averagePosition.x, averagePosition.y); } } } else { - this.emitGoToPlayerEvent(attack.attackerID); + this.emitGoToPlayerEvent(attack.attackerId); } } private handleRetaliate(attack: AttackUpdate) { - const attacker = this.game.playerBySmallID(attack.attackerID) as PlayerView; + const attacker = this.game.playerBySmallID(attack.attackerId) as PlayerView; if (!attacker) return; const myPlayer = this.game.myPlayer(); @@ -780,7 +775,7 @@ export class EventsDisplay extends LitElement implements Layer { ${renderTroops(attack.troops)} ${( this.game.playerBySmallID( - attack.attackerID, + attack.attackerId, ) as PlayerView )?.name()} ${attack.retreating @@ -822,7 +817,7 @@ export class EventsDisplay extends LitElement implements Layer { ${renderTroops(attack.troops)} ${( this.game.playerBySmallID( - attack.targetID, + attack.targetId, ) as PlayerView )?.name()} `, @@ -1032,7 +1027,10 @@ export class EventsDisplay extends LitElement implements Layer { allianceIcon, MessageCategory.ALLIANCE, )} - ${this.renderToggleButton(chatIcon, MessageCategory.CHAT)} + ${this.renderToggleButton( + chatIcon, + MessageCategory.CHAT_CATEGORY, + )}
${this.latestGoldAmount !== null diff --git a/src/client/graphics/layers/FxLayer.ts b/src/client/graphics/layers/FxLayer.ts index a2e0990a2..5091186a1 100644 --- a/src/client/graphics/layers/FxLayer.ts +++ b/src/client/graphics/layers/FxLayer.ts @@ -1,10 +1,10 @@ import { Theme } from "../../../core/configuration/Config"; -import { UnitType } from "../../../core/game/Game"; import { BonusEventUpdate, ConquestUpdate, GameUpdateType, RailroadUpdate, + UnitType, } from "../../../core/game/GameUpdates"; import { GameView, UnitView } from "../../../core/game/GameView"; import SoundManager, { SoundEffect } from "../../sound/SoundManager"; @@ -45,29 +45,31 @@ export class FxLayer implements Layer { this.manageBoatTargetFx(); this.game .updatesSinceLastTick() - ?.[GameUpdateType.Unit]?.map((unit) => this.game.unit(unit.id)) + ?.[GameUpdateType.Unit]?.updates.map((update) => + this.game.unit(update.unit!.id), + ) ?.forEach((unitView) => { if (unitView === undefined) return; this.onUnitEvent(unitView); }); this.game .updatesSinceLastTick() - ?.[GameUpdateType.BonusEvent]?.forEach((bonusEvent) => { - if (bonusEvent === undefined) return; - this.onBonusEvent(bonusEvent); + ?.[GameUpdateType.BonusEvent]?.updates.forEach((update) => { + if (update === undefined) return; + this.onBonusEvent(update.bonusEvent!); }); this.game .updatesSinceLastTick() - ?.[GameUpdateType.RailroadEvent]?.forEach((update) => { + ?.[GameUpdateType.RailroadEvent]?.updates.forEach((update) => { if (update === undefined) return; - this.onRailroadEvent(update); + this.onRailroadEvent(update.railroad!); }); this.game .updatesSinceLastTick() - ?.[GameUpdateType.ConquestEvent]?.forEach((update) => { + ?.[GameUpdateType.ConquestEvent]?.updates.forEach((update) => { if (update === undefined) return; - this.onConquestEvent(update); + this.onConquestEvent(update.conquest!); }); } @@ -249,7 +251,7 @@ export class FxLayer implements Layer { onConquestEvent(conquest: ConquestUpdate) { // Only display fx for the current player - const conqueror = this.game.player(conquest.conquerorId); + const conqueror = this.game.playerBySmallID(conquest.conquerorId); if (conqueror !== this.game.myPlayer()) { return; } diff --git a/src/client/graphics/layers/GameRightSidebar.ts b/src/client/graphics/layers/GameRightSidebar.ts index 394668e03..4d3ee320d 100644 --- a/src/client/graphics/layers/GameRightSidebar.ts +++ b/src/client/graphics/layers/GameRightSidebar.ts @@ -54,7 +54,8 @@ export class GameRightSidebar extends LitElement implements Layer { // Timer logic const updates = this.game.updatesSinceLastTick(); if (updates) { - this.hasWinner = this.hasWinner || updates[GameUpdateType.Win].length > 0; + this.hasWinner = + this.hasWinner || updates[GameUpdateType.Win]?.updates.length > 0; } const maxTimerValue = this.game.config().gameConfig().maxTimerValue; if (maxTimerValue !== undefined) { diff --git a/src/client/graphics/layers/NukeTrajectoryPreviewLayer.ts b/src/client/graphics/layers/NukeTrajectoryPreviewLayer.ts index c0e74af83..cd0560f05 100644 --- a/src/client/graphics/layers/NukeTrajectoryPreviewLayer.ts +++ b/src/client/graphics/layers/NukeTrajectoryPreviewLayer.ts @@ -1,6 +1,6 @@ import { EventBus } from "../../../core/EventBus"; -import { UnitType } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; +import { UnitType } from "../../../core/game/GameUpdates"; import { GameView } from "../../../core/game/GameView"; import { ParabolaPathFinder } from "../../../core/pathfinding/PathFinding"; import { GhostStructureChangedEvent, MouseMoveEvent } from "../../InputHandler"; diff --git a/src/client/graphics/layers/PlayerInfoOverlay.ts b/src/client/graphics/layers/PlayerInfoOverlay.ts index 0ccce9208..250cd3a53 100644 --- a/src/client/graphics/layers/PlayerInfoOverlay.ts +++ b/src/client/graphics/layers/PlayerInfoOverlay.ts @@ -11,15 +11,13 @@ import portIcon from "../../../../resources/images/PortIcon.svg"; import samLauncherIcon from "../../../../resources/images/SamLauncherIconWhite.svg"; import { renderPlayerFlag } from "../../../core/CustomFlag"; import { EventBus } from "../../../core/EventBus"; -import { - PlayerProfile, - PlayerType, - Relation, - Unit, - UnitType, -} from "../../../core/game/Game"; +import { PlayerProfile, Relation, Unit } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; -import { AllianceView } from "../../../core/game/GameUpdates"; +import { + AllianceView, + PlayerType, + UnitType, +} from "../../../core/game/GameUpdates"; import { GameView, PlayerView, UnitView } from "../../../core/game/GameView"; import { ContextMenuEvent, MouseMoveEvent } from "../../InputHandler"; import { diff --git a/src/client/graphics/layers/PlayerPanel.ts b/src/client/graphics/layers/PlayerPanel.ts index 27fc45e7c..10fecc2fc 100644 --- a/src/client/graphics/layers/PlayerPanel.ts +++ b/src/client/graphics/layers/PlayerPanel.ts @@ -15,10 +15,10 @@ import { AllPlayers, PlayerActions, PlayerProfile, - PlayerType, Relation, } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; +import { PlayerType } from "../../../core/game/GameUpdates"; import { GameView, PlayerView } from "../../../core/game/GameView"; import { Emoji, flattenedEmojiTable } from "../../../core/Util"; import { actionButton } from "../../components/ui/ActionButton"; diff --git a/src/client/graphics/layers/RadialMenuElements.ts b/src/client/graphics/layers/RadialMenuElements.ts index 7eeb88f29..514c2b6d3 100644 --- a/src/client/graphics/layers/RadialMenuElements.ts +++ b/src/client/graphics/layers/RadialMenuElements.ts @@ -1,6 +1,7 @@ import { Config } from "../../../core/configuration/Config"; -import { AllPlayers, PlayerActions, UnitType } from "../../../core/game/Game"; +import { AllPlayers, PlayerActions } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; +import { UnitType } from "../../../core/game/GameUpdates"; import { GameView, PlayerView } from "../../../core/game/GameView"; import { Emoji, flattenedEmojiTable } from "../../../core/Util"; import { renderNumber, translateText } from "../../Utils"; diff --git a/src/client/graphics/layers/RailroadLayer.ts b/src/client/graphics/layers/RailroadLayer.ts index d53ad2470..71dcc76c7 100644 --- a/src/client/graphics/layers/RailroadLayer.ts +++ b/src/client/graphics/layers/RailroadLayer.ts @@ -45,9 +45,9 @@ export class RailroadLayer implements Layer { tick() { const updates = this.game.updatesSinceLastTick(); const railUpdates = - updates !== null ? updates[GameUpdateType.RailroadEvent] : []; + updates !== null ? updates[GameUpdateType.RailroadEvent].updates : []; for (const rail of railUpdates) { - this.handleRailroadRendering(rail); + this.handleRailroadRendering(rail.railroad!); } } diff --git a/src/client/graphics/layers/RailroadSprites.ts b/src/client/graphics/layers/RailroadSprites.ts index d0734acad..f7747c6e3 100644 --- a/src/client/graphics/layers/RailroadSprites.ts +++ b/src/client/graphics/layers/RailroadSprites.ts @@ -1,21 +1,21 @@ import { RailType } from "../../../core/game/GameUpdates"; const railTypeToFunctionMap: Record number[][]> = { - [RailType.TOP_RIGHT]: topRightRailroadCornerRects, - [RailType.BOTTOM_LEFT]: bottomLeftRailroadCornerRects, - [RailType.TOP_LEFT]: topLeftRailroadCornerRects, - [RailType.BOTTOM_RIGHT]: bottomRightRailroadCornerRects, - [RailType.HORIZONTAL]: horizontalRailroadRects, - [RailType.VERTICAL]: verticalRailroadRects, + [RailType.topRight]: topRightRailroadCornerRects, + [RailType.bottomLeft]: bottomLeftRailroadCornerRects, + [RailType.topLeft]: topLeftRailroadCornerRects, + [RailType.bottomRight]: bottomRightRailroadCornerRects, + [RailType.horizontal]: horizontalRailroadRects, + [RailType.vertical]: verticalRailroadRects, }; const railTypeToBridgeFunctionMap: Record number[][]> = { - [RailType.TOP_RIGHT]: topRightBridgeCornerRects, - [RailType.BOTTOM_LEFT]: bottomLeftBridgeCornerRects, - [RailType.TOP_LEFT]: topLeftBridgeCornerRects, - [RailType.BOTTOM_RIGHT]: bottomRightBridgeCornerRects, - [RailType.HORIZONTAL]: horizontalBridge, - [RailType.VERTICAL]: verticalBridge, + [RailType.topRight]: topRightBridgeCornerRects, + [RailType.bottomLeft]: bottomLeftBridgeCornerRects, + [RailType.topLeft]: topLeftBridgeCornerRects, + [RailType.bottomRight]: bottomRightBridgeCornerRects, + [RailType.horizontal]: horizontalBridge, + [RailType.vertical]: verticalBridge, }; export function getRailroadRects(type: RailType): number[][] { diff --git a/src/client/graphics/layers/SAMRadiusLayer.ts b/src/client/graphics/layers/SAMRadiusLayer.ts index e790e81d7..2f2c9f196 100644 --- a/src/client/graphics/layers/SAMRadiusLayer.ts +++ b/src/client/graphics/layers/SAMRadiusLayer.ts @@ -1,6 +1,5 @@ import type { EventBus } from "../../../core/EventBus"; -import { UnitType } from "../../../core/game/Game"; -import { GameUpdateType } from "../../../core/game/GameUpdates"; +import { GameUpdateType, UnitType } from "../../../core/game/GameUpdates"; import type { GameView, PlayerView } from "../../../core/game/GameView"; import { ToggleStructureEvent } from "../../InputHandler"; import { TransformHandler } from "../TransformHandler"; @@ -76,7 +75,8 @@ export class SAMRadiusLayer implements Layer { if (unitUpdates) { let hasChanges = false; - for (const update of unitUpdates) { + for (const u of unitUpdates?.updates ?? []) { + const update = u.unit!; const unit = this.game.unit(update.id); if (unit && unit.type() === UnitType.SAMLauncher) { const wasTracked = this.samLaunchers.has(update.id); diff --git a/src/client/graphics/layers/StructureDrawingUtils.ts b/src/client/graphics/layers/StructureDrawingUtils.ts index db34d496a..5deca0b29 100644 --- a/src/client/graphics/layers/StructureDrawingUtils.ts +++ b/src/client/graphics/layers/StructureDrawingUtils.ts @@ -1,6 +1,7 @@ import * as PIXI from "pixi.js"; import { Theme } from "../../../core/configuration/Config"; -import { Cell, UnitType } from "../../../core/game/Game"; +import { Cell } from "../../../core/game/Game"; +import { UnitType } from "../../../core/game/GameUpdates"; import { GameView, PlayerView, UnitView } from "../../../core/game/GameView"; import { TransformHandler } from "../TransformHandler"; diff --git a/src/client/graphics/layers/StructureIconsLayer.ts b/src/client/graphics/layers/StructureIconsLayer.ts index 1458e7aff..55eb1c040 100644 --- a/src/client/graphics/layers/StructureIconsLayer.ts +++ b/src/client/graphics/layers/StructureIconsLayer.ts @@ -10,10 +10,9 @@ import { Cell, PlayerActions, PlayerID, - UnitType, } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; -import { GameUpdateType } from "../../../core/game/GameUpdates"; +import { GameUpdateType, UnitType } from "../../../core/game/GameUpdates"; import { GameView, UnitView } from "../../../core/game/GameView"; import { GhostStructureChangedEvent, @@ -178,7 +177,9 @@ export class StructureIconsLayer implements Layer { tick() { this.game .updatesSinceLastTick() - ?.[GameUpdateType.Unit]?.map((unit) => this.game.unit(unit.id)) + ?.[GameUpdateType.Unit]?.updates.map((unit) => + this.game.unit(unit.unit!.id), + ) ?.forEach((unitView) => { if (unitView === undefined) return; diff --git a/src/client/graphics/layers/StructureLayer.ts b/src/client/graphics/layers/StructureLayer.ts index 55ec7dd89..a05ea5232 100644 --- a/src/client/graphics/layers/StructureLayer.ts +++ b/src/client/graphics/layers/StructureLayer.ts @@ -10,9 +10,9 @@ import shieldIcon from "../../../../resources/images/buildings/fortAlt3.png"; import anchorIcon from "../../../../resources/images/buildings/port1.png"; import missileSiloIcon from "../../../../resources/images/buildings/silo1.png"; import SAMMissileIcon from "../../../../resources/images/buildings/silo4.png"; -import { Cell, UnitType } from "../../../core/game/Game"; +import { AllUnitTypes, Cell } from "../../../core/game/Game"; import { euclDistFN, isometricDistFN } from "../../../core/game/GameMap"; -import { GameUpdateType } from "../../../core/game/GameUpdates"; +import { GameUpdateType, UnitType } from "../../../core/game/GameUpdates"; import { GameView, UnitView } from "../../../core/game/GameView"; const underConstructionColor = colord("rgb(150,150,150)"); @@ -32,7 +32,7 @@ interface UnitRenderConfig { export class StructureLayer implements Layer { private canvas: HTMLCanvasElement; private context: CanvasRenderingContext2D; - private unitIcons: Map = new Map(); + private unitIcons: Map = new Map(); private theme: Theme; private tempCanvas: HTMLCanvasElement; private tempContext: CanvasRenderingContext2D; @@ -84,7 +84,7 @@ export class StructureLayer implements Layer { this.loadIconData(); } - private loadIcon(unitType: string, config: UnitRenderConfig) { + private loadIcon(unitType: UnitType, config: UnitRenderConfig) { const image = new Image(); image.src = config.icon; image.onload = () => { @@ -99,8 +99,11 @@ export class StructureLayer implements Layer { } private loadIconData() { - Object.entries(this.unitConfigs).forEach(([unitType, config]) => { - this.loadIcon(unitType, config); + AllUnitTypes.forEach((unitType) => { + const config = this.unitConfigs[unitType]; + if (config) { + this.loadIcon(unitType, this.unitConfigs[unitType]!); + } }); } @@ -110,9 +113,10 @@ export class StructureLayer implements Layer { tick() { const updates = this.game.updatesSinceLastTick(); - const unitUpdates = updates !== null ? updates[GameUpdateType.Unit] : []; + const unitUpdates = + updates !== null ? (updates[GameUpdateType.Unit]?.updates ?? []) : []; for (const u of unitUpdates) { - const unit = this.game.unit(u.id); + const unit = this.game.unit(u.unit!.id); if (unit === undefined) continue; this.handleUnitRendering(unit); } diff --git a/src/client/graphics/layers/TeamStats.ts b/src/client/graphics/layers/TeamStats.ts index 120b4b60c..ecb4e6bc3 100644 --- a/src/client/graphics/layers/TeamStats.ts +++ b/src/client/graphics/layers/TeamStats.ts @@ -1,7 +1,8 @@ import { LitElement, html } from "lit"; import { customElement, property } from "lit/decorators.js"; import { EventBus } from "../../../core/EventBus"; -import { GameMode, Team, UnitType } from "../../../core/game/Game"; +import { GameMode, Team } from "../../../core/game/Game"; +import { UnitType } from "../../../core/game/GameUpdates"; import { GameView, PlayerView } from "../../../core/game/GameView"; import { renderNumber, translateText } from "../../Utils"; import { Layer } from "./Layer"; diff --git a/src/client/graphics/layers/TerritoryLayer.ts b/src/client/graphics/layers/TerritoryLayer.ts index 2e6fa2113..ba5b8790a 100644 --- a/src/client/graphics/layers/TerritoryLayer.ts +++ b/src/client/graphics/layers/TerritoryLayer.ts @@ -2,15 +2,13 @@ import { PriorityQueue } from "@datastructures-js/priority-queue"; import { Colord } from "colord"; import { Theme } from "../../../core/configuration/Config"; import { EventBus } from "../../../core/EventBus"; -import { - Cell, - ColoredTeams, - PlayerType, - Team, - UnitType, -} from "../../../core/game/Game"; +import { Cell, ColoredTeams, Team } from "../../../core/game/Game"; import { euclDistFN, TileRef } from "../../../core/game/GameMap"; -import { GameUpdateType } from "../../../core/game/GameUpdates"; +import { + GameUpdateType, + PlayerType, + UnitType, +} from "../../../core/game/GameUpdates"; import { GameView, PlayerView } from "../../../core/game/GameView"; import { UserSettings } from "../../../core/game/UserSettings"; import { PseudoRandom } from "../../../core/PseudoRandom"; @@ -87,8 +85,8 @@ export class TerritoryLayer implements Layer { this.game.recentlyUpdatedTiles().forEach((t) => this.enqueueTile(t)); const updates = this.game.updatesSinceLastTick(); - const unitUpdates = updates !== null ? updates[GameUpdateType.Unit] : []; - unitUpdates.forEach((update) => { + updates[GameUpdateType.Unit]?.updates.forEach((u) => { + const update = u.unit!; if (update.unitType === UnitType.DefensePost) { // Only update borders if the defense post is not under construction if (update.underConstruction) { @@ -101,8 +99,8 @@ export class TerritoryLayer implements Layer { .forEach((t) => { if ( this.game.isBorder(t) && - (this.game.ownerID(t) === update.ownerID || - this.game.ownerID(t) === update.lastOwnerID) + (this.game.ownerID(t) === update.ownerId || + this.game.ownerID(t) === update.lastOwnerId) ) { this.enqueueTile(t); } @@ -113,33 +111,42 @@ export class TerritoryLayer implements Layer { // Detect alliance mutations const myPlayer = this.game.myPlayer(); if (myPlayer) { - updates?.[GameUpdateType.BrokeAlliance]?.forEach((update) => { - const territory = this.game.playerBySmallID(update.betrayedID); + updates?.[GameUpdateType.BrokeAlliance]?.updates.forEach((update) => { + const brokeAllianceUpdate = update.brokeAlliance!; + const territory = this.game.playerBySmallID( + brokeAllianceUpdate.betrayedId, + ); if (territory && territory instanceof PlayerView) { this.redrawBorder(territory); } }); - updates?.[GameUpdateType.AllianceRequestReply]?.forEach((update) => { - if ( - update.accepted && - (update.request.requestorID === myPlayer.smallID() || - update.request.recipientID === myPlayer.smallID()) - ) { - const territoryId = - update.request.requestorID === myPlayer.smallID() - ? update.request.recipientID - : update.request.requestorID; - const territory = this.game.playerBySmallID(territoryId); - if (territory && territory instanceof PlayerView) { - this.redrawBorder(territory); + updates?.[GameUpdateType.AllianceRequestReply]?.updates.forEach( + (update) => { + const au = update.allianceRequestReply!; + if ( + au.accepted && + (au.request!.requestorId === myPlayer.smallID() || + au.request!.recipientId === myPlayer.smallID()) + ) { + const territoryId = + au.request!.requestorId === myPlayer.smallID() + ? au.request!.recipientId + : au.request!.requestorId; + const territory = this.game.playerBySmallID(territoryId); + if (territory && territory instanceof PlayerView) { + this.redrawBorder(territory); + } } - } - }); - updates?.[GameUpdateType.EmbargoEvent]?.forEach((update) => { - const player = this.game.playerBySmallID(update.playerID) as PlayerView; + }, + ); + updates?.[GameUpdateType.EmbargoEvent]?.updates.forEach((update) => { + const embargoUpdate = update.embargo!; + const player = this.game.playerBySmallID( + embargoUpdate.playerId, + ) as PlayerView; const embargoed = this.game.playerBySmallID( - update.embargoedID, + embargoUpdate.embargoedId, ) as PlayerView; if ( diff --git a/src/client/graphics/layers/UILayer.ts b/src/client/graphics/layers/UILayer.ts index d8edb3f02..9b74ae96b 100644 --- a/src/client/graphics/layers/UILayer.ts +++ b/src/client/graphics/layers/UILayer.ts @@ -1,8 +1,7 @@ import { Colord } from "colord"; import { EventBus } from "../../../core/EventBus"; import { Theme } from "../../../core/configuration/Config"; -import { UnitType } from "../../../core/game/Game"; -import { GameUpdateType } from "../../../core/game/GameUpdates"; +import { GameUpdateType, UnitType } from "../../../core/game/GameUpdates"; import { GameView, UnitView } from "../../../core/game/GameView"; import { UserSettings } from "../../../core/game/UserSettings"; import { UnitSelectionEvent } from "../../InputHandler"; @@ -71,7 +70,9 @@ export class UILayer implements Layer { this.game .updatesSinceLastTick() - ?.[GameUpdateType.Unit]?.map((unit) => this.game.unit(unit.id)) + ?.[GameUpdateType.Unit]?.updates.map((unit) => + this.game.unit(unit.unit!.id), + ) ?.forEach((unitView) => { if (unitView === undefined) return; this.onUnitEvent(unitView); diff --git a/src/client/graphics/layers/UnitDisplay.ts b/src/client/graphics/layers/UnitDisplay.ts index 55b7d7ccb..afe870d80 100644 --- a/src/client/graphics/layers/UnitDisplay.ts +++ b/src/client/graphics/layers/UnitDisplay.ts @@ -11,7 +11,8 @@ import portIcon from "../../../../resources/images/PortIcon.svg"; import samLauncherIcon from "../../../../resources/images/SamLauncherIconWhite.svg"; import defensePostIcon from "../../../../resources/images/ShieldIconWhite.svg"; import { EventBus } from "../../../core/EventBus"; -import { Gold, PlayerActions, UnitType } from "../../../core/game/Game"; +import { Gold, PlayerActions } from "../../../core/game/Game"; +import { UnitType } from "../../../core/game/GameUpdates"; import { GameView } from "../../../core/game/GameView"; import { GhostStructureChangedEvent, diff --git a/src/client/graphics/layers/UnitLayer.ts b/src/client/graphics/layers/UnitLayer.ts index ca1de78e7..1c68c5814 100644 --- a/src/client/graphics/layers/UnitLayer.ts +++ b/src/client/graphics/layers/UnitLayer.ts @@ -1,8 +1,8 @@ import { colord, Colord } from "colord"; import { EventBus } from "../../../core/EventBus"; import { Theme } from "../../../core/configuration/Config"; -import { UnitType } from "../../../core/game/Game"; import { TileRef } from "../../../core/game/GameMap"; +import { UnitType } from "../../../core/game/GameUpdates"; import { GameView, UnitView } from "../../../core/game/GameView"; import { BezenhamLine } from "../../../core/utilities/Line"; import { @@ -67,7 +67,7 @@ export class UnitLayer implements Layer { tick() { const unitIds = this.game .updatesSinceLastTick() - ?.[GameUpdateType.Unit]?.map((unit) => unit.id); + ?.[GameUpdateType.Unit]?.updates.map((unit) => unit.unit!.id); this.updateUnitsSprites(unitIds ?? []); } diff --git a/src/client/graphics/layers/WinModal.ts b/src/client/graphics/layers/WinModal.ts index 8de7b4abf..4fc5c530a 100644 --- a/src/client/graphics/layers/WinModal.ts +++ b/src/client/graphics/layers/WinModal.ts @@ -315,12 +315,17 @@ export class WinModal extends LitElement implements Layer { this.show(); } const updates = this.game.updatesSinceLastTick(); - const winUpdates = updates !== null ? updates[GameUpdateType.Win] : []; - winUpdates.forEach((wu) => { + const winUpdates = + updates !== null ? updates[GameUpdateType.Win].updates : []; + winUpdates.forEach((update) => { + const wu = update.win!; + if (wu.winner === undefined) { // ... } else if (wu.winner[0] === "team") { - this.eventBus.emit(new SendWinnerEvent(wu.winner, wu.allPlayersStats)); + this.eventBus.emit( + new SendWinnerEvent(JSON.parse(wu.winner), JSON.parse(wu.stats)), + ); if (wu.winner[1] === this.game.myPlayer()?.team()) { this._title = translateText("win_modal.your_team"); this.isWin = true; @@ -337,7 +342,7 @@ export class WinModal extends LitElement implements Layer { const winnerClient = winner.clientID(); if (winnerClient !== null) { this.eventBus.emit( - new SendWinnerEvent(["player", winnerClient], wu.allPlayersStats), + new SendWinnerEvent(["player", winnerClient], JSON.parse(wu.stats)), ); } if ( diff --git a/src/client/utilities/RenderUnitTypeOptions.ts b/src/client/utilities/RenderUnitTypeOptions.ts index 0392935d6..d73a729a7 100644 --- a/src/client/utilities/RenderUnitTypeOptions.ts +++ b/src/client/utilities/RenderUnitTypeOptions.ts @@ -1,6 +1,6 @@ // renderUnitTypeOptions.ts import { html, TemplateResult } from "lit"; -import { UnitType } from "../../core/game/Game"; +import { UnitType } from "../../core/game/GameUpdates"; import { translateText } from "../Utils"; export interface UnitTypeRenderContext { diff --git a/src/core/GameRunner.ts b/src/core/GameRunner.ts index d7c74307a..fec4319c5 100644 --- a/src/core/GameRunner.ts +++ b/src/core/GameRunner.ts @@ -7,8 +7,6 @@ import { Attack, Cell, Game, - GameUpdates, - NameViewData, Nation, Player, PlayerActions, @@ -16,15 +14,15 @@ import { PlayerID, PlayerInfo, PlayerProfile, - PlayerType, } from "./game/Game"; import { createGame } from "./game/GameImpl"; import { TileRef } from "./game/GameMap"; import { GameMapLoader } from "./game/GameMapLoader"; import { ErrorUpdate, - GameUpdateType, GameUpdateViewData, + NameViewData, + PlayerType, } from "./game/GameUpdates"; import { loadTerrainMap as loadGameMap } from "./game/TerrainMapLoader"; import { PseudoRandom } from "./PseudoRandom"; @@ -134,17 +132,14 @@ export class GameRunner { ); this.currTurn++; - let updates: GameUpdates; - let tickExecutionDuration: number = 0; + let updates: GameUpdateViewData; try { - const startTime = performance.now(); updates = this.game.executeNextTick(); - const endTime = performance.now(); - tickExecutionDuration = endTime - startTime; } catch (error: unknown) { if (error instanceof Error) { console.error("Game tick error:", error.message); + console.error("Stack trace:", error.stack); this.callBack({ errMsg: error.message, stack: error.stack, @@ -173,17 +168,7 @@ export class GameRunner { }); } - // Many tiles are updated to pack it into an array - const packedTileUpdates = updates[GameUpdateType.Tile].map((u) => u.update); - updates[GameUpdateType.Tile] = []; - - this.callBack({ - tick: this.game.ticks(), - packedTileUpdates: new BigUint64Array(packedTileUpdates), - updates: updates, - playerNameViewData: this.playerViewData, - tickExecutionDuration: tickExecutionDuration, - }); + this.callBack(updates); this.isExecuting = false; } diff --git a/src/core/Schemas.ts b/src/core/Schemas.ts index 5ba0b04a5..8400dab01 100644 --- a/src/core/Schemas.ts +++ b/src/core/Schemas.ts @@ -17,8 +17,8 @@ import { HumansVsNations, Quads, Trios, - UnitType, } from "./game/Game"; +import { UnitType } from "./game/GameUpdates"; import { PlayerStatsSchema } from "./StatsSchemas"; import { flattenedEmojiTable } from "./Util"; diff --git a/src/core/StatsSchemas.ts b/src/core/StatsSchemas.ts index a911d9459..7354d692d 100644 --- a/src/core/StatsSchemas.ts +++ b/src/core/StatsSchemas.ts @@ -1,5 +1,5 @@ import { z } from "zod"; -import { UnitType } from "./game/Game"; +import { UnitType } from "./game/GameUpdates"; export const bombUnits = ["abomb", "hbomb", "mirv", "mirvw"] as const; export const BombUnitSchema = z.enum(bombUnits); diff --git a/src/core/Util.ts b/src/core/Util.ts index ff71c1a3d..bf75689df 100644 --- a/src/core/Util.ts +++ b/src/core/Util.ts @@ -16,6 +16,7 @@ import { BOT_NAME_PREFIXES, BOT_NAME_SUFFIXES, } from "./execution/utils/BotNames"; +import { PlayerType } from "./game/GameUpdates"; export function manhattanDistWrapped( c1: Cell, @@ -290,10 +291,10 @@ export function withinInt(num: bigint, min: bigint, max: bigint): bigint { export function createRandomName( name: string, - playerType: string, + playerType: PlayerType, ): string | null { let randomName: string | null = null; - if (playerType === "HUMAN") { + if (playerType === PlayerType.Human) { const hash = simpleHash(name); const prefixIndex = hash % BOT_NAME_PREFIXES.length; const suffixIndex = diff --git a/src/core/configuration/Config.ts b/src/core/configuration/Config.ts index 9f7301cd3..92b67384f 100644 --- a/src/core/configuration/Config.ts +++ b/src/core/configuration/Config.ts @@ -12,9 +12,9 @@ import { TerraNullius, Tick, UnitInfo, - UnitType, } from "../game/Game"; import { GameMap, TileRef } from "../game/GameMap"; +import { UnitType } from "../game/GameUpdates"; import { PlayerView } from "../game/GameView"; import { UserSettings } from "../game/UserSettings"; import { GameConfig, GameID, TeamCountConfig } from "../Schemas"; diff --git a/src/core/configuration/DefaultConfig.ts b/src/core/configuration/DefaultConfig.ts index a0b3ba208..8c65c4ba9 100644 --- a/src/core/configuration/DefaultConfig.ts +++ b/src/core/configuration/DefaultConfig.ts @@ -11,16 +11,15 @@ import { HumansVsNations, Player, PlayerInfo, - PlayerType, Quads, TerrainType, TerraNullius, Tick, Trios, UnitInfo, - UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { PlayerType, UnitType } from "../game/GameUpdates"; import { PlayerView } from "../game/GameView"; import { UserSettings } from "../game/UserSettings"; import { GameConfig, GameID, TeamCountConfig } from "../Schemas"; diff --git a/src/core/configuration/PastelTheme.ts b/src/core/configuration/PastelTheme.ts index e024afc32..8ad788a6b 100644 --- a/src/core/configuration/PastelTheme.ts +++ b/src/core/configuration/PastelTheme.ts @@ -1,7 +1,8 @@ import { Colord, colord, LabaColor } from "colord"; import { PseudoRandom } from "../PseudoRandom"; -import { PlayerType, Team, TerrainType } from "../game/Game"; +import { Team, TerrainType } from "../game/Game"; import { GameMap, TileRef } from "../game/GameMap"; +import { PlayerType } from "../game/GameUpdates"; import { PlayerView } from "../game/GameView"; import { ColorAllocator } from "./ColorAllocator"; import { botColors, fallbackColors, humanColors, nationColors } from "./Colors"; diff --git a/src/core/execution/AttackExecution.ts b/src/core/execution/AttackExecution.ts index 5997c1320..f49550822 100644 --- a/src/core/execution/AttackExecution.ts +++ b/src/core/execution/AttackExecution.ts @@ -3,14 +3,13 @@ import { Attack, Execution, Game, - MessageType, Player, PlayerID, - PlayerType, TerrainType, TerraNullius, } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { MessageType, PlayerType } from "../game/GameUpdates"; import { PseudoRandom } from "../PseudoRandom"; import { FlatBinaryHeap } from "./utils/FlatBinaryHeap"; // adjust path if needed diff --git a/src/core/execution/BoatRetreatExecution.ts b/src/core/execution/BoatRetreatExecution.ts index c6afedff1..de0dc1a02 100644 --- a/src/core/execution/BoatRetreatExecution.ts +++ b/src/core/execution/BoatRetreatExecution.ts @@ -1,4 +1,5 @@ -import { Execution, Game, Player, UnitType } from "../game/Game"; +import { Execution, Game, Player } from "../game/Game"; +import { UnitType } from "../game/GameUpdates"; export class BoatRetreatExecution implements Execution { private active = true; diff --git a/src/core/execution/BotSpawner.ts b/src/core/execution/BotSpawner.ts index 9c77bad38..ff3cbb7d8 100644 --- a/src/core/execution/BotSpawner.ts +++ b/src/core/execution/BotSpawner.ts @@ -1,5 +1,6 @@ -import { Game, PlayerInfo, PlayerType } from "../game/Game"; +import { Game, PlayerInfo } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { PlayerType } from "../game/GameUpdates"; import { PseudoRandom } from "../PseudoRandom"; import { GameID } from "../Schemas"; import { simpleHash } from "../Util"; diff --git a/src/core/execution/CityExecution.ts b/src/core/execution/CityExecution.ts index fd31c940e..17dd46c39 100644 --- a/src/core/execution/CityExecution.ts +++ b/src/core/execution/CityExecution.ts @@ -1,4 +1,5 @@ -import { Execution, Game, Unit, UnitType } from "../game/Game"; +import { Execution, Game, Unit } from "../game/Game"; +import { UnitType } from "../game/GameUpdates"; import { TrainStationExecution } from "./TrainStationExecution"; export class CityExecution implements Execution { diff --git a/src/core/execution/ConstructionExecution.ts b/src/core/execution/ConstructionExecution.ts index 799556fe0..cc0786f4a 100644 --- a/src/core/execution/ConstructionExecution.ts +++ b/src/core/execution/ConstructionExecution.ts @@ -1,5 +1,6 @@ -import { Execution, Game, Player, Tick, Unit, UnitType } from "../game/Game"; +import { Execution, Game, Player, Tick, Unit } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { UnitType } from "../game/GameUpdates"; import { CityExecution } from "./CityExecution"; import { DefensePostExecution } from "./DefensePostExecution"; import { FactoryExecution } from "./FactoryExecution"; diff --git a/src/core/execution/DeleteUnitExecution.ts b/src/core/execution/DeleteUnitExecution.ts index 9ba68ee50..bcb3d52bd 100644 --- a/src/core/execution/DeleteUnitExecution.ts +++ b/src/core/execution/DeleteUnitExecution.ts @@ -1,4 +1,5 @@ -import { Execution, Game, MessageType, Player, Unit } from "../game/Game"; +import { Execution, Game, Player, Unit } from "../game/Game"; +import { MessageType } from "../game/GameUpdates"; export class DeleteUnitExecution implements Execution { private active: boolean = true; diff --git a/src/core/execution/EmbargoAllExecution.ts b/src/core/execution/EmbargoAllExecution.ts index 4a0fb731a..697262cb9 100644 --- a/src/core/execution/EmbargoAllExecution.ts +++ b/src/core/execution/EmbargoAllExecution.ts @@ -1,4 +1,5 @@ -import { Execution, Game, Player, PlayerType } from "../game/Game"; +import { Execution, Game, Player } from "../game/Game"; +import { PlayerType } from "../game/GameUpdates"; export class EmbargoAllExecution implements Execution { constructor( diff --git a/src/core/execution/EmojiExecution.ts b/src/core/execution/EmojiExecution.ts index 94f84e58d..c13d5bb1c 100644 --- a/src/core/execution/EmojiExecution.ts +++ b/src/core/execution/EmojiExecution.ts @@ -1,11 +1,5 @@ -import { - AllPlayers, - Execution, - Game, - Player, - PlayerID, - PlayerType, -} from "../game/Game"; +import { AllPlayers, Execution, Game, Player, PlayerID } from "../game/Game"; +import { PlayerType } from "../game/GameUpdates"; import { flattenedEmojiTable } from "../Util"; export class EmojiExecution implements Execution { diff --git a/src/core/execution/FactoryExecution.ts b/src/core/execution/FactoryExecution.ts index 92908ed39..8fca2a19e 100644 --- a/src/core/execution/FactoryExecution.ts +++ b/src/core/execution/FactoryExecution.ts @@ -1,4 +1,5 @@ -import { Execution, Game, Unit, UnitType } from "../game/Game"; +import { Execution, Game, Unit } from "../game/Game"; +import { UnitType } from "../game/GameUpdates"; import { TrainStationExecution } from "./TrainStationExecution"; export class FactoryExecution implements Execution { diff --git a/src/core/execution/FakeHumanExecution.ts b/src/core/execution/FakeHumanExecution.ts index 7e3b64401..328d4d694 100644 --- a/src/core/execution/FakeHumanExecution.ts +++ b/src/core/execution/FakeHumanExecution.ts @@ -7,14 +7,13 @@ import { Nation, Player, PlayerID, - PlayerType, Relation, TerrainType, Tick, Unit, - UnitType, } from "../game/Game"; import { TileRef, euclDistFN } from "../game/GameMap"; +import { PlayerType, UnitType } from "../game/GameUpdates"; import { PseudoRandom } from "../PseudoRandom"; import { GameID } from "../Schemas"; import { boundingBoxTiles, calculateBoundingBox, simpleHash } from "../Util"; diff --git a/src/core/execution/MIRVExecution.ts b/src/core/execution/MIRVExecution.ts index b79a4e1ef..180f1be0d 100644 --- a/src/core/execution/MIRVExecution.ts +++ b/src/core/execution/MIRVExecution.ts @@ -1,13 +1,6 @@ -import { - Execution, - Game, - MessageType, - Player, - TerraNullius, - Unit, - UnitType, -} from "../game/Game"; +import { Execution, Game, Player, TerraNullius, Unit } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { MessageType, UnitType } from "../game/GameUpdates"; import { ParabolaPathFinder } from "../pathfinding/PathFinding"; import { PseudoRandom } from "../PseudoRandom"; import { simpleHash } from "../Util"; diff --git a/src/core/execution/MoveWarshipExecution.ts b/src/core/execution/MoveWarshipExecution.ts index 0a0aad166..f2f3284d0 100644 --- a/src/core/execution/MoveWarshipExecution.ts +++ b/src/core/execution/MoveWarshipExecution.ts @@ -1,5 +1,6 @@ -import { Execution, Game, Player, UnitType } from "../game/Game"; +import { Execution, Game, Player } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { UnitType } from "../game/GameUpdates"; export class MoveWarshipExecution implements Execution { constructor( diff --git a/src/core/execution/NukeExecution.ts b/src/core/execution/NukeExecution.ts index 131533784..101403cb0 100644 --- a/src/core/execution/NukeExecution.ts +++ b/src/core/execution/NukeExecution.ts @@ -2,14 +2,13 @@ import { Execution, Game, isStructureType, - MessageType, Player, TerraNullius, TrajectoryTile, Unit, - UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { MessageType, UnitType } from "../game/GameUpdates"; import { ParabolaPathFinder } from "../pathfinding/PathFinding"; import { PseudoRandom } from "../PseudoRandom"; import { NukeType } from "../StatsSchemas"; diff --git a/src/core/execution/PlayerExecution.ts b/src/core/execution/PlayerExecution.ts index c7e452e5d..ed1329dd2 100644 --- a/src/core/execution/PlayerExecution.ts +++ b/src/core/execution/PlayerExecution.ts @@ -1,6 +1,7 @@ import { Config } from "../configuration/Config"; -import { Execution, Game, Player, UnitType } from "../game/Game"; +import { Execution, Game, Player } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { UnitType } from "../game/GameUpdates"; import { calculateBoundingBox, getMode, inscribed, simpleHash } from "../Util"; interface ClusterTraversalState { diff --git a/src/core/execution/PortExecution.ts b/src/core/execution/PortExecution.ts index 1b042a4a5..fada2da63 100644 --- a/src/core/execution/PortExecution.ts +++ b/src/core/execution/PortExecution.ts @@ -1,4 +1,5 @@ -import { Execution, Game, Unit, UnitType } from "../game/Game"; +import { Execution, Game, Unit } from "../game/Game"; +import { UnitType } from "../game/GameUpdates"; import { PseudoRandom } from "../PseudoRandom"; import { TradeShipExecution } from "./TradeShipExecution"; import { TrainStationExecution } from "./TrainStationExecution"; diff --git a/src/core/execution/RailroadExecution.ts b/src/core/execution/RailroadExecution.ts index 97bc8d1d9..46ed1d8e2 100644 --- a/src/core/execution/RailroadExecution.ts +++ b/src/core/execution/RailroadExecution.ts @@ -27,7 +27,7 @@ export class RailroadExecution implements Execution { railType: tiles.length > 0 ? this.computeExtremityDirection(tiles[0], tiles[1]) - : RailType.VERTICAL, + : RailType.vertical, }); for (let i = 1; i < tiles.length - 1; i++) { const direction = this.computeDirection( @@ -45,7 +45,7 @@ export class RailroadExecution implements Execution { tiles[tiles.length - 1], tiles[tiles.length - 2], ) - : RailType.VERTICAL, + : RailType.vertical, }); } @@ -58,14 +58,14 @@ export class RailroadExecution implements Execution { const dx = nextX - x; const dy = nextY - y; - if (dx === 0 && dy === 0) return RailType.VERTICAL; // No movement + if (dx === 0 && dy === 0) return RailType.vertical; // No movement if (dx === 0) { - return RailType.VERTICAL; + return RailType.vertical; } else if (dy === 0) { - return RailType.HORIZONTAL; + return RailType.horizontal; } - return RailType.VERTICAL; + return RailType.vertical; } private computeDirection( @@ -90,25 +90,25 @@ export class RailroadExecution implements Execution { // Straight line if (dx1 === dx2 && dy1 === dy2) { - if (dx1 !== 0) return RailType.HORIZONTAL; - if (dy1 !== 0) return RailType.VERTICAL; + if (dx1 !== 0) return RailType.horizontal; + if (dy1 !== 0) return RailType.vertical; } // Turn (corner) cases if ((dx1 === 0 && dx2 !== 0) || (dx1 !== 0 && dx2 === 0)) { // Now figure out which type of corner - if (dx1 === 0 && dx2 === 1 && dy1 === -1) return RailType.BOTTOM_RIGHT; - if (dx1 === 0 && dx2 === -1 && dy1 === -1) return RailType.BOTTOM_LEFT; - if (dx1 === 0 && dx2 === 1 && dy1 === 1) return RailType.TOP_RIGHT; - if (dx1 === 0 && dx2 === -1 && dy1 === 1) return RailType.TOP_LEFT; + if (dx1 === 0 && dx2 === 1 && dy1 === -1) return RailType.bottomRight; + if (dx1 === 0 && dx2 === -1 && dy1 === -1) return RailType.bottomLeft; + if (dx1 === 0 && dx2 === 1 && dy1 === 1) return RailType.topRight; + if (dx1 === 0 && dx2 === -1 && dy1 === 1) return RailType.topLeft; - if (dx1 === 1 && dx2 === 0 && dy2 === -1) return RailType.TOP_LEFT; - if (dx1 === -1 && dx2 === 0 && dy2 === -1) return RailType.TOP_RIGHT; - if (dx1 === 1 && dx2 === 0 && dy2 === 1) return RailType.BOTTOM_LEFT; - if (dx1 === -1 && dx2 === 0 && dy2 === 1) return RailType.BOTTOM_RIGHT; + if (dx1 === 1 && dx2 === 0 && dy2 === -1) return RailType.topLeft; + if (dx1 === -1 && dx2 === 0 && dy2 === -1) return RailType.topRight; + if (dx1 === 1 && dx2 === 0 && dy2 === 1) return RailType.bottomLeft; + if (dx1 === -1 && dx2 === 0 && dy2 === 1) return RailType.bottomRight; } console.warn(`Invalid rail segment: ${dx1}:${dy1}, ${dx2}:${dy2}`); - return RailType.VERTICAL; + return RailType.vertical; } tick(ticks: number): void { @@ -144,8 +144,10 @@ export class RailroadExecution implements Execution { if (updatedRailTiles) { this.mg.addUpdate({ type: GameUpdateType.RailroadEvent, - isActive: true, - railTiles: updatedRailTiles, + railroad: { + isActive: true, + railTiles: updatedRailTiles, + }, }); } } diff --git a/src/core/execution/SAMLauncherExecution.ts b/src/core/execution/SAMLauncherExecution.ts index c669b42fd..05cb40cea 100644 --- a/src/core/execution/SAMLauncherExecution.ts +++ b/src/core/execution/SAMLauncherExecution.ts @@ -1,13 +1,6 @@ -import { - Execution, - Game, - isUnit, - MessageType, - Player, - Unit, - UnitType, -} from "../game/Game"; +import { Execution, Game, isUnit, Player, Unit } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { MessageType, UnitType } from "../game/GameUpdates"; import { PseudoRandom } from "../PseudoRandom"; import { SAMMissileExecution } from "./SAMMissileExecution"; diff --git a/src/core/execution/SAMMissileExecution.ts b/src/core/execution/SAMMissileExecution.ts index e313acd8c..4ac918666 100644 --- a/src/core/execution/SAMMissileExecution.ts +++ b/src/core/execution/SAMMissileExecution.ts @@ -1,12 +1,6 @@ -import { - Execution, - Game, - MessageType, - Player, - Unit, - UnitType, -} from "../game/Game"; +import { Execution, Game, Player, Unit } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { MessageType, UnitType } from "../game/GameUpdates"; import { AirPathFinder } from "../pathfinding/PathFinding"; import { PseudoRandom } from "../PseudoRandom"; import { NukeType } from "../StatsSchemas"; diff --git a/src/core/execution/ShellExecution.ts b/src/core/execution/ShellExecution.ts index 4bf1103ec..acc65de36 100644 --- a/src/core/execution/ShellExecution.ts +++ b/src/core/execution/ShellExecution.ts @@ -1,5 +1,6 @@ -import { Execution, Game, Player, Unit, UnitType } from "../game/Game"; +import { Execution, Game, Player, Unit } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { UnitType } from "../game/GameUpdates"; import { AirPathFinder } from "../pathfinding/PathFinding"; import { PseudoRandom } from "../PseudoRandom"; diff --git a/src/core/execution/SpawnExecution.ts b/src/core/execution/SpawnExecution.ts index 57baff6ee..3c254b8e8 100644 --- a/src/core/execution/SpawnExecution.ts +++ b/src/core/execution/SpawnExecution.ts @@ -1,5 +1,6 @@ -import { Execution, Game, Player, PlayerInfo, PlayerType } from "../game/Game"; +import { Execution, Game, Player, PlayerInfo } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { PlayerType } from "../game/GameUpdates"; import { BotExecution } from "./BotExecution"; import { PlayerExecution } from "./PlayerExecution"; import { getSpawnTiles } from "./Util"; diff --git a/src/core/execution/TradeShipExecution.ts b/src/core/execution/TradeShipExecution.ts index 0da513b8e..a1aa4dedc 100644 --- a/src/core/execution/TradeShipExecution.ts +++ b/src/core/execution/TradeShipExecution.ts @@ -1,13 +1,7 @@ import { renderNumber } from "../../client/Utils"; -import { - Execution, - Game, - MessageType, - Player, - Unit, - UnitType, -} from "../game/Game"; +import { Execution, Game, Player, Unit } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { MessageType, UnitType } from "../game/GameUpdates"; import { PathFindResultType } from "../pathfinding/AStar"; import { PathFinder } from "../pathfinding/PathFinding"; import { distSortUnit } from "../Util"; diff --git a/src/core/execution/TrainExecution.ts b/src/core/execution/TrainExecution.ts index 5e165067a..0813b5c63 100644 --- a/src/core/execution/TrainExecution.ts +++ b/src/core/execution/TrainExecution.ts @@ -1,12 +1,6 @@ -import { - Execution, - Game, - Player, - TrainType, - Unit, - UnitType, -} from "../game/Game"; +import { Execution, Game, Player, Unit } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { TrainType, UnitType } from "../game/GameUpdates"; import { RailNetwork } from "../game/RailNetwork"; import { getOrientedRailroad, OrientedRailroad } from "../game/Railroad"; import { TrainStation } from "../game/TrainStation"; diff --git a/src/core/execution/TrainStationExecution.ts b/src/core/execution/TrainStationExecution.ts index af8a5bd3f..b77e4f551 100644 --- a/src/core/execution/TrainStationExecution.ts +++ b/src/core/execution/TrainStationExecution.ts @@ -1,4 +1,5 @@ -import { Execution, Game, Unit, UnitType } from "../game/Game"; +import { Execution, Game, Unit } from "../game/Game"; +import { UnitType } from "../game/GameUpdates"; import { TrainStation } from "../game/TrainStation"; import { PseudoRandom } from "../PseudoRandom"; import { TrainExecution } from "./TrainExecution"; diff --git a/src/core/execution/TransportShipExecution.ts b/src/core/execution/TransportShipExecution.ts index 6e37e066d..e186e0141 100644 --- a/src/core/execution/TransportShipExecution.ts +++ b/src/core/execution/TransportShipExecution.ts @@ -2,14 +2,13 @@ import { renderTroops } from "../../client/Utils"; import { Execution, Game, - MessageType, Player, PlayerID, TerraNullius, Unit, - UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { MessageType, UnitType } from "../game/GameUpdates"; import { targetTransportTile } from "../game/TransportShipUtils"; import { PathFindResultType } from "../pathfinding/AStar"; import { PathFinder } from "../pathfinding/PathFinding"; diff --git a/src/core/execution/WarshipExecution.ts b/src/core/execution/WarshipExecution.ts index 1ddb064cb..86ebf0f9b 100644 --- a/src/core/execution/WarshipExecution.ts +++ b/src/core/execution/WarshipExecution.ts @@ -5,9 +5,9 @@ import { OwnerComp, Unit, UnitParams, - UnitType, } from "../game/Game"; import { TileRef } from "../game/GameMap"; +import { UnitType } from "../game/GameUpdates"; import { PathFindResultType } from "../pathfinding/AStar"; import { PathFinder } from "../pathfinding/PathFinding"; import { PseudoRandom } from "../PseudoRandom"; diff --git a/src/core/execution/alliance/AllianceExtensionExecution.ts b/src/core/execution/alliance/AllianceExtensionExecution.ts index 699d4182d..3c91f66fc 100644 --- a/src/core/execution/alliance/AllianceExtensionExecution.ts +++ b/src/core/execution/alliance/AllianceExtensionExecution.ts @@ -1,10 +1,5 @@ -import { - Execution, - Game, - MessageType, - Player, - PlayerID, -} from "../../game/Game"; +import { Execution, Game, Player, PlayerID } from "../../game/Game"; +import { MessageType } from "../../game/GameUpdates"; export class AllianceExtensionExecution implements Execution { constructor( diff --git a/src/core/execution/nation/structureSpawnTileValue.ts b/src/core/execution/nation/structureSpawnTileValue.ts index b01df682a..84155ed71 100644 --- a/src/core/execution/nation/structureSpawnTileValue.ts +++ b/src/core/execution/nation/structureSpawnTileValue.ts @@ -1,5 +1,6 @@ -import { Game, Player, Relation, UnitType } from "../../game/Game"; +import { Game, Player, Relation } from "../../game/Game"; import { TileRef } from "../../game/GameMap"; +import { UnitType } from "../../game/GameUpdates"; import { closestTile, closestTwoTiles } from "../Util"; export function structureSpawnTileValue( diff --git a/src/core/execution/utils/AllianceBehavior.ts b/src/core/execution/utils/AllianceBehavior.ts index 781b0e359..ba4a5ef49 100644 --- a/src/core/execution/utils/AllianceBehavior.ts +++ b/src/core/execution/utils/AllianceBehavior.ts @@ -1,10 +1,5 @@ -import { - Difficulty, - Game, - Player, - PlayerType, - Relation, -} from "../../game/Game"; +import { Difficulty, Game, Player, Relation } from "../../game/Game"; +import { PlayerType } from "../../game/GameUpdates"; import { PseudoRandom } from "../../PseudoRandom"; import { AllianceExtensionExecution } from "../alliance/AllianceExtensionExecution"; import { AllianceRequestExecution } from "../alliance/AllianceRequestExecution"; diff --git a/src/core/execution/utils/BotBehavior.ts b/src/core/execution/utils/BotBehavior.ts index 2d79275c3..06e48e7bb 100644 --- a/src/core/execution/utils/BotBehavior.ts +++ b/src/core/execution/utils/BotBehavior.ts @@ -2,11 +2,11 @@ import { Difficulty, Game, Player, - PlayerType, Relation, TerraNullius, Tick, } from "../../game/Game"; +import { PlayerType } from "../../game/GameUpdates"; import { PseudoRandom } from "../../PseudoRandom"; import { boundingBoxCenter, diff --git a/src/core/execution/utils/PlayerSpawner.ts b/src/core/execution/utils/PlayerSpawner.ts index 29c0fe1a6..439717638 100644 --- a/src/core/execution/utils/PlayerSpawner.ts +++ b/src/core/execution/utils/PlayerSpawner.ts @@ -1,5 +1,6 @@ -import { Game, PlayerType } from "../../game/Game"; +import { Game } from "../../game/Game"; import { TileRef } from "../../game/GameMap"; +import { PlayerType } from "../../game/GameUpdates"; import { PseudoRandom } from "../../PseudoRandom"; import { GameID } from "../../Schemas"; import { simpleHash } from "../../Util"; diff --git a/src/core/game/AllianceRequestImpl.ts b/src/core/game/AllianceRequestImpl.ts index b40247329..cc47c9e2a 100644 --- a/src/core/game/AllianceRequestImpl.ts +++ b/src/core/game/AllianceRequestImpl.ts @@ -1,6 +1,6 @@ import { AllianceRequest, Player, Tick } from "./Game"; import { GameImpl } from "./GameImpl"; -import { AllianceRequestUpdate, GameUpdateType } from "./GameUpdates"; +import { GameUpdate, GameUpdateType } from "./GameUpdates"; export class AllianceRequestImpl implements AllianceRequest { private status_: "pending" | "accepted" | "rejected" = "pending"; @@ -37,12 +37,14 @@ export class AllianceRequestImpl implements AllianceRequest { this.game.rejectAllianceRequest(this); } - toUpdate(): AllianceRequestUpdate { + toUpdate(): GameUpdate { return { type: GameUpdateType.AllianceRequest, - requestorID: this.requestor_.smallID(), - recipientID: this.recipient_.smallID(), - createdAt: this.tickCreated, + allianceRequest: { + requestorId: this.requestor_.smallID(), + recipientId: this.recipient_.smallID(), + createdAt: this.tickCreated, + }, }; } } diff --git a/src/core/game/Game.ts b/src/core/game/Game.ts index a3cb9f4c3..7f30bb6ae 100644 --- a/src/core/game/Game.ts +++ b/src/core/game/Game.ts @@ -3,9 +3,14 @@ import { AllPlayersStats, ClientID } from "../Schemas"; import { getClanTag } from "../Util"; import { GameMap, TileRef } from "./GameMap"; import { + EmojiMessage, GameUpdate, - GameUpdateType, - PlayerUpdate, + GameUpdateViewData, + MessageCategory, + MessageType, + PlayerType, + TrainType, + UnitType, UnitUpdate, } from "./GameUpdates"; import { RailNetwork } from "./RailNetwork"; @@ -25,14 +30,9 @@ export type Gold = bigint; export const AllPlayers = "AllPlayers" as const; -// export type GameUpdates = Record; -// Create a type that maps GameUpdateType to its corresponding update type -type UpdateTypeMap = Extract; - -// Then use it to create the record type -export type GameUpdates = { - [K in GameUpdateType]: UpdateTypeMap[]; -}; +export const AllUnitTypes = Object.values(UnitType).filter( + (v): v is UnitType => typeof v === "number", +) as UnitType[]; export interface MapPos { x: number; @@ -188,30 +188,6 @@ export interface UnitInfo { experimental?: boolean; } -export enum UnitType { - TransportShip = "Transport", - Warship = "Warship", - Shell = "Shell", - SAMMissile = "SAMMissile", - Port = "Port", - AtomBomb = "Atom Bomb", - HydrogenBomb = "Hydrogen Bomb", - TradeShip = "Trade Ship", - MissileSilo = "Missile Silo", - DefensePost = "Defense Post", - SAMLauncher = "SAM Launcher", - City = "City", - MIRV = "MIRV", - MIRVWarhead = "MIRV Warhead", - Train = "Train", - Factory = "Factory", -} - -export enum TrainType { - Engine = "Engine", - Carriage = "Carriage", -} - const _structureTypes: ReadonlySet = new Set([ UnitType.City, UnitType.DefensePost, @@ -290,7 +266,7 @@ export interface UnitParamsMap { } // Type helper to get params type for a specific unit type -export type UnitParams = UnitParamsMap[T]; +export type UnitParams = UnitParamsMap[T]; export type AllUnitParams = UnitParamsMap[keyof UnitParamsMap]; @@ -347,12 +323,6 @@ export enum TerrainType { Ocean, } -export enum PlayerType { - Bot = "BOT", - Human = "HUMAN", - FakeHuman = "FAKEHUMAN", -} - export interface Execution { isActive(): boolean; activeDuringSpawnPhase(): boolean; @@ -579,7 +549,7 @@ export interface Player { buildUnit( type: T, spawnTile: TileRef, - params: UnitParams, + params: UnitParams, ): Unit; // Returns the existing unit that can be upgraded, @@ -660,7 +630,7 @@ export interface Player { executeRetreat(attackID: string): void; // Misc - toUpdate(): PlayerUpdate; + toUpdate(): GameUpdate; playerProfile(): PlayerProfile; // WARNING: this operation is expensive. bestTransportShipSpawn(tile: TileRef): TileRef | false; @@ -704,7 +674,7 @@ export interface Game extends GameMap { // Game State ticks(): Tick; inSpawnPhase(): boolean; - executeNextTick(): GameUpdates; + executeNextTick(): GameUpdateViewData; setWinner(winner: Player | Team, allPlayersStats: AllPlayersStats): void; config(): Config; @@ -799,52 +769,8 @@ export interface PlayerInteraction { allianceExpiresAt?: Tick; } -export interface EmojiMessage { - message: string; - senderID: number; - recipientID: number | typeof AllPlayers; - createdAt: Tick; -} - -export enum MessageType { - ATTACK_FAILED, - ATTACK_CANCELLED, - ATTACK_REQUEST, - CONQUERED_PLAYER, - MIRV_INBOUND, - NUKE_INBOUND, - HYDROGEN_BOMB_INBOUND, - NAVAL_INVASION_INBOUND, - SAM_MISS, - SAM_HIT, - CAPTURED_ENEMY_UNIT, - UNIT_CAPTURED_BY_ENEMY, - UNIT_DESTROYED, - ALLIANCE_ACCEPTED, - ALLIANCE_REJECTED, - ALLIANCE_REQUEST, - ALLIANCE_BROKEN, - ALLIANCE_EXPIRED, - SENT_GOLD_TO_PLAYER, - RECEIVED_GOLD_FROM_PLAYER, - RECEIVED_GOLD_FROM_TRADE, - SENT_TROOPS_TO_PLAYER, - RECEIVED_TROOPS_FROM_PLAYER, - CHAT, - RENEW_ALLIANCE, -} - -// Message categories used for filtering events in the EventsDisplay -export enum MessageCategory { - ATTACK = "ATTACK", - NUKE = "NUKE", - ALLIANCE = "ALLIANCE", - TRADE = "TRADE", - CHAT = "CHAT", -} - // Ensures that all message types are included in a category -export const MESSAGE_TYPE_CATEGORIES: Record = { +export const MESSAGE_TYPE_CATEGORIES: Record = { [MessageType.ATTACK_FAILED]: MessageCategory.ATTACK, [MessageType.ATTACK_CANCELLED]: MessageCategory.ATTACK, [MessageType.ATTACK_REQUEST]: MessageCategory.ATTACK, @@ -869,7 +795,7 @@ export const MESSAGE_TYPE_CATEGORIES: Record = { [MessageType.RECEIVED_GOLD_FROM_TRADE]: MessageCategory.TRADE, [MessageType.SENT_TROOPS_TO_PLAYER]: MessageCategory.TRADE, [MessageType.RECEIVED_TROOPS_FROM_PLAYER]: MessageCategory.TRADE, - [MessageType.CHAT]: MessageCategory.CHAT, + [MessageType.CHAT]: MessageCategory.CHAT_CATEGORY, } as const; /** @@ -878,9 +804,3 @@ export const MESSAGE_TYPE_CATEGORIES: Record = { export function getMessageCategory(messageType: MessageType): MessageCategory { return MESSAGE_TYPE_CATEGORIES[messageType]; } - -export interface NameViewData { - x: number; - y: number; - size: number; -} diff --git a/src/core/game/GameImpl.ts b/src/core/game/GameImpl.ts index 61a6e38d7..59eac11c7 100644 --- a/src/core/game/GameImpl.ts +++ b/src/core/game/GameImpl.ts @@ -10,19 +10,15 @@ import { Cell, ColoredTeams, Duos, - EmojiMessage, Execution, Game, GameMode, - GameUpdates, HumansVsNations, - MessageType, MutableAlliance, Nation, Player, PlayerID, PlayerInfo, - PlayerType, Quads, Team, TerrainType, @@ -30,10 +26,18 @@ import { Trios, Unit, UnitInfo, - UnitType, } from "./Game"; import { GameMap, TileRef, TileUpdate } from "./GameMap"; -import { GameUpdate, GameUpdateType } from "./GameUpdates"; +import { + EmojiMessage, + GameUpdate, + GameUpdates, + GameUpdateType, + GameUpdateViewData, + MessageType, + PlayerType, + UnitType, +} from "./GameUpdates"; import { PlayerImpl } from "./PlayerImpl"; import { RailNetwork } from "./RailNetwork"; import { createRailNetwork } from "./RailNetworkImpl"; @@ -75,7 +79,7 @@ export class GameImpl implements Game { private nextPlayerID = 1; private _nextUnitID = 1; - private updates: GameUpdates = createGameUpdatesMap(); + private gameViewData = createGameUpdateViewData(); private unitGrid: UnitGrid; private playerTeams: Team[]; @@ -197,12 +201,17 @@ export class GameImpl implements Game { map(): GameMap { return this._map; } + miniMap(): GameMap { return this.miniGameMap; } + addTileUpdate(tile: TileRef) { + this.gameViewData.tileUpdates.push(Number(this.toTileUpdate(tile))); + } + addUpdate(update: GameUpdate) { - (this.updates[update.type] as GameUpdate[]).push(update); + this.gameViewData.updates[update.type].updates.push(update); } nextUnitID(): number { @@ -219,10 +228,7 @@ export class GameImpl implements Game { return; } this._map.setFallout(tile, value); - this.addUpdate({ - type: GameUpdateType.Tile, - update: this.toTileUpdate(tile), - }); + this.addTileUpdate(tile); } units(...types: UnitType[]): Unit[] { @@ -311,8 +317,14 @@ export class GameImpl implements Game { this.addUpdate({ type: GameUpdateType.AllianceRequestReply, - request: request.toUpdate(), - accepted: true, + allianceRequestReply: { + request: { + requestorId: requestor.smallID(), + recipientId: recipient.smallID(), + createdAt: request.createdAt(), + }, + accepted: true, + }, }); } @@ -325,8 +337,14 @@ export class GameImpl implements Game { ); this.addUpdate({ type: GameUpdateType.AllianceRequestReply, - request: request.toUpdate(), - accepted: false, + allianceRequestReply: { + request: { + requestorId: request.requestor().smallID(), + recipientId: request.recipient().smallID(), + createdAt: request.createdAt(), + }, + accepted: false, + }, }); } @@ -345,8 +363,8 @@ export class GameImpl implements Game { return this._ticks; } - executeNextTick(): GameUpdates { - this.updates = createGameUpdatesMap(); + executeNextTick(): GameUpdateViewData { + this.gameViewData = createGameUpdateViewData(); this.execs.forEach((e) => { if ( (!this.inSpawnPhase() || e.activeDuringSpawnPhase()) && @@ -377,12 +395,14 @@ export class GameImpl implements Game { if (this.ticks() % 10 === 0) { this.addUpdate({ type: GameUpdateType.Hash, - tick: this.ticks(), - hash: this.hash(), + hash: { + tick: this.ticks(), + hash: this.hash(), + }, }); } this._ticks++; - return this.updates; + return this.gameViewData; } private hash(): number { @@ -556,10 +576,7 @@ export class GameImpl implements Game { owner._lastTileChange = this._ticks; this.updateBorders(tile); this._map.setFallout(tile, false); - this.addUpdate({ - type: GameUpdateType.Tile, - update: this.toTileUpdate(tile), - }); + this.addTileUpdate(tile); } relinquish(tile: TileRef) { @@ -577,10 +594,7 @@ export class GameImpl implements Game { this._map.setOwnerID(tile, 0); this.updateBorders(tile); - this.addUpdate({ - type: GameUpdateType.Tile, - update: this.toTileUpdate(tile), - }); + this.addTileUpdate(tile); } private updateBorders(tile: TileRef) { @@ -616,8 +630,10 @@ export class GameImpl implements Game { target(targeter: Player, target: Player) { this.addUpdate({ type: GameUpdateType.TargetPlayer, - playerID: targeter.smallID(), - targetID: target.smallID(), + targetPlayer: { + playerId: targeter.smallID(), + targetId: target.smallID(), + }, }); } @@ -647,8 +663,10 @@ export class GameImpl implements Game { this.alliances_ = this.alliances_.filter((a) => a !== alliances[0]); this.addUpdate({ type: GameUpdateType.BrokeAlliance, - traitorID: breaker.smallID(), - betrayedID: other.smallID(), + brokeAlliance: { + traitorId: breaker.smallID(), + betrayedId: other.smallID(), + }, }); } @@ -666,23 +684,29 @@ export class GameImpl implements Game { this.alliances_ = this.alliances_.filter((a) => a !== alliances[0]); this.addUpdate({ type: GameUpdateType.AllianceExpired, - player1ID: alliance.requestor().smallID(), - player2ID: alliance.recipient().smallID(), + allianceExpired: { + player1Id: alliance.requestor().smallID(), + player2Id: alliance.recipient().smallID(), + }, }); } sendEmojiUpdate(msg: EmojiMessage): void { this.addUpdate({ type: GameUpdateType.Emoji, - emoji: msg, + emoji: { + emoji: msg, + }, }); } setWinner(winner: Player | Team, allPlayersStats: AllPlayersStats): void { this.addUpdate({ type: GameUpdateType.Win, - winner: this.makeWinner(winner), - allPlayersStats, + win: { + winner: JSON.stringify(this.makeWinner(winner)), + stats: JSON.stringify(allPlayersStats), + }, }); } @@ -718,7 +742,7 @@ export class GameImpl implements Game { type: MessageType, playerID: PlayerID | null, goldAmount?: bigint, - params?: Record, + params?: Record, ): void { let id: number | null = null; if (playerID !== null) { @@ -726,11 +750,13 @@ export class GameImpl implements Game { } this.addUpdate({ type: GameUpdateType.DisplayEvent, - messageType: type, - message: message, - playerID: id, - goldAmount: goldAmount, - params: params, + displayMessage: { + message: message, + messageType: type, + playerId: id ?? undefined, + goldAmount: Number(goldAmount), + params: params ?? {}, + }, }); } @@ -748,12 +774,14 @@ export class GameImpl implements Game { } this.addUpdate({ type: GameUpdateType.DisplayChatEvent, - key: message, - category: category, - target: target, - playerID: id, - isFrom, - recipient: recipient, + displayChatMessage: { + key: message, + category: category, + target: target, + playerId: id ?? undefined, + isFrom: isFrom, + recipient: recipient, + }, }); } @@ -767,10 +795,12 @@ export class GameImpl implements Game { this.addUpdate({ type: GameUpdateType.UnitIncoming, - unitID: unitID, - message: message, - messageType: type, - playerID: id, + unitIncoming: { + unitId: unitID, + message: message, + messageType: type, + playerId: id, + }, }); } @@ -964,9 +994,11 @@ export class GameImpl implements Game { conquered.removeGold(gold); this.addUpdate({ type: GameUpdateType.ConquestEvent, - conquerorId: conqueror.id(), - conqueredId: conquered.id(), - gold, + conquest: { + conquerorId: conqueror.smallID(), + conqueredId: conquered.smallID(), + gold: Number(gold), + }, }); // Record stats @@ -975,12 +1007,25 @@ export class GameImpl implements Game { } // Or a more dynamic approach that will catch new enum values: -const createGameUpdatesMap = (): GameUpdates => { - const map = {} as GameUpdates; +const createGameUpdatesMap = (): Record => { + const map = {} as Record; Object.values(GameUpdateType) .filter((key) => !isNaN(Number(key))) // Filter out reverse mappings .forEach((key) => { - map[key as GameUpdateType] = []; + map[key as GameUpdateType] = { + type: key as GameUpdateType, + updates: [], + }; }); return map; }; + +const createGameUpdateViewData = (): GameUpdateViewData => { + return { + tick: 0, + updates: createGameUpdatesMap(), + tileUpdates: [], + playerNameViewData: {}, + tickExecutionDuration: undefined, + }; +}; diff --git a/src/core/game/GameUpdates.proto b/src/core/game/GameUpdates.proto new file mode 100644 index 000000000..3f0315fce --- /dev/null +++ b/src/core/game/GameUpdates.proto @@ -0,0 +1,337 @@ +syntax = "proto3"; + +package game; + +enum PlayerType { + Bot = 0; + Human = 1; + FakeHuman = 2; +} + +enum UnitType { + TransportShip = 0; + Warship = 1; + Shell = 2; + SAMMissile = 3; + Port = 4; + AtomBomb = 5; + HydrogenBomb = 6; + TradeShip = 7; + MissileSilo = 8; + DefensePost = 9; + SAMLauncher = 10; + City = 11; + MIRV = 12; + MIRVWarhead = 13; + Train = 14; + Factory = 15; +} + +enum TrainType { + Engine = 0; + Carriage = 1; +} + +message NameViewData { + int32 x = 1; + int32 y = 2; + int32 size = 3; +} + +message EmojiMessage { + int32 sender_id = 1; + string emoji = 2; + oneof recipient { + bool allPlayers = 3; + int32 recipient_id = 4; + } + int32 createdAt = 5; +} + +// Enums +enum GameUpdateType { + Tile = 0; + Unit = 1; + Player = 2; + DisplayEvent = 3; + DisplayChatEvent = 4; + AllianceRequest = 5; + AllianceRequestReply = 6; + BrokeAlliance = 7; + AllianceExpired = 8; + AllianceExtension = 9; + TargetPlayer = 10; + Emoji = 11; + Win = 12; + Hash = 13; + UnitIncoming = 14; + BonusEvent = 15; + RailroadEvent = 16; + ConquestEvent = 17; + EmbargoEvent = 18; +} + +enum MessageType { + messageTypeUnspecified = 0; + ATTACK_FAILED = 1; + ATTACK_CANCELLED = 2; + ATTACK_REQUEST = 3; + CONQUERED_PLAYER = 4; + MIRV_INBOUND = 5; + NUKE_INBOUND = 6; + HYDROGEN_BOMB_INBOUND = 7; + NAVAL_INVASION_INBOUND = 8; + SAM_MISS = 9; + SAM_HIT = 10; + CAPTURED_ENEMY_UNIT = 11; + UNIT_CAPTURED_BY_ENEMY = 12; + UNIT_DESTROYED = 13; + ALLIANCE_ACCEPTED = 14; + ALLIANCE_REJECTED = 15; + ALLIANCE_REQUEST = 16; + ALLIANCE_BROKEN = 17; + ALLIANCE_EXPIRED = 18; + SENT_GOLD_TO_PLAYER = 19; + RECEIVED_GOLD_FROM_PLAYER = 20; + RECEIVED_GOLD_FROM_TRADE = 21; + SENT_TROOPS_TO_PLAYER = 22; + RECEIVED_TROOPS_FROM_PLAYER = 23; + CHAT = 24; + RENEW_ALLIANCE = 25; +} + +enum MessageCategory { + messageCategoryUnspecified = 0; + ATTACK = 1; + NUKE = 2; + ALLIANCE = 3; + TRADE = 4; + CHAT_CATEGORY = 5; +} + +enum RailType { + vertical = 0; + horizontal = 1; + topLeft = 2; + topRight = 3; + bottomLeft = 4; + bottomRight = 5; +} + +// Update messages +message BonusEventUpdate { + string player = 1; + int64 tile = 2; // TileRef encoded as int64 + int64 gold = 3; + int64 troops = 4; +} + +message RailTile { + int64 tile = 1; // TileRef encoded as int64 + RailType rail_type = 2; +} + +message RailroadUpdate { + bool is_active = 1; + repeated RailTile rail_tiles = 2; +} + +message ConquestUpdate { + int32 conqueror_id = 1; + int32 conquered_id = 2; + int64 gold = 3; +} + +message UnitUpdate { + GameUpdateType type = 22; + UnitType unit_type = 1; + int32 troops = 2; + int32 id = 3; + int32 owner_id = 4; + optional int32 last_owner_id = 5; + int64 pos = 6; // TileRef encoded as int64 + int64 last_pos = 7; // TileRef encoded as int64 + bool is_active = 8; + bool reached_target = 9; + bool retreating = 10; + bool targetable = 11; + oneof marked_for_deletion_value { + int32 marked_for_deletion = 12; + } + optional int32 target_unit_id = 13; // Only for trade ships + optional int64 target_tile = 14; // TileRef encoded as int64, only for nukes + optional int32 health = 15; + optional bool under_construction = 16; + repeated int32 missile_timer_queue = 17; + int32 level = 18; + bool has_train_station = 19; + optional TrainType train_type = 20; // Only for trains + optional bool loaded = 21; // Only for trains +} + +message AttackUpdate { + int32 attacker_id = 1; + int32 target_id = 2; + int32 troops = 3; + string id = 4; + bool retreating = 5; +} + +message AllianceView { + int32 id = 1; + string other = 2; + int32 created_at = 3; + int32 expires_at = 4; + bool has_extension_request = 5; +} + +message PlayerUpdate { + optional NameViewData name_view_data = 1; + optional string client_id = 2; + string name = 3; + string display_name = 4; + string id = 5; + optional string team = 6; + int32 small_id = 7; + PlayerType player_type = 8; + bool is_alive = 9; + bool is_disconnected = 10; + int32 tiles_owned = 11; + uint64 gold = 12; + int32 troops = 13; + repeated int32 allies = 14; + repeated string embargoes = 15; + bool is_traitor = 16; + optional int32 traitor_remaining_ticks = 17; + repeated int32 targets = 18; + repeated EmojiMessage outgoing_emojis = 19; + repeated AttackUpdate outgoing_attacks = 20; + repeated AttackUpdate incoming_attacks = 21; + repeated string outgoing_alliance_requests = 22; + repeated AllianceView alliances = 23; + bool has_spawned = 24; + int32 betrayals = 25; + int32 last_delete_unit_tick = 26; +} + +message AllianceRequestUpdate { + int32 requestor_id = 1; + int32 recipient_id = 2; + int32 created_at = 3; +} + +message AllianceRequestReplyUpdate { + AllianceRequestUpdate request = 1; + bool accepted = 2; +} + +message BrokeAllianceUpdate { + int32 traitor_id = 1; + int32 betrayed_id = 2; +} + +message AllianceExpiredUpdate { + int32 player1_id = 1; + int32 player2_id = 2; +} + +message AllianceExtensionUpdate { + string player_id = 1; + int32 alliance_id = 2; +} + +message TargetPlayerUpdate { + int32 player_id = 1; + int32 target_id = 2; +} + +message EmojiUpdate { + EmojiMessage emoji = 1; +} + +message DisplayMessageUpdate { + string message = 1; + MessageType message_type = 2; + optional int64 gold_amount = 3; + optional int64 player_id = 4; + map params = 5; +} + +message DisplayChatMessageUpdate { + string key = 1; + string category = 2; + optional string target = 3; + optional int32 player_id = 4; + bool is_from = 5; + string recipient = 6; +} + +message WinUpdate { + string winner = 1; + string stats = 2; +} + +message HashUpdate { + int32 tick = 1; + int32 hash = 2; +} + +message UnitIncomingUpdate { + int32 unit_id = 1; + string message = 2; + MessageType message_type = 3; + int32 player_id = 4; +} + +message EmbargoUpdate { + enum EmbargoEvent { + start = 0; + stop = 1; + } + EmbargoEvent event = 1; + int32 player_id = 2; + int32 embargoed_id = 3; +} + +// Main GameUpdate message using oneof for polymorphism +message GameUpdate { + GameUpdateType type = 1; + oneof update { + UnitUpdate unit = 3; + PlayerUpdate player = 4; + AllianceRequestUpdate alliance_request = 5; + AllianceRequestReplyUpdate alliance_request_reply = 6; + BrokeAllianceUpdate broke_alliance = 7; + AllianceExpiredUpdate alliance_expired = 8; + DisplayMessageUpdate display_message = 9; + DisplayChatMessageUpdate display_chat_message = 10; + TargetPlayerUpdate target_player = 11; + EmojiUpdate emoji = 12; + WinUpdate win = 13; + HashUpdate hash = 14; + UnitIncomingUpdate unit_incoming = 15; + AllianceExtensionUpdate alliance_extension = 16; + BonusEventUpdate bonus_event = 17; + RailroadUpdate railroad = 18; + ConquestUpdate conquest = 19; + EmbargoUpdate embargo = 20; + } +} + +message GameUpdates { + GameUpdateType type = 1; + repeated GameUpdate updates = 2; +} + +message GameUpdateViewData { + int32 tick = 1; + map updates = 2; + repeated int64 tile_updates = 3; + map player_name_view_data = 4; + optional double tick_execution_duration = 5; +} + +message ErrorUpdate { + string err_msg = 1; + optional string stack = 2; +} diff --git a/src/core/game/GameUpdates.ts b/src/core/game/GameUpdates.ts index c558a3391..1f0c5f869 100644 --- a/src/core/game/GameUpdates.ts +++ b/src/core/game/GameUpdates.ts @@ -1,271 +1,5498 @@ -import { AllPlayersStats, ClientID, Winner } from "../Schemas"; -import { - EmojiMessage, - GameUpdates, - Gold, - MessageType, - NameViewData, - PlayerID, - PlayerType, - Team, - Tick, - TrainType, - UnitType, -} from "./Game"; -import { TileRef, TileUpdate } from "./GameMap"; +// Code generated by protoc-gen-ts_proto. DO NOT EDIT. +// versions: +// protoc-gen-ts_proto v2.8.3 +// protoc v6.33.2 +// source: src/core/game/GameUpdates.proto -export interface GameUpdateViewData { - tick: number; - updates: GameUpdates; - packedTileUpdates: BigUint64Array; - playerNameViewData: Record; - tickExecutionDuration?: number; +/* eslint-disable */ +import { BinaryReader, BinaryWriter } from "@bufbuild/protobuf/wire"; + +export const protobufPackage = "game"; + +export enum PlayerType { + Bot = 0, + Human = 1, + FakeHuman = 2, } -export interface ErrorUpdate { - errMsg: string; - stack?: string; +export function playerTypeFromJSON(object: any): PlayerType { + switch (object) { + case 0: + case "Bot": + return PlayerType.Bot; + case 1: + case "Human": + return PlayerType.Human; + case 2: + case "FakeHuman": + return PlayerType.FakeHuman; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum PlayerType", + ); + } } +export function playerTypeToJSON(object: PlayerType): string { + switch (object) { + case PlayerType.Bot: + return "Bot"; + case PlayerType.Human: + return "Human"; + case PlayerType.FakeHuman: + return "FakeHuman"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum PlayerType", + ); + } +} + +export enum UnitType { + TransportShip = 0, + Warship = 1, + Shell = 2, + SAMMissile = 3, + Port = 4, + AtomBomb = 5, + HydrogenBomb = 6, + TradeShip = 7, + MissileSilo = 8, + DefensePost = 9, + SAMLauncher = 10, + City = 11, + MIRV = 12, + MIRVWarhead = 13, + Train = 14, + Factory = 15, +} + +export function unitTypeFromJSON(object: any): UnitType { + switch (object) { + case 0: + case "TransportShip": + return UnitType.TransportShip; + case 1: + case "Warship": + return UnitType.Warship; + case 2: + case "Shell": + return UnitType.Shell; + case 3: + case "SAMMissile": + return UnitType.SAMMissile; + case 4: + case "Port": + return UnitType.Port; + case 5: + case "AtomBomb": + return UnitType.AtomBomb; + case 6: + case "HydrogenBomb": + return UnitType.HydrogenBomb; + case 7: + case "TradeShip": + return UnitType.TradeShip; + case 8: + case "MissileSilo": + return UnitType.MissileSilo; + case 9: + case "DefensePost": + return UnitType.DefensePost; + case 10: + case "SAMLauncher": + return UnitType.SAMLauncher; + case 11: + case "City": + return UnitType.City; + case 12: + case "MIRV": + return UnitType.MIRV; + case 13: + case "MIRVWarhead": + return UnitType.MIRVWarhead; + case 14: + case "Train": + return UnitType.Train; + case 15: + case "Factory": + return UnitType.Factory; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum UnitType", + ); + } +} + +export function unitTypeToJSON(object: UnitType): string { + switch (object) { + case UnitType.TransportShip: + return "TransportShip"; + case UnitType.Warship: + return "Warship"; + case UnitType.Shell: + return "Shell"; + case UnitType.SAMMissile: + return "SAMMissile"; + case UnitType.Port: + return "Port"; + case UnitType.AtomBomb: + return "AtomBomb"; + case UnitType.HydrogenBomb: + return "HydrogenBomb"; + case UnitType.TradeShip: + return "TradeShip"; + case UnitType.MissileSilo: + return "MissileSilo"; + case UnitType.DefensePost: + return "DefensePost"; + case UnitType.SAMLauncher: + return "SAMLauncher"; + case UnitType.City: + return "City"; + case UnitType.MIRV: + return "MIRV"; + case UnitType.MIRVWarhead: + return "MIRVWarhead"; + case UnitType.Train: + return "Train"; + case UnitType.Factory: + return "Factory"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum UnitType", + ); + } +} + +export enum TrainType { + Engine = 0, + Carriage = 1, +} + +export function trainTypeFromJSON(object: any): TrainType { + switch (object) { + case 0: + case "Engine": + return TrainType.Engine; + case 1: + case "Carriage": + return TrainType.Carriage; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum TrainType", + ); + } +} + +export function trainTypeToJSON(object: TrainType): string { + switch (object) { + case TrainType.Engine: + return "Engine"; + case TrainType.Carriage: + return "Carriage"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum TrainType", + ); + } +} + +/** Enums */ export enum GameUpdateType { - Tile, - Unit, - Player, - DisplayEvent, - DisplayChatEvent, - AllianceRequest, - AllianceRequestReply, - BrokeAlliance, - AllianceExpired, - AllianceExtension, - TargetPlayer, - Emoji, - Win, - Hash, - UnitIncoming, - BonusEvent, - RailroadEvent, - ConquestEvent, - EmbargoEvent, + Tile = 0, + Unit = 1, + Player = 2, + DisplayEvent = 3, + DisplayChatEvent = 4, + AllianceRequest = 5, + AllianceRequestReply = 6, + BrokeAlliance = 7, + AllianceExpired = 8, + AllianceExtension = 9, + TargetPlayer = 10, + Emoji = 11, + Win = 12, + Hash = 13, + UnitIncoming = 14, + BonusEvent = 15, + RailroadEvent = 16, + ConquestEvent = 17, + EmbargoEvent = 18, } -export type GameUpdate = - | TileUpdateWrapper - | UnitUpdate - | PlayerUpdate - | AllianceRequestUpdate - | AllianceRequestReplyUpdate - | BrokeAllianceUpdate - | AllianceExpiredUpdate - | DisplayMessageUpdate - | DisplayChatMessageUpdate - | TargetPlayerUpdate - | EmojiUpdate - | WinUpdate - | HashUpdate - | UnitIncomingUpdate - | AllianceExtensionUpdate - | BonusEventUpdate - | RailroadUpdate - | ConquestUpdate - | EmbargoUpdate; +export function gameUpdateTypeFromJSON(object: any): GameUpdateType { + switch (object) { + case 0: + case "Tile": + return GameUpdateType.Tile; + case 1: + case "Unit": + return GameUpdateType.Unit; + case 2: + case "Player": + return GameUpdateType.Player; + case 3: + case "DisplayEvent": + return GameUpdateType.DisplayEvent; + case 4: + case "DisplayChatEvent": + return GameUpdateType.DisplayChatEvent; + case 5: + case "AllianceRequest": + return GameUpdateType.AllianceRequest; + case 6: + case "AllianceRequestReply": + return GameUpdateType.AllianceRequestReply; + case 7: + case "BrokeAlliance": + return GameUpdateType.BrokeAlliance; + case 8: + case "AllianceExpired": + return GameUpdateType.AllianceExpired; + case 9: + case "AllianceExtension": + return GameUpdateType.AllianceExtension; + case 10: + case "TargetPlayer": + return GameUpdateType.TargetPlayer; + case 11: + case "Emoji": + return GameUpdateType.Emoji; + case 12: + case "Win": + return GameUpdateType.Win; + case 13: + case "Hash": + return GameUpdateType.Hash; + case 14: + case "UnitIncoming": + return GameUpdateType.UnitIncoming; + case 15: + case "BonusEvent": + return GameUpdateType.BonusEvent; + case 16: + case "RailroadEvent": + return GameUpdateType.RailroadEvent; + case 17: + case "ConquestEvent": + return GameUpdateType.ConquestEvent; + case 18: + case "EmbargoEvent": + return GameUpdateType.EmbargoEvent; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum GameUpdateType", + ); + } +} +export function gameUpdateTypeToJSON(object: GameUpdateType): string { + switch (object) { + case GameUpdateType.Tile: + return "Tile"; + case GameUpdateType.Unit: + return "Unit"; + case GameUpdateType.Player: + return "Player"; + case GameUpdateType.DisplayEvent: + return "DisplayEvent"; + case GameUpdateType.DisplayChatEvent: + return "DisplayChatEvent"; + case GameUpdateType.AllianceRequest: + return "AllianceRequest"; + case GameUpdateType.AllianceRequestReply: + return "AllianceRequestReply"; + case GameUpdateType.BrokeAlliance: + return "BrokeAlliance"; + case GameUpdateType.AllianceExpired: + return "AllianceExpired"; + case GameUpdateType.AllianceExtension: + return "AllianceExtension"; + case GameUpdateType.TargetPlayer: + return "TargetPlayer"; + case GameUpdateType.Emoji: + return "Emoji"; + case GameUpdateType.Win: + return "Win"; + case GameUpdateType.Hash: + return "Hash"; + case GameUpdateType.UnitIncoming: + return "UnitIncoming"; + case GameUpdateType.BonusEvent: + return "BonusEvent"; + case GameUpdateType.RailroadEvent: + return "RailroadEvent"; + case GameUpdateType.ConquestEvent: + return "ConquestEvent"; + case GameUpdateType.EmbargoEvent: + return "EmbargoEvent"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum GameUpdateType", + ); + } +} + +export enum MessageType { + messageTypeUnspecified = 0, + ATTACK_FAILED = 1, + ATTACK_CANCELLED = 2, + ATTACK_REQUEST = 3, + CONQUERED_PLAYER = 4, + MIRV_INBOUND = 5, + NUKE_INBOUND = 6, + HYDROGEN_BOMB_INBOUND = 7, + NAVAL_INVASION_INBOUND = 8, + SAM_MISS = 9, + SAM_HIT = 10, + CAPTURED_ENEMY_UNIT = 11, + UNIT_CAPTURED_BY_ENEMY = 12, + UNIT_DESTROYED = 13, + ALLIANCE_ACCEPTED = 14, + ALLIANCE_REJECTED = 15, + ALLIANCE_REQUEST = 16, + ALLIANCE_BROKEN = 17, + ALLIANCE_EXPIRED = 18, + SENT_GOLD_TO_PLAYER = 19, + RECEIVED_GOLD_FROM_PLAYER = 20, + RECEIVED_GOLD_FROM_TRADE = 21, + SENT_TROOPS_TO_PLAYER = 22, + RECEIVED_TROOPS_FROM_PLAYER = 23, + CHAT = 24, + RENEW_ALLIANCE = 25, +} + +export function messageTypeFromJSON(object: any): MessageType { + switch (object) { + case 0: + case "messageTypeUnspecified": + return MessageType.messageTypeUnspecified; + case 1: + case "ATTACK_FAILED": + return MessageType.ATTACK_FAILED; + case 2: + case "ATTACK_CANCELLED": + return MessageType.ATTACK_CANCELLED; + case 3: + case "ATTACK_REQUEST": + return MessageType.ATTACK_REQUEST; + case 4: + case "CONQUERED_PLAYER": + return MessageType.CONQUERED_PLAYER; + case 5: + case "MIRV_INBOUND": + return MessageType.MIRV_INBOUND; + case 6: + case "NUKE_INBOUND": + return MessageType.NUKE_INBOUND; + case 7: + case "HYDROGEN_BOMB_INBOUND": + return MessageType.HYDROGEN_BOMB_INBOUND; + case 8: + case "NAVAL_INVASION_INBOUND": + return MessageType.NAVAL_INVASION_INBOUND; + case 9: + case "SAM_MISS": + return MessageType.SAM_MISS; + case 10: + case "SAM_HIT": + return MessageType.SAM_HIT; + case 11: + case "CAPTURED_ENEMY_UNIT": + return MessageType.CAPTURED_ENEMY_UNIT; + case 12: + case "UNIT_CAPTURED_BY_ENEMY": + return MessageType.UNIT_CAPTURED_BY_ENEMY; + case 13: + case "UNIT_DESTROYED": + return MessageType.UNIT_DESTROYED; + case 14: + case "ALLIANCE_ACCEPTED": + return MessageType.ALLIANCE_ACCEPTED; + case 15: + case "ALLIANCE_REJECTED": + return MessageType.ALLIANCE_REJECTED; + case 16: + case "ALLIANCE_REQUEST": + return MessageType.ALLIANCE_REQUEST; + case 17: + case "ALLIANCE_BROKEN": + return MessageType.ALLIANCE_BROKEN; + case 18: + case "ALLIANCE_EXPIRED": + return MessageType.ALLIANCE_EXPIRED; + case 19: + case "SENT_GOLD_TO_PLAYER": + return MessageType.SENT_GOLD_TO_PLAYER; + case 20: + case "RECEIVED_GOLD_FROM_PLAYER": + return MessageType.RECEIVED_GOLD_FROM_PLAYER; + case 21: + case "RECEIVED_GOLD_FROM_TRADE": + return MessageType.RECEIVED_GOLD_FROM_TRADE; + case 22: + case "SENT_TROOPS_TO_PLAYER": + return MessageType.SENT_TROOPS_TO_PLAYER; + case 23: + case "RECEIVED_TROOPS_FROM_PLAYER": + return MessageType.RECEIVED_TROOPS_FROM_PLAYER; + case 24: + case "CHAT": + return MessageType.CHAT; + case 25: + case "RENEW_ALLIANCE": + return MessageType.RENEW_ALLIANCE; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum MessageType", + ); + } +} + +export function messageTypeToJSON(object: MessageType): string { + switch (object) { + case MessageType.messageTypeUnspecified: + return "messageTypeUnspecified"; + case MessageType.ATTACK_FAILED: + return "ATTACK_FAILED"; + case MessageType.ATTACK_CANCELLED: + return "ATTACK_CANCELLED"; + case MessageType.ATTACK_REQUEST: + return "ATTACK_REQUEST"; + case MessageType.CONQUERED_PLAYER: + return "CONQUERED_PLAYER"; + case MessageType.MIRV_INBOUND: + return "MIRV_INBOUND"; + case MessageType.NUKE_INBOUND: + return "NUKE_INBOUND"; + case MessageType.HYDROGEN_BOMB_INBOUND: + return "HYDROGEN_BOMB_INBOUND"; + case MessageType.NAVAL_INVASION_INBOUND: + return "NAVAL_INVASION_INBOUND"; + case MessageType.SAM_MISS: + return "SAM_MISS"; + case MessageType.SAM_HIT: + return "SAM_HIT"; + case MessageType.CAPTURED_ENEMY_UNIT: + return "CAPTURED_ENEMY_UNIT"; + case MessageType.UNIT_CAPTURED_BY_ENEMY: + return "UNIT_CAPTURED_BY_ENEMY"; + case MessageType.UNIT_DESTROYED: + return "UNIT_DESTROYED"; + case MessageType.ALLIANCE_ACCEPTED: + return "ALLIANCE_ACCEPTED"; + case MessageType.ALLIANCE_REJECTED: + return "ALLIANCE_REJECTED"; + case MessageType.ALLIANCE_REQUEST: + return "ALLIANCE_REQUEST"; + case MessageType.ALLIANCE_BROKEN: + return "ALLIANCE_BROKEN"; + case MessageType.ALLIANCE_EXPIRED: + return "ALLIANCE_EXPIRED"; + case MessageType.SENT_GOLD_TO_PLAYER: + return "SENT_GOLD_TO_PLAYER"; + case MessageType.RECEIVED_GOLD_FROM_PLAYER: + return "RECEIVED_GOLD_FROM_PLAYER"; + case MessageType.RECEIVED_GOLD_FROM_TRADE: + return "RECEIVED_GOLD_FROM_TRADE"; + case MessageType.SENT_TROOPS_TO_PLAYER: + return "SENT_TROOPS_TO_PLAYER"; + case MessageType.RECEIVED_TROOPS_FROM_PLAYER: + return "RECEIVED_TROOPS_FROM_PLAYER"; + case MessageType.CHAT: + return "CHAT"; + case MessageType.RENEW_ALLIANCE: + return "RENEW_ALLIANCE"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum MessageType", + ); + } +} + +export enum MessageCategory { + messageCategoryUnspecified = 0, + ATTACK = 1, + NUKE = 2, + ALLIANCE = 3, + TRADE = 4, + CHAT_CATEGORY = 5, +} + +export function messageCategoryFromJSON(object: any): MessageCategory { + switch (object) { + case 0: + case "messageCategoryUnspecified": + return MessageCategory.messageCategoryUnspecified; + case 1: + case "ATTACK": + return MessageCategory.ATTACK; + case 2: + case "NUKE": + return MessageCategory.NUKE; + case 3: + case "ALLIANCE": + return MessageCategory.ALLIANCE; + case 4: + case "TRADE": + return MessageCategory.TRADE; + case 5: + case "CHAT_CATEGORY": + return MessageCategory.CHAT_CATEGORY; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum MessageCategory", + ); + } +} + +export function messageCategoryToJSON(object: MessageCategory): string { + switch (object) { + case MessageCategory.messageCategoryUnspecified: + return "messageCategoryUnspecified"; + case MessageCategory.ATTACK: + return "ATTACK"; + case MessageCategory.NUKE: + return "NUKE"; + case MessageCategory.ALLIANCE: + return "ALLIANCE"; + case MessageCategory.TRADE: + return "TRADE"; + case MessageCategory.CHAT_CATEGORY: + return "CHAT_CATEGORY"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum MessageCategory", + ); + } +} + +export enum RailType { + vertical = 0, + horizontal = 1, + topLeft = 2, + topRight = 3, + bottomLeft = 4, + bottomRight = 5, +} + +export function railTypeFromJSON(object: any): RailType { + switch (object) { + case 0: + case "vertical": + return RailType.vertical; + case 1: + case "horizontal": + return RailType.horizontal; + case 2: + case "topLeft": + return RailType.topLeft; + case 3: + case "topRight": + return RailType.topRight; + case 4: + case "bottomLeft": + return RailType.bottomLeft; + case 5: + case "bottomRight": + return RailType.bottomRight; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum RailType", + ); + } +} + +export function railTypeToJSON(object: RailType): string { + switch (object) { + case RailType.vertical: + return "vertical"; + case RailType.horizontal: + return "horizontal"; + case RailType.topLeft: + return "topLeft"; + case RailType.topRight: + return "topRight"; + case RailType.bottomLeft: + return "bottomLeft"; + case RailType.bottomRight: + return "bottomRight"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + object + " for enum RailType", + ); + } +} + +export interface NameViewData { + x: number; + y: number; + size: number; +} + +export interface EmojiMessage { + senderId: number; + emoji: string; + allPlayers?: boolean | undefined; + recipientId?: number | undefined; + createdAt: number; +} + +/** Update messages */ export interface BonusEventUpdate { - type: GameUpdateType.BonusEvent; - player: PlayerID; - tile: TileRef; + player: string; + /** TileRef encoded as int64 */ + tile: number; gold: number; troops: number; } -export enum RailType { - VERTICAL, - HORIZONTAL, - TOP_LEFT, - TOP_RIGHT, - BOTTOM_LEFT, - BOTTOM_RIGHT, -} - export interface RailTile { - tile: TileRef; + /** TileRef encoded as int64 */ + tile: number; railType: RailType; } export interface RailroadUpdate { - type: GameUpdateType.RailroadEvent; isActive: boolean; railTiles: RailTile[]; } export interface ConquestUpdate { - type: GameUpdateType.ConquestEvent; - conquerorId: PlayerID; - conqueredId: PlayerID; - gold: Gold; -} - -export interface TileUpdateWrapper { - type: GameUpdateType.Tile; - update: TileUpdate; + conquerorId: number; + conqueredId: number; + gold: number; } export interface UnitUpdate { - type: GameUpdateType.Unit; + type: GameUpdateType; unitType: UnitType; troops: number; id: number; - ownerID: number; - lastOwnerID?: number; - // TODO: make these tilerefs - pos: TileRef; - lastPos: TileRef; + ownerId: number; + lastOwnerId?: number | undefined; + /** TileRef encoded as int64 */ + pos: number; + /** TileRef encoded as int64 */ + lastPos: number; isActive: boolean; reachedTarget: boolean; retreating: boolean; targetable: boolean; - markedForDeletion: number | false; - targetUnitId?: number; // Only for trade ships - targetTile?: TileRef; // Only for nukes - health?: number; - underConstruction?: boolean; + markedForDeletion?: number | undefined; + /** Only for trade ships */ + targetUnitId?: number | undefined; + /** TileRef encoded as int64, only for nukes */ + targetTile?: number | undefined; + health?: number | undefined; + underConstruction?: boolean | undefined; missileTimerQueue: number[]; level: number; hasTrainStation: boolean; - trainType?: TrainType; // Only for trains - loaded?: boolean; // Only for trains + /** Only for trains */ + trainType?: TrainType | undefined; + /** Only for trains */ + loaded?: boolean | undefined; } export interface AttackUpdate { - attackerID: number; - targetID: number; + attackerId: number; + targetId: number; troops: number; id: string; retreating: boolean; } +export interface AllianceView { + id: number; + other: string; + createdAt: number; + expiresAt: number; + hasExtensionRequest: boolean; +} + export interface PlayerUpdate { - type: GameUpdateType.Player; - nameViewData?: NameViewData; - clientID: ClientID | null; + nameViewData?: NameViewData | undefined; + clientId?: string | undefined; name: string; displayName: string; - id: PlayerID; - team?: Team; - smallID: number; + id: string; + team?: string | undefined; + smallId: number; playerType: PlayerType; isAlive: boolean; isDisconnected: boolean; tilesOwned: number; - gold: Gold; + gold: number; troops: number; allies: number[]; - embargoes: Set; + embargoes: string[]; isTraitor: boolean; - traitorRemainingTicks?: number; + traitorRemainingTicks?: number | undefined; targets: number[]; outgoingEmojis: EmojiMessage[]; outgoingAttacks: AttackUpdate[]; incomingAttacks: AttackUpdate[]; - outgoingAllianceRequests: PlayerID[]; + outgoingAllianceRequests: string[]; alliances: AllianceView[]; hasSpawned: boolean; betrayals: number; - lastDeleteUnitTick: Tick; -} - -export interface AllianceView { - id: number; - other: PlayerID; - createdAt: Tick; - expiresAt: Tick; - hasExtensionRequest: boolean; + lastDeleteUnitTick: number; } export interface AllianceRequestUpdate { - type: GameUpdateType.AllianceRequest; - requestorID: number; - recipientID: number; - createdAt: Tick; + requestorId: number; + recipientId: number; + createdAt: number; } export interface AllianceRequestReplyUpdate { - type: GameUpdateType.AllianceRequestReply; - request: AllianceRequestUpdate; + request: AllianceRequestUpdate | undefined; accepted: boolean; } export interface BrokeAllianceUpdate { - type: GameUpdateType.BrokeAlliance; - traitorID: number; - betrayedID: number; + traitorId: number; + betrayedId: number; } export interface AllianceExpiredUpdate { - type: GameUpdateType.AllianceExpired; - player1ID: number; - player2ID: number; + player1Id: number; + player2Id: number; } export interface AllianceExtensionUpdate { - type: GameUpdateType.AllianceExtension; - playerID: number; - allianceID: number; + playerId: string; + allianceId: number; } export interface TargetPlayerUpdate { - type: GameUpdateType.TargetPlayer; - playerID: number; - targetID: number; + playerId: number; + targetId: number; } export interface EmojiUpdate { - type: GameUpdateType.Emoji; - emoji: EmojiMessage; + emoji: EmojiMessage | undefined; } export interface DisplayMessageUpdate { - type: GameUpdateType.DisplayEvent; message: string; messageType: MessageType; - goldAmount?: bigint; - playerID: number | null; - params?: Record; + goldAmount?: number | undefined; + playerId?: number | undefined; + params: { [key: string]: string }; } -export type DisplayChatMessageUpdate = { - type: GameUpdateType.DisplayChatEvent; +export interface DisplayMessageUpdate_ParamsEntry { + key: string; + value: string; +} + +export interface DisplayChatMessageUpdate { key: string; category: string; - target: string | undefined; - playerID: number | null; + target?: string | undefined; + playerId?: number | undefined; isFrom: boolean; recipient: string; -}; +} export interface WinUpdate { - type: GameUpdateType.Win; - allPlayersStats: AllPlayersStats; - winner: Winner; + winner: string; + stats: string; } export interface HashUpdate { - type: GameUpdateType.Hash; - tick: Tick; + tick: number; hash: number; } export interface UnitIncomingUpdate { - type: GameUpdateType.UnitIncoming; - unitID: number; + unitId: number; message: string; messageType: MessageType; - playerID: number; + playerId: number; } export interface EmbargoUpdate { - type: GameUpdateType.EmbargoEvent; - event: "start" | "stop"; - playerID: number; - embargoedID: number; + event: EmbargoUpdate_EmbargoEvent; + playerId: number; + embargoedId: number; +} + +export enum EmbargoUpdate_EmbargoEvent { + start = 0, + stop = 1, +} + +export function embargoUpdate_EmbargoEventFromJSON( + object: any, +): EmbargoUpdate_EmbargoEvent { + switch (object) { + case 0: + case "start": + return EmbargoUpdate_EmbargoEvent.start; + case 1: + case "stop": + return EmbargoUpdate_EmbargoEvent.stop; + default: + throw new globalThis.Error( + "Unrecognized enum value " + + object + + " for enum EmbargoUpdate_EmbargoEvent", + ); + } +} + +export function embargoUpdate_EmbargoEventToJSON( + object: EmbargoUpdate_EmbargoEvent, +): string { + switch (object) { + case EmbargoUpdate_EmbargoEvent.start: + return "start"; + case EmbargoUpdate_EmbargoEvent.stop: + return "stop"; + default: + throw new globalThis.Error( + "Unrecognized enum value " + + object + + " for enum EmbargoUpdate_EmbargoEvent", + ); + } +} + +/** Main GameUpdate message using oneof for polymorphism */ +export interface GameUpdate { + type: GameUpdateType; + unit?: UnitUpdate | undefined; + player?: PlayerUpdate | undefined; + allianceRequest?: AllianceRequestUpdate | undefined; + allianceRequestReply?: AllianceRequestReplyUpdate | undefined; + brokeAlliance?: BrokeAllianceUpdate | undefined; + allianceExpired?: AllianceExpiredUpdate | undefined; + displayMessage?: DisplayMessageUpdate | undefined; + displayChatMessage?: DisplayChatMessageUpdate | undefined; + targetPlayer?: TargetPlayerUpdate | undefined; + emoji?: EmojiUpdate | undefined; + win?: WinUpdate | undefined; + hash?: HashUpdate | undefined; + unitIncoming?: UnitIncomingUpdate | undefined; + allianceExtension?: AllianceExtensionUpdate | undefined; + bonusEvent?: BonusEventUpdate | undefined; + railroad?: RailroadUpdate | undefined; + conquest?: ConquestUpdate | undefined; + embargo?: EmbargoUpdate | undefined; +} + +export interface GameUpdates { + type: GameUpdateType; + updates: GameUpdate[]; +} + +export interface GameUpdateViewData { + tick: number; + updates: { [key: number]: GameUpdates }; + tileUpdates: number[]; + playerNameViewData: { [key: string]: NameViewData }; + tickExecutionDuration?: number | undefined; +} + +export interface GameUpdateViewData_UpdatesEntry { + key: number; + value: GameUpdates | undefined; +} + +export interface GameUpdateViewData_PlayerNameViewDataEntry { + key: string; + value: NameViewData | undefined; +} + +export interface ErrorUpdate { + errMsg: string; + stack?: string | undefined; +} + +function createBaseNameViewData(): NameViewData { + return { x: 0, y: 0, size: 0 }; +} + +export const NameViewData: MessageFns = { + encode( + message: NameViewData, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.x !== 0) { + writer.uint32(8).int32(message.x); + } + if (message.y !== 0) { + writer.uint32(16).int32(message.y); + } + if (message.size !== 0) { + writer.uint32(24).int32(message.size); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): NameViewData { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseNameViewData(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.x = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.y = reader.int32(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.size = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): NameViewData { + return { + x: isSet(object.x) ? globalThis.Number(object.x) : 0, + y: isSet(object.y) ? globalThis.Number(object.y) : 0, + size: isSet(object.size) ? globalThis.Number(object.size) : 0, + }; + }, + + toJSON(message: NameViewData): unknown { + const obj: any = {}; + if (message.x !== 0) { + obj.x = Math.round(message.x); + } + if (message.y !== 0) { + obj.y = Math.round(message.y); + } + if (message.size !== 0) { + obj.size = Math.round(message.size); + } + return obj; + }, + + create, I>>( + base?: I, + ): NameViewData { + return NameViewData.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): NameViewData { + const message = createBaseNameViewData(); + message.x = object.x ?? 0; + message.y = object.y ?? 0; + message.size = object.size ?? 0; + return message; + }, +}; + +function createBaseEmojiMessage(): EmojiMessage { + return { + senderId: 0, + emoji: "", + allPlayers: undefined, + recipientId: undefined, + createdAt: 0, + }; +} + +export const EmojiMessage: MessageFns = { + encode( + message: EmojiMessage, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.senderId !== 0) { + writer.uint32(8).int32(message.senderId); + } + if (message.emoji !== "") { + writer.uint32(18).string(message.emoji); + } + if (message.allPlayers !== undefined) { + writer.uint32(24).bool(message.allPlayers); + } + if (message.recipientId !== undefined) { + writer.uint32(32).int32(message.recipientId); + } + if (message.createdAt !== 0) { + writer.uint32(40).int32(message.createdAt); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): EmojiMessage { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseEmojiMessage(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.senderId = reader.int32(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.emoji = reader.string(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.allPlayers = reader.bool(); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.recipientId = reader.int32(); + continue; + } + case 5: { + if (tag !== 40) { + break; + } + + message.createdAt = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): EmojiMessage { + return { + senderId: isSet(object.senderId) ? globalThis.Number(object.senderId) : 0, + emoji: isSet(object.emoji) ? globalThis.String(object.emoji) : "", + allPlayers: isSet(object.allPlayers) + ? globalThis.Boolean(object.allPlayers) + : undefined, + recipientId: isSet(object.recipientId) + ? globalThis.Number(object.recipientId) + : undefined, + createdAt: isSet(object.createdAt) + ? globalThis.Number(object.createdAt) + : 0, + }; + }, + + toJSON(message: EmojiMessage): unknown { + const obj: any = {}; + if (message.senderId !== 0) { + obj.senderId = Math.round(message.senderId); + } + if (message.emoji !== "") { + obj.emoji = message.emoji; + } + if (message.allPlayers !== undefined) { + obj.allPlayers = message.allPlayers; + } + if (message.recipientId !== undefined) { + obj.recipientId = Math.round(message.recipientId); + } + if (message.createdAt !== 0) { + obj.createdAt = Math.round(message.createdAt); + } + return obj; + }, + + create, I>>( + base?: I, + ): EmojiMessage { + return EmojiMessage.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): EmojiMessage { + const message = createBaseEmojiMessage(); + message.senderId = object.senderId ?? 0; + message.emoji = object.emoji ?? ""; + message.allPlayers = object.allPlayers ?? undefined; + message.recipientId = object.recipientId ?? undefined; + message.createdAt = object.createdAt ?? 0; + return message; + }, +}; + +function createBaseBonusEventUpdate(): BonusEventUpdate { + return { player: "", tile: 0, gold: 0, troops: 0 }; +} + +export const BonusEventUpdate: MessageFns = { + encode( + message: BonusEventUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.player !== "") { + writer.uint32(10).string(message.player); + } + if (message.tile !== 0) { + writer.uint32(16).int64(message.tile); + } + if (message.gold !== 0) { + writer.uint32(24).int64(message.gold); + } + if (message.troops !== 0) { + writer.uint32(32).int64(message.troops); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): BonusEventUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBonusEventUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.player = reader.string(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.tile = longToNumber(reader.int64()); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.gold = longToNumber(reader.int64()); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.troops = longToNumber(reader.int64()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): BonusEventUpdate { + return { + player: isSet(object.player) ? globalThis.String(object.player) : "", + tile: isSet(object.tile) ? globalThis.Number(object.tile) : 0, + gold: isSet(object.gold) ? globalThis.Number(object.gold) : 0, + troops: isSet(object.troops) ? globalThis.Number(object.troops) : 0, + }; + }, + + toJSON(message: BonusEventUpdate): unknown { + const obj: any = {}; + if (message.player !== "") { + obj.player = message.player; + } + if (message.tile !== 0) { + obj.tile = Math.round(message.tile); + } + if (message.gold !== 0) { + obj.gold = Math.round(message.gold); + } + if (message.troops !== 0) { + obj.troops = Math.round(message.troops); + } + return obj; + }, + + create, I>>( + base?: I, + ): BonusEventUpdate { + return BonusEventUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): BonusEventUpdate { + const message = createBaseBonusEventUpdate(); + message.player = object.player ?? ""; + message.tile = object.tile ?? 0; + message.gold = object.gold ?? 0; + message.troops = object.troops ?? 0; + return message; + }, +}; + +function createBaseRailTile(): RailTile { + return { tile: 0, railType: 0 }; +} + +export const RailTile: MessageFns = { + encode( + message: RailTile, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.tile !== 0) { + writer.uint32(8).int64(message.tile); + } + if (message.railType !== 0) { + writer.uint32(16).int32(message.railType); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): RailTile { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseRailTile(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.tile = longToNumber(reader.int64()); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.railType = reader.int32() as any; + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): RailTile { + return { + tile: isSet(object.tile) ? globalThis.Number(object.tile) : 0, + railType: isSet(object.railType) ? railTypeFromJSON(object.railType) : 0, + }; + }, + + toJSON(message: RailTile): unknown { + const obj: any = {}; + if (message.tile !== 0) { + obj.tile = Math.round(message.tile); + } + if (message.railType !== 0) { + obj.railType = railTypeToJSON(message.railType); + } + return obj; + }, + + create, I>>(base?: I): RailTile { + return RailTile.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>(object: I): RailTile { + const message = createBaseRailTile(); + message.tile = object.tile ?? 0; + message.railType = object.railType ?? 0; + return message; + }, +}; + +function createBaseRailroadUpdate(): RailroadUpdate { + return { isActive: false, railTiles: [] }; +} + +export const RailroadUpdate: MessageFns = { + encode( + message: RailroadUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.isActive !== false) { + writer.uint32(8).bool(message.isActive); + } + for (const v of message.railTiles) { + RailTile.encode(v!, writer.uint32(18).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): RailroadUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseRailroadUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.isActive = reader.bool(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.railTiles.push(RailTile.decode(reader, reader.uint32())); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): RailroadUpdate { + return { + isActive: isSet(object.isActive) + ? globalThis.Boolean(object.isActive) + : false, + railTiles: globalThis.Array.isArray(object?.railTiles) + ? object.railTiles.map((e: any) => RailTile.fromJSON(e)) + : [], + }; + }, + + toJSON(message: RailroadUpdate): unknown { + const obj: any = {}; + if (message.isActive !== false) { + obj.isActive = message.isActive; + } + if (message.railTiles?.length) { + obj.railTiles = message.railTiles.map((e) => RailTile.toJSON(e)); + } + return obj; + }, + + create, I>>( + base?: I, + ): RailroadUpdate { + return RailroadUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): RailroadUpdate { + const message = createBaseRailroadUpdate(); + message.isActive = object.isActive ?? false; + message.railTiles = + object.railTiles?.map((e) => RailTile.fromPartial(e)) || []; + return message; + }, +}; + +function createBaseConquestUpdate(): ConquestUpdate { + return { conquerorId: 0, conqueredId: 0, gold: 0 }; +} + +export const ConquestUpdate: MessageFns = { + encode( + message: ConquestUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.conquerorId !== 0) { + writer.uint32(8).int32(message.conquerorId); + } + if (message.conqueredId !== 0) { + writer.uint32(16).int32(message.conqueredId); + } + if (message.gold !== 0) { + writer.uint32(24).int64(message.gold); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ConquestUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseConquestUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.conquerorId = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.conqueredId = reader.int32(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.gold = longToNumber(reader.int64()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): ConquestUpdate { + return { + conquerorId: isSet(object.conquerorId) + ? globalThis.Number(object.conquerorId) + : 0, + conqueredId: isSet(object.conqueredId) + ? globalThis.Number(object.conqueredId) + : 0, + gold: isSet(object.gold) ? globalThis.Number(object.gold) : 0, + }; + }, + + toJSON(message: ConquestUpdate): unknown { + const obj: any = {}; + if (message.conquerorId !== 0) { + obj.conquerorId = Math.round(message.conquerorId); + } + if (message.conqueredId !== 0) { + obj.conqueredId = Math.round(message.conqueredId); + } + if (message.gold !== 0) { + obj.gold = Math.round(message.gold); + } + return obj; + }, + + create, I>>( + base?: I, + ): ConquestUpdate { + return ConquestUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): ConquestUpdate { + const message = createBaseConquestUpdate(); + message.conquerorId = object.conquerorId ?? 0; + message.conqueredId = object.conqueredId ?? 0; + message.gold = object.gold ?? 0; + return message; + }, +}; + +function createBaseUnitUpdate(): UnitUpdate { + return { + type: 0, + unitType: 0, + troops: 0, + id: 0, + ownerId: 0, + lastOwnerId: undefined, + pos: 0, + lastPos: 0, + isActive: false, + reachedTarget: false, + retreating: false, + targetable: false, + markedForDeletion: undefined, + targetUnitId: undefined, + targetTile: undefined, + health: undefined, + underConstruction: undefined, + missileTimerQueue: [], + level: 0, + hasTrainStation: false, + trainType: undefined, + loaded: undefined, + }; +} + +export const UnitUpdate: MessageFns = { + encode( + message: UnitUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.type !== 0) { + writer.uint32(176).int32(message.type); + } + if (message.unitType !== 0) { + writer.uint32(8).int32(message.unitType); + } + if (message.troops !== 0) { + writer.uint32(16).int32(message.troops); + } + if (message.id !== 0) { + writer.uint32(24).int32(message.id); + } + if (message.ownerId !== 0) { + writer.uint32(32).int32(message.ownerId); + } + if (message.lastOwnerId !== undefined) { + writer.uint32(40).int32(message.lastOwnerId); + } + if (message.pos !== 0) { + writer.uint32(48).int64(message.pos); + } + if (message.lastPos !== 0) { + writer.uint32(56).int64(message.lastPos); + } + if (message.isActive !== false) { + writer.uint32(64).bool(message.isActive); + } + if (message.reachedTarget !== false) { + writer.uint32(72).bool(message.reachedTarget); + } + if (message.retreating !== false) { + writer.uint32(80).bool(message.retreating); + } + if (message.targetable !== false) { + writer.uint32(88).bool(message.targetable); + } + if (message.markedForDeletion !== undefined) { + writer.uint32(96).int32(message.markedForDeletion); + } + if (message.targetUnitId !== undefined) { + writer.uint32(104).int32(message.targetUnitId); + } + if (message.targetTile !== undefined) { + writer.uint32(112).int64(message.targetTile); + } + if (message.health !== undefined) { + writer.uint32(120).int32(message.health); + } + if (message.underConstruction !== undefined) { + writer.uint32(128).bool(message.underConstruction); + } + writer.uint32(138).fork(); + for (const v of message.missileTimerQueue) { + writer.int32(v); + } + writer.join(); + if (message.level !== 0) { + writer.uint32(144).int32(message.level); + } + if (message.hasTrainStation !== false) { + writer.uint32(152).bool(message.hasTrainStation); + } + if (message.trainType !== undefined) { + writer.uint32(160).int32(message.trainType); + } + if (message.loaded !== undefined) { + writer.uint32(168).bool(message.loaded); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): UnitUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseUnitUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 22: { + if (tag !== 176) { + break; + } + + message.type = reader.int32() as any; + continue; + } + case 1: { + if (tag !== 8) { + break; + } + + message.unitType = reader.int32() as any; + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.troops = reader.int32(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.id = reader.int32(); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.ownerId = reader.int32(); + continue; + } + case 5: { + if (tag !== 40) { + break; + } + + message.lastOwnerId = reader.int32(); + continue; + } + case 6: { + if (tag !== 48) { + break; + } + + message.pos = longToNumber(reader.int64()); + continue; + } + case 7: { + if (tag !== 56) { + break; + } + + message.lastPos = longToNumber(reader.int64()); + continue; + } + case 8: { + if (tag !== 64) { + break; + } + + message.isActive = reader.bool(); + continue; + } + case 9: { + if (tag !== 72) { + break; + } + + message.reachedTarget = reader.bool(); + continue; + } + case 10: { + if (tag !== 80) { + break; + } + + message.retreating = reader.bool(); + continue; + } + case 11: { + if (tag !== 88) { + break; + } + + message.targetable = reader.bool(); + continue; + } + case 12: { + if (tag !== 96) { + break; + } + + message.markedForDeletion = reader.int32(); + continue; + } + case 13: { + if (tag !== 104) { + break; + } + + message.targetUnitId = reader.int32(); + continue; + } + case 14: { + if (tag !== 112) { + break; + } + + message.targetTile = longToNumber(reader.int64()); + continue; + } + case 15: { + if (tag !== 120) { + break; + } + + message.health = reader.int32(); + continue; + } + case 16: { + if (tag !== 128) { + break; + } + + message.underConstruction = reader.bool(); + continue; + } + case 17: { + if (tag === 136) { + message.missileTimerQueue.push(reader.int32()); + + continue; + } + + if (tag === 138) { + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.missileTimerQueue.push(reader.int32()); + } + + continue; + } + + break; + } + case 18: { + if (tag !== 144) { + break; + } + + message.level = reader.int32(); + continue; + } + case 19: { + if (tag !== 152) { + break; + } + + message.hasTrainStation = reader.bool(); + continue; + } + case 20: { + if (tag !== 160) { + break; + } + + message.trainType = reader.int32() as any; + continue; + } + case 21: { + if (tag !== 168) { + break; + } + + message.loaded = reader.bool(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): UnitUpdate { + return { + type: isSet(object.type) ? gameUpdateTypeFromJSON(object.type) : 0, + unitType: isSet(object.unitType) ? unitTypeFromJSON(object.unitType) : 0, + troops: isSet(object.troops) ? globalThis.Number(object.troops) : 0, + id: isSet(object.id) ? globalThis.Number(object.id) : 0, + ownerId: isSet(object.ownerId) ? globalThis.Number(object.ownerId) : 0, + lastOwnerId: isSet(object.lastOwnerId) + ? globalThis.Number(object.lastOwnerId) + : undefined, + pos: isSet(object.pos) ? globalThis.Number(object.pos) : 0, + lastPos: isSet(object.lastPos) ? globalThis.Number(object.lastPos) : 0, + isActive: isSet(object.isActive) + ? globalThis.Boolean(object.isActive) + : false, + reachedTarget: isSet(object.reachedTarget) + ? globalThis.Boolean(object.reachedTarget) + : false, + retreating: isSet(object.retreating) + ? globalThis.Boolean(object.retreating) + : false, + targetable: isSet(object.targetable) + ? globalThis.Boolean(object.targetable) + : false, + markedForDeletion: isSet(object.markedForDeletion) + ? globalThis.Number(object.markedForDeletion) + : undefined, + targetUnitId: isSet(object.targetUnitId) + ? globalThis.Number(object.targetUnitId) + : undefined, + targetTile: isSet(object.targetTile) + ? globalThis.Number(object.targetTile) + : undefined, + health: isSet(object.health) + ? globalThis.Number(object.health) + : undefined, + underConstruction: isSet(object.underConstruction) + ? globalThis.Boolean(object.underConstruction) + : undefined, + missileTimerQueue: globalThis.Array.isArray(object?.missileTimerQueue) + ? object.missileTimerQueue.map((e: any) => globalThis.Number(e)) + : [], + level: isSet(object.level) ? globalThis.Number(object.level) : 0, + hasTrainStation: isSet(object.hasTrainStation) + ? globalThis.Boolean(object.hasTrainStation) + : false, + trainType: isSet(object.trainType) + ? trainTypeFromJSON(object.trainType) + : undefined, + loaded: isSet(object.loaded) + ? globalThis.Boolean(object.loaded) + : undefined, + }; + }, + + toJSON(message: UnitUpdate): unknown { + const obj: any = {}; + if (message.type !== 0) { + obj.type = gameUpdateTypeToJSON(message.type); + } + if (message.unitType !== 0) { + obj.unitType = unitTypeToJSON(message.unitType); + } + if (message.troops !== 0) { + obj.troops = Math.round(message.troops); + } + if (message.id !== 0) { + obj.id = Math.round(message.id); + } + if (message.ownerId !== 0) { + obj.ownerId = Math.round(message.ownerId); + } + if (message.lastOwnerId !== undefined) { + obj.lastOwnerId = Math.round(message.lastOwnerId); + } + if (message.pos !== 0) { + obj.pos = Math.round(message.pos); + } + if (message.lastPos !== 0) { + obj.lastPos = Math.round(message.lastPos); + } + if (message.isActive !== false) { + obj.isActive = message.isActive; + } + if (message.reachedTarget !== false) { + obj.reachedTarget = message.reachedTarget; + } + if (message.retreating !== false) { + obj.retreating = message.retreating; + } + if (message.targetable !== false) { + obj.targetable = message.targetable; + } + if (message.markedForDeletion !== undefined) { + obj.markedForDeletion = Math.round(message.markedForDeletion); + } + if (message.targetUnitId !== undefined) { + obj.targetUnitId = Math.round(message.targetUnitId); + } + if (message.targetTile !== undefined) { + obj.targetTile = Math.round(message.targetTile); + } + if (message.health !== undefined) { + obj.health = Math.round(message.health); + } + if (message.underConstruction !== undefined) { + obj.underConstruction = message.underConstruction; + } + if (message.missileTimerQueue?.length) { + obj.missileTimerQueue = message.missileTimerQueue.map((e) => + Math.round(e), + ); + } + if (message.level !== 0) { + obj.level = Math.round(message.level); + } + if (message.hasTrainStation !== false) { + obj.hasTrainStation = message.hasTrainStation; + } + if (message.trainType !== undefined) { + obj.trainType = trainTypeToJSON(message.trainType); + } + if (message.loaded !== undefined) { + obj.loaded = message.loaded; + } + return obj; + }, + + create, I>>(base?: I): UnitUpdate { + return UnitUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): UnitUpdate { + const message = createBaseUnitUpdate(); + message.type = object.type ?? 0; + message.unitType = object.unitType ?? 0; + message.troops = object.troops ?? 0; + message.id = object.id ?? 0; + message.ownerId = object.ownerId ?? 0; + message.lastOwnerId = object.lastOwnerId ?? undefined; + message.pos = object.pos ?? 0; + message.lastPos = object.lastPos ?? 0; + message.isActive = object.isActive ?? false; + message.reachedTarget = object.reachedTarget ?? false; + message.retreating = object.retreating ?? false; + message.targetable = object.targetable ?? false; + message.markedForDeletion = object.markedForDeletion ?? undefined; + message.targetUnitId = object.targetUnitId ?? undefined; + message.targetTile = object.targetTile ?? undefined; + message.health = object.health ?? undefined; + message.underConstruction = object.underConstruction ?? undefined; + message.missileTimerQueue = object.missileTimerQueue?.map((e) => e) || []; + message.level = object.level ?? 0; + message.hasTrainStation = object.hasTrainStation ?? false; + message.trainType = object.trainType ?? undefined; + message.loaded = object.loaded ?? undefined; + return message; + }, +}; + +function createBaseAttackUpdate(): AttackUpdate { + return { attackerId: 0, targetId: 0, troops: 0, id: "", retreating: false }; +} + +export const AttackUpdate: MessageFns = { + encode( + message: AttackUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.attackerId !== 0) { + writer.uint32(8).int32(message.attackerId); + } + if (message.targetId !== 0) { + writer.uint32(16).int32(message.targetId); + } + if (message.troops !== 0) { + writer.uint32(24).int32(message.troops); + } + if (message.id !== "") { + writer.uint32(34).string(message.id); + } + if (message.retreating !== false) { + writer.uint32(40).bool(message.retreating); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): AttackUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAttackUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.attackerId = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.targetId = reader.int32(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.troops = reader.int32(); + continue; + } + case 4: { + if (tag !== 34) { + break; + } + + message.id = reader.string(); + continue; + } + case 5: { + if (tag !== 40) { + break; + } + + message.retreating = reader.bool(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): AttackUpdate { + return { + attackerId: isSet(object.attackerId) + ? globalThis.Number(object.attackerId) + : 0, + targetId: isSet(object.targetId) ? globalThis.Number(object.targetId) : 0, + troops: isSet(object.troops) ? globalThis.Number(object.troops) : 0, + id: isSet(object.id) ? globalThis.String(object.id) : "", + retreating: isSet(object.retreating) + ? globalThis.Boolean(object.retreating) + : false, + }; + }, + + toJSON(message: AttackUpdate): unknown { + const obj: any = {}; + if (message.attackerId !== 0) { + obj.attackerId = Math.round(message.attackerId); + } + if (message.targetId !== 0) { + obj.targetId = Math.round(message.targetId); + } + if (message.troops !== 0) { + obj.troops = Math.round(message.troops); + } + if (message.id !== "") { + obj.id = message.id; + } + if (message.retreating !== false) { + obj.retreating = message.retreating; + } + return obj; + }, + + create, I>>( + base?: I, + ): AttackUpdate { + return AttackUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): AttackUpdate { + const message = createBaseAttackUpdate(); + message.attackerId = object.attackerId ?? 0; + message.targetId = object.targetId ?? 0; + message.troops = object.troops ?? 0; + message.id = object.id ?? ""; + message.retreating = object.retreating ?? false; + return message; + }, +}; + +function createBaseAllianceView(): AllianceView { + return { + id: 0, + other: "", + createdAt: 0, + expiresAt: 0, + hasExtensionRequest: false, + }; +} + +export const AllianceView: MessageFns = { + encode( + message: AllianceView, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.id !== 0) { + writer.uint32(8).int32(message.id); + } + if (message.other !== "") { + writer.uint32(18).string(message.other); + } + if (message.createdAt !== 0) { + writer.uint32(24).int32(message.createdAt); + } + if (message.expiresAt !== 0) { + writer.uint32(32).int32(message.expiresAt); + } + if (message.hasExtensionRequest !== false) { + writer.uint32(40).bool(message.hasExtensionRequest); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): AllianceView { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAllianceView(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.id = reader.int32(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.other = reader.string(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.createdAt = reader.int32(); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.expiresAt = reader.int32(); + continue; + } + case 5: { + if (tag !== 40) { + break; + } + + message.hasExtensionRequest = reader.bool(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): AllianceView { + return { + id: isSet(object.id) ? globalThis.Number(object.id) : 0, + other: isSet(object.other) ? globalThis.String(object.other) : "", + createdAt: isSet(object.createdAt) + ? globalThis.Number(object.createdAt) + : 0, + expiresAt: isSet(object.expiresAt) + ? globalThis.Number(object.expiresAt) + : 0, + hasExtensionRequest: isSet(object.hasExtensionRequest) + ? globalThis.Boolean(object.hasExtensionRequest) + : false, + }; + }, + + toJSON(message: AllianceView): unknown { + const obj: any = {}; + if (message.id !== 0) { + obj.id = Math.round(message.id); + } + if (message.other !== "") { + obj.other = message.other; + } + if (message.createdAt !== 0) { + obj.createdAt = Math.round(message.createdAt); + } + if (message.expiresAt !== 0) { + obj.expiresAt = Math.round(message.expiresAt); + } + if (message.hasExtensionRequest !== false) { + obj.hasExtensionRequest = message.hasExtensionRequest; + } + return obj; + }, + + create, I>>( + base?: I, + ): AllianceView { + return AllianceView.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): AllianceView { + const message = createBaseAllianceView(); + message.id = object.id ?? 0; + message.other = object.other ?? ""; + message.createdAt = object.createdAt ?? 0; + message.expiresAt = object.expiresAt ?? 0; + message.hasExtensionRequest = object.hasExtensionRequest ?? false; + return message; + }, +}; + +function createBasePlayerUpdate(): PlayerUpdate { + return { + nameViewData: undefined, + clientId: undefined, + name: "", + displayName: "", + id: "", + team: undefined, + smallId: 0, + playerType: 0, + isAlive: false, + isDisconnected: false, + tilesOwned: 0, + gold: 0, + troops: 0, + allies: [], + embargoes: [], + isTraitor: false, + traitorRemainingTicks: undefined, + targets: [], + outgoingEmojis: [], + outgoingAttacks: [], + incomingAttacks: [], + outgoingAllianceRequests: [], + alliances: [], + hasSpawned: false, + betrayals: 0, + lastDeleteUnitTick: 0, + }; +} + +export const PlayerUpdate: MessageFns = { + encode( + message: PlayerUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.nameViewData !== undefined) { + NameViewData.encode( + message.nameViewData, + writer.uint32(10).fork(), + ).join(); + } + if (message.clientId !== undefined) { + writer.uint32(18).string(message.clientId); + } + if (message.name !== "") { + writer.uint32(26).string(message.name); + } + if (message.displayName !== "") { + writer.uint32(34).string(message.displayName); + } + if (message.id !== "") { + writer.uint32(42).string(message.id); + } + if (message.team !== undefined) { + writer.uint32(50).string(message.team); + } + if (message.smallId !== 0) { + writer.uint32(56).int32(message.smallId); + } + if (message.playerType !== 0) { + writer.uint32(64).int32(message.playerType); + } + if (message.isAlive !== false) { + writer.uint32(72).bool(message.isAlive); + } + if (message.isDisconnected !== false) { + writer.uint32(80).bool(message.isDisconnected); + } + if (message.tilesOwned !== 0) { + writer.uint32(88).int32(message.tilesOwned); + } + if (message.gold !== 0) { + writer.uint32(96).uint64(message.gold); + } + if (message.troops !== 0) { + writer.uint32(104).int32(message.troops); + } + writer.uint32(114).fork(); + for (const v of message.allies) { + writer.int32(v); + } + writer.join(); + for (const v of message.embargoes) { + writer.uint32(122).string(v!); + } + if (message.isTraitor !== false) { + writer.uint32(128).bool(message.isTraitor); + } + if (message.traitorRemainingTicks !== undefined) { + writer.uint32(136).int32(message.traitorRemainingTicks); + } + writer.uint32(146).fork(); + for (const v of message.targets) { + writer.int32(v); + } + writer.join(); + for (const v of message.outgoingEmojis) { + EmojiMessage.encode(v!, writer.uint32(154).fork()).join(); + } + for (const v of message.outgoingAttacks) { + AttackUpdate.encode(v!, writer.uint32(162).fork()).join(); + } + for (const v of message.incomingAttacks) { + AttackUpdate.encode(v!, writer.uint32(170).fork()).join(); + } + for (const v of message.outgoingAllianceRequests) { + writer.uint32(178).string(v!); + } + for (const v of message.alliances) { + AllianceView.encode(v!, writer.uint32(186).fork()).join(); + } + if (message.hasSpawned !== false) { + writer.uint32(192).bool(message.hasSpawned); + } + if (message.betrayals !== 0) { + writer.uint32(200).int32(message.betrayals); + } + if (message.lastDeleteUnitTick !== 0) { + writer.uint32(208).int32(message.lastDeleteUnitTick); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): PlayerUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBasePlayerUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.nameViewData = NameViewData.decode(reader, reader.uint32()); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.clientId = reader.string(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.name = reader.string(); + continue; + } + case 4: { + if (tag !== 34) { + break; + } + + message.displayName = reader.string(); + continue; + } + case 5: { + if (tag !== 42) { + break; + } + + message.id = reader.string(); + continue; + } + case 6: { + if (tag !== 50) { + break; + } + + message.team = reader.string(); + continue; + } + case 7: { + if (tag !== 56) { + break; + } + + message.smallId = reader.int32(); + continue; + } + case 8: { + if (tag !== 64) { + break; + } + + message.playerType = reader.int32() as any; + continue; + } + case 9: { + if (tag !== 72) { + break; + } + + message.isAlive = reader.bool(); + continue; + } + case 10: { + if (tag !== 80) { + break; + } + + message.isDisconnected = reader.bool(); + continue; + } + case 11: { + if (tag !== 88) { + break; + } + + message.tilesOwned = reader.int32(); + continue; + } + case 12: { + if (tag !== 96) { + break; + } + + message.gold = longToNumber(reader.uint64()); + continue; + } + case 13: { + if (tag !== 104) { + break; + } + + message.troops = reader.int32(); + continue; + } + case 14: { + if (tag === 112) { + message.allies.push(reader.int32()); + + continue; + } + + if (tag === 114) { + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.allies.push(reader.int32()); + } + + continue; + } + + break; + } + case 15: { + if (tag !== 122) { + break; + } + + message.embargoes.push(reader.string()); + continue; + } + case 16: { + if (tag !== 128) { + break; + } + + message.isTraitor = reader.bool(); + continue; + } + case 17: { + if (tag !== 136) { + break; + } + + message.traitorRemainingTicks = reader.int32(); + continue; + } + case 18: { + if (tag === 144) { + message.targets.push(reader.int32()); + + continue; + } + + if (tag === 146) { + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.targets.push(reader.int32()); + } + + continue; + } + + break; + } + case 19: { + if (tag !== 154) { + break; + } + + message.outgoingEmojis.push( + EmojiMessage.decode(reader, reader.uint32()), + ); + continue; + } + case 20: { + if (tag !== 162) { + break; + } + + message.outgoingAttacks.push( + AttackUpdate.decode(reader, reader.uint32()), + ); + continue; + } + case 21: { + if (tag !== 170) { + break; + } + + message.incomingAttacks.push( + AttackUpdate.decode(reader, reader.uint32()), + ); + continue; + } + case 22: { + if (tag !== 178) { + break; + } + + message.outgoingAllianceRequests.push(reader.string()); + continue; + } + case 23: { + if (tag !== 186) { + break; + } + + message.alliances.push(AllianceView.decode(reader, reader.uint32())); + continue; + } + case 24: { + if (tag !== 192) { + break; + } + + message.hasSpawned = reader.bool(); + continue; + } + case 25: { + if (tag !== 200) { + break; + } + + message.betrayals = reader.int32(); + continue; + } + case 26: { + if (tag !== 208) { + break; + } + + message.lastDeleteUnitTick = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): PlayerUpdate { + return { + nameViewData: isSet(object.nameViewData) + ? NameViewData.fromJSON(object.nameViewData) + : undefined, + clientId: isSet(object.clientId) + ? globalThis.String(object.clientId) + : undefined, + name: isSet(object.name) ? globalThis.String(object.name) : "", + displayName: isSet(object.displayName) + ? globalThis.String(object.displayName) + : "", + id: isSet(object.id) ? globalThis.String(object.id) : "", + team: isSet(object.team) ? globalThis.String(object.team) : undefined, + smallId: isSet(object.smallId) ? globalThis.Number(object.smallId) : 0, + playerType: isSet(object.playerType) + ? playerTypeFromJSON(object.playerType) + : 0, + isAlive: isSet(object.isAlive) + ? globalThis.Boolean(object.isAlive) + : false, + isDisconnected: isSet(object.isDisconnected) + ? globalThis.Boolean(object.isDisconnected) + : false, + tilesOwned: isSet(object.tilesOwned) + ? globalThis.Number(object.tilesOwned) + : 0, + gold: isSet(object.gold) ? globalThis.Number(object.gold) : 0, + troops: isSet(object.troops) ? globalThis.Number(object.troops) : 0, + allies: globalThis.Array.isArray(object?.allies) + ? object.allies.map((e: any) => globalThis.Number(e)) + : [], + embargoes: globalThis.Array.isArray(object?.embargoes) + ? object.embargoes.map((e: any) => globalThis.String(e)) + : [], + isTraitor: isSet(object.isTraitor) + ? globalThis.Boolean(object.isTraitor) + : false, + traitorRemainingTicks: isSet(object.traitorRemainingTicks) + ? globalThis.Number(object.traitorRemainingTicks) + : undefined, + targets: globalThis.Array.isArray(object?.targets) + ? object.targets.map((e: any) => globalThis.Number(e)) + : [], + outgoingEmojis: globalThis.Array.isArray(object?.outgoingEmojis) + ? object.outgoingEmojis.map((e: any) => EmojiMessage.fromJSON(e)) + : [], + outgoingAttacks: globalThis.Array.isArray(object?.outgoingAttacks) + ? object.outgoingAttacks.map((e: any) => AttackUpdate.fromJSON(e)) + : [], + incomingAttacks: globalThis.Array.isArray(object?.incomingAttacks) + ? object.incomingAttacks.map((e: any) => AttackUpdate.fromJSON(e)) + : [], + outgoingAllianceRequests: globalThis.Array.isArray( + object?.outgoingAllianceRequests, + ) + ? object.outgoingAllianceRequests.map((e: any) => globalThis.String(e)) + : [], + alliances: globalThis.Array.isArray(object?.alliances) + ? object.alliances.map((e: any) => AllianceView.fromJSON(e)) + : [], + hasSpawned: isSet(object.hasSpawned) + ? globalThis.Boolean(object.hasSpawned) + : false, + betrayals: isSet(object.betrayals) + ? globalThis.Number(object.betrayals) + : 0, + lastDeleteUnitTick: isSet(object.lastDeleteUnitTick) + ? globalThis.Number(object.lastDeleteUnitTick) + : 0, + }; + }, + + toJSON(message: PlayerUpdate): unknown { + const obj: any = {}; + if (message.nameViewData !== undefined) { + obj.nameViewData = NameViewData.toJSON(message.nameViewData); + } + if (message.clientId !== undefined) { + obj.clientId = message.clientId; + } + if (message.name !== "") { + obj.name = message.name; + } + if (message.displayName !== "") { + obj.displayName = message.displayName; + } + if (message.id !== "") { + obj.id = message.id; + } + if (message.team !== undefined) { + obj.team = message.team; + } + if (message.smallId !== 0) { + obj.smallId = Math.round(message.smallId); + } + if (message.playerType !== 0) { + obj.playerType = playerTypeToJSON(message.playerType); + } + if (message.isAlive !== false) { + obj.isAlive = message.isAlive; + } + if (message.isDisconnected !== false) { + obj.isDisconnected = message.isDisconnected; + } + if (message.tilesOwned !== 0) { + obj.tilesOwned = Math.round(message.tilesOwned); + } + if (message.gold !== 0) { + obj.gold = Math.round(message.gold); + } + if (message.troops !== 0) { + obj.troops = Math.round(message.troops); + } + if (message.allies?.length) { + obj.allies = message.allies.map((e) => Math.round(e)); + } + if (message.embargoes?.length) { + obj.embargoes = message.embargoes; + } + if (message.isTraitor !== false) { + obj.isTraitor = message.isTraitor; + } + if (message.traitorRemainingTicks !== undefined) { + obj.traitorRemainingTicks = Math.round(message.traitorRemainingTicks); + } + if (message.targets?.length) { + obj.targets = message.targets.map((e) => Math.round(e)); + } + if (message.outgoingEmojis?.length) { + obj.outgoingEmojis = message.outgoingEmojis.map((e) => + EmojiMessage.toJSON(e), + ); + } + if (message.outgoingAttacks?.length) { + obj.outgoingAttacks = message.outgoingAttacks.map((e) => + AttackUpdate.toJSON(e), + ); + } + if (message.incomingAttacks?.length) { + obj.incomingAttacks = message.incomingAttacks.map((e) => + AttackUpdate.toJSON(e), + ); + } + if (message.outgoingAllianceRequests?.length) { + obj.outgoingAllianceRequests = message.outgoingAllianceRequests; + } + if (message.alliances?.length) { + obj.alliances = message.alliances.map((e) => AllianceView.toJSON(e)); + } + if (message.hasSpawned !== false) { + obj.hasSpawned = message.hasSpawned; + } + if (message.betrayals !== 0) { + obj.betrayals = Math.round(message.betrayals); + } + if (message.lastDeleteUnitTick !== 0) { + obj.lastDeleteUnitTick = Math.round(message.lastDeleteUnitTick); + } + return obj; + }, + + create, I>>( + base?: I, + ): PlayerUpdate { + return PlayerUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): PlayerUpdate { + const message = createBasePlayerUpdate(); + message.nameViewData = + object.nameViewData !== undefined && object.nameViewData !== null + ? NameViewData.fromPartial(object.nameViewData) + : undefined; + message.clientId = object.clientId ?? undefined; + message.name = object.name ?? ""; + message.displayName = object.displayName ?? ""; + message.id = object.id ?? ""; + message.team = object.team ?? undefined; + message.smallId = object.smallId ?? 0; + message.playerType = object.playerType ?? 0; + message.isAlive = object.isAlive ?? false; + message.isDisconnected = object.isDisconnected ?? false; + message.tilesOwned = object.tilesOwned ?? 0; + message.gold = object.gold ?? 0; + message.troops = object.troops ?? 0; + message.allies = object.allies?.map((e) => e) || []; + message.embargoes = object.embargoes?.map((e) => e) || []; + message.isTraitor = object.isTraitor ?? false; + message.traitorRemainingTicks = object.traitorRemainingTicks ?? undefined; + message.targets = object.targets?.map((e) => e) || []; + message.outgoingEmojis = + object.outgoingEmojis?.map((e) => EmojiMessage.fromPartial(e)) || []; + message.outgoingAttacks = + object.outgoingAttacks?.map((e) => AttackUpdate.fromPartial(e)) || []; + message.incomingAttacks = + object.incomingAttacks?.map((e) => AttackUpdate.fromPartial(e)) || []; + message.outgoingAllianceRequests = + object.outgoingAllianceRequests?.map((e) => e) || []; + message.alliances = + object.alliances?.map((e) => AllianceView.fromPartial(e)) || []; + message.hasSpawned = object.hasSpawned ?? false; + message.betrayals = object.betrayals ?? 0; + message.lastDeleteUnitTick = object.lastDeleteUnitTick ?? 0; + return message; + }, +}; + +function createBaseAllianceRequestUpdate(): AllianceRequestUpdate { + return { requestorId: 0, recipientId: 0, createdAt: 0 }; +} + +export const AllianceRequestUpdate: MessageFns = { + encode( + message: AllianceRequestUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.requestorId !== 0) { + writer.uint32(8).int32(message.requestorId); + } + if (message.recipientId !== 0) { + writer.uint32(16).int32(message.recipientId); + } + if (message.createdAt !== 0) { + writer.uint32(24).int32(message.createdAt); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): AllianceRequestUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAllianceRequestUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.requestorId = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.recipientId = reader.int32(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.createdAt = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): AllianceRequestUpdate { + return { + requestorId: isSet(object.requestorId) + ? globalThis.Number(object.requestorId) + : 0, + recipientId: isSet(object.recipientId) + ? globalThis.Number(object.recipientId) + : 0, + createdAt: isSet(object.createdAt) + ? globalThis.Number(object.createdAt) + : 0, + }; + }, + + toJSON(message: AllianceRequestUpdate): unknown { + const obj: any = {}; + if (message.requestorId !== 0) { + obj.requestorId = Math.round(message.requestorId); + } + if (message.recipientId !== 0) { + obj.recipientId = Math.round(message.recipientId); + } + if (message.createdAt !== 0) { + obj.createdAt = Math.round(message.createdAt); + } + return obj; + }, + + create, I>>( + base?: I, + ): AllianceRequestUpdate { + return AllianceRequestUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): AllianceRequestUpdate { + const message = createBaseAllianceRequestUpdate(); + message.requestorId = object.requestorId ?? 0; + message.recipientId = object.recipientId ?? 0; + message.createdAt = object.createdAt ?? 0; + return message; + }, +}; + +function createBaseAllianceRequestReplyUpdate(): AllianceRequestReplyUpdate { + return { request: undefined, accepted: false }; +} + +export const AllianceRequestReplyUpdate: MessageFns = + { + encode( + message: AllianceRequestReplyUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.request !== undefined) { + AllianceRequestUpdate.encode( + message.request, + writer.uint32(10).fork(), + ).join(); + } + if (message.accepted !== false) { + writer.uint32(16).bool(message.accepted); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): AllianceRequestReplyUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAllianceRequestReplyUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.request = AllianceRequestUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.accepted = reader.bool(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): AllianceRequestReplyUpdate { + return { + request: isSet(object.request) + ? AllianceRequestUpdate.fromJSON(object.request) + : undefined, + accepted: isSet(object.accepted) + ? globalThis.Boolean(object.accepted) + : false, + }; + }, + + toJSON(message: AllianceRequestReplyUpdate): unknown { + const obj: any = {}; + if (message.request !== undefined) { + obj.request = AllianceRequestUpdate.toJSON(message.request); + } + if (message.accepted !== false) { + obj.accepted = message.accepted; + } + return obj; + }, + + create, I>>( + base?: I, + ): AllianceRequestReplyUpdate { + return AllianceRequestReplyUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): AllianceRequestReplyUpdate { + const message = createBaseAllianceRequestReplyUpdate(); + message.request = + object.request !== undefined && object.request !== null + ? AllianceRequestUpdate.fromPartial(object.request) + : undefined; + message.accepted = object.accepted ?? false; + return message; + }, + }; + +function createBaseBrokeAllianceUpdate(): BrokeAllianceUpdate { + return { traitorId: 0, betrayedId: 0 }; +} + +export const BrokeAllianceUpdate: MessageFns = { + encode( + message: BrokeAllianceUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.traitorId !== 0) { + writer.uint32(8).int32(message.traitorId); + } + if (message.betrayedId !== 0) { + writer.uint32(16).int32(message.betrayedId); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): BrokeAllianceUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseBrokeAllianceUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.traitorId = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.betrayedId = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): BrokeAllianceUpdate { + return { + traitorId: isSet(object.traitorId) + ? globalThis.Number(object.traitorId) + : 0, + betrayedId: isSet(object.betrayedId) + ? globalThis.Number(object.betrayedId) + : 0, + }; + }, + + toJSON(message: BrokeAllianceUpdate): unknown { + const obj: any = {}; + if (message.traitorId !== 0) { + obj.traitorId = Math.round(message.traitorId); + } + if (message.betrayedId !== 0) { + obj.betrayedId = Math.round(message.betrayedId); + } + return obj; + }, + + create, I>>( + base?: I, + ): BrokeAllianceUpdate { + return BrokeAllianceUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): BrokeAllianceUpdate { + const message = createBaseBrokeAllianceUpdate(); + message.traitorId = object.traitorId ?? 0; + message.betrayedId = object.betrayedId ?? 0; + return message; + }, +}; + +function createBaseAllianceExpiredUpdate(): AllianceExpiredUpdate { + return { player1Id: 0, player2Id: 0 }; +} + +export const AllianceExpiredUpdate: MessageFns = { + encode( + message: AllianceExpiredUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.player1Id !== 0) { + writer.uint32(8).int32(message.player1Id); + } + if (message.player2Id !== 0) { + writer.uint32(16).int32(message.player2Id); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): AllianceExpiredUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAllianceExpiredUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.player1Id = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.player2Id = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): AllianceExpiredUpdate { + return { + player1Id: isSet(object.player1Id) + ? globalThis.Number(object.player1Id) + : 0, + player2Id: isSet(object.player2Id) + ? globalThis.Number(object.player2Id) + : 0, + }; + }, + + toJSON(message: AllianceExpiredUpdate): unknown { + const obj: any = {}; + if (message.player1Id !== 0) { + obj.player1Id = Math.round(message.player1Id); + } + if (message.player2Id !== 0) { + obj.player2Id = Math.round(message.player2Id); + } + return obj; + }, + + create, I>>( + base?: I, + ): AllianceExpiredUpdate { + return AllianceExpiredUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): AllianceExpiredUpdate { + const message = createBaseAllianceExpiredUpdate(); + message.player1Id = object.player1Id ?? 0; + message.player2Id = object.player2Id ?? 0; + return message; + }, +}; + +function createBaseAllianceExtensionUpdate(): AllianceExtensionUpdate { + return { playerId: "", allianceId: 0 }; +} + +export const AllianceExtensionUpdate: MessageFns = { + encode( + message: AllianceExtensionUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.playerId !== "") { + writer.uint32(10).string(message.playerId); + } + if (message.allianceId !== 0) { + writer.uint32(16).int32(message.allianceId); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): AllianceExtensionUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseAllianceExtensionUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.playerId = reader.string(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.allianceId = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): AllianceExtensionUpdate { + return { + playerId: isSet(object.playerId) + ? globalThis.String(object.playerId) + : "", + allianceId: isSet(object.allianceId) + ? globalThis.Number(object.allianceId) + : 0, + }; + }, + + toJSON(message: AllianceExtensionUpdate): unknown { + const obj: any = {}; + if (message.playerId !== "") { + obj.playerId = message.playerId; + } + if (message.allianceId !== 0) { + obj.allianceId = Math.round(message.allianceId); + } + return obj; + }, + + create, I>>( + base?: I, + ): AllianceExtensionUpdate { + return AllianceExtensionUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): AllianceExtensionUpdate { + const message = createBaseAllianceExtensionUpdate(); + message.playerId = object.playerId ?? ""; + message.allianceId = object.allianceId ?? 0; + return message; + }, +}; + +function createBaseTargetPlayerUpdate(): TargetPlayerUpdate { + return { playerId: 0, targetId: 0 }; +} + +export const TargetPlayerUpdate: MessageFns = { + encode( + message: TargetPlayerUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.playerId !== 0) { + writer.uint32(8).int32(message.playerId); + } + if (message.targetId !== 0) { + writer.uint32(16).int32(message.targetId); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): TargetPlayerUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseTargetPlayerUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.playerId = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.targetId = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): TargetPlayerUpdate { + return { + playerId: isSet(object.playerId) ? globalThis.Number(object.playerId) : 0, + targetId: isSet(object.targetId) ? globalThis.Number(object.targetId) : 0, + }; + }, + + toJSON(message: TargetPlayerUpdate): unknown { + const obj: any = {}; + if (message.playerId !== 0) { + obj.playerId = Math.round(message.playerId); + } + if (message.targetId !== 0) { + obj.targetId = Math.round(message.targetId); + } + return obj; + }, + + create, I>>( + base?: I, + ): TargetPlayerUpdate { + return TargetPlayerUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): TargetPlayerUpdate { + const message = createBaseTargetPlayerUpdate(); + message.playerId = object.playerId ?? 0; + message.targetId = object.targetId ?? 0; + return message; + }, +}; + +function createBaseEmojiUpdate(): EmojiUpdate { + return { emoji: undefined }; +} + +export const EmojiUpdate: MessageFns = { + encode( + message: EmojiUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.emoji !== undefined) { + EmojiMessage.encode(message.emoji, writer.uint32(10).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): EmojiUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseEmojiUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.emoji = EmojiMessage.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): EmojiUpdate { + return { + emoji: isSet(object.emoji) + ? EmojiMessage.fromJSON(object.emoji) + : undefined, + }; + }, + + toJSON(message: EmojiUpdate): unknown { + const obj: any = {}; + if (message.emoji !== undefined) { + obj.emoji = EmojiMessage.toJSON(message.emoji); + } + return obj; + }, + + create, I>>(base?: I): EmojiUpdate { + return EmojiUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): EmojiUpdate { + const message = createBaseEmojiUpdate(); + message.emoji = + object.emoji !== undefined && object.emoji !== null + ? EmojiMessage.fromPartial(object.emoji) + : undefined; + return message; + }, +}; + +function createBaseDisplayMessageUpdate(): DisplayMessageUpdate { + return { + message: "", + messageType: 0, + goldAmount: undefined, + playerId: undefined, + params: {}, + }; +} + +export const DisplayMessageUpdate: MessageFns = { + encode( + message: DisplayMessageUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.message !== "") { + writer.uint32(10).string(message.message); + } + if (message.messageType !== 0) { + writer.uint32(16).int32(message.messageType); + } + if (message.goldAmount !== undefined) { + writer.uint32(24).int64(message.goldAmount); + } + if (message.playerId !== undefined) { + writer.uint32(32).int64(message.playerId); + } + Object.entries(message.params).forEach(([key, value]) => { + DisplayMessageUpdate_ParamsEntry.encode( + { key: key as any, value }, + writer.uint32(42).fork(), + ).join(); + }); + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): DisplayMessageUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseDisplayMessageUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.message = reader.string(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.messageType = reader.int32() as any; + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.goldAmount = longToNumber(reader.int64()); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.playerId = longToNumber(reader.int64()); + continue; + } + case 5: { + if (tag !== 42) { + break; + } + + const entry5 = DisplayMessageUpdate_ParamsEntry.decode( + reader, + reader.uint32(), + ); + if (entry5.value !== undefined) { + message.params[entry5.key] = entry5.value; + } + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): DisplayMessageUpdate { + return { + message: isSet(object.message) ? globalThis.String(object.message) : "", + messageType: isSet(object.messageType) + ? messageTypeFromJSON(object.messageType) + : 0, + goldAmount: isSet(object.goldAmount) + ? globalThis.Number(object.goldAmount) + : undefined, + playerId: isSet(object.playerId) + ? globalThis.Number(object.playerId) + : undefined, + params: isObject(object.params) + ? Object.entries(object.params).reduce<{ [key: string]: string }>( + (acc, [key, value]) => { + acc[key] = String(value); + return acc; + }, + {}, + ) + : {}, + }; + }, + + toJSON(message: DisplayMessageUpdate): unknown { + const obj: any = {}; + if (message.message !== "") { + obj.message = message.message; + } + if (message.messageType !== 0) { + obj.messageType = messageTypeToJSON(message.messageType); + } + if (message.goldAmount !== undefined) { + obj.goldAmount = Math.round(message.goldAmount); + } + if (message.playerId !== undefined) { + obj.playerId = Math.round(message.playerId); + } + if (message.params) { + const entries = Object.entries(message.params); + if (entries.length > 0) { + obj.params = {}; + entries.forEach(([k, v]) => { + obj.params[k] = v; + }); + } + } + return obj; + }, + + create, I>>( + base?: I, + ): DisplayMessageUpdate { + return DisplayMessageUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): DisplayMessageUpdate { + const message = createBaseDisplayMessageUpdate(); + message.message = object.message ?? ""; + message.messageType = object.messageType ?? 0; + message.goldAmount = object.goldAmount ?? undefined; + message.playerId = object.playerId ?? undefined; + message.params = Object.entries(object.params ?? {}).reduce<{ + [key: string]: string; + }>((acc, [key, value]) => { + if (value !== undefined) { + acc[key] = globalThis.String(value); + } + return acc; + }, {}); + return message; + }, +}; + +function createBaseDisplayMessageUpdate_ParamsEntry(): DisplayMessageUpdate_ParamsEntry { + return { key: "", value: "" }; +} + +export const DisplayMessageUpdate_ParamsEntry: MessageFns = + { + encode( + message: DisplayMessageUpdate_ParamsEntry, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.key !== "") { + writer.uint32(10).string(message.key); + } + if (message.value !== "") { + writer.uint32(18).string(message.value); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): DisplayMessageUpdate_ParamsEntry { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseDisplayMessageUpdate_ParamsEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.key = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.value = reader.string(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): DisplayMessageUpdate_ParamsEntry { + return { + key: isSet(object.key) ? globalThis.String(object.key) : "", + value: isSet(object.value) ? globalThis.String(object.value) : "", + }; + }, + + toJSON(message: DisplayMessageUpdate_ParamsEntry): unknown { + const obj: any = {}; + if (message.key !== "") { + obj.key = message.key; + } + if (message.value !== "") { + obj.value = message.value; + } + return obj; + }, + + create, I>>( + base?: I, + ): DisplayMessageUpdate_ParamsEntry { + return DisplayMessageUpdate_ParamsEntry.fromPartial(base ?? ({} as any)); + }, + fromPartial< + I extends Exact, I>, + >(object: I): DisplayMessageUpdate_ParamsEntry { + const message = createBaseDisplayMessageUpdate_ParamsEntry(); + message.key = object.key ?? ""; + message.value = object.value ?? ""; + return message; + }, + }; + +function createBaseDisplayChatMessageUpdate(): DisplayChatMessageUpdate { + return { + key: "", + category: "", + target: undefined, + playerId: undefined, + isFrom: false, + recipient: "", + }; +} + +export const DisplayChatMessageUpdate: MessageFns = { + encode( + message: DisplayChatMessageUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.key !== "") { + writer.uint32(10).string(message.key); + } + if (message.category !== "") { + writer.uint32(18).string(message.category); + } + if (message.target !== undefined) { + writer.uint32(26).string(message.target); + } + if (message.playerId !== undefined) { + writer.uint32(32).int32(message.playerId); + } + if (message.isFrom !== false) { + writer.uint32(40).bool(message.isFrom); + } + if (message.recipient !== "") { + writer.uint32(50).string(message.recipient); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): DisplayChatMessageUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseDisplayChatMessageUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.key = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.category = reader.string(); + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.target = reader.string(); + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.playerId = reader.int32(); + continue; + } + case 5: { + if (tag !== 40) { + break; + } + + message.isFrom = reader.bool(); + continue; + } + case 6: { + if (tag !== 50) { + break; + } + + message.recipient = reader.string(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): DisplayChatMessageUpdate { + return { + key: isSet(object.key) ? globalThis.String(object.key) : "", + category: isSet(object.category) + ? globalThis.String(object.category) + : "", + target: isSet(object.target) + ? globalThis.String(object.target) + : undefined, + playerId: isSet(object.playerId) + ? globalThis.Number(object.playerId) + : undefined, + isFrom: isSet(object.isFrom) ? globalThis.Boolean(object.isFrom) : false, + recipient: isSet(object.recipient) + ? globalThis.String(object.recipient) + : "", + }; + }, + + toJSON(message: DisplayChatMessageUpdate): unknown { + const obj: any = {}; + if (message.key !== "") { + obj.key = message.key; + } + if (message.category !== "") { + obj.category = message.category; + } + if (message.target !== undefined) { + obj.target = message.target; + } + if (message.playerId !== undefined) { + obj.playerId = Math.round(message.playerId); + } + if (message.isFrom !== false) { + obj.isFrom = message.isFrom; + } + if (message.recipient !== "") { + obj.recipient = message.recipient; + } + return obj; + }, + + create, I>>( + base?: I, + ): DisplayChatMessageUpdate { + return DisplayChatMessageUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): DisplayChatMessageUpdate { + const message = createBaseDisplayChatMessageUpdate(); + message.key = object.key ?? ""; + message.category = object.category ?? ""; + message.target = object.target ?? undefined; + message.playerId = object.playerId ?? undefined; + message.isFrom = object.isFrom ?? false; + message.recipient = object.recipient ?? ""; + return message; + }, +}; + +function createBaseWinUpdate(): WinUpdate { + return { winner: "", stats: "" }; +} + +export const WinUpdate: MessageFns = { + encode( + message: WinUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.winner !== "") { + writer.uint32(10).string(message.winner); + } + if (message.stats !== "") { + writer.uint32(18).string(message.stats); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): WinUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseWinUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.winner = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.stats = reader.string(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): WinUpdate { + return { + winner: isSet(object.winner) ? globalThis.String(object.winner) : "", + stats: isSet(object.stats) ? globalThis.String(object.stats) : "", + }; + }, + + toJSON(message: WinUpdate): unknown { + const obj: any = {}; + if (message.winner !== "") { + obj.winner = message.winner; + } + if (message.stats !== "") { + obj.stats = message.stats; + } + return obj; + }, + + create, I>>(base?: I): WinUpdate { + return WinUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): WinUpdate { + const message = createBaseWinUpdate(); + message.winner = object.winner ?? ""; + message.stats = object.stats ?? ""; + return message; + }, +}; + +function createBaseHashUpdate(): HashUpdate { + return { tick: 0, hash: 0 }; +} + +export const HashUpdate: MessageFns = { + encode( + message: HashUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.tick !== 0) { + writer.uint32(8).int32(message.tick); + } + if (message.hash !== 0) { + writer.uint32(16).int32(message.hash); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): HashUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseHashUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.tick = reader.int32(); + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.hash = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): HashUpdate { + return { + tick: isSet(object.tick) ? globalThis.Number(object.tick) : 0, + hash: isSet(object.hash) ? globalThis.Number(object.hash) : 0, + }; + }, + + toJSON(message: HashUpdate): unknown { + const obj: any = {}; + if (message.tick !== 0) { + obj.tick = Math.round(message.tick); + } + if (message.hash !== 0) { + obj.hash = Math.round(message.hash); + } + return obj; + }, + + create, I>>(base?: I): HashUpdate { + return HashUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): HashUpdate { + const message = createBaseHashUpdate(); + message.tick = object.tick ?? 0; + message.hash = object.hash ?? 0; + return message; + }, +}; + +function createBaseUnitIncomingUpdate(): UnitIncomingUpdate { + return { unitId: 0, message: "", messageType: 0, playerId: 0 }; +} + +export const UnitIncomingUpdate: MessageFns = { + encode( + message: UnitIncomingUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.unitId !== 0) { + writer.uint32(8).int32(message.unitId); + } + if (message.message !== "") { + writer.uint32(18).string(message.message); + } + if (message.messageType !== 0) { + writer.uint32(24).int32(message.messageType); + } + if (message.playerId !== 0) { + writer.uint32(32).int32(message.playerId); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): UnitIncomingUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseUnitIncomingUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.unitId = reader.int32(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.message = reader.string(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.messageType = reader.int32() as any; + continue; + } + case 4: { + if (tag !== 32) { + break; + } + + message.playerId = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): UnitIncomingUpdate { + return { + unitId: isSet(object.unitId) ? globalThis.Number(object.unitId) : 0, + message: isSet(object.message) ? globalThis.String(object.message) : "", + messageType: isSet(object.messageType) + ? messageTypeFromJSON(object.messageType) + : 0, + playerId: isSet(object.playerId) ? globalThis.Number(object.playerId) : 0, + }; + }, + + toJSON(message: UnitIncomingUpdate): unknown { + const obj: any = {}; + if (message.unitId !== 0) { + obj.unitId = Math.round(message.unitId); + } + if (message.message !== "") { + obj.message = message.message; + } + if (message.messageType !== 0) { + obj.messageType = messageTypeToJSON(message.messageType); + } + if (message.playerId !== 0) { + obj.playerId = Math.round(message.playerId); + } + return obj; + }, + + create, I>>( + base?: I, + ): UnitIncomingUpdate { + return UnitIncomingUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): UnitIncomingUpdate { + const message = createBaseUnitIncomingUpdate(); + message.unitId = object.unitId ?? 0; + message.message = object.message ?? ""; + message.messageType = object.messageType ?? 0; + message.playerId = object.playerId ?? 0; + return message; + }, +}; + +function createBaseEmbargoUpdate(): EmbargoUpdate { + return { event: 0, playerId: 0, embargoedId: 0 }; +} + +export const EmbargoUpdate: MessageFns = { + encode( + message: EmbargoUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.event !== 0) { + writer.uint32(8).int32(message.event); + } + if (message.playerId !== 0) { + writer.uint32(16).int32(message.playerId); + } + if (message.embargoedId !== 0) { + writer.uint32(24).int32(message.embargoedId); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): EmbargoUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseEmbargoUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.event = reader.int32() as any; + continue; + } + case 2: { + if (tag !== 16) { + break; + } + + message.playerId = reader.int32(); + continue; + } + case 3: { + if (tag !== 24) { + break; + } + + message.embargoedId = reader.int32(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): EmbargoUpdate { + return { + event: isSet(object.event) + ? embargoUpdate_EmbargoEventFromJSON(object.event) + : 0, + playerId: isSet(object.playerId) ? globalThis.Number(object.playerId) : 0, + embargoedId: isSet(object.embargoedId) + ? globalThis.Number(object.embargoedId) + : 0, + }; + }, + + toJSON(message: EmbargoUpdate): unknown { + const obj: any = {}; + if (message.event !== 0) { + obj.event = embargoUpdate_EmbargoEventToJSON(message.event); + } + if (message.playerId !== 0) { + obj.playerId = Math.round(message.playerId); + } + if (message.embargoedId !== 0) { + obj.embargoedId = Math.round(message.embargoedId); + } + return obj; + }, + + create, I>>( + base?: I, + ): EmbargoUpdate { + return EmbargoUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): EmbargoUpdate { + const message = createBaseEmbargoUpdate(); + message.event = object.event ?? 0; + message.playerId = object.playerId ?? 0; + message.embargoedId = object.embargoedId ?? 0; + return message; + }, +}; + +function createBaseGameUpdate(): GameUpdate { + return { + type: 0, + unit: undefined, + player: undefined, + allianceRequest: undefined, + allianceRequestReply: undefined, + brokeAlliance: undefined, + allianceExpired: undefined, + displayMessage: undefined, + displayChatMessage: undefined, + targetPlayer: undefined, + emoji: undefined, + win: undefined, + hash: undefined, + unitIncoming: undefined, + allianceExtension: undefined, + bonusEvent: undefined, + railroad: undefined, + conquest: undefined, + embargo: undefined, + }; +} + +export const GameUpdate: MessageFns = { + encode( + message: GameUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.type !== 0) { + writer.uint32(8).int32(message.type); + } + if (message.unit !== undefined) { + UnitUpdate.encode(message.unit, writer.uint32(26).fork()).join(); + } + if (message.player !== undefined) { + PlayerUpdate.encode(message.player, writer.uint32(34).fork()).join(); + } + if (message.allianceRequest !== undefined) { + AllianceRequestUpdate.encode( + message.allianceRequest, + writer.uint32(42).fork(), + ).join(); + } + if (message.allianceRequestReply !== undefined) { + AllianceRequestReplyUpdate.encode( + message.allianceRequestReply, + writer.uint32(50).fork(), + ).join(); + } + if (message.brokeAlliance !== undefined) { + BrokeAllianceUpdate.encode( + message.brokeAlliance, + writer.uint32(58).fork(), + ).join(); + } + if (message.allianceExpired !== undefined) { + AllianceExpiredUpdate.encode( + message.allianceExpired, + writer.uint32(66).fork(), + ).join(); + } + if (message.displayMessage !== undefined) { + DisplayMessageUpdate.encode( + message.displayMessage, + writer.uint32(74).fork(), + ).join(); + } + if (message.displayChatMessage !== undefined) { + DisplayChatMessageUpdate.encode( + message.displayChatMessage, + writer.uint32(82).fork(), + ).join(); + } + if (message.targetPlayer !== undefined) { + TargetPlayerUpdate.encode( + message.targetPlayer, + writer.uint32(90).fork(), + ).join(); + } + if (message.emoji !== undefined) { + EmojiUpdate.encode(message.emoji, writer.uint32(98).fork()).join(); + } + if (message.win !== undefined) { + WinUpdate.encode(message.win, writer.uint32(106).fork()).join(); + } + if (message.hash !== undefined) { + HashUpdate.encode(message.hash, writer.uint32(114).fork()).join(); + } + if (message.unitIncoming !== undefined) { + UnitIncomingUpdate.encode( + message.unitIncoming, + writer.uint32(122).fork(), + ).join(); + } + if (message.allianceExtension !== undefined) { + AllianceExtensionUpdate.encode( + message.allianceExtension, + writer.uint32(130).fork(), + ).join(); + } + if (message.bonusEvent !== undefined) { + BonusEventUpdate.encode( + message.bonusEvent, + writer.uint32(138).fork(), + ).join(); + } + if (message.railroad !== undefined) { + RailroadUpdate.encode(message.railroad, writer.uint32(146).fork()).join(); + } + if (message.conquest !== undefined) { + ConquestUpdate.encode(message.conquest, writer.uint32(154).fork()).join(); + } + if (message.embargo !== undefined) { + EmbargoUpdate.encode(message.embargo, writer.uint32(162).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): GameUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGameUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.type = reader.int32() as any; + continue; + } + case 3: { + if (tag !== 26) { + break; + } + + message.unit = UnitUpdate.decode(reader, reader.uint32()); + continue; + } + case 4: { + if (tag !== 34) { + break; + } + + message.player = PlayerUpdate.decode(reader, reader.uint32()); + continue; + } + case 5: { + if (tag !== 42) { + break; + } + + message.allianceRequest = AllianceRequestUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 6: { + if (tag !== 50) { + break; + } + + message.allianceRequestReply = AllianceRequestReplyUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 7: { + if (tag !== 58) { + break; + } + + message.brokeAlliance = BrokeAllianceUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 8: { + if (tag !== 66) { + break; + } + + message.allianceExpired = AllianceExpiredUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 9: { + if (tag !== 74) { + break; + } + + message.displayMessage = DisplayMessageUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 10: { + if (tag !== 82) { + break; + } + + message.displayChatMessage = DisplayChatMessageUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 11: { + if (tag !== 90) { + break; + } + + message.targetPlayer = TargetPlayerUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 12: { + if (tag !== 98) { + break; + } + + message.emoji = EmojiUpdate.decode(reader, reader.uint32()); + continue; + } + case 13: { + if (tag !== 106) { + break; + } + + message.win = WinUpdate.decode(reader, reader.uint32()); + continue; + } + case 14: { + if (tag !== 114) { + break; + } + + message.hash = HashUpdate.decode(reader, reader.uint32()); + continue; + } + case 15: { + if (tag !== 122) { + break; + } + + message.unitIncoming = UnitIncomingUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 16: { + if (tag !== 130) { + break; + } + + message.allianceExtension = AllianceExtensionUpdate.decode( + reader, + reader.uint32(), + ); + continue; + } + case 17: { + if (tag !== 138) { + break; + } + + message.bonusEvent = BonusEventUpdate.decode(reader, reader.uint32()); + continue; + } + case 18: { + if (tag !== 146) { + break; + } + + message.railroad = RailroadUpdate.decode(reader, reader.uint32()); + continue; + } + case 19: { + if (tag !== 154) { + break; + } + + message.conquest = ConquestUpdate.decode(reader, reader.uint32()); + continue; + } + case 20: { + if (tag !== 162) { + break; + } + + message.embargo = EmbargoUpdate.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): GameUpdate { + return { + type: isSet(object.type) ? gameUpdateTypeFromJSON(object.type) : 0, + unit: isSet(object.unit) ? UnitUpdate.fromJSON(object.unit) : undefined, + player: isSet(object.player) + ? PlayerUpdate.fromJSON(object.player) + : undefined, + allianceRequest: isSet(object.allianceRequest) + ? AllianceRequestUpdate.fromJSON(object.allianceRequest) + : undefined, + allianceRequestReply: isSet(object.allianceRequestReply) + ? AllianceRequestReplyUpdate.fromJSON(object.allianceRequestReply) + : undefined, + brokeAlliance: isSet(object.brokeAlliance) + ? BrokeAllianceUpdate.fromJSON(object.brokeAlliance) + : undefined, + allianceExpired: isSet(object.allianceExpired) + ? AllianceExpiredUpdate.fromJSON(object.allianceExpired) + : undefined, + displayMessage: isSet(object.displayMessage) + ? DisplayMessageUpdate.fromJSON(object.displayMessage) + : undefined, + displayChatMessage: isSet(object.displayChatMessage) + ? DisplayChatMessageUpdate.fromJSON(object.displayChatMessage) + : undefined, + targetPlayer: isSet(object.targetPlayer) + ? TargetPlayerUpdate.fromJSON(object.targetPlayer) + : undefined, + emoji: isSet(object.emoji) + ? EmojiUpdate.fromJSON(object.emoji) + : undefined, + win: isSet(object.win) ? WinUpdate.fromJSON(object.win) : undefined, + hash: isSet(object.hash) ? HashUpdate.fromJSON(object.hash) : undefined, + unitIncoming: isSet(object.unitIncoming) + ? UnitIncomingUpdate.fromJSON(object.unitIncoming) + : undefined, + allianceExtension: isSet(object.allianceExtension) + ? AllianceExtensionUpdate.fromJSON(object.allianceExtension) + : undefined, + bonusEvent: isSet(object.bonusEvent) + ? BonusEventUpdate.fromJSON(object.bonusEvent) + : undefined, + railroad: isSet(object.railroad) + ? RailroadUpdate.fromJSON(object.railroad) + : undefined, + conquest: isSet(object.conquest) + ? ConquestUpdate.fromJSON(object.conquest) + : undefined, + embargo: isSet(object.embargo) + ? EmbargoUpdate.fromJSON(object.embargo) + : undefined, + }; + }, + + toJSON(message: GameUpdate): unknown { + const obj: any = {}; + if (message.type !== 0) { + obj.type = gameUpdateTypeToJSON(message.type); + } + if (message.unit !== undefined) { + obj.unit = UnitUpdate.toJSON(message.unit); + } + if (message.player !== undefined) { + obj.player = PlayerUpdate.toJSON(message.player); + } + if (message.allianceRequest !== undefined) { + obj.allianceRequest = AllianceRequestUpdate.toJSON( + message.allianceRequest, + ); + } + if (message.allianceRequestReply !== undefined) { + obj.allianceRequestReply = AllianceRequestReplyUpdate.toJSON( + message.allianceRequestReply, + ); + } + if (message.brokeAlliance !== undefined) { + obj.brokeAlliance = BrokeAllianceUpdate.toJSON(message.brokeAlliance); + } + if (message.allianceExpired !== undefined) { + obj.allianceExpired = AllianceExpiredUpdate.toJSON( + message.allianceExpired, + ); + } + if (message.displayMessage !== undefined) { + obj.displayMessage = DisplayMessageUpdate.toJSON(message.displayMessage); + } + if (message.displayChatMessage !== undefined) { + obj.displayChatMessage = DisplayChatMessageUpdate.toJSON( + message.displayChatMessage, + ); + } + if (message.targetPlayer !== undefined) { + obj.targetPlayer = TargetPlayerUpdate.toJSON(message.targetPlayer); + } + if (message.emoji !== undefined) { + obj.emoji = EmojiUpdate.toJSON(message.emoji); + } + if (message.win !== undefined) { + obj.win = WinUpdate.toJSON(message.win); + } + if (message.hash !== undefined) { + obj.hash = HashUpdate.toJSON(message.hash); + } + if (message.unitIncoming !== undefined) { + obj.unitIncoming = UnitIncomingUpdate.toJSON(message.unitIncoming); + } + if (message.allianceExtension !== undefined) { + obj.allianceExtension = AllianceExtensionUpdate.toJSON( + message.allianceExtension, + ); + } + if (message.bonusEvent !== undefined) { + obj.bonusEvent = BonusEventUpdate.toJSON(message.bonusEvent); + } + if (message.railroad !== undefined) { + obj.railroad = RailroadUpdate.toJSON(message.railroad); + } + if (message.conquest !== undefined) { + obj.conquest = ConquestUpdate.toJSON(message.conquest); + } + if (message.embargo !== undefined) { + obj.embargo = EmbargoUpdate.toJSON(message.embargo); + } + return obj; + }, + + create, I>>(base?: I): GameUpdate { + return GameUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): GameUpdate { + const message = createBaseGameUpdate(); + message.type = object.type ?? 0; + message.unit = + object.unit !== undefined && object.unit !== null + ? UnitUpdate.fromPartial(object.unit) + : undefined; + message.player = + object.player !== undefined && object.player !== null + ? PlayerUpdate.fromPartial(object.player) + : undefined; + message.allianceRequest = + object.allianceRequest !== undefined && object.allianceRequest !== null + ? AllianceRequestUpdate.fromPartial(object.allianceRequest) + : undefined; + message.allianceRequestReply = + object.allianceRequestReply !== undefined && + object.allianceRequestReply !== null + ? AllianceRequestReplyUpdate.fromPartial(object.allianceRequestReply) + : undefined; + message.brokeAlliance = + object.brokeAlliance !== undefined && object.brokeAlliance !== null + ? BrokeAllianceUpdate.fromPartial(object.brokeAlliance) + : undefined; + message.allianceExpired = + object.allianceExpired !== undefined && object.allianceExpired !== null + ? AllianceExpiredUpdate.fromPartial(object.allianceExpired) + : undefined; + message.displayMessage = + object.displayMessage !== undefined && object.displayMessage !== null + ? DisplayMessageUpdate.fromPartial(object.displayMessage) + : undefined; + message.displayChatMessage = + object.displayChatMessage !== undefined && + object.displayChatMessage !== null + ? DisplayChatMessageUpdate.fromPartial(object.displayChatMessage) + : undefined; + message.targetPlayer = + object.targetPlayer !== undefined && object.targetPlayer !== null + ? TargetPlayerUpdate.fromPartial(object.targetPlayer) + : undefined; + message.emoji = + object.emoji !== undefined && object.emoji !== null + ? EmojiUpdate.fromPartial(object.emoji) + : undefined; + message.win = + object.win !== undefined && object.win !== null + ? WinUpdate.fromPartial(object.win) + : undefined; + message.hash = + object.hash !== undefined && object.hash !== null + ? HashUpdate.fromPartial(object.hash) + : undefined; + message.unitIncoming = + object.unitIncoming !== undefined && object.unitIncoming !== null + ? UnitIncomingUpdate.fromPartial(object.unitIncoming) + : undefined; + message.allianceExtension = + object.allianceExtension !== undefined && + object.allianceExtension !== null + ? AllianceExtensionUpdate.fromPartial(object.allianceExtension) + : undefined; + message.bonusEvent = + object.bonusEvent !== undefined && object.bonusEvent !== null + ? BonusEventUpdate.fromPartial(object.bonusEvent) + : undefined; + message.railroad = + object.railroad !== undefined && object.railroad !== null + ? RailroadUpdate.fromPartial(object.railroad) + : undefined; + message.conquest = + object.conquest !== undefined && object.conquest !== null + ? ConquestUpdate.fromPartial(object.conquest) + : undefined; + message.embargo = + object.embargo !== undefined && object.embargo !== null + ? EmbargoUpdate.fromPartial(object.embargo) + : undefined; + return message; + }, +}; + +function createBaseGameUpdates(): GameUpdates { + return { type: 0, updates: [] }; +} + +export const GameUpdates: MessageFns = { + encode( + message: GameUpdates, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.type !== 0) { + writer.uint32(8).int32(message.type); + } + for (const v of message.updates) { + GameUpdate.encode(v!, writer.uint32(18).fork()).join(); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): GameUpdates { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGameUpdates(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.type = reader.int32() as any; + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.updates.push(GameUpdate.decode(reader, reader.uint32())); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): GameUpdates { + return { + type: isSet(object.type) ? gameUpdateTypeFromJSON(object.type) : 0, + updates: globalThis.Array.isArray(object?.updates) + ? object.updates.map((e: any) => GameUpdate.fromJSON(e)) + : [], + }; + }, + + toJSON(message: GameUpdates): unknown { + const obj: any = {}; + if (message.type !== 0) { + obj.type = gameUpdateTypeToJSON(message.type); + } + if (message.updates?.length) { + obj.updates = message.updates.map((e) => GameUpdate.toJSON(e)); + } + return obj; + }, + + create, I>>(base?: I): GameUpdates { + return GameUpdates.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): GameUpdates { + const message = createBaseGameUpdates(); + message.type = object.type ?? 0; + message.updates = + object.updates?.map((e) => GameUpdate.fromPartial(e)) || []; + return message; + }, +}; + +function createBaseGameUpdateViewData(): GameUpdateViewData { + return { + tick: 0, + updates: {}, + tileUpdates: [], + playerNameViewData: {}, + tickExecutionDuration: undefined, + }; +} + +export const GameUpdateViewData: MessageFns = { + encode( + message: GameUpdateViewData, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.tick !== 0) { + writer.uint32(8).int32(message.tick); + } + Object.entries(message.updates).forEach(([key, value]) => { + GameUpdateViewData_UpdatesEntry.encode( + { key: key as any, value }, + writer.uint32(18).fork(), + ).join(); + }); + writer.uint32(26).fork(); + for (const v of message.tileUpdates) { + writer.int64(v); + } + writer.join(); + Object.entries(message.playerNameViewData).forEach(([key, value]) => { + GameUpdateViewData_PlayerNameViewDataEntry.encode( + { key: key as any, value }, + writer.uint32(34).fork(), + ).join(); + }); + if (message.tickExecutionDuration !== undefined) { + writer.uint32(41).double(message.tickExecutionDuration); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): GameUpdateViewData { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGameUpdateViewData(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.tick = reader.int32(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + const entry2 = GameUpdateViewData_UpdatesEntry.decode( + reader, + reader.uint32(), + ); + if (entry2.value !== undefined) { + message.updates[entry2.key] = entry2.value; + } + continue; + } + case 3: { + if (tag === 24) { + message.tileUpdates.push(longToNumber(reader.int64())); + + continue; + } + + if (tag === 26) { + const end2 = reader.uint32() + reader.pos; + while (reader.pos < end2) { + message.tileUpdates.push(longToNumber(reader.int64())); + } + + continue; + } + + break; + } + case 4: { + if (tag !== 34) { + break; + } + + const entry4 = GameUpdateViewData_PlayerNameViewDataEntry.decode( + reader, + reader.uint32(), + ); + if (entry4.value !== undefined) { + message.playerNameViewData[entry4.key] = entry4.value; + } + continue; + } + case 5: { + if (tag !== 41) { + break; + } + + message.tickExecutionDuration = reader.double(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): GameUpdateViewData { + return { + tick: isSet(object.tick) ? globalThis.Number(object.tick) : 0, + updates: isObject(object.updates) + ? Object.entries(object.updates).reduce<{ [key: number]: GameUpdates }>( + (acc, [key, value]) => { + acc[globalThis.Number(key)] = GameUpdates.fromJSON(value); + return acc; + }, + {}, + ) + : {}, + tileUpdates: globalThis.Array.isArray(object?.tileUpdates) + ? object.tileUpdates.map((e: any) => globalThis.Number(e)) + : [], + playerNameViewData: isObject(object.playerNameViewData) + ? Object.entries(object.playerNameViewData).reduce<{ + [key: string]: NameViewData; + }>((acc, [key, value]) => { + acc[key] = NameViewData.fromJSON(value); + return acc; + }, {}) + : {}, + tickExecutionDuration: isSet(object.tickExecutionDuration) + ? globalThis.Number(object.tickExecutionDuration) + : undefined, + }; + }, + + toJSON(message: GameUpdateViewData): unknown { + const obj: any = {}; + if (message.tick !== 0) { + obj.tick = Math.round(message.tick); + } + if (message.updates) { + const entries = Object.entries(message.updates); + if (entries.length > 0) { + obj.updates = {}; + entries.forEach(([k, v]) => { + obj.updates[k] = GameUpdates.toJSON(v); + }); + } + } + if (message.tileUpdates?.length) { + obj.tileUpdates = message.tileUpdates.map((e) => Math.round(e)); + } + if (message.playerNameViewData) { + const entries = Object.entries(message.playerNameViewData); + if (entries.length > 0) { + obj.playerNameViewData = {}; + entries.forEach(([k, v]) => { + obj.playerNameViewData[k] = NameViewData.toJSON(v); + }); + } + } + if (message.tickExecutionDuration !== undefined) { + obj.tickExecutionDuration = message.tickExecutionDuration; + } + return obj; + }, + + create, I>>( + base?: I, + ): GameUpdateViewData { + return GameUpdateViewData.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): GameUpdateViewData { + const message = createBaseGameUpdateViewData(); + message.tick = object.tick ?? 0; + message.updates = Object.entries(object.updates ?? {}).reduce<{ + [key: number]: GameUpdates; + }>((acc, [key, value]) => { + if (value !== undefined) { + acc[globalThis.Number(key)] = GameUpdates.fromPartial(value); + } + return acc; + }, {}); + message.tileUpdates = object.tileUpdates?.map((e) => e) || []; + message.playerNameViewData = Object.entries( + object.playerNameViewData ?? {}, + ).reduce<{ [key: string]: NameViewData }>((acc, [key, value]) => { + if (value !== undefined) { + acc[key] = NameViewData.fromPartial(value); + } + return acc; + }, {}); + message.tickExecutionDuration = object.tickExecutionDuration ?? undefined; + return message; + }, +}; + +function createBaseGameUpdateViewData_UpdatesEntry(): GameUpdateViewData_UpdatesEntry { + return { key: 0, value: undefined }; +} + +export const GameUpdateViewData_UpdatesEntry: MessageFns = + { + encode( + message: GameUpdateViewData_UpdatesEntry, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.key !== 0) { + writer.uint32(8).int32(message.key); + } + if (message.value !== undefined) { + GameUpdates.encode(message.value, writer.uint32(18).fork()).join(); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): GameUpdateViewData_UpdatesEntry { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGameUpdateViewData_UpdatesEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 8) { + break; + } + + message.key = reader.int32(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.value = GameUpdates.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): GameUpdateViewData_UpdatesEntry { + return { + key: isSet(object.key) ? globalThis.Number(object.key) : 0, + value: isSet(object.value) + ? GameUpdates.fromJSON(object.value) + : undefined, + }; + }, + + toJSON(message: GameUpdateViewData_UpdatesEntry): unknown { + const obj: any = {}; + if (message.key !== 0) { + obj.key = Math.round(message.key); + } + if (message.value !== undefined) { + obj.value = GameUpdates.toJSON(message.value); + } + return obj; + }, + + create, I>>( + base?: I, + ): GameUpdateViewData_UpdatesEntry { + return GameUpdateViewData_UpdatesEntry.fromPartial(base ?? ({} as any)); + }, + fromPartial< + I extends Exact, I>, + >(object: I): GameUpdateViewData_UpdatesEntry { + const message = createBaseGameUpdateViewData_UpdatesEntry(); + message.key = object.key ?? 0; + message.value = + object.value !== undefined && object.value !== null + ? GameUpdates.fromPartial(object.value) + : undefined; + return message; + }, + }; + +function createBaseGameUpdateViewData_PlayerNameViewDataEntry(): GameUpdateViewData_PlayerNameViewDataEntry { + return { key: "", value: undefined }; +} + +export const GameUpdateViewData_PlayerNameViewDataEntry: MessageFns = + { + encode( + message: GameUpdateViewData_PlayerNameViewDataEntry, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.key !== "") { + writer.uint32(10).string(message.key); + } + if (message.value !== undefined) { + NameViewData.encode(message.value, writer.uint32(18).fork()).join(); + } + return writer; + }, + + decode( + input: BinaryReader | Uint8Array, + length?: number, + ): GameUpdateViewData_PlayerNameViewDataEntry { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseGameUpdateViewData_PlayerNameViewDataEntry(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.key = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.value = NameViewData.decode(reader, reader.uint32()); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): GameUpdateViewData_PlayerNameViewDataEntry { + return { + key: isSet(object.key) ? globalThis.String(object.key) : "", + value: isSet(object.value) + ? NameViewData.fromJSON(object.value) + : undefined, + }; + }, + + toJSON(message: GameUpdateViewData_PlayerNameViewDataEntry): unknown { + const obj: any = {}; + if (message.key !== "") { + obj.key = message.key; + } + if (message.value !== undefined) { + obj.value = NameViewData.toJSON(message.value); + } + return obj; + }, + + create< + I extends Exact< + DeepPartial, + I + >, + >(base?: I): GameUpdateViewData_PlayerNameViewDataEntry { + return GameUpdateViewData_PlayerNameViewDataEntry.fromPartial( + base ?? ({} as any), + ); + }, + fromPartial< + I extends Exact< + DeepPartial, + I + >, + >(object: I): GameUpdateViewData_PlayerNameViewDataEntry { + const message = createBaseGameUpdateViewData_PlayerNameViewDataEntry(); + message.key = object.key ?? ""; + message.value = + object.value !== undefined && object.value !== null + ? NameViewData.fromPartial(object.value) + : undefined; + return message; + }, + }; + +function createBaseErrorUpdate(): ErrorUpdate { + return { errMsg: "", stack: undefined }; +} + +export const ErrorUpdate: MessageFns = { + encode( + message: ErrorUpdate, + writer: BinaryWriter = new BinaryWriter(), + ): BinaryWriter { + if (message.errMsg !== "") { + writer.uint32(10).string(message.errMsg); + } + if (message.stack !== undefined) { + writer.uint32(18).string(message.stack); + } + return writer; + }, + + decode(input: BinaryReader | Uint8Array, length?: number): ErrorUpdate { + const reader = + input instanceof BinaryReader ? input : new BinaryReader(input); + const end = length === undefined ? reader.len : reader.pos + length; + const message = createBaseErrorUpdate(); + while (reader.pos < end) { + const tag = reader.uint32(); + switch (tag >>> 3) { + case 1: { + if (tag !== 10) { + break; + } + + message.errMsg = reader.string(); + continue; + } + case 2: { + if (tag !== 18) { + break; + } + + message.stack = reader.string(); + continue; + } + } + if ((tag & 7) === 4 || tag === 0) { + break; + } + reader.skip(tag & 7); + } + return message; + }, + + fromJSON(object: any): ErrorUpdate { + return { + errMsg: isSet(object.errMsg) ? globalThis.String(object.errMsg) : "", + stack: isSet(object.stack) ? globalThis.String(object.stack) : undefined, + }; + }, + + toJSON(message: ErrorUpdate): unknown { + const obj: any = {}; + if (message.errMsg !== "") { + obj.errMsg = message.errMsg; + } + if (message.stack !== undefined) { + obj.stack = message.stack; + } + return obj; + }, + + create, I>>(base?: I): ErrorUpdate { + return ErrorUpdate.fromPartial(base ?? ({} as any)); + }, + fromPartial, I>>( + object: I, + ): ErrorUpdate { + const message = createBaseErrorUpdate(); + message.errMsg = object.errMsg ?? ""; + message.stack = object.stack ?? undefined; + return message; + }, +}; + +type Builtin = + | Date + | Function + | Uint8Array + | string + | number + | boolean + | undefined; + +export type DeepPartial = T extends Builtin + ? T + : T extends globalThis.Array + ? globalThis.Array> + : T extends ReadonlyArray + ? ReadonlyArray> + : T extends {} + ? { [K in keyof T]?: DeepPartial } + : Partial; + +type KeysOfUnion = T extends T ? keyof T : never; +export type Exact = P extends Builtin + ? P + : P & { [K in keyof P]: Exact } & { + [K in Exclude>]: never; + }; + +function longToNumber(int64: { toString(): string }): number { + const num = globalThis.Number(int64.toString()); + if (num > globalThis.Number.MAX_SAFE_INTEGER) { + throw new globalThis.Error("Value is larger than Number.MAX_SAFE_INTEGER"); + } + if (num < globalThis.Number.MIN_SAFE_INTEGER) { + throw new globalThis.Error("Value is smaller than Number.MIN_SAFE_INTEGER"); + } + return num; +} + +function isObject(value: any): boolean { + return typeof value === "object" && value !== null; +} + +function isSet(value: any): boolean { + return value !== null && value !== undefined; +} + +export interface MessageFns { + encode(message: T, writer?: BinaryWriter): BinaryWriter; + decode(input: BinaryReader | Uint8Array, length?: number): T; + fromJSON(object: any): T; + toJSON(message: T): unknown; + create, I>>(base?: I): T; + fromPartial, I>>(object: I): T; } diff --git a/src/core/game/GameView.ts b/src/core/game/GameView.ts index d1d2fb83e..e2e11314f 100644 --- a/src/core/game/GameView.ts +++ b/src/core/game/GameView.ts @@ -8,30 +8,30 @@ import { createRandomName } from "../Util"; import { WorkerClient } from "../worker/WorkerClient"; import { Cell, - EmojiMessage, - GameUpdates, Gold, - NameViewData, PlayerActions, PlayerBorderTiles, PlayerID, PlayerProfile, - PlayerType, Team, TerrainType, TerraNullius, Tick, - TrainType, UnitInfo, - UnitType, } from "./Game"; import { GameMap, TileRef, TileUpdate } from "./GameMap"; import { AllianceView, AttackUpdate, + EmojiMessage, + GameUpdates, GameUpdateType, GameUpdateViewData, + NameViewData, + PlayerType, PlayerUpdate, + TrainType, + UnitType, UnitUpdate, } from "./GameUpdates"; import { TerrainMapData } from "./TerrainMapLoader"; @@ -88,7 +88,7 @@ export class UnitView { } markedForDeletion(): number | false { - return this.data.markedForDeletion; + return this.data.markedForDeletion ?? false; } type(): UnitType { @@ -107,7 +107,7 @@ export class UnitView { return this.data.pos; } owner(): PlayerView { - return this.gameView.playerBySmallID(this.data.ownerID)! as PlayerView; + return this.gameView.playerBySmallID(this.data.ownerId)! as PlayerView; } isActive(): boolean { return this.data.isActive; @@ -194,7 +194,7 @@ export class PlayerView { public nameData: NameViewData, public cosmetics: PlayerCosmetics, ) { - if (data.clientID === game.myClientID()) { + if (data.clientId === game.myClientID()) { this.anonymousName = this.data.name; } else { this.anonymousName = createRandomName( @@ -239,7 +239,7 @@ export class PlayerView { .structureColors(this._territoryColor); const maybeFocusedBorderColor = - this.game.myClientID() === this.data.clientID + this.game.myClientID() === this.data.clientId ? this.game.config().theme().focusedBorderColor() : defaultBorderColor; @@ -327,7 +327,7 @@ export class PlayerView { } smallID(): number { - return this.data.smallID; + return this.data.smallId; } name(): string { @@ -342,7 +342,7 @@ export class PlayerView { } clientID(): ClientID | null { - return this.data.clientID; + return this.data.clientId ?? null; } id(): PlayerID { return this.data.id; @@ -373,7 +373,7 @@ export class PlayerView { ); } gold(): Gold { - return this.data.gold; + return BigInt(this.data.gold); } troops(): number { @@ -412,7 +412,7 @@ export class PlayerView { } hasEmbargoAgainst(other: PlayerView): boolean { - return this.data.embargoes.has(other.id()); + return this.data.embargoes.some((id) => id === other.id()); } hasEmbargo(other: PlayerView): boolean { @@ -506,8 +506,8 @@ export class GameView implements GameMap { return this._map.isOnEdgeOfMap(ref); } - public updatesSinceLastTick(): GameUpdates | null { - return this.lastUpdate?.updates ?? null; + public updatesSinceLastTick(): { [key: number]: GameUpdates } { + return this.lastUpdate!.updates; } public update(gu: GameUpdateViewData) { @@ -517,34 +517,36 @@ export class GameView implements GameMap { this.lastUpdate = gu; this.updatedTiles = []; - this.lastUpdate.packedTileUpdates.forEach((tu) => { - this.updatedTiles.push(this.updateTile(tu)); + this.lastUpdate.tileUpdates.forEach((tu) => { + this.updatedTiles.push(this.updateTile(BigInt(tu))); }); if (gu.updates === null) { throw new Error("lastUpdate.updates not initialized"); } - gu.updates[GameUpdateType.Player].forEach((pu) => { - this.smallIDToID.set(pu.smallID, pu.id); - const player = this._players.get(pu.id); - if (player !== undefined) { - player.data = pu; - player.nameData = gu.playerNameViewData[pu.id]; - } else { - this._players.set( - pu.id, - new PlayerView( - this, - pu, - gu.playerNameViewData[pu.id], - // First check human by clientID, then check nation by name. - this._cosmetics.get(pu.clientID ?? "") ?? - this._cosmetics.get(pu.name) ?? - {}, - ), - ); - } - }); + gu.updates[GameUpdateType.Player].updates + .map((pu) => pu.player!) + .forEach((pu) => { + this.smallIDToID.set(pu.smallId, pu.id); + const player = this._players.get(pu.id); + if (player !== undefined) { + player.data = pu; + player.nameData = gu.playerNameViewData[pu.id]; + } else { + this._players.set( + pu.id, + new PlayerView( + this, + pu, + gu.playerNameViewData[pu.id], + // First check human by clientID, then check nation by name. + this._cosmetics.get(pu.clientId ?? "") ?? + this._cosmetics.get(pu.name) ?? + {}, + ), + ); + } + }); this._myPlayer ??= this.playerByClientID(this._myClientID); @@ -552,16 +554,17 @@ export class GameView implements GameMap { unit._wasUpdated = false; unit.lastPos = unit.lastPos.slice(-1); } - gu.updates[GameUpdateType.Unit].forEach((update) => { - let unit = this._units.get(update.id); + gu.updates[GameUpdateType.Unit].updates.forEach((update) => { + const ud = update.unit!; + let unit = this._units.get(ud.id); if (unit !== undefined) { - unit.update(update); + unit.update(ud); } else { - unit = new UnitView(this, update); - this._units.set(update.id, unit); + unit = new UnitView(this, ud); + this._units.set(ud.id, unit); this.unitGrid.addUnit(unit); } - if (!update.isActive) { + if (!ud.isActive) { this.unitGrid.removeUnit(unit); } else if (unit.tile() !== unit.lastTile()) { this.unitGrid.updateUnitCell(unit); diff --git a/src/core/game/PlayerImpl.ts b/src/core/game/PlayerImpl.ts index 9d9d7ecf1..b8f985c76 100644 --- a/src/core/game/PlayerImpl.ts +++ b/src/core/game/PlayerImpl.ts @@ -14,35 +14,38 @@ import { Alliance, AllianceRequest, AllPlayers, + AllUnitTypes, Attack, BuildableUnit, Cell, ColoredTeams, Embargo, - EmojiMessage, Gold, - MessageType, MutableAlliance, Player, PlayerID, PlayerInfo, PlayerProfile, - PlayerType, Relation, Team, TerraNullius, Tick, Unit, UnitParams, - UnitType, + UnitParamsMap, } from "./Game"; import { GameImpl } from "./GameImpl"; import { andFN, manhattanDistFN, TileRef } from "./GameMap"; import { AllianceView, AttackUpdate, + EmbargoUpdate_EmbargoEvent, + EmojiMessage, + GameUpdate, GameUpdateType, - PlayerUpdate, + MessageType, + PlayerType, + UnitType, } from "./GameUpdates"; import { bestShoreDeploymentSource, @@ -119,66 +122,66 @@ export class PlayerImpl implements Player { largestClusterBoundingBox: { min: Cell; max: Cell } | null; - toUpdate(): PlayerUpdate { - const outgoingAllianceRequests = this.outgoingAllianceRequests().map((ar) => - ar.recipient().id(), - ); - + toUpdate(): GameUpdate { return { type: GameUpdateType.Player, - clientID: this.clientID(), - name: this.name(), - displayName: this.displayName(), - id: this.id(), - team: this.team() ?? undefined, - smallID: this.smallID(), - playerType: this.type(), - isAlive: this.isAlive(), - isDisconnected: this.isDisconnected(), - tilesOwned: this.numTilesOwned(), - gold: this._gold, - troops: this.troops(), - allies: this.alliances().map((a) => a.other(this).smallID()), - embargoes: new Set([...this.embargoes.keys()].map((p) => p.toString())), - isTraitor: this.isTraitor(), - traitorRemainingTicks: this.getTraitorRemainingTicks(), - targets: this.targets().map((p) => p.smallID()), - outgoingEmojis: this.outgoingEmojis(), - outgoingAttacks: this._outgoingAttacks.map((a) => { - return { - attackerID: a.attacker().smallID(), - targetID: a.target().smallID(), - troops: a.troops(), - id: a.id(), - retreating: a.retreating(), - } satisfies AttackUpdate; - }), - incomingAttacks: this._incomingAttacks.map((a) => { - return { - attackerID: a.attacker().smallID(), - targetID: a.target().smallID(), - troops: a.troops(), - id: a.id(), - retreating: a.retreating(), - } satisfies AttackUpdate; - }), - outgoingAllianceRequests: outgoingAllianceRequests, - alliances: this.alliances().map( - (a) => - ({ + player: { + clientId: this.clientID() ?? undefined, + name: this.name(), + displayName: this.displayName(), + id: this.id(), + team: this.team() ?? undefined, + smallId: this.smallID(), + playerType: this.type(), + isAlive: this.isAlive(), + isDisconnected: this.isDisconnected(), + tilesOwned: this.numTilesOwned(), + gold: Number(this._gold), + troops: this.troops(), + allies: this.alliances().map((a) => a.other(this).smallID()), + embargoes: [...this.embargoes.keys()].map((p) => p.toString()), + isTraitor: this.isTraitor(), + traitorRemainingTicks: this.getTraitorRemainingTicks(), + targets: this.targets().map((p) => p.smallID()), + outgoingEmojis: this.outgoingEmojis(), + outgoingAttacks: this._outgoingAttacks.map((a) => { + return { + attackerId: a.attacker().smallID(), + targetId: a.target().smallID(), + troops: a.troops(), id: a.id(), - other: a.other(this).id(), - createdAt: a.createdAt(), - expiresAt: a.expiresAt(), - hasExtensionRequest: - a.expiresAt() <= - this.mg.ticks() + - this.mg.config().allianceExtensionPromptOffset(), - }) satisfies AllianceView, - ), - hasSpawned: this.hasSpawned(), - betrayals: this._betrayalCount, - lastDeleteUnitTick: this.lastDeleteUnitTick, + retreating: a.retreating(), + } satisfies AttackUpdate; + }), + incomingAttacks: this._incomingAttacks.map((a) => { + return { + attackerId: a.attacker().smallID(), + targetId: a.target().smallID(), + troops: a.troops(), + id: a.id(), + retreating: a.retreating(), + } satisfies AttackUpdate; + }), + outgoingAllianceRequests: this.outgoingAllianceRequests().map((ar) => + ar.recipient().id(), + ), + alliances: this.alliances().map( + (a) => + ({ + id: a.id(), + other: a.other(this).id(), + createdAt: a.createdAt(), + expiresAt: a.expiresAt(), + hasExtensionRequest: + a.expiresAt() <= + this.mg.ticks() + + this.mg.config().allianceExtensionPromptOffset(), + }) satisfies AllianceView, + ), + hasSpawned: this.hasSpawned(), + betrayals: this._betrayalCount, + lastDeleteUnitTick: this.lastDeleteUnitTick, + }, }; } @@ -553,9 +556,10 @@ export class PlayerImpl implements Player { throw Error(`Cannot send emoji to oneself: ${this}`); } const msg: EmojiMessage = { - message: emoji, - senderID: this.smallID(), - recipientID: recipient === AllPlayers ? recipient : recipient.smallID(), + emoji: emoji, + senderId: this.smallID(), + allPlayers: recipient === AllPlayers, + recipientId: recipient === AllPlayers ? undefined : recipient.smallID(), createdAt: this.mg.ticks(), }; this.outgoingEmojis_.push(msg); @@ -578,9 +582,9 @@ export class PlayerImpl implements Player { } const recipientID = recipient === AllPlayers ? AllPlayers : recipient.smallID(); - const prevMsgs = this.outgoingEmojis_.filter( - (msg) => msg.recipientID === recipientID, - ); + const prevMsgs = this.outgoingEmojis_.filter((msg) => { + return msg.allPlayers ?? msg.recipientId === recipientID; + }); for (const msg of prevMsgs) { if ( this.mg.ticks() - msg.createdAt < @@ -740,9 +744,11 @@ export class PlayerImpl implements Player { this.mg.addUpdate({ type: GameUpdateType.EmbargoEvent, - event: "start", - playerID: this.smallID(), - embargoedID: other.smallID(), + embargo: { + playerId: this.smallID(), + embargoedId: other.smallID(), + event: EmbargoUpdate_EmbargoEvent.start, + }, }); this.embargoes.set(other.id(), { @@ -756,9 +762,11 @@ export class PlayerImpl implements Player { this.embargoes.delete(other.id()); this.mg.addUpdate({ type: GameUpdateType.EmbargoEvent, - event: "stop", - playerID: this.smallID(), - embargoedID: other.smallID(), + embargo: { + playerId: this.smallID(), + embargoedId: other.smallID(), + event: EmbargoUpdate_EmbargoEvent.stop, + }, }); } @@ -808,10 +816,12 @@ export class PlayerImpl implements Player { if (tile) { this.mg.addUpdate({ type: GameUpdateType.BonusEvent, - player: this.id(), - tile, - gold: Number(toAdd), - troops: 0, + bonusEvent: { + player: this.id(), + tile, + gold: Number(toAdd), + troops: 0, + }, }); } } @@ -855,7 +865,7 @@ export class PlayerImpl implements Player { buildUnit( type: T, spawnTile: TileRef, - params: UnitParams, + params: UnitParams, ): Unit { if (this.mg.config().isUnitDisabled(type)) { throw new Error( @@ -930,7 +940,7 @@ export class PlayerImpl implements Player { public buildableUnits(tile: TileRef | null): BuildableUnit[] { const validTiles = tile !== null ? this.validStructureSpawnTiles(tile) : []; - return Object.values(UnitType).map((u) => { + return AllUnitTypes.map((u) => { let canUpgrade: number | false = false; if (!this.mg.inSpawnPhase()) { const existingUnit = tile !== null && this.findUnitToUpgrade(u, tile); @@ -1076,7 +1086,7 @@ export class PlayerImpl implements Player { } const searchRadius = 15; const searchRadiusSquared = searchRadius ** 2; - const types = Object.values(UnitType).filter((unitTypeValue) => { + const types = AllUnitTypes.filter((unitTypeValue) => { return this.mg.config().unitInfo(unitTypeValue).territoryBound; }); diff --git a/src/core/game/RailNetworkImpl.ts b/src/core/game/RailNetworkImpl.ts index ca1a3319e..49d447d2f 100644 --- a/src/core/game/RailNetworkImpl.ts +++ b/src/core/game/RailNetworkImpl.ts @@ -2,8 +2,9 @@ import { RailroadExecution } from "../execution/RailroadExecution"; import { PathFindResultType } from "../pathfinding/AStar"; import { MiniAStar } from "../pathfinding/MiniAStar"; import { SerialAStar } from "../pathfinding/SerialAStar"; -import { Game, Unit, UnitType } from "./Game"; +import { Game, Unit } from "./Game"; import { TileRef } from "./GameMap"; +import { UnitType } from "./GameUpdates"; import { RailNetwork } from "./RailNetwork"; import { Railroad } from "./Railroad"; import { Cluster, TrainStation, TrainStationMapAdapter } from "./TrainStation"; diff --git a/src/core/game/Railroad.ts b/src/core/game/Railroad.ts index 8b0f3086a..9763d60f1 100644 --- a/src/core/game/Railroad.ts +++ b/src/core/game/Railroad.ts @@ -13,12 +13,14 @@ export class Railroad { delete(game: Game) { const railTiles: RailTile[] = this.tiles.map((tile) => ({ tile, - railType: RailType.VERTICAL, + railType: RailType.vertical, })); game.addUpdate({ type: GameUpdateType.RailroadEvent, - isActive: false, - railTiles, + railroad: { + isActive: false, + railTiles, + }, }); this.from.removeRailroad(this); this.to.removeRailroad(this); diff --git a/src/core/game/StatsImpl.ts b/src/core/game/StatsImpl.ts index b62956108..c2603782f 100644 --- a/src/core/game/StatsImpl.ts +++ b/src/core/game/StatsImpl.ts @@ -26,7 +26,8 @@ import { unitTypeToBombUnit, unitTypeToOtherUnit, } from "../StatsSchemas"; -import { Player, TerraNullius, UnitType } from "./Game"; +import { Player, TerraNullius } from "./Game"; +import { UnitType } from "./GameUpdates"; import { Stats } from "./Stats"; type BigIntLike = bigint | number; diff --git a/src/core/game/TeamAssignment.ts b/src/core/game/TeamAssignment.ts index 13e2f6c64..1fb6012d6 100644 --- a/src/core/game/TeamAssignment.ts +++ b/src/core/game/TeamAssignment.ts @@ -1,6 +1,7 @@ import { PseudoRandom } from "../PseudoRandom"; import { simpleHash } from "../Util"; -import { PlayerInfo, PlayerType, Team } from "./Game"; +import { PlayerInfo, Team } from "./Game"; +import { PlayerType } from "./GameUpdates"; export function assignTeams( players: PlayerInfo[], diff --git a/src/core/game/TrainStation.ts b/src/core/game/TrainStation.ts index 9318fab25..125b0acc4 100644 --- a/src/core/game/TrainStation.ts +++ b/src/core/game/TrainStation.ts @@ -1,9 +1,9 @@ import { TrainExecution } from "../execution/TrainExecution"; import { GraphAdapter } from "../pathfinding/SerialAStar"; import { PseudoRandom } from "../PseudoRandom"; -import { Game, Player, Unit, UnitType } from "./Game"; +import { Game, Player, Unit } from "./Game"; import { TileRef } from "./GameMap"; -import { GameUpdateType, RailTile, RailType } from "./GameUpdates"; +import { GameUpdateType, RailTile, RailType, UnitType } from "./GameUpdates"; import { Railroad } from "./Railroad"; /** @@ -115,12 +115,14 @@ export class TrainStation { if (toRemove) { const railTiles: RailTile[] = toRemove.tiles.map((tile) => ({ tile, - railType: RailType.VERTICAL, + railType: RailType.vertical, })); this.mg.addUpdate({ type: GameUpdateType.RailroadEvent, - isActive: false, - railTiles, + railroad: { + isActive: false, + railTiles, + }, }); this.removeRailroad(toRemove); } diff --git a/src/core/game/TransportShipUtils.ts b/src/core/game/TransportShipUtils.ts index a0af53526..054d11a6c 100644 --- a/src/core/game/TransportShipUtils.ts +++ b/src/core/game/TransportShipUtils.ts @@ -1,7 +1,8 @@ import { PathFindResultType } from "../pathfinding/AStar"; import { MiniAStar } from "../pathfinding/MiniAStar"; -import { Game, Player, UnitType } from "./Game"; +import { Game, Player } from "./Game"; import { andFN, GameMap, manhattanDistFN, TileRef } from "./GameMap"; +import { UnitType } from "./GameUpdates"; export function canBuildTransportShip( game: Game, diff --git a/src/core/game/UnitGrid.ts b/src/core/game/UnitGrid.ts index 68b20fac5..6e4ad15eb 100644 --- a/src/core/game/UnitGrid.ts +++ b/src/core/game/UnitGrid.ts @@ -1,5 +1,6 @@ -import { PlayerID, Unit, UnitType } from "./Game"; +import { PlayerID, Unit } from "./Game"; import { GameMap, TileRef } from "./GameMap"; +import { UnitType } from "./GameUpdates"; import { UnitView } from "./GameView"; export type UnitPredicate = (value: { diff --git a/src/core/game/UnitImpl.ts b/src/core/game/UnitImpl.ts index b4db4366e..00a4e8500 100644 --- a/src/core/game/UnitImpl.ts +++ b/src/core/game/UnitImpl.ts @@ -1,18 +1,21 @@ -import { simpleHash, toInt, withinInt } from "../Util"; +import { toInt, withinInt } from "../Util"; import { AllUnitParams, - MessageType, Player, Tick, - TrainType, TrajectoryTile, Unit, UnitInfo, - UnitType, } from "./Game"; import { GameImpl } from "./GameImpl"; import { TileRef } from "./GameMap"; -import { GameUpdateType, UnitUpdate } from "./GameUpdates"; +import { + GameUpdateType, + MessageType, + TrainType, + UnitType, + UnitUpdate, +} from "./GameUpdates"; import { PlayerImpl } from "./PlayerImpl"; export class UnitImpl implements Unit { @@ -123,13 +126,13 @@ export class UnitImpl implements Unit { unitType: this._type, id: this._id, troops: this._troops, - ownerID: this._owner.smallID(), - lastOwnerID: this._lastOwner?.smallID(), + ownerId: this._owner.smallID(), + lastOwnerId: this._lastOwner?.smallID(), isActive: this._active, reachedTarget: this._reachedTarget, retreating: this._retreating, pos: this._tile, - markedForDeletion: this._deletionAt ?? false, + markedForDeletion: this._deletionAt ?? undefined, targetable: this._targetable, lastPos: this._lastTile, health: this.hasHealth() ? Number(this._health) : undefined, @@ -325,7 +328,7 @@ export class UnitImpl implements Unit { } hash(): number { - return this.tile() + simpleHash(this.type()) * this._id; + return this.tile() + this.type() * this._id; } toString(): string { diff --git a/tests/AllianceBehaviour.test.ts b/tests/AllianceBehaviour.test.ts index 45ad6ff44..e30d23965 100644 --- a/tests/AllianceBehaviour.test.ts +++ b/tests/AllianceBehaviour.test.ts @@ -4,9 +4,9 @@ import { Game, Player, PlayerInfo, - PlayerType, Tick, } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { PseudoRandom } from "../src/core/PseudoRandom"; import { setup } from "./util/Setup"; diff --git a/tests/AllianceDonation.test.ts b/tests/AllianceDonation.test.ts index 22cab40df..b3375190e 100644 --- a/tests/AllianceDonation.test.ts +++ b/tests/AllianceDonation.test.ts @@ -1,7 +1,8 @@ import { AllianceRequestExecution } from "../src/core/execution/alliance/AllianceRequestExecution"; import { AllianceRequestReplyExecution } from "../src/core/execution/alliance/AllianceRequestReplyExecution"; import { DonateGoldExecution } from "../src/core/execution/DonateGoldExecution"; -import { Game, Player, PlayerType } from "../src/core/game/Game"; +import { Game, Player } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { playerInfo, setup } from "./util/Setup"; let game: Game; diff --git a/tests/AllianceExtensionExecution.test.ts b/tests/AllianceExtensionExecution.test.ts index 4c4b8b7b9..3f2b3e86e 100644 --- a/tests/AllianceExtensionExecution.test.ts +++ b/tests/AllianceExtensionExecution.test.ts @@ -1,7 +1,8 @@ import { AllianceExtensionExecution } from "../src/core/execution/alliance/AllianceExtensionExecution"; import { AllianceRequestExecution } from "../src/core/execution/alliance/AllianceRequestExecution"; import { AllianceRequestReplyExecution } from "../src/core/execution/alliance/AllianceRequestReplyExecution"; -import { Game, MessageType, Player, PlayerType } from "../src/core/game/Game"; +import { Game, Player } from "../src/core/game/Game"; +import { MessageType, PlayerType } from "../src/core/game/GameUpdates"; import { playerInfo, setup } from "./util/Setup"; let game: Game; diff --git a/tests/AllianceRequestExecution.test.ts b/tests/AllianceRequestExecution.test.ts index 7aa20ee9a..0f6fb363a 100644 --- a/tests/AllianceRequestExecution.test.ts +++ b/tests/AllianceRequestExecution.test.ts @@ -1,7 +1,8 @@ import { AllianceRequestExecution } from "../src/core/execution/alliance/AllianceRequestExecution"; import { AllianceRequestReplyExecution } from "../src/core/execution/alliance/AllianceRequestReplyExecution"; import { NukeExecution } from "../src/core/execution/NukeExecution"; -import { Game, Player, PlayerType, UnitType } from "../src/core/game/Game"; +import { Game, Player } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { playerInfo, setup } from "./util/Setup"; import { constructionExecution } from "./util/utils"; diff --git a/tests/Attack.test.ts b/tests/Attack.test.ts index fceeb365a..299250d21 100644 --- a/tests/Attack.test.ts +++ b/tests/Attack.test.ts @@ -1,14 +1,9 @@ import { AttackExecution } from "../src/core/execution/AttackExecution"; import { SpawnExecution } from "../src/core/execution/SpawnExecution"; import { TransportShipExecution } from "../src/core/execution/TransportShipExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; import { TileRef } from "../src/core/game/GameMap"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; import { TestConfig } from "./util/TestConfig"; import { constructionExecution } from "./util/utils"; diff --git a/tests/AttackStats.test.ts b/tests/AttackStats.test.ts index 1955aec11..a3a0ff756 100644 --- a/tests/AttackStats.test.ts +++ b/tests/AttackStats.test.ts @@ -1,6 +1,7 @@ import { AttackExecution } from "../src/core/execution/AttackExecution"; import { SpawnExecution } from "../src/core/execution/SpawnExecution"; -import { Game, Player, PlayerInfo, PlayerType } from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { GOLD_INDEX_WAR, GOLD_INDEX_WORK } from "../src/core/StatsSchemas"; import { setup } from "./util/Setup"; diff --git a/tests/BotBehavior.test.ts b/tests/BotBehavior.test.ts index 377d3192c..754de961d 100644 --- a/tests/BotBehavior.test.ts +++ b/tests/BotBehavior.test.ts @@ -1,5 +1,6 @@ import { BotBehavior } from "../src/core/execution/utils/BotBehavior"; -import { Game, Player, PlayerInfo, PlayerType } from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { PseudoRandom } from "../src/core/PseudoRandom"; import { setup } from "./util/Setup"; diff --git a/tests/DeleteUnitExecution.test.ts b/tests/DeleteUnitExecution.test.ts index 71444dca5..33aaf651f 100644 --- a/tests/DeleteUnitExecution.test.ts +++ b/tests/DeleteUnitExecution.test.ts @@ -1,14 +1,8 @@ import { DeleteUnitExecution } from "../src/core/execution/DeleteUnitExecution"; import { SpawnExecution } from "../src/core/execution/SpawnExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - Unit, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo, Unit } from "../src/core/game/Game"; import { TileRef } from "../src/core/game/GameMap"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; import { executeTicks } from "./util/utils"; diff --git a/tests/Disconnected.test.ts b/tests/Disconnected.test.ts index ab630eb73..c32658e06 100644 --- a/tests/Disconnected.test.ts +++ b/tests/Disconnected.test.ts @@ -3,14 +3,8 @@ import { MarkDisconnectedExecution } from "../src/core/execution/MarkDisconnecte import { SpawnExecution } from "../src/core/execution/SpawnExecution"; import { TransportShipExecution } from "../src/core/execution/TransportShipExecution"; import { WarshipExecution } from "../src/core/execution/WarshipExecution"; -import { - Game, - GameMode, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, GameMode, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { toInt } from "../src/core/Util"; import { setup } from "./util/Setup"; import { UseRealAttackLogic } from "./util/TestConfig"; @@ -72,7 +66,7 @@ describe("Disconnected", () => { test("should include disconnected state in player update", () => { player1.markDisconnected(true); const update = player1.toUpdate(); - expect(update.isDisconnected).toBe(true); + expect(update.player!.isDisconnected).toBe(true); }); }); @@ -146,7 +140,7 @@ describe("Disconnected", () => { player1.markDisconnected(true); executeTicks(game, 3); const update = player1.toUpdate(); - expect(update.isDisconnected).toBe(true); + expect(update.player!.isDisconnected).toBe(true); }); }); diff --git a/tests/Donate.test.ts b/tests/Donate.test.ts index 966f9d493..17125ecb3 100644 --- a/tests/Donate.test.ts +++ b/tests/Donate.test.ts @@ -1,7 +1,8 @@ import { DonateGoldExecution } from "../src/core/execution/DonateGoldExecution"; import { DonateTroopsExecution } from "../src/core/execution/DonateTroopExecution"; import { SpawnExecution } from "../src/core/execution/SpawnExecution"; -import { PlayerInfo, PlayerType } from "../src/core/game/Game"; +import { PlayerInfo } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; describe("Donate troops to an ally", () => { diff --git a/tests/FakeHumanMIRV.test.ts b/tests/FakeHumanMIRV.test.ts index 1981bcf53..5afe75279 100644 --- a/tests/FakeHumanMIRV.test.ts +++ b/tests/FakeHumanMIRV.test.ts @@ -1,13 +1,7 @@ import { FakeHumanExecution } from "../src/core/execution/FakeHumanExecution"; import { MirvExecution } from "../src/core/execution/MIRVExecution"; -import { - Cell, - GameMode, - Nation, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Cell, GameMode, Nation, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; import { executeTicks } from "./util/utils"; diff --git a/tests/MessageTypeClasses.test.ts b/tests/MessageTypeClasses.test.ts index 3b7368fc6..5d00b5bb2 100644 --- a/tests/MessageTypeClasses.test.ts +++ b/tests/MessageTypeClasses.test.ts @@ -1,5 +1,5 @@ import { getMessageTypeClasses, severityColors } from "../src/client/Utils"; -import { MessageType } from "../src/core/game/Game"; +import { MessageType } from "../src/core/game/GameUpdates"; describe("getMessageTypeClasses", () => { // Spy on console.warn to track when the default case is hit diff --git a/tests/MissileSilo.test.ts b/tests/MissileSilo.test.ts index 5045d4622..69f75223d 100644 --- a/tests/MissileSilo.test.ts +++ b/tests/MissileSilo.test.ts @@ -1,14 +1,9 @@ import { NukeExecution } from "../src/core/execution/NukeExecution"; import { SpawnExecution } from "../src/core/execution/SpawnExecution"; import { UpgradeStructureExecution } from "../src/core/execution/UpgradeStructureExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; import { TileRef } from "../src/core/game/GameMap"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; import { constructionExecution, executeTicks } from "./util/utils"; diff --git a/tests/PlayerImpl.test.ts b/tests/PlayerImpl.test.ts index 71d022f22..a978c1e1f 100644 --- a/tests/PlayerImpl.test.ts +++ b/tests/PlayerImpl.test.ts @@ -1,10 +1,5 @@ -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; let game: Game; diff --git a/tests/PlayerInfo.test.ts b/tests/PlayerInfo.test.ts index c1fa8b559..75b716612 100644 --- a/tests/PlayerInfo.test.ts +++ b/tests/PlayerInfo.test.ts @@ -1,4 +1,5 @@ -import { PlayerInfo, PlayerType } from "../src/core/game/Game"; +import { PlayerInfo } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; describe("PlayerInfo", () => { describe("clan", () => { diff --git a/tests/PortExecution.test.ts b/tests/PortExecution.test.ts index 287a0f022..82c9338d7 100644 --- a/tests/PortExecution.test.ts +++ b/tests/PortExecution.test.ts @@ -1,11 +1,6 @@ import { PortExecution } from "../src/core/execution/PortExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; let game: Game; diff --git a/tests/ShellRandom.test.ts b/tests/ShellRandom.test.ts index 19ec5ed52..0baa04ef0 100644 --- a/tests/ShellRandom.test.ts +++ b/tests/ShellRandom.test.ts @@ -1,13 +1,8 @@ import { DefensePostExecution } from "../src/core/execution/DefensePostExecution"; import { ShellExecution } from "../src/core/execution/ShellExecution"; import { WarshipExecution } from "../src/core/execution/WarshipExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; const coastX = 7; diff --git a/tests/Stats.test.ts b/tests/Stats.test.ts index 1b654210b..cb3add290 100644 --- a/tests/Stats.test.ts +++ b/tests/Stats.test.ts @@ -1,10 +1,5 @@ -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { Stats } from "../src/core/game/Stats"; import { StatsImpl } from "../src/core/game/StatsImpl"; import { replacer } from "../src/core/Util"; diff --git a/tests/Team.test.ts b/tests/Team.test.ts index 414bb6c35..3e4402e17 100644 --- a/tests/Team.test.ts +++ b/tests/Team.test.ts @@ -1,9 +1,5 @@ -import { - ColoredTeams, - Game, - GameMode, - PlayerType, -} from "../src/core/game/Game"; +import { ColoredTeams, Game, GameMode } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { playerInfo, setup } from "./util/Setup"; let game: Game; diff --git a/tests/TeamAssignment.test.ts b/tests/TeamAssignment.test.ts index c3e11671b..9bbc1da24 100644 --- a/tests/TeamAssignment.test.ts +++ b/tests/TeamAssignment.test.ts @@ -1,4 +1,5 @@ -import { ColoredTeams, PlayerInfo, PlayerType } from "../src/core/game/Game"; +import { ColoredTeams, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { assignTeams } from "../src/core/game/TeamAssignment"; const teams = [ColoredTeams.Red, ColoredTeams.Blue]; diff --git a/tests/TerritoryCapture.test.ts b/tests/TerritoryCapture.test.ts index e46678c08..8ad5986f8 100644 --- a/tests/TerritoryCapture.test.ts +++ b/tests/TerritoryCapture.test.ts @@ -1,5 +1,6 @@ import { SpawnExecution } from "../src/core/execution/SpawnExecution"; -import { Player, PlayerInfo, PlayerType } from "../src/core/game/Game"; +import { Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; describe("Territory management", () => { diff --git a/tests/UnitGrid.test.ts b/tests/UnitGrid.test.ts index bd6629910..9694272a9 100644 --- a/tests/UnitGrid.test.ts +++ b/tests/UnitGrid.test.ts @@ -1,4 +1,5 @@ -import { PlayerInfo, PlayerType, UnitType } from "../src/core/game/Game"; +import { PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { UnitGrid } from "../src/core/game/UnitGrid"; import { setup } from "./util/Setup"; diff --git a/tests/Warship.test.ts b/tests/Warship.test.ts index ee6c556de..774de3490 100644 --- a/tests/Warship.test.ts +++ b/tests/Warship.test.ts @@ -1,12 +1,7 @@ import { MoveWarshipExecution } from "../src/core/execution/MoveWarshipExecution"; import { WarshipExecution } from "../src/core/execution/WarshipExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../src/core/game/Game"; +import { PlayerType, UnitType } from "../src/core/game/GameUpdates"; import { setup } from "./util/Setup"; import { executeTicks } from "./util/utils"; diff --git a/tests/client/graphics/RadialMenuElements.test.ts b/tests/client/graphics/RadialMenuElements.test.ts index 67021fee9..6406f649b 100644 --- a/tests/client/graphics/RadialMenuElements.test.ts +++ b/tests/client/graphics/RadialMenuElements.test.ts @@ -9,8 +9,8 @@ import { rootMenuElement, Slot, } from "../../../src/client/graphics/layers/RadialMenuElements"; -import { UnitType } from "../../../src/core/game/Game"; import { TileRef } from "../../../src/core/game/GameMap"; +import { UnitType } from "../../../src/core/game/GameUpdates"; import { GameView, PlayerView } from "../../../src/core/game/GameView"; jest.mock("../../../src/client/Utils", () => ({ diff --git a/tests/client/graphics/UILayer.test.ts b/tests/client/graphics/UILayer.test.ts index 7b4fc2ebc..27c2d41ea 100644 --- a/tests/client/graphics/UILayer.test.ts +++ b/tests/client/graphics/UILayer.test.ts @@ -51,7 +51,7 @@ describe("UILayer", () => { }; const event = { isSelected: true, unit }; ui.drawSelectionBox = jest.fn(); - ui["onUnitSelection"](event as UnitSelectionEvent); + ui["onUnitSelection"](event as unknown as UnitSelectionEvent); expect(ui.drawSelectionBox).toHaveBeenCalledWith(unit); }); diff --git a/tests/core/execution/utils/PlayerSpawner.test.ts b/tests/core/execution/utils/PlayerSpawner.test.ts index 6e719c2db..3c8bbaf9d 100644 --- a/tests/core/execution/utils/PlayerSpawner.test.ts +++ b/tests/core/execution/utils/PlayerSpawner.test.ts @@ -1,5 +1,6 @@ import { PlayerSpawner } from "../../../../src/core/execution/utils/PlayerSpawner"; -import { PlayerInfo, PlayerType } from "../../../../src/core/game/Game"; +import { PlayerInfo } from "../../../../src/core/game/Game"; +import { PlayerType } from "../../../../src/core/game/GameUpdates"; import { setup } from "../../../util/Setup"; describe("PlayerSpawner", () => { diff --git a/tests/core/executions/NukeExecution.test.ts b/tests/core/executions/NukeExecution.test.ts index 00810eb89..52ac8697e 100644 --- a/tests/core/executions/NukeExecution.test.ts +++ b/tests/core/executions/NukeExecution.test.ts @@ -1,11 +1,6 @@ import { NukeExecution } from "../../../src/core/execution/NukeExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../../../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../../../src/core/game/Game"; +import { PlayerType, UnitType } from "../../../src/core/game/GameUpdates"; import { setup } from "../../util/Setup"; import { TestConfig } from "../../util/TestConfig"; import { executeTicks } from "../../util/utils"; diff --git a/tests/core/executions/PlayerExecution.test.ts b/tests/core/executions/PlayerExecution.test.ts index bbb74b32b..4edaba33d 100644 --- a/tests/core/executions/PlayerExecution.test.ts +++ b/tests/core/executions/PlayerExecution.test.ts @@ -1,11 +1,6 @@ import { PlayerExecution } from "../../../src/core/execution/PlayerExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../../../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../../../src/core/game/Game"; +import { PlayerType, UnitType } from "../../../src/core/game/GameUpdates"; import { setup } from "../../util/Setup"; import { executeTicks } from "../../util/utils"; diff --git a/tests/core/executions/SAMLauncherExecution.test.ts b/tests/core/executions/SAMLauncherExecution.test.ts index ed7ba534b..79d807111 100644 --- a/tests/core/executions/SAMLauncherExecution.test.ts +++ b/tests/core/executions/SAMLauncherExecution.test.ts @@ -2,13 +2,8 @@ import { NukeExecution } from "../../../src/core/execution/NukeExecution"; import { SAMLauncherExecution } from "../../../src/core/execution/SAMLauncherExecution"; import { SpawnExecution } from "../../../src/core/execution/SpawnExecution"; import { UpgradeStructureExecution } from "../../../src/core/execution/UpgradeStructureExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../../../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../../../src/core/game/Game"; +import { PlayerType, UnitType } from "../../../src/core/game/GameUpdates"; import { setup } from "../../util/Setup"; import { constructionExecution, executeTicks } from "../../util/utils"; diff --git a/tests/core/game/GameImpl.test.ts b/tests/core/game/GameImpl.test.ts index 831036c2f..3d19f90cd 100644 --- a/tests/core/game/GameImpl.test.ts +++ b/tests/core/game/GameImpl.test.ts @@ -3,13 +3,9 @@ import { SpawnExecution } from "../../../src/core/execution/SpawnExecution"; //import { TransportShipExecution } from "../../../src/core/execution/TransportShipExecution"; import { AllianceRequestExecution } from "../../../src/core/execution/alliance/AllianceRequestExecution"; import { AllianceRequestReplyExecution } from "../../../src/core/execution/alliance/AllianceRequestReplyExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, -} from "../../../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../../../src/core/game/Game"; import { TileRef } from "../../../src/core/game/GameMap"; +import { PlayerType } from "../../../src/core/game/GameUpdates"; import { setup } from "../../util/Setup"; let game: Game; diff --git a/tests/core/game/TrainStation.test.ts b/tests/core/game/TrainStation.test.ts index f99847ee2..5d5ece8d0 100644 --- a/tests/core/game/TrainStation.test.ts +++ b/tests/core/game/TrainStation.test.ts @@ -1,5 +1,6 @@ import { TrainExecution } from "../../../src/core/execution/TrainExecution"; -import { Game, Player, Unit, UnitType } from "../../../src/core/game/Game"; +import { Game, Player, Unit } from "../../../src/core/game/Game"; +import { UnitType } from "../../../src/core/game/GameUpdates"; import { Cluster, TrainStation } from "../../../src/core/game/TrainStation"; jest.mock("../../../src/core/game/Game"); diff --git a/tests/economy/ConstructionGold.test.ts b/tests/economy/ConstructionGold.test.ts index d763aeecf..5fc8df60f 100644 --- a/tests/economy/ConstructionGold.test.ts +++ b/tests/economy/ConstructionGold.test.ts @@ -1,13 +1,8 @@ import { ConstructionExecution } from "../../src/core/execution/ConstructionExecution"; import { NukeExecution } from "../../src/core/execution/NukeExecution"; import { SpawnExecution } from "../../src/core/execution/SpawnExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../../src/core/game/Game"; +import { PlayerType, UnitType } from "../../src/core/game/GameUpdates"; import { setup } from "../util/Setup"; describe("Construction economy", () => { diff --git a/tests/nukes/HydrogenAndMirv.test.ts b/tests/nukes/HydrogenAndMirv.test.ts index edfca7f67..7d33a68ab 100644 --- a/tests/nukes/HydrogenAndMirv.test.ts +++ b/tests/nukes/HydrogenAndMirv.test.ts @@ -1,12 +1,7 @@ import { ConstructionExecution } from "../../src/core/execution/ConstructionExecution"; import { SpawnExecution } from "../../src/core/execution/SpawnExecution"; -import { - Game, - Player, - PlayerInfo, - PlayerType, - UnitType, -} from "../../src/core/game/Game"; +import { Game, Player, PlayerInfo } from "../../src/core/game/Game"; +import { PlayerType, UnitType } from "../../src/core/game/GameUpdates"; import { setup } from "../util/Setup"; describe("Hydrogen Bomb and MIRV flows", () => { diff --git a/tests/util/Setup.ts b/tests/util/Setup.ts index 963b134c1..47d10abdc 100644 --- a/tests/util/Setup.ts +++ b/tests/util/Setup.ts @@ -8,9 +8,9 @@ import { GameMode, GameType, PlayerInfo, - PlayerType, } from "../../src/core/game/Game"; import { createGame } from "../../src/core/game/GameImpl"; +import { PlayerType } from "../../src/core/game/GameUpdates"; import { genTerrainFromBin, MapManifest, diff --git a/tests/util/TestConfig.ts b/tests/util/TestConfig.ts index c5f514ab0..dd088fccd 100644 --- a/tests/util/TestConfig.ts +++ b/tests/util/TestConfig.ts @@ -1,13 +1,8 @@ import { NukeMagnitude } from "../../src/core/configuration/Config"; import { DefaultConfig } from "../../src/core/configuration/DefaultConfig"; -import { - Game, - Player, - TerraNullius, - Tick, - UnitType, -} from "../../src/core/game/Game"; +import { Game, Player, TerraNullius, Tick } from "../../src/core/game/Game"; import { TileRef } from "../../src/core/game/GameMap"; +import { UnitType } from "../../src/core/game/GameUpdates"; export class TestConfig extends DefaultConfig { private _proximityBonusPortsNb: number = 0; diff --git a/tests/util/utils.ts b/tests/util/utils.ts index dbdfb3d1d..d4a941dcd 100644 --- a/tests/util/utils.ts +++ b/tests/util/utils.ts @@ -4,7 +4,8 @@ // If you also need execution use function below. Does not work with things not import { ConstructionExecution } from "../../src/core/execution/ConstructionExecution"; -import { Game, Player, UnitType } from "../../src/core/game/Game"; +import { Game, Player } from "../../src/core/game/Game"; +import { UnitType } from "../../src/core/game/GameUpdates"; // built via UI (e.g.: trade ships) export function constructionExecution(