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(