mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-22 16:46:38 +00:00
fixed name leak
This commit is contained in:
+16
-3
@@ -577,10 +577,23 @@
|
||||
"focus": "Focus",
|
||||
"accept_alliance": "Accept",
|
||||
"reject_alliance": "Reject",
|
||||
"alliance_renewed": "Your alliance with {name} has been renewed",
|
||||
"wants_to_renew_alliance": "{name} wants to renew your alliance",
|
||||
"alliance_renewed": "Your alliance with {otherPlayerName} has been renewed",
|
||||
"wants_to_renew_alliance": "{otherPlayerName} wants to renew your alliance",
|
||||
"ignore": "Ignore",
|
||||
"unit_voluntarily_deleted": "Unit voluntarily deleted"
|
||||
"unit_voluntarily_deleted": "Unit voluntarily deleted",
|
||||
"sent_troops_to_player": "Sent {troops} troops to {recipientPlayerName}",
|
||||
"received_troops_from_player": "Received {troops} troops from {senderPlayerName}",
|
||||
"sent_gold_to_player": "Sent {gold} gold to {recipientPlayerName}",
|
||||
"received_gold_from_player": "Received {gold} gold from {senderPlayerName}",
|
||||
"unit_captured_by_enemy": "Your {unitType} was captured by {captorPlayerName}",
|
||||
"captured_enemy_unit": "Captured {unitType} from {previousOwnerPlayerName}",
|
||||
"conquered_player": "Conquered {conqueredPlayerName} received {gold} gold",
|
||||
"received_gold_from_trade": "Received {gold} gold from trade with {tradingPartnerPlayerName}",
|
||||
"received_gold_from_captured_ship": "Received {gold} gold from ship captured from {originalOwnerPlayerName}",
|
||||
"mirv_inbound": "{attackerPlayerName} - MIRV INBOUND",
|
||||
"atom_bomb_inbound": "{attackerPlayerName} - atom bomb inbound",
|
||||
"hydrogen_bomb_inbound": "{attackerPlayerName} - hydrogen bomb inbound",
|
||||
"naval_invasion_inbound": "Naval invasion incoming from {attackerPlayerName}"
|
||||
},
|
||||
"unit_info_modal": {
|
||||
"structure_info": "Structure Info",
|
||||
|
||||
@@ -286,7 +286,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
this.addEvent({
|
||||
description: translateText("events_display.about_to_expire", {
|
||||
name: other.name(),
|
||||
name: other.displayName(),
|
||||
}),
|
||||
type: MessageType.RENEW_ALLIANCE,
|
||||
duration: this.game.config().allianceExtensionPromptOffset() - 3 * 10, // 3 second buffer
|
||||
@@ -299,7 +299,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
},
|
||||
{
|
||||
text: translateText("events_display.renew_alliance", {
|
||||
name: other.name(),
|
||||
name: other.displayName(),
|
||||
}),
|
||||
className: "btn",
|
||||
action: () =>
|
||||
@@ -373,7 +373,43 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
let description: string = event.message;
|
||||
if (event.message.startsWith("events_display.")) {
|
||||
description = translateText(event.message, event.params ?? {});
|
||||
// Resolve player IDs in params to displayName() for hidden names support
|
||||
// Pattern: Server sends params with keys ending in "PlayerID" (e.g., "recipientPlayerID")
|
||||
// Client resolves these to displayName() and replaces "ID" with "Name" in the key
|
||||
// (e.g., "recipientPlayerID" -> "recipientPlayerName") for translation
|
||||
// This ensures hidden names work correctly and messages are translatable
|
||||
const resolvedParams: Record<string, string | number> = {};
|
||||
if (event.params) {
|
||||
for (const [key, value] of Object.entries(event.params)) {
|
||||
// If param ends with "PlayerID" or "PlayerId", resolve it to displayName
|
||||
if (
|
||||
(key.endsWith("PlayerID") ||
|
||||
key.endsWith("PlayerId") ||
|
||||
key.endsWith("playerID") ||
|
||||
key.endsWith("playerId")) &&
|
||||
(typeof value === "string" || typeof value === "number")
|
||||
) {
|
||||
try {
|
||||
const player =
|
||||
typeof value === "string"
|
||||
? this.game.player(value)
|
||||
: this.game.playerBySmallID(value);
|
||||
if (player && player instanceof PlayerView) {
|
||||
resolvedParams[key.replace(/ID$/i, "Name")] =
|
||||
player.displayName();
|
||||
} else {
|
||||
resolvedParams[key] = value;
|
||||
}
|
||||
} catch (e) {
|
||||
// If player not found, keep original value
|
||||
resolvedParams[key] = value;
|
||||
}
|
||||
} else {
|
||||
resolvedParams[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
description = translateText(event.message, resolvedParams);
|
||||
}
|
||||
|
||||
this.addEvent({
|
||||
@@ -445,7 +481,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
this.addEvent({
|
||||
description: translateText("events_display.request_alliance", {
|
||||
name: requestor.name(),
|
||||
name: requestor.displayName(),
|
||||
}),
|
||||
buttons: [
|
||||
{
|
||||
@@ -512,7 +548,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
) as PlayerView;
|
||||
this.addEvent({
|
||||
description: translateText("events_display.alliance_request_status", {
|
||||
name: recipient.name(),
|
||||
name: recipient.displayName(),
|
||||
status: update.accepted
|
||||
? translateText("events_display.alliance_accepted")
|
||||
: translateText("events_display.alliance_rejected"),
|
||||
@@ -552,7 +588,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
this.addEvent({
|
||||
description: translateText("events_display.betrayal_description", {
|
||||
name: betrayed.name(),
|
||||
name: betrayed.displayName(),
|
||||
malusPercent: malusPercent,
|
||||
durationText: durationText,
|
||||
}),
|
||||
@@ -572,7 +608,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
];
|
||||
this.addEvent({
|
||||
description: translateText("events_display.betrayed_you", {
|
||||
name: traitor.name(),
|
||||
name: traitor.displayName(),
|
||||
}),
|
||||
type: MessageType.ALLIANCE_BROKEN,
|
||||
highlight: true,
|
||||
@@ -599,7 +635,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
this.addEvent({
|
||||
description: translateText("events_display.alliance_expired", {
|
||||
name: other.name(),
|
||||
name: other.displayName(),
|
||||
}),
|
||||
type: MessageType.ALLIANCE_EXPIRED,
|
||||
highlight: true,
|
||||
@@ -617,8 +653,8 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
this.addEvent({
|
||||
description: translateText("events_display.attack_request", {
|
||||
name: other.name(),
|
||||
target: target.name(),
|
||||
name: other.displayName(),
|
||||
target: target.displayName(),
|
||||
}),
|
||||
type: MessageType.ATTACK_REQUEST,
|
||||
highlight: true,
|
||||
@@ -698,8 +734,49 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
|
||||
const unitView = this.game.unit(event.unitID);
|
||||
|
||||
let description: string = event.message;
|
||||
// Resolve player IDs in params to displayName() for hidden names support
|
||||
if (event.message.startsWith("events_display.")) {
|
||||
const resolvedParams: Record<string, string | number> = {};
|
||||
if (event.params) {
|
||||
for (const [key, value] of Object.entries(event.params)) {
|
||||
// If param ends with "PlayerID" or "PlayerId", resolve it to displayName
|
||||
if (
|
||||
(key.endsWith("PlayerID") ||
|
||||
key.endsWith("PlayerId") ||
|
||||
key.endsWith("playerID") ||
|
||||
key.endsWith("playerId")) &&
|
||||
(typeof value === "string" || typeof value === "number")
|
||||
) {
|
||||
try {
|
||||
const player =
|
||||
typeof value === "string"
|
||||
? this.game.player(value)
|
||||
: this.game.playerBySmallID(value);
|
||||
if (player && player instanceof PlayerView) {
|
||||
resolvedParams[key.replace(/ID$/i, "Name")] =
|
||||
player.displayName();
|
||||
} else {
|
||||
resolvedParams[key] = value;
|
||||
}
|
||||
} catch (e) {
|
||||
// If player not found, keep original value
|
||||
resolvedParams[key] = value;
|
||||
}
|
||||
} else {
|
||||
resolvedParams[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
description = translateText(event.message, resolvedParams);
|
||||
// Add emojis for MIRV messages in code (not in translation)
|
||||
if (event.message === "events_display.mirv_inbound") {
|
||||
description = `⚠️⚠️⚠️ ${description} ⚠️⚠️⚠️`;
|
||||
}
|
||||
}
|
||||
|
||||
this.addEvent({
|
||||
description: event.message,
|
||||
description: description,
|
||||
type: event.messageType,
|
||||
unsafeDescription: false,
|
||||
highlight: true,
|
||||
@@ -747,7 +824,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
${renderTroops(attack.troops)}
|
||||
${(
|
||||
this.game.playerBySmallID(attack.attackerID) as PlayerView
|
||||
)?.name()}
|
||||
)?.displayName()}
|
||||
${attack.retreating
|
||||
? `(${translateText("events_display.retreating")}...)`
|
||||
: ""}
|
||||
@@ -778,7 +855,7 @@ export class EventsDisplay extends LitElement implements Layer {
|
||||
this.game.playerBySmallID(
|
||||
attack.targetID,
|
||||
) as PlayerView
|
||||
)?.name()}
|
||||
)?.displayName()}
|
||||
`,
|
||||
onClick: async () => this.attackWarningOnClick(attack),
|
||||
className: "text-left text-blue-400",
|
||||
|
||||
@@ -80,10 +80,12 @@ export class MirvExecution implements Execution {
|
||||
|
||||
this.mg.displayIncomingUnit(
|
||||
this.nuke.id(),
|
||||
// TODO TranslateText
|
||||
`⚠️⚠️⚠️ ${this.player.name()} - MIRV INBOUND ⚠️⚠️⚠️`,
|
||||
"events_display.mirv_inbound",
|
||||
MessageType.MIRV_INBOUND,
|
||||
this.targetPlayer.id(),
|
||||
{
|
||||
attackerPlayerID: this.player.id(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -128,18 +128,22 @@ export class NukeExecution implements Execution {
|
||||
} else if (this.nukeType === UnitType.AtomBomb) {
|
||||
this.mg.displayIncomingUnit(
|
||||
this.nuke.id(),
|
||||
// TODO TranslateText
|
||||
`${this.player.name()} - atom bomb inbound`,
|
||||
"events_display.atom_bomb_inbound",
|
||||
MessageType.NUKE_INBOUND,
|
||||
target.id(),
|
||||
{
|
||||
attackerPlayerID: this.player.id(),
|
||||
},
|
||||
);
|
||||
} else if (this.nukeType === UnitType.HydrogenBomb) {
|
||||
this.mg.displayIncomingUnit(
|
||||
this.nuke.id(),
|
||||
// TODO TranslateText
|
||||
`${this.player.name()} - hydrogen bomb inbound`,
|
||||
"events_display.hydrogen_bomb_inbound",
|
||||
MessageType.HYDROGEN_BOMB_INBOUND,
|
||||
target.id(),
|
||||
{
|
||||
attackerPlayerID: this.player.id(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -143,10 +143,14 @@ export class TradeShipExecution implements Execution {
|
||||
if (this.wasCaptured) {
|
||||
this.tradeShip!.owner().addGold(gold, this._dstPort.tile());
|
||||
this.mg.displayMessage(
|
||||
`Received ${renderNumber(gold)} gold from ship captured from ${this.origOwner.displayName()}`,
|
||||
"events_display.received_gold_from_captured_ship",
|
||||
MessageType.CAPTURED_ENEMY_UNIT,
|
||||
this.tradeShip!.owner().id(),
|
||||
gold,
|
||||
{
|
||||
gold: renderNumber(gold),
|
||||
originalOwnerPlayerID: this.origOwner.id(),
|
||||
},
|
||||
);
|
||||
// Record stats
|
||||
this.mg
|
||||
@@ -156,16 +160,24 @@ export class TradeShipExecution implements Execution {
|
||||
this.srcPort.owner().addGold(gold);
|
||||
this._dstPort.owner().addGold(gold, this._dstPort.tile());
|
||||
this.mg.displayMessage(
|
||||
`Received ${renderNumber(gold)} gold from trade with ${this.srcPort.owner().displayName()}`,
|
||||
"events_display.received_gold_from_trade",
|
||||
MessageType.RECEIVED_GOLD_FROM_TRADE,
|
||||
this._dstPort.owner().id(),
|
||||
gold,
|
||||
{
|
||||
gold: renderNumber(gold),
|
||||
tradingPartnerPlayerID: this.srcPort.owner().id(),
|
||||
},
|
||||
);
|
||||
this.mg.displayMessage(
|
||||
`Received ${renderNumber(gold)} gold from trade with ${this._dstPort.owner().displayName()}`,
|
||||
"events_display.received_gold_from_trade",
|
||||
MessageType.RECEIVED_GOLD_FROM_TRADE,
|
||||
this.srcPort.owner().id(),
|
||||
gold,
|
||||
{
|
||||
gold: renderNumber(gold),
|
||||
tradingPartnerPlayerID: this._dstPort.owner().id(),
|
||||
},
|
||||
);
|
||||
// Record stats
|
||||
this.mg
|
||||
|
||||
@@ -143,10 +143,12 @@ export class TransportShipExecution implements Execution {
|
||||
if (this.targetID && this.targetID !== mg.terraNullius().id()) {
|
||||
mg.displayIncomingUnit(
|
||||
this.boat.id(),
|
||||
// TODO TranslateText
|
||||
`Naval invasion incoming from ${this.attacker.displayName()}`,
|
||||
"events_display.naval_invasion_inbound",
|
||||
MessageType.NAVAL_INVASION_INBOUND,
|
||||
this.targetID,
|
||||
{
|
||||
attackerPlayerID: this.attacker.id(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,14 +50,14 @@ export class AllianceExtensionExecution implements Execution {
|
||||
MessageType.ALLIANCE_ACCEPTED,
|
||||
this.from.id(),
|
||||
undefined,
|
||||
{ name: to.displayName() },
|
||||
{ otherPlayerID: to.id() },
|
||||
);
|
||||
mg.displayMessage(
|
||||
"events_display.alliance_renewed",
|
||||
MessageType.ALLIANCE_ACCEPTED,
|
||||
this.toID,
|
||||
undefined,
|
||||
{ name: this.from.displayName() },
|
||||
{ otherPlayerID: this.from.id() },
|
||||
);
|
||||
} else if (alliance.onlyOneAgreedToExtend() && !wasOnlyOneAgreed) {
|
||||
// Send message to the other player that someone wants to renew
|
||||
@@ -67,7 +67,7 @@ export class AllianceExtensionExecution implements Execution {
|
||||
MessageType.RENEW_ALLIANCE,
|
||||
this.toID,
|
||||
undefined,
|
||||
{ name: this.from.displayName() },
|
||||
{ otherPlayerID: this.from.id() },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,6 +723,7 @@ export interface Game extends GameMap {
|
||||
message: string,
|
||||
type: MessageType,
|
||||
playerID: PlayerID | null,
|
||||
params?: Record<string, string | number>,
|
||||
): void;
|
||||
|
||||
displayChat(
|
||||
|
||||
@@ -738,6 +738,7 @@ export class GameImpl implements Game {
|
||||
message: string,
|
||||
type: MessageType,
|
||||
playerID: PlayerID,
|
||||
params?: Record<string, string | number>,
|
||||
): void {
|
||||
const id = this.player(playerID).smallID();
|
||||
|
||||
@@ -747,6 +748,7 @@ export class GameImpl implements Game {
|
||||
message: message,
|
||||
messageType: type,
|
||||
playerID: id,
|
||||
params: params,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -897,12 +899,14 @@ export class GameImpl implements Game {
|
||||
conquerPlayer(conqueror: Player, conquered: Player) {
|
||||
const gold = conquered.gold();
|
||||
this.displayMessage(
|
||||
`Conquered ${conquered.displayName()} received ${renderNumber(
|
||||
gold,
|
||||
)} gold`,
|
||||
"events_display.conquered_player",
|
||||
MessageType.CONQUERED_PLAYER,
|
||||
conqueror.id(),
|
||||
gold,
|
||||
{
|
||||
conqueredPlayerID: conquered.id(),
|
||||
gold: renderNumber(gold),
|
||||
},
|
||||
);
|
||||
conqueror.addGold(gold);
|
||||
conquered.removeGold(gold);
|
||||
|
||||
@@ -260,6 +260,7 @@ export interface UnitIncomingUpdate {
|
||||
message: string;
|
||||
messageType: MessageType;
|
||||
playerID: number;
|
||||
params?: Record<string, string | number>;
|
||||
}
|
||||
|
||||
export interface EmbargoUpdate {
|
||||
|
||||
@@ -651,14 +651,24 @@ export class PlayerImpl implements Player {
|
||||
|
||||
this.sentDonations.push(new Donation(recipient, this.mg.ticks()));
|
||||
this.mg.displayMessage(
|
||||
`Sent ${renderTroops(troops)} troops to ${recipient.name()}`,
|
||||
"events_display.sent_troops_to_player",
|
||||
MessageType.SENT_TROOPS_TO_PLAYER,
|
||||
this.id(),
|
||||
undefined,
|
||||
{
|
||||
troops: renderTroops(troops),
|
||||
recipientPlayerID: recipient.id(),
|
||||
},
|
||||
);
|
||||
this.mg.displayMessage(
|
||||
`Received ${renderTroops(troops)} troops from ${this.name()}`,
|
||||
"events_display.received_troops_from_player",
|
||||
MessageType.RECEIVED_TROOPS_FROM_PLAYER,
|
||||
recipient.id(),
|
||||
undefined,
|
||||
{
|
||||
troops: renderTroops(troops),
|
||||
senderPlayerID: this.id(),
|
||||
},
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -671,15 +681,24 @@ export class PlayerImpl implements Player {
|
||||
|
||||
this.sentDonations.push(new Donation(recipient, this.mg.ticks()));
|
||||
this.mg.displayMessage(
|
||||
`Sent ${renderNumber(gold)} gold to ${recipient.name()}`,
|
||||
"events_display.sent_gold_to_player",
|
||||
MessageType.SENT_GOLD_TO_PLAYER,
|
||||
this.id(),
|
||||
undefined,
|
||||
{
|
||||
gold: renderNumber(gold),
|
||||
recipientPlayerID: recipient.id(),
|
||||
},
|
||||
);
|
||||
this.mg.displayMessage(
|
||||
`Received ${renderNumber(gold)} gold from ${this.name()}`,
|
||||
"events_display.received_gold_from_player",
|
||||
MessageType.RECEIVED_GOLD_FROM_PLAYER,
|
||||
recipient.id(),
|
||||
gold,
|
||||
{
|
||||
gold: renderNumber(gold),
|
||||
senderPlayerID: this.id(),
|
||||
},
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -202,14 +202,24 @@ export class UnitImpl implements Unit {
|
||||
this._owner._units.push(this);
|
||||
this.mg.addUpdate(this.toUpdate());
|
||||
this.mg.displayMessage(
|
||||
`Your ${this.type()} was captured by ${newOwner.displayName()}`,
|
||||
"events_display.unit_captured_by_enemy",
|
||||
MessageType.UNIT_CAPTURED_BY_ENEMY,
|
||||
this._lastOwner.id(),
|
||||
undefined,
|
||||
{
|
||||
unitType: this.type(),
|
||||
captorPlayerID: newOwner.id(),
|
||||
},
|
||||
);
|
||||
this.mg.displayMessage(
|
||||
`Captured ${this.type()} from ${this._lastOwner.displayName()}`,
|
||||
"events_display.captured_enemy_unit",
|
||||
MessageType.CAPTURED_ENEMY_UNIT,
|
||||
newOwner.id(),
|
||||
undefined,
|
||||
{
|
||||
unitType: this.type(),
|
||||
previousOwnerPlayerID: this._lastOwner.id(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -152,7 +152,7 @@ describe("AllianceExtensionExecution", () => {
|
||||
MessageType.RENEW_ALLIANCE,
|
||||
player2.id(),
|
||||
undefined,
|
||||
{ name: player1.displayName() },
|
||||
{ otherPlayerID: player1.id() },
|
||||
);
|
||||
expect(displayMessageSpy).toHaveBeenCalledTimes(1);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user