mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-17 16:29:24 +00:00
format codebase with prettier
This commit is contained in:
@@ -1,110 +1,114 @@
|
||||
import { createGameRunner, GameRunner } from "../GameRunner";
|
||||
import { GameUpdateViewData } from '../game/GameUpdates';
|
||||
import { GameUpdateViewData } from "../game/GameUpdates";
|
||||
import {
|
||||
MainThreadMessage,
|
||||
WorkerMessage,
|
||||
InitializedMessage,
|
||||
PlayerActionsResultMessage,
|
||||
PlayerProfileResultMessage,
|
||||
} from './WorkerMessages';
|
||||
MainThreadMessage,
|
||||
WorkerMessage,
|
||||
InitializedMessage,
|
||||
PlayerActionsResultMessage,
|
||||
PlayerProfileResultMessage,
|
||||
} from "./WorkerMessages";
|
||||
|
||||
const ctx: Worker = self as any;
|
||||
let gameRunner: Promise<GameRunner> | null = null;
|
||||
|
||||
function gameUpdate(gu: GameUpdateViewData) {
|
||||
sendMessage({
|
||||
type: "game_update",
|
||||
gameUpdate: gu
|
||||
});
|
||||
sendMessage({
|
||||
type: "game_update",
|
||||
gameUpdate: gu,
|
||||
});
|
||||
}
|
||||
|
||||
function sendMessage(message: WorkerMessage) {
|
||||
ctx.postMessage(message);
|
||||
ctx.postMessage(message);
|
||||
}
|
||||
|
||||
ctx.addEventListener('message', async (e: MessageEvent<MainThreadMessage>) => {
|
||||
const message = e.data;
|
||||
ctx.addEventListener("message", async (e: MessageEvent<MainThreadMessage>) => {
|
||||
const message = e.data;
|
||||
|
||||
switch (message.type) {
|
||||
case 'heartbeat':
|
||||
break
|
||||
case 'init':
|
||||
try {
|
||||
gameRunner = createGameRunner(
|
||||
message.gameID,
|
||||
message.gameConfig,
|
||||
gameUpdate
|
||||
).then(gr => {
|
||||
sendMessage({
|
||||
type: 'initialized',
|
||||
id: message.id
|
||||
} as InitializedMessage);
|
||||
return gr;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize game runner:', error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
switch (message.type) {
|
||||
case "heartbeat":
|
||||
break;
|
||||
case "init":
|
||||
try {
|
||||
gameRunner = createGameRunner(
|
||||
message.gameID,
|
||||
message.gameConfig,
|
||||
gameUpdate,
|
||||
).then((gr) => {
|
||||
sendMessage({
|
||||
type: "initialized",
|
||||
id: message.id,
|
||||
} as InitializedMessage);
|
||||
return gr;
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize game runner:", error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'turn':
|
||||
if (!gameRunner) {
|
||||
throw new Error('Game runner not initialized');
|
||||
}
|
||||
case "turn":
|
||||
if (!gameRunner) {
|
||||
throw new Error("Game runner not initialized");
|
||||
}
|
||||
|
||||
try {
|
||||
const gr = await gameRunner;
|
||||
await gr.addTurn(message.turn);
|
||||
} catch (error) {
|
||||
console.error('Failed to process turn:', error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
try {
|
||||
const gr = await gameRunner;
|
||||
await gr.addTurn(message.turn);
|
||||
} catch (error) {
|
||||
console.error("Failed to process turn:", error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'player_actions':
|
||||
if (!gameRunner) {
|
||||
throw new Error('Game runner not initialized');
|
||||
}
|
||||
case "player_actions":
|
||||
if (!gameRunner) {
|
||||
throw new Error("Game runner not initialized");
|
||||
}
|
||||
|
||||
try {
|
||||
const actions = (await gameRunner).playerActions(message.playerID, message.x, message.y)
|
||||
sendMessage({
|
||||
type: 'player_actions_result',
|
||||
id: message.id,
|
||||
result: actions
|
||||
} as PlayerActionsResultMessage);
|
||||
} catch (error) {
|
||||
console.error('Failed to check borders:', error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
case 'player_profile':
|
||||
if (!gameRunner) {
|
||||
throw new Error('Game runner not initialized');
|
||||
}
|
||||
try {
|
||||
const actions = (await gameRunner).playerActions(
|
||||
message.playerID,
|
||||
message.x,
|
||||
message.y,
|
||||
);
|
||||
sendMessage({
|
||||
type: "player_actions_result",
|
||||
id: message.id,
|
||||
result: actions,
|
||||
} as PlayerActionsResultMessage);
|
||||
} catch (error) {
|
||||
console.error("Failed to check borders:", error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
case "player_profile":
|
||||
if (!gameRunner) {
|
||||
throw new Error("Game runner not initialized");
|
||||
}
|
||||
|
||||
try {
|
||||
const profile = (await gameRunner).playerProfile(message.playerID)
|
||||
sendMessage({
|
||||
type: 'player_profile_result',
|
||||
id: message.id,
|
||||
result: profile
|
||||
} as PlayerProfileResultMessage);
|
||||
} catch (error) {
|
||||
console.error('Failed to check borders:', error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn('Unknown message :', message);
|
||||
}
|
||||
try {
|
||||
const profile = (await gameRunner).playerProfile(message.playerID);
|
||||
sendMessage({
|
||||
type: "player_profile_result",
|
||||
id: message.id,
|
||||
result: profile,
|
||||
} as PlayerProfileResultMessage);
|
||||
} catch (error) {
|
||||
console.error("Failed to check borders:", error);
|
||||
throw error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
console.warn("Unknown message :", message);
|
||||
}
|
||||
});
|
||||
|
||||
// Error handling
|
||||
ctx.addEventListener('error', (error) => {
|
||||
console.error('Worker error:', error);
|
||||
ctx.addEventListener("error", (error) => {
|
||||
console.error("Worker error:", error);
|
||||
});
|
||||
|
||||
ctx.addEventListener('unhandledrejection', (event) => {
|
||||
console.error('Unhandled promise rejection in worker:', event);
|
||||
});
|
||||
ctx.addEventListener("unhandledrejection", (event) => {
|
||||
console.error("Unhandled promise rejection in worker:", event);
|
||||
});
|
||||
|
||||
+144
-124
@@ -1,150 +1,170 @@
|
||||
import { PlayerActions, PlayerID, PlayerInfo, PlayerProfile } from "../game/Game";
|
||||
import { ErrorUpdate, GameUpdateViewData } from '../game/GameUpdates';
|
||||
import {
|
||||
PlayerActions,
|
||||
PlayerID,
|
||||
PlayerInfo,
|
||||
PlayerProfile,
|
||||
} from "../game/Game";
|
||||
import { ErrorUpdate, GameUpdateViewData } from "../game/GameUpdates";
|
||||
import { GameConfig, GameID, Turn } from "../Schemas";
|
||||
import { generateID } from "../Util";
|
||||
import { WorkerMessage } from "./WorkerMessages";
|
||||
|
||||
export class WorkerClient {
|
||||
private worker: Worker;
|
||||
private isInitialized = false;
|
||||
private messageHandlers: Map<string, (message: WorkerMessage) => void>;
|
||||
private gameUpdateCallback?: (update: GameUpdateViewData | ErrorUpdate) => void;
|
||||
private worker: Worker;
|
||||
private isInitialized = false;
|
||||
private messageHandlers: Map<string, (message: WorkerMessage) => void>;
|
||||
private gameUpdateCallback?: (
|
||||
update: GameUpdateViewData | ErrorUpdate,
|
||||
) => void;
|
||||
|
||||
constructor(private gameID: GameID, private gameConfig: GameConfig) {
|
||||
this.worker = new Worker(new URL('./Worker.worker.ts', import.meta.url));
|
||||
this.messageHandlers = new Map();
|
||||
constructor(
|
||||
private gameID: GameID,
|
||||
private gameConfig: GameConfig,
|
||||
) {
|
||||
this.worker = new Worker(new URL("./Worker.worker.ts", import.meta.url));
|
||||
this.messageHandlers = new Map();
|
||||
|
||||
// Set up global message handler
|
||||
this.worker.addEventListener('message', this.handleWorkerMessage.bind(this));
|
||||
}
|
||||
// Set up global message handler
|
||||
this.worker.addEventListener(
|
||||
"message",
|
||||
this.handleWorkerMessage.bind(this),
|
||||
);
|
||||
}
|
||||
|
||||
private handleWorkerMessage(event: MessageEvent<WorkerMessage>) {
|
||||
const message = event.data;
|
||||
private handleWorkerMessage(event: MessageEvent<WorkerMessage>) {
|
||||
const message = event.data;
|
||||
|
||||
switch (message.type) {
|
||||
case 'game_update':
|
||||
if (this.gameUpdateCallback && message.gameUpdate) {
|
||||
this.gameUpdateCallback(message.gameUpdate);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'initialized':
|
||||
default:
|
||||
if (message.id && this.messageHandlers.has(message.id)) {
|
||||
const handler = this.messageHandlers.get(message.id)!;
|
||||
handler(message);
|
||||
this.messageHandlers.delete(message.id);
|
||||
}
|
||||
break;
|
||||
switch (message.type) {
|
||||
case "game_update":
|
||||
if (this.gameUpdateCallback && message.gameUpdate) {
|
||||
this.gameUpdateCallback(message.gameUpdate);
|
||||
}
|
||||
break;
|
||||
|
||||
case "initialized":
|
||||
default:
|
||||
if (message.id && this.messageHandlers.has(message.id)) {
|
||||
const handler = this.messageHandlers.get(message.id)!;
|
||||
handler(message);
|
||||
this.messageHandlers.delete(message.id);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
initialize(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const messageId = generateID()
|
||||
initialize(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const messageId = generateID();
|
||||
|
||||
this.messageHandlers.set(messageId, (message) => {
|
||||
if (message.type === 'initialized') {
|
||||
this.isInitialized = true;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
this.messageHandlers.set(messageId, (message) => {
|
||||
if (message.type === "initialized") {
|
||||
this.isInitialized = true;
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
|
||||
this.worker.postMessage({
|
||||
type: 'init',
|
||||
id: messageId,
|
||||
gameID: this.gameID,
|
||||
gameConfig: this.gameConfig
|
||||
});
|
||||
this.worker.postMessage({
|
||||
type: "init",
|
||||
id: messageId,
|
||||
gameID: this.gameID,
|
||||
gameConfig: this.gameConfig,
|
||||
});
|
||||
|
||||
// Add timeout for initialization
|
||||
setTimeout(() => {
|
||||
if (!this.isInitialized) {
|
||||
this.messageHandlers.delete(messageId);
|
||||
reject(new Error('Worker initialization timeout'));
|
||||
}
|
||||
}, 5000); // 5 second timeout
|
||||
});
|
||||
}
|
||||
|
||||
start(gameUpdate: (gu: GameUpdateViewData | ErrorUpdate) => void) {
|
||||
// Add timeout for initialization
|
||||
setTimeout(() => {
|
||||
if (!this.isInitialized) {
|
||||
throw new Error('Failed to initialize pathfinder');
|
||||
this.messageHandlers.delete(messageId);
|
||||
reject(new Error("Worker initialization timeout"));
|
||||
}
|
||||
this.gameUpdateCallback = gameUpdate;
|
||||
}, 5000); // 5 second timeout
|
||||
});
|
||||
}
|
||||
|
||||
start(gameUpdate: (gu: GameUpdateViewData | ErrorUpdate) => void) {
|
||||
if (!this.isInitialized) {
|
||||
throw new Error("Failed to initialize pathfinder");
|
||||
}
|
||||
this.gameUpdateCallback = gameUpdate;
|
||||
}
|
||||
|
||||
sendTurn(turn: Turn) {
|
||||
if (!this.isInitialized) {
|
||||
throw new Error("Worker not initialized");
|
||||
}
|
||||
|
||||
sendTurn(turn: Turn) {
|
||||
if (!this.isInitialized) {
|
||||
throw new Error('Worker not initialized');
|
||||
this.worker.postMessage({
|
||||
type: "turn",
|
||||
turn,
|
||||
});
|
||||
}
|
||||
|
||||
sendHeartbeat() {
|
||||
this.worker.postMessage({
|
||||
type: "heartbeat",
|
||||
});
|
||||
}
|
||||
|
||||
playerProfile(playerID: number): Promise<PlayerProfile> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInitialized) {
|
||||
reject(new Error("Worker not initialized"));
|
||||
return;
|
||||
}
|
||||
|
||||
const messageId = generateID();
|
||||
|
||||
this.messageHandlers.set(messageId, (message) => {
|
||||
if (
|
||||
message.type === "player_profile_result" &&
|
||||
message.result !== undefined
|
||||
) {
|
||||
resolve(message.result);
|
||||
}
|
||||
});
|
||||
|
||||
this.worker.postMessage({
|
||||
type: 'turn',
|
||||
turn
|
||||
});
|
||||
}
|
||||
this.worker.postMessage({
|
||||
type: "player_profile",
|
||||
id: messageId,
|
||||
playerID: playerID,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
sendHeartbeat() {
|
||||
this.worker.postMessage({
|
||||
type: 'heartbeat'
|
||||
});
|
||||
}
|
||||
playerInteraction(
|
||||
playerID: PlayerID,
|
||||
x: number,
|
||||
y: number,
|
||||
): Promise<PlayerActions> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInitialized) {
|
||||
reject(new Error("Worker not initialized"));
|
||||
return;
|
||||
}
|
||||
|
||||
playerProfile(playerID: number): Promise<PlayerProfile> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInitialized) {
|
||||
reject(new Error('Worker not initialized'));
|
||||
return;
|
||||
}
|
||||
const messageId = generateID();
|
||||
|
||||
const messageId = generateID()
|
||||
this.messageHandlers.set(messageId, (message) => {
|
||||
if (
|
||||
message.type === "player_actions_result" &&
|
||||
message.result !== undefined
|
||||
) {
|
||||
resolve(message.result);
|
||||
}
|
||||
});
|
||||
|
||||
this.messageHandlers.set(messageId, (message) => {
|
||||
if (message.type === 'player_profile_result' && message.result !== undefined) {
|
||||
resolve(message.result);
|
||||
}
|
||||
});
|
||||
this.worker.postMessage({
|
||||
type: "player_actions",
|
||||
id: messageId,
|
||||
playerID: playerID,
|
||||
x: x,
|
||||
y: y,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
this.worker.postMessage({
|
||||
type: 'player_profile',
|
||||
id: messageId,
|
||||
playerID: playerID,
|
||||
});
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
playerInteraction(playerID: PlayerID, x: number, y: number): Promise<PlayerActions> {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isInitialized) {
|
||||
reject(new Error('Worker not initialized'));
|
||||
return;
|
||||
}
|
||||
|
||||
const messageId = generateID()
|
||||
|
||||
this.messageHandlers.set(messageId, (message) => {
|
||||
if (message.type === 'player_actions_result' && message.result !== undefined) {
|
||||
resolve(message.result);
|
||||
}
|
||||
});
|
||||
|
||||
this.worker.postMessage({
|
||||
type: 'player_actions',
|
||||
id: messageId,
|
||||
playerID: playerID,
|
||||
x: x,
|
||||
y: y
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
cleanup() {
|
||||
this.worker.terminate();
|
||||
this.messageHandlers.clear();
|
||||
this.gameUpdateCallback = undefined;
|
||||
}
|
||||
}
|
||||
cleanup() {
|
||||
this.worker.terminate();
|
||||
this.messageHandlers.clear();
|
||||
this.gameUpdateCallback = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,74 +1,83 @@
|
||||
import { GameUpdateViewData } from '../game/GameUpdates';
|
||||
import { GameUpdateViewData } from "../game/GameUpdates";
|
||||
import { GameConfig, GameID, Turn } from "../Schemas";
|
||||
import { PlayerActions, PlayerID, PlayerProfile } from "../game/Game";
|
||||
|
||||
export type WorkerMessageType =
|
||||
| 'heartbeat'
|
||||
| 'init'
|
||||
| 'initialized'
|
||||
| 'turn'
|
||||
| 'game_update'
|
||||
| 'player_actions'
|
||||
| 'player_actions_result'
|
||||
| 'player_profile'
|
||||
| 'player_profile_result'
|
||||
| "heartbeat"
|
||||
| "init"
|
||||
| "initialized"
|
||||
| "turn"
|
||||
| "game_update"
|
||||
| "player_actions"
|
||||
| "player_actions_result"
|
||||
| "player_profile"
|
||||
| "player_profile_result";
|
||||
|
||||
// Base interface for all messages
|
||||
interface BaseWorkerMessage {
|
||||
type: WorkerMessageType;
|
||||
id?: string;
|
||||
type: WorkerMessageType;
|
||||
id?: string;
|
||||
}
|
||||
|
||||
export interface HeartbeatMessage extends BaseWorkerMessage {
|
||||
type: 'heartbeat'
|
||||
type: "heartbeat";
|
||||
}
|
||||
|
||||
// Messages from main thread to worker
|
||||
export interface InitMessage extends BaseWorkerMessage {
|
||||
type: 'init';
|
||||
gameID: GameID;
|
||||
gameConfig: GameConfig;
|
||||
type: "init";
|
||||
gameID: GameID;
|
||||
gameConfig: GameConfig;
|
||||
}
|
||||
|
||||
export interface TurnMessage extends BaseWorkerMessage {
|
||||
type: 'turn';
|
||||
turn: Turn;
|
||||
type: "turn";
|
||||
turn: Turn;
|
||||
}
|
||||
|
||||
// Messages from worker to main thread
|
||||
export interface InitializedMessage extends BaseWorkerMessage {
|
||||
type: 'initialized';
|
||||
type: "initialized";
|
||||
}
|
||||
|
||||
export interface GameUpdateMessage extends BaseWorkerMessage {
|
||||
type: 'game_update';
|
||||
gameUpdate: GameUpdateViewData;
|
||||
type: "game_update";
|
||||
gameUpdate: GameUpdateViewData;
|
||||
}
|
||||
|
||||
export interface PlayerActionsMessage extends BaseWorkerMessage {
|
||||
type: 'player_actions'
|
||||
playerID: PlayerID
|
||||
x: number,
|
||||
y: number
|
||||
type: "player_actions";
|
||||
playerID: PlayerID;
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface PlayerActionsResultMessage extends BaseWorkerMessage {
|
||||
type: 'player_actions_result';
|
||||
result: PlayerActions;
|
||||
type: "player_actions_result";
|
||||
result: PlayerActions;
|
||||
}
|
||||
|
||||
export interface PlayerProfileMessage extends BaseWorkerMessage {
|
||||
type: 'player_profile'
|
||||
playerID: number
|
||||
type: "player_profile";
|
||||
playerID: number;
|
||||
}
|
||||
|
||||
export interface PlayerProfileResultMessage extends BaseWorkerMessage {
|
||||
type: 'player_profile_result'
|
||||
result: PlayerProfile
|
||||
type: "player_profile_result";
|
||||
result: PlayerProfile;
|
||||
}
|
||||
|
||||
// Union types for type safety
|
||||
export type MainThreadMessage = HeartbeatMessage | InitMessage | TurnMessage | PlayerActionsMessage | PlayerProfileMessage
|
||||
export type MainThreadMessage =
|
||||
| HeartbeatMessage
|
||||
| InitMessage
|
||||
| TurnMessage
|
||||
| PlayerActionsMessage
|
||||
| PlayerProfileMessage;
|
||||
|
||||
// Message send from worker
|
||||
export type WorkerMessage = InitializedMessage | GameUpdateMessage | PlayerActionsResultMessage | PlayerProfileResultMessage
|
||||
export type WorkerMessage =
|
||||
| InitializedMessage
|
||||
| GameUpdateMessage
|
||||
| PlayerActionsResultMessage
|
||||
| PlayerProfileResultMessage;
|
||||
|
||||
Reference in New Issue
Block a user