mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-20 05:00:18 +00:00
feat(ping): implement ping communication and visual enhancements
This commit implements the full communication loop for the ping system, including: - **Schema Definitions:** Added and schemas. - **Client-Side Sending:** Configured to emit , which now intercepts and uses to send to the server. - **Server-Side Execution:** Implemented to process , generating (for chat) and (for visual pings) for friendly players. - **Client-Side Receiving:** handles by emitting for local display. - **Visual Enhancements:** Updated the ping animation with a glow effect, adjusted duration to 6 seconds, and increased maximum radius to 48 for a more prominent visual. - **Test:** Added a unit test for to verify server-side logic.
This commit is contained in:
@@ -30,6 +30,8 @@ import {
|
||||
AutoUpgradeEvent,
|
||||
DoBoatAttackEvent,
|
||||
DoGroundAttackEvent,
|
||||
GoToPlayerEvent,
|
||||
GoToPositionEvent,
|
||||
InputHandler,
|
||||
MouseMoveEvent,
|
||||
MouseUpEvent,
|
||||
@@ -49,7 +51,6 @@ import {
|
||||
} from "./Transport";
|
||||
import { createCanvas } from "./Utils";
|
||||
import { createRenderer, GameRenderer } from "./graphics/GameRenderer";
|
||||
import { GoToPlayerEvent } from "./graphics/layers/Leaderboard";
|
||||
import SoundManager from "./sound/SoundManager";
|
||||
|
||||
export interface LobbyConfig {
|
||||
@@ -224,6 +225,12 @@ export class ClientGameRunner {
|
||||
private gameView: GameView,
|
||||
) {
|
||||
this.lastMessageTime = Date.now();
|
||||
|
||||
this.eventBus.on(GoToPositionEvent, (e) => this.onGoToPosition(e));
|
||||
}
|
||||
|
||||
private onGoToPosition(event: GoToPositionEvent) {
|
||||
this.eventBus.emit(new GoToPositionEvent(event.x, event.y));
|
||||
}
|
||||
|
||||
private saveGame(update: WinUpdate) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { EventBus, GameEvent } from "../core/EventBus";
|
||||
import { UnitType } from "../core/game/Game";
|
||||
import { UnitView } from "../core/game/GameView";
|
||||
import { PlayerView, UnitView } from "../core/game/GameView";
|
||||
import { PingType } from "../core/game/Ping";
|
||||
import { UserSettings } from "../core/game/UserSettings";
|
||||
import { TransformHandler } from "./graphics/TransformHandler";
|
||||
@@ -144,6 +144,21 @@ export class PingPlacedEvent implements GameEvent {
|
||||
) {}
|
||||
}
|
||||
|
||||
export class GoToPositionEvent implements GameEvent {
|
||||
constructor(
|
||||
public readonly x: number,
|
||||
public readonly y: number,
|
||||
) {}
|
||||
}
|
||||
|
||||
export class GoToPlayerEvent implements GameEvent {
|
||||
constructor(public player: PlayerView) {}
|
||||
}
|
||||
|
||||
export class GoToUnitEvent implements GameEvent {
|
||||
constructor(public unit: UnitView) {}
|
||||
}
|
||||
|
||||
export class InputHandler {
|
||||
private lastPointerX: number = 0;
|
||||
private lastPointerY: number = 0;
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
import { EventBus } from "../../core/EventBus";
|
||||
import { Cell } from "../../core/game/Game";
|
||||
import { GameView } from "../../core/game/GameView";
|
||||
import { CenterCameraEvent, DragEvent, ZoomEvent } from "../InputHandler";
|
||||
import {
|
||||
CenterCameraEvent,
|
||||
DragEvent,
|
||||
GoToPlayerEvent,
|
||||
GoToPositionEvent,
|
||||
GoToUnitEvent,
|
||||
} from "./layers/Leaderboard";
|
||||
ZoomEvent,
|
||||
} from "../InputHandler";
|
||||
|
||||
export const GOTO_INTERVAL_MS = 16;
|
||||
export const CAMERA_MAX_SPEED = 15;
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
} from "../../../core/game/GameUpdates";
|
||||
import { GameView } from "../../../core/game/GameView";
|
||||
import { onlyImages } from "../../../core/Util";
|
||||
import { GoToPositionEvent } from "../../InputHandler";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
interface ChatEvent {
|
||||
@@ -17,6 +18,8 @@ interface ChatEvent {
|
||||
unsafeDescription?: boolean;
|
||||
createdAt: number;
|
||||
highlight?: boolean;
|
||||
x?: number; // New optional field
|
||||
y?: number; // New optional field
|
||||
}
|
||||
|
||||
@customElement("chat-display")
|
||||
@@ -68,6 +71,8 @@ export class ChatDisplay extends LitElement implements Layer {
|
||||
createdAt: this.game.ticks(),
|
||||
highlight: true,
|
||||
unsafeDescription: true,
|
||||
x: event.x, // Transfer coordinates
|
||||
y: event.y, // Transfer coordinates
|
||||
});
|
||||
}
|
||||
|
||||
@@ -119,6 +124,7 @@ export class ChatDisplay extends LitElement implements Layer {
|
||||
: chat.description;
|
||||
}
|
||||
|
||||
// ...
|
||||
render() {
|
||||
if (!this.active) {
|
||||
return html``;
|
||||
@@ -170,7 +176,19 @@ export class ChatDisplay extends LitElement implements Layer {
|
||||
(chat) => html`
|
||||
<tr class="border-b border-opacity-0">
|
||||
<td class="lg:p-3 p-1 text-left">
|
||||
${this.getChatContent(chat)}
|
||||
${chat.x !== undefined && chat.y !== undefined
|
||||
? html`
|
||||
<div
|
||||
class="cursor-pointer text-blue-400 hover:underline"
|
||||
@click=${() =>
|
||||
this.eventBus.emit(
|
||||
new GoToPositionEvent(chat.x!, chat.y!),
|
||||
)}
|
||||
>
|
||||
${this.getChatContent(chat)}
|
||||
</div>
|
||||
`
|
||||
: this.getChatContent(chat)}
|
||||
</td>
|
||||
</tr>
|
||||
`,
|
||||
|
||||
@@ -40,12 +40,12 @@ import { Layer } from "./Layer";
|
||||
|
||||
import { GameView, PlayerView, UnitView } from "../../../core/game/GameView";
|
||||
import { onlyImages } from "../../../core/Util";
|
||||
import { renderNumber, renderTroops } from "../../Utils";
|
||||
import {
|
||||
GoToPlayerEvent,
|
||||
GoToPositionEvent,
|
||||
GoToUnitEvent,
|
||||
} from "./Leaderboard";
|
||||
} from "../../InputHandler";
|
||||
import { renderNumber, renderTroops } from "../../Utils";
|
||||
|
||||
import { getMessageTypeClasses, translateText } from "../../Utils";
|
||||
|
||||
|
||||
@@ -2,8 +2,9 @@ import { LitElement, html } from "lit";
|
||||
import { customElement, property, state } from "lit/decorators.js";
|
||||
import { repeat } from "lit/directives/repeat.js";
|
||||
import { translateText } from "../../../client/Utils";
|
||||
import { EventBus, GameEvent } from "../../../core/EventBus";
|
||||
import { GameView, PlayerView, UnitView } from "../../../core/game/GameView";
|
||||
import { EventBus } from "../../../core/EventBus";
|
||||
import { GameView, PlayerView } from "../../../core/game/GameView";
|
||||
import { GoToPlayerEvent } from "../../InputHandler";
|
||||
import { renderNumber } from "../../Utils";
|
||||
import { Layer } from "./Layer";
|
||||
|
||||
@@ -18,21 +19,6 @@ interface Entry {
|
||||
player: PlayerView;
|
||||
}
|
||||
|
||||
export class GoToPlayerEvent implements GameEvent {
|
||||
constructor(public player: PlayerView) {}
|
||||
}
|
||||
|
||||
export class GoToPositionEvent implements GameEvent {
|
||||
constructor(
|
||||
public x: number,
|
||||
public y: number,
|
||||
) {}
|
||||
}
|
||||
|
||||
export class GoToUnitEvent implements GameEvent {
|
||||
constructor(public unit: UnitView) {}
|
||||
}
|
||||
|
||||
@customElement("leader-board")
|
||||
export class Leaderboard extends LitElement implements Layer {
|
||||
public game: GameView | null = null;
|
||||
|
||||
@@ -18,7 +18,15 @@ export class PingExecution implements Execution {
|
||||
for (const recipient of recipients) {
|
||||
// Create chat message
|
||||
const message = `${this.sender.name()} pinged ${this.pingType}`;
|
||||
game.displayMessage(message, MessageType.CHAT, recipient.id());
|
||||
game.displayMessage(
|
||||
message,
|
||||
MessageType.CHAT,
|
||||
recipient.id(),
|
||||
undefined,
|
||||
undefined,
|
||||
this.x,
|
||||
this.y,
|
||||
);
|
||||
|
||||
// Create visual ping update
|
||||
game.addUpdate({
|
||||
|
||||
@@ -718,6 +718,8 @@ export interface Game extends GameMap {
|
||||
playerID: PlayerID | null,
|
||||
goldAmount?: bigint,
|
||||
params?: Record<string, string | number>,
|
||||
x?: number, // New optional field
|
||||
y?: number, // New optional field
|
||||
): void;
|
||||
displayIncomingUnit(
|
||||
unitID: number,
|
||||
|
||||
@@ -233,6 +233,8 @@ export interface DisplayMessageUpdate {
|
||||
goldAmount?: bigint;
|
||||
playerID: number | null;
|
||||
params?: Record<string, string | number>;
|
||||
x?: number; // New optional field
|
||||
y?: number; // New optional field
|
||||
}
|
||||
|
||||
export type DisplayChatMessageUpdate = {
|
||||
|
||||
Reference in New Issue
Block a user