Compare commits

..

8 Commits

Author SHA1 Message Date
hacker
ef0c9533a4 Updated version
Some checks failed
Continuous Integration / Linux (.NET 6.0) (push) Has been cancelled
Continuous Integration / Linux (mono) (push) Has been cancelled
Continuous Integration / Windows (.NET 6.0) (push) Has been cancelled
2025-11-02 02:58:11 +00:00
hacker
3aa84277a3 Added Dockerfile 2025-11-02 02:57:32 +00:00
hacker
f9bca71b15 Log chat messages on the server 2025-11-02 02:57:32 +00:00
Pavel Penev
0bbe6e58f6 Added a new helper method - a temporary fix
(cherry picked from commit d83e579dfe)
2025-11-02 02:57:04 +00:00
Gustas
ee4403f923 Add vote kick
(cherry picked from commit 144e716cdf)
2025-11-02 02:57:04 +00:00
Gustas
aacf0e2b8d Add backup ExplicitSequenceFilenames to update rules
(cherry picked from commit 29eaab59be)
2025-11-02 02:55:35 +00:00
penev92
499a40e32d Bumped Eluant NuGet version
The new version fixes the windows 32-bit build not working.
2025-11-02 02:55:04 +00:00
dnqbob
68fd987856 Autocarryall put down unit if destination is cancelled when picking up 2025-11-02 02:54:39 +00:00
20 changed files with 220 additions and 136 deletions

View File

@@ -637,6 +637,11 @@ namespace OpenRA
{ {
return new LineSplitEnumerator(str.AsSpan(), separator); return new LineSplitEnumerator(str.AsSpan(), separator);
} }
public static bool TryParseInt32Invariant(string s, out int i)
{
return int.TryParse(s, NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out i);
}
} }
public ref struct LineSplitEnumerator public ref struct LineSplitEnumerator

View File

@@ -20,24 +20,6 @@ namespace OpenRA.Network
{ {
public const int ChatMessageMaxLength = 2500; public const int ChatMessageMaxLength = 2500;
[FluentReference("player")]
const string Joined = "notification-joined";
[FluentReference("player")]
const string Left = "notification-lobby-disconnected";
[FluentReference]
const string GameStarted = "notification-game-has-started";
[FluentReference]
const string GameSaved = "notification-game-saved";
[FluentReference("player")]
const string GamePaused = "notification-game-paused";
[FluentReference("player")]
const string GameUnpaused = "notification-game-unpaused";
public static int? KickVoteTarget { get; internal set; } public static int? KickVoteTarget { get; internal set; }
static Player FindPlayerByClient(this World world, Session.Client c) static Player FindPlayerByClient(this World world, Session.Client c)
@@ -78,8 +60,16 @@ namespace OpenRA.Network
} }
case "DisableChatEntry": case "DisableChatEntry":
{ {
if (OrderNotFromServerOrWorldIsReplay(clientId, world)) if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
// Server may send MaxValue to indicate that it is disabled until further notice
if (order.ExtraData == uint.MaxValue)
TextNotificationsManager.ChatDisabledUntil = uint.MaxValue;
else
TextNotificationsManager.ChatDisabledUntil = Game.RunTime + order.ExtraData;
break; break;
// Server may send MaxValue to indicate that it is disabled until further notice // Server may send MaxValue to indicate that it is disabled until further notice
@@ -111,6 +101,26 @@ namespace OpenRA.Network
break; break;
} }
case "StartKickVote":
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
KickVoteTarget = (int)order.ExtraData;
break;
}
case "EndKickVote":
{
if (OrderNotFromServerOrWorldIsReplay(clientId, world))
break;
if (KickVoteTarget == (int)order.ExtraData)
KickVoteTarget = null;
break;
}
case "Chat": case "Chat":
{ {
var client = orderManager.LobbyInfo.ClientWithIndex(clientId); var client = orderManager.LobbyInfo.ClientWithIndex(clientId);

View File

@@ -10,7 +10,7 @@
<PackageReference Include="System.Collections.Immutable" Version="6.0.0" /> <PackageReference Include="System.Collections.Immutable" Version="6.0.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Linguini.Bundle" Version="0.8.1" /> <PackageReference Include="Linguini.Bundle" Version="0.5.0" />
<PackageReference Include="OpenRA-Eluant" Version="1.0.22" /> <PackageReference Include="OpenRA-Eluant" Version="1.0.22" />
<PackageReference Include="Mono.NAT" Version="3.0.4" /> <PackageReference Include="Mono.NAT" Version="3.0.4" />
<PackageReference Include="SharpZipLib" Version="1.4.2" /> <PackageReference Include="SharpZipLib" Version="1.4.2" />

View File

@@ -319,7 +319,7 @@ namespace OpenRA.Server
MapStatusCache = new MapStatusCache(modData, MapStatusChanged, type == ServerType.Dedicated && settings.EnableLintChecks); MapStatusCache = new MapStatusCache(modData, MapStatusChanged, type == ServerType.Dedicated && settings.EnableLintChecks);
playerMessageTracker = new PlayerMessageTracker(this, DispatchOrdersToClient, SendFluentMessageTo); playerMessageTracker = new PlayerMessageTracker(this, DispatchOrdersToClient, SendLocalizedMessageTo);
VoteKickTracker = new VoteKickTracker(this); VoteKickTracker = new VoteKickTracker(this);
LobbyInfo = new Session LobbyInfo = new Session

View File

@@ -17,22 +17,22 @@ namespace OpenRA.Server
{ {
public sealed class VoteKickTracker public sealed class VoteKickTracker
{ {
[FluentReference("kickee")] [TranslationReference("kickee")]
const string InsufficientVotes = "notification-insufficient-votes-to-kick"; const string InsufficientVotes = "notification-insufficient-votes-to-kick";
[FluentReference] [TranslationReference]
const string AlreadyVoted = "notification-kick-already-voted"; const string AlreadyVoted = "notification-kick-already-voted";
[FluentReference("kicker", "kickee")] [TranslationReference("kicker", "kickee")]
const string VoteKickStarted = "notification-vote-kick-started"; const string VoteKickStarted = "notification-vote-kick-started";
[FluentReference] [TranslationReference]
const string UnableToStartAVote = "notification-unable-to-start-a-vote"; const string UnableToStartAVote = "notification-unable-to-start-a-vote";
[FluentReference("kickee", "percentage")] [TranslationReference("kickee", "percentage")]
const string VoteKickProgress = "notification-vote-kick-in-progress"; const string VoteKickProgress = "notification-vote-kick-in-progress";
[FluentReference("kickee")] [TranslationReference("kickee")]
const string VoteKickEnded = "notification-vote-kick-ended"; const string VoteKickEnded = "notification-vote-kick-ended";
readonly Dictionary<int, bool> voteTracker = new(); readonly Dictionary<int, bool> voteTracker = new();
@@ -76,7 +76,7 @@ namespace OpenRA.Server
|| (voteInProgress && this.kickee.Client != kickee) // Disallow starting new votes when one is already ongoing. || (voteInProgress && this.kickee.Client != kickee) // Disallow starting new votes when one is already ongoing.
|| !ClientHasPower(kicker)) || !ClientHasPower(kicker))
{ {
server.SendFluentMessageTo(conn, UnableToStartAVote); server.SendLocalizedMessageTo(conn, UnableToStartAVote);
return false; return false;
} }
@@ -107,7 +107,7 @@ namespace OpenRA.Server
if (!kickee.IsObserver && !server.HasClientWonOrLost(kickee)) if (!kickee.IsObserver && !server.HasClientWonOrLost(kickee))
{ {
// Vote kick cannot be the sole deciding factor for a game. // Vote kick cannot be the sole deciding factor for a game.
server.SendFluentMessageTo(conn, InsufficientVotes, new object[] { "kickee", kickee.Name }); server.SendLocalizedMessageTo(conn, InsufficientVotes, Translation.Arguments("kickee", kickee.Name));
EndKickVote(); EndKickVote();
return false; return false;
} }
@@ -126,7 +126,7 @@ namespace OpenRA.Server
{ {
if (time + server.Settings.VoteKickerCooldown > kickeeConn.ConnectionTimer.ElapsedMilliseconds) if (time + server.Settings.VoteKickerCooldown > kickeeConn.ConnectionTimer.ElapsedMilliseconds)
{ {
server.SendFluentMessageTo(conn, UnableToStartAVote); server.SendLocalizedMessageTo(conn, UnableToStartAVote);
return false; return false;
} }
else else
@@ -135,7 +135,7 @@ namespace OpenRA.Server
Log.Write("server", $"Vote kick started on {kickeeID}."); Log.Write("server", $"Vote kick started on {kickeeID}.");
voteKickTimer = Stopwatch.StartNew(); voteKickTimer = Stopwatch.StartNew();
server.SendFluentMessage(VoteKickStarted, "kicker", kicker.Name, "kickee", kickee.Name); server.SendLocalizedMessage(VoteKickStarted, Translation.Arguments("kicker", kicker.Name, "kickee", kickee.Name));
server.DispatchServerOrdersToClients(new Order("StartKickVote", null, false) { ExtraData = (uint)kickeeID }.Serialize()); server.DispatchServerOrdersToClients(new Order("StartKickVote", null, false) { ExtraData = (uint)kickeeID }.Serialize());
this.kickee = (kickee, kickeeConn); this.kickee = (kickee, kickeeConn);
voteKickerStarter = (kicker, conn); voteKickerStarter = (kicker, conn);
@@ -145,7 +145,7 @@ namespace OpenRA.Server
voteTracker[conn.PlayerIndex] = vote; voteTracker[conn.PlayerIndex] = vote;
else else
{ {
server.SendFluentMessageTo(conn, AlreadyVoted); server.SendLocalizedMessageTo(conn, AlreadyVoted, null);
return false; return false;
} }
@@ -168,9 +168,9 @@ namespace OpenRA.Server
} }
var votesNeeded = eligiblePlayers / 2 + 1; var votesNeeded = eligiblePlayers / 2 + 1;
server.SendFluentMessage(VoteKickProgress, server.SendLocalizedMessage(VoteKickProgress, Translation.Arguments(
"kickee", kickee.Name, "kickee", kickee.Name,
"percentage", votesFor * 100 / eligiblePlayers); "percentage", votesFor * 100 / eligiblePlayers));
// If a player or players during a vote lose or disconnect, it is possible that a downvote will // If a player or players during a vote lose or disconnect, it is possible that a downvote will
// kick a client. Guard against that situation. // kick a client. Guard against that situation.
@@ -210,7 +210,7 @@ namespace OpenRA.Server
return; return;
if (sendMessage) if (sendMessage)
server.SendFluentMessage(VoteKickEnded, "kickee", kickee.Client.Name); server.SendLocalizedMessage(VoteKickEnded, Translation.Arguments("kickee", kickee.Client.Name));
server.DispatchServerOrdersToClients(new Order("EndKickVote", null, false) { ExtraData = (uint)kickee.Client.Index }.Serialize()); server.DispatchServerOrdersToClients(new Order("EndKickVote", null, false) { ExtraData = (uint)kickee.Client.Index }.Serialize());

View File

@@ -57,10 +57,10 @@ namespace OpenRA.Mods.Common.Server
[FluentReference] [FluentReference]
const string NoKickGameStarted = "notification-no-kick-game-started"; const string NoKickGameStarted = "notification-no-kick-game-started";
[FluentReference("admin", "player")] [TranslationReference("admin", "player")]
const string AdminKicked = "notification-admin-kicked"; const string AdminKicked = "notification-admin-kicked";
[FluentReference("player")] [TranslationReference("player")]
const string Kicked = "notification-kicked"; const string Kicked = "notification-kicked";
[FluentReference("admin", "player")] [FluentReference("admin", "player")]
@@ -159,37 +159,35 @@ namespace OpenRA.Mods.Common.Server
[FluentReference] [FluentReference]
const string YouWereKicked = "notification-you-were-kicked"; const string YouWereKicked = "notification-you-were-kicked";
[FluentReference] [TranslationReference]
const string VoteKickDisabled = "notification-vote-kick-disabled"; const string VoteKickDisabled = "notification-vote-kick-disabled";
readonly IDictionary<string, Func<S, Connection, Session.Client, string, bool>> commandHandlers = readonly IDictionary<string, Func<S, Connection, Session.Client, string, bool>> commandHandlers = new Dictionary<string, Func<S, Connection, Session.Client, string, bool>>
new Dictionary<string, Func<S, Connection, Session.Client, string, bool>> {
{ { "state", State },
{ "state", State }, { "startgame", StartGame },
{ "startgame", StartGame }, { "slot", Slot },
{ "slot", Slot }, { "allow_spectators", AllowSpectators },
{ "allow_spectators", AllowSpectators }, { "spectate", Specate },
{ "spectate", Specate }, { "slot_close", SlotClose },
{ "slot_close", SlotClose }, { "slot_open", SlotOpen },
{ "slot_open", SlotOpen }, { "slot_bot", SlotBot },
{ "slot_bot", SlotBot }, { "map", Map },
{ "map", Map }, { "option", Option },
{ "option", Option }, { "assignteams", AssignTeams },
{ "reset_options", ResetOptions }, { "kick", Kick },
{ "assignteams", AssignTeams }, { "vote_kick", VoteKick },
{ "kick", Kick }, { "make_admin", MakeAdmin },
{ "vote_kick", VoteKick }, { "make_spectator", MakeSpectator },
{ "make_admin", MakeAdmin }, { "name", Name },
{ "make_spectator", MakeSpectator }, { "faction", Faction },
{ "name", Name }, { "team", Team },
{ "faction", Faction }, { "handicap", Handicap },
{ "team", Team }, { "spawn", Spawn },
{ "handicap", Handicap }, { "clear_spawn", ClearPlayerSpawn },
{ "spawn", Spawn }, { "color", PlayerColor },
{ "clear_spawn", ClearPlayerSpawn }, { "sync_lobby", SyncLobby }
{ "color", PlayerColor }, };
{ "sync_lobby", SyncLobby }
};
static bool ValidateSlotCommand(S server, Connection conn, Session.Client client, string arg, bool requiresHost) static bool ValidateSlotCommand(S server, Connection conn, Session.Client client, string arg, bool requiresHost)
{ {
@@ -873,7 +871,7 @@ namespace OpenRA.Mods.Common.Server
} }
Log.Write("server", $"Kicking client {kickClientID}."); Log.Write("server", $"Kicking client {kickClientID}.");
server.SendFluentMessage(AdminKicked, "admin", client.Name, "player", kickClient.Name); server.SendLocalizedMessage(AdminKicked, Translation.Arguments("admin", client.Name, "player", kickClient.Name));
server.SendOrderTo(kickConn, "ServerError", YouWereKicked); server.SendOrderTo(kickConn, "ServerError", YouWereKicked);
server.DropClient(kickConn); server.DropClient(kickConn);
@@ -898,13 +896,13 @@ namespace OpenRA.Mods.Common.Server
var split = s.Split(' '); var split = s.Split(' ');
if (split.Length != 2) if (split.Length != 2)
{ {
server.SendFluentMessageTo(conn, MalformedCommand, new object[] { "command", "vote_kick" }); server.SendLocalizedMessageTo(conn, MalformedCommand, Translation.Arguments("command", "vote_kick"));
return true; return true;
} }
if (!server.Settings.EnableVoteKick) if (!server.Settings.EnableVoteKick)
{ {
server.SendFluentMessageTo(conn, VoteKickDisabled); server.SendLocalizedMessageTo(conn, VoteKickDisabled);
return true; return true;
} }
@@ -913,27 +911,27 @@ namespace OpenRA.Mods.Common.Server
if (kickConn == null) if (kickConn == null)
{ {
server.SendFluentMessageTo(conn, KickNone); server.SendLocalizedMessageTo(conn, KickNone);
return true; return true;
} }
var kickClient = server.GetClient(kickConn); var kickClient = server.GetClient(kickConn);
if (client == kickClient) if (client == kickClient)
{ {
server.SendFluentMessageTo(conn, NoKickSelf); server.SendLocalizedMessageTo(conn, NoKickSelf);
return true; return true;
} }
if (!bool.TryParse(split[1], out var vote)) if (!bool.TryParse(split[1], out var vote))
{ {
server.SendFluentMessageTo(conn, MalformedCommand, new object[] { "command", "vote_kick" }); server.SendLocalizedMessageTo(conn, MalformedCommand, Translation.Arguments("command", "vote_kick"));
return true; return true;
} }
if (server.VoteKickTracker.VoteKick(conn, client, kickConn, kickClient, kickClientID, vote)) if (server.VoteKickTracker.VoteKick(conn, client, kickConn, kickClient, kickClientID, vote))
{ {
Log.Write("server", $"Kicking client {kickClientID}."); Log.Write("server", $"Kicking client {kickClientID}.");
server.SendFluentMessage(Kicked, "player", kickClient.Name); server.SendLocalizedMessage(Kicked, Translation.Arguments("player", kickClient.Name));
server.SendOrderTo(kickConn, "ServerError", YouWereKicked); server.SendOrderTo(kickConn, "ServerError", YouWereKicked);
server.DropClient(kickConn); server.DropClient(kickConn);

View File

@@ -192,8 +192,7 @@ namespace OpenRA.Mods.Common.Traits
return true; return true;
var dropRange = carryall.Info.DropRange; var dropRange = carryall.Info.DropRange;
QueueChild(new DeliverUnit(self, Target.FromCell(self.World, carryable.Destination ?? self.Location), dropRange, carryall.Info.TargetLineColor)); self.QueueActivity(true, new DeliverUnit(self, Target.FromCell(self.World, carryable.Destination ?? self.Location), dropRange, carryall.Info.TargetLineColor));
return true; return true;
} }
} }

View File

@@ -103,31 +103,31 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
{ {
case "cnc": case "cnc":
fromBackup = true; fromBackup = true;
tilesetExtensionsNode = new List<MiniYamlNodeBuilder>() tilesetExtensionsNode = new List<MiniYamlNode>()
{ {
new("TEMPERAT", ".tem"), new MiniYamlNode("TEMPERAT", ".tem"),
new("SNOW", ".sno"), new MiniYamlNode("SNOW", ".sno"),
new("INTERIOR", ".int"), new MiniYamlNode("INTERIOR", ".int"),
new("DESERT", ".des"), new MiniYamlNode("DESERT", ".des"),
new("JUNGLE", ".jun"), new MiniYamlNode("JUNGLE", ".jun"),
}; };
break; break;
case "ra": case "ra":
fromBackup = true; fromBackup = true;
tilesetExtensionsNode = new List<MiniYamlNodeBuilder>() tilesetExtensionsNode = new List<MiniYamlNode>()
{ {
new("TEMPERAT", ".tem"), new MiniYamlNode("TEMPERAT", ".tem"),
new("SNOW", ".sno"), new MiniYamlNode("SNOW", ".sno"),
new("INTERIOR", ".int"), new MiniYamlNode("INTERIOR", ".int"),
new("DESERT", ".des"), new MiniYamlNode("DESERT", ".des"),
}; };
break; break;
case "ts": case "ts":
fromBackup = true; fromBackup = true;
tilesetExtensionsNode = new List<MiniYamlNodeBuilder>() tilesetExtensionsNode = new List<MiniYamlNode>()
{ {
new("TEMPERATE", ".tem"), new MiniYamlNode("TEMPERATE", ".tem"),
new("SNOW", ".sno"), new MiniYamlNode("SNOW", ".sno"),
}; };
break; break;
} }
@@ -148,10 +148,10 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules
if (tilesetCodesNode == null && modData.Manifest.Id == "ts") if (tilesetCodesNode == null && modData.Manifest.Id == "ts")
{ {
fromBackup = true; fromBackup = true;
tilesetCodesNode = new List<MiniYamlNodeBuilder>() tilesetCodesNode = new List<MiniYamlNode>()
{ {
new("TEMPERATE", "t"), new MiniYamlNode("TEMPERATE", "t"),
new("SNOW", "a"), new MiniYamlNode("SNOW", "a"),
}; };
} }

View File

@@ -50,10 +50,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
[FluentReference] [FluentReference]
const string Gone = "label-client-state-disconnected"; const string Gone = "label-client-state-disconnected";
[FluentReference] [TranslationReference]
const string KickTooltip = "button-kick-player"; const string KickTooltip = "button-kick-player";
[FluentReference("player")] [TranslationReference("player")]
const string KickTitle = "dialog-kick.title"; const string KickTitle = "dialog-kick.title";
[FluentReference] [FluentReference]
@@ -62,28 +62,28 @@ namespace OpenRA.Mods.Common.Widgets.Logic
[FluentReference] [FluentReference]
const string KickAccept = "dialog-kick.confirm"; const string KickAccept = "dialog-kick.confirm";
[FluentReference] [TranslationReference]
const string KickVoteTooltip = "button-vote-kick-player"; const string KickVoteTooltip = "button-vote-kick-player";
[FluentReference("player")] [TranslationReference("player")]
const string VoteKickTitle = "dialog-vote-kick.title"; const string VoteKickTitle = "dialog-vote-kick.title";
[FluentReference] [TranslationReference]
const string VoteKickPrompt = "dialog-vote-kick.prompt"; const string VoteKickPrompt = "dialog-vote-kick.prompt";
[FluentReference("bots")] [TranslationReference("bots")]
const string VoteKickPromptBreakBots = "dialog-vote-kick.prompt-break-bots"; const string VoteKickPromptBreakBots = "dialog-vote-kick.prompt-break-bots";
[FluentReference] [TranslationReference]
const string VoteKickVoteStart = "dialog-vote-kick.vote-start"; const string VoteKickVoteStart = "dialog-vote-kick.vote-start";
[FluentReference] [TranslationReference]
const string VoteKickVoteFor = "dialog-vote-kick.vote-for"; const string VoteKickVoteFor = "dialog-vote-kick.vote-for";
[FluentReference] [TranslationReference]
const string VoteKickVoteAgainst = "dialog-vote-kick.vote-against"; const string VoteKickVoteAgainst = "dialog-vote-kick.vote-against";
[FluentReference] [TranslationReference]
const string VoteKickVoteCancel = "dialog-vote-kick.vote-cancel"; const string VoteKickVoteCancel = "dialog-vote-kick.vote-cancel";
[ObjectCreator.UseCtor] [ObjectCreator.UseCtor]
@@ -133,10 +133,10 @@ namespace OpenRA.Mods.Common.Widgets.Logic
var teamTemplate = playerPanel.Get<ScrollItemWidget>("TEAM_TEMPLATE"); var teamTemplate = playerPanel.Get<ScrollItemWidget>("TEAM_TEMPLATE");
var playerTemplate = playerPanel.Get("PLAYER_TEMPLATE"); var playerTemplate = playerPanel.Get("PLAYER_TEMPLATE");
var spectatorTemplate = playerPanel.Get("SPECTATOR_TEMPLATE"); var spectatorTemplate = playerPanel.Get("SPECTATOR_TEMPLATE");
var unmuteTooltip = FluentProvider.GetMessage(Unmute); var unmuteTooltip = TranslationProvider.GetString(Unmute);
var muteTooltip = FluentProvider.GetMessage(Mute); var muteTooltip = TranslationProvider.GetString(Mute);
var kickTooltip = FluentProvider.GetMessage(KickTooltip); var kickTooltip = TranslationProvider.GetString(KickTooltip);
var voteKickTooltip = FluentProvider.GetMessage(KickVoteTooltip); var voteKickTooltip = TranslationProvider.GetString(KickVoteTooltip);
playerPanel.RemoveChildren(); playerPanel.RemoveChildren();
var teams = world.Players.Where(p => !p.NonCombatant && p.Playable) var teams = world.Players.Where(p => !p.NonCombatant && p.Playable)
@@ -159,14 +159,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
{ {
ConfirmationDialogs.ButtonPrompt(modData, ConfirmationDialogs.ButtonPrompt(modData,
title: VoteKickTitle, title: VoteKickTitle,
titleArguments: Translation.Arguments("player", client.Name),
text: botsCount > 0 ? VoteKickPromptBreakBots : VoteKickPrompt, text: botsCount > 0 ? VoteKickPromptBreakBots : VoteKickPrompt,
titleArguments: new object[] { "player", client.Name }, textArguments: Translation.Arguments("bots", botsCount),
textArguments: new object[] { "bots", botsCount },
onConfirm: () => onConfirm: () =>
{ {
orderManager.IssueOrder(Order.Command($"vote_kick {client.Index} {true}")); orderManager.IssueOrder(Order.Command($"vote_kick {client.Index} {true}"));
hideMenu(false); hideMenu(false);
closeMenu();
}, },
confirmText: VoteKickVoteStart, confirmText: VoteKickVoteStart,
onCancel: () => hideMenu(false)); onCancel: () => hideMenu(false));
@@ -175,33 +174,31 @@ namespace OpenRA.Mods.Common.Widgets.Logic
ConfirmationDialogs.ButtonPrompt(modData, ConfirmationDialogs.ButtonPrompt(modData,
title: VoteKickTitle, title: VoteKickTitle,
titleArguments: Translation.Arguments("player", client.Name),
text: botsCount > 0 ? VoteKickPromptBreakBots : VoteKickPrompt, text: botsCount > 0 ? VoteKickPromptBreakBots : VoteKickPrompt,
titleArguments: new object[] { "player", client.Name }, textArguments: Translation.Arguments("bots", botsCount),
textArguments: new object[] { "bots", botsCount },
onConfirm: () => onConfirm: () =>
{ {
orderManager.IssueOrder(Order.Command($"vote_kick {client.Index} {true}")); orderManager.IssueOrder(Order.Command($"vote_kick {client.Index} {true}"));
hideMenu(false); hideMenu(false);
closeMenu();
}, },
confirmText: VoteKickVoteFor, confirmText: VoteKickVoteFor,
onCancel: () => hideMenu(false),
cancelText: VoteKickVoteCancel,
onOther: () => onOther: () =>
{ {
Ui.CloseWindow(); Ui.CloseWindow();
orderManager.IssueOrder(Order.Command($"vote_kick {client.Index} {false}")); orderManager.IssueOrder(Order.Command($"vote_kick {client.Index} {false}"));
hideMenu(false); hideMenu(false);
closeMenu();
}, },
otherText: VoteKickVoteAgainst); otherText: VoteKickVoteAgainst,
onCancel: () => hideMenu(false),
cancelText: VoteKickVoteCancel);
} }
else else
{ {
ConfirmationDialogs.ButtonPrompt(modData, ConfirmationDialogs.ButtonPrompt(modData,
title: KickTitle, title: KickTitle,
titleArguments: Translation.Arguments("player", client.Name),
text: KickPrompt, text: KickPrompt,
titleArguments: new object[] { "player", client.Name },
onConfirm: () => onConfirm: () =>
{ {
orderManager.IssueOrder(Order.Command($"kick {client.Index} {false}")); orderManager.IssueOrder(Order.Command($"kick {client.Index} {false}"));

View File

@@ -1 +1 @@
{DEV_VERSION} release-20231010

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: All mods Title: All mods
Version: release-20250330 Version: release-20231010
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: mod-title
Version: release-20250330 Version: {DEV_VERSION}
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: Tiberian Dawn
Version: release-20250330 Version: release-20231010
Website: https://www.openra.net Website: https://www.openra.net
WebIcon32: https://www.openra.net/images/icons/cnc_32x32.png WebIcon32: https://www.openra.net/images/icons/cnc_32x32.png
WindowTitle: mod-windowtitle WindowTitle: mod-windowtitle
@@ -40,7 +40,7 @@ FileSystem: ContentInstallerFileSystem
MapFolders: MapFolders:
cnc|maps: System cnc|maps: System
~^SupportDir|maps/cnc/release-20250330: User ~^SupportDir|maps/cnc/release-20231010: User
Rules: Rules:
cnc|rules/misc.yaml cnc|rules/misc.yaml

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: mod-title
Version: release-20250330 Version: {DEV_VERSION}
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: Dune 2000
Version: release-20250330 Version: release-20231010
Website: https://www.openra.net Website: https://www.openra.net
WebIcon32: https://www.openra.net/images/icons/d2k_32x32.png WebIcon32: https://www.openra.net/images/icons/d2k_32x32.png
WindowTitle: mod-windowtitle WindowTitle: mod-windowtitle
@@ -37,7 +37,7 @@ FileSystem: ContentInstallerFileSystem
MapFolders: MapFolders:
d2k|maps: System d2k|maps: System
~^SupportDir|maps/d2k/release-20250330: User ~^SupportDir|maps/d2k/release-20231010: User
Rules: Rules:
d2k|rules/misc.yaml d2k|rules/misc.yaml

75
mods/modcontent/mod.yaml Normal file
View File

@@ -0,0 +1,75 @@
Metadata:
Title: Mod Content Manager
Version: release-20231010
Hidden: true
Packages:
^EngineDir
^EngineDir|mods/modcontent: modcontent
^EngineDir|mods/common: common
Rules:
modcontent|rules.yaml
Cursors:
modcontent|cursors.yaml
Chrome:
modcontent|chrome.yaml
Assemblies:
^BinDir|OpenRA.Mods.Common.dll
ChromeLayout:
modcontent|content.yaml
Notifications:
modcontent|notifications.yaml
LoadScreen: ModContentLoadScreen
Image: ^EngineDir|mods/modcontent/chrome.png
Image2x: ^EngineDir|mods/modcontent/chrome-2x.png
Image3x: ^EngineDir|mods/modcontent/chrome-3x.png
ChromeMetrics:
common|metrics.yaml
modcontent|metrics.yaml
Translations:
common|languages/en.ftl
Fonts:
Tiny:
Font: common|FreeSans.ttf
Size: 10
Ascender: 8
TinyBold:
Font: common|FreeSansBold.ttf
Size: 10
Ascender: 8
Regular:
Font: common|FreeSans.ttf
Size: 14
Ascender: 11
Bold:
Font: common|FreeSansBold.ttf
Size: 14
Ascender: 11
MediumBold:
Font: common|FreeSansBold.ttf
Size: 18
Ascender: 14
BigBold:
Font: common|FreeSansBold.ttf
Size: 24
Ascender: 18
SoundFormats:
SpriteFormats: PngSheet
TerrainFormat: DefaultTerrain
SpriteSequenceFormat: DefaultSpriteSequence
ModelSequenceFormat: PlaceholderModelSequence

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: mod-title
Version: release-20250330 Version: {DEV_VERSION}
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: Red Alert
Version: release-20250330 Version: release-20231010
Website: https://www.openra.net Website: https://www.openra.net
WebIcon32: https://www.openra.net/images/icons/ra_32x32.png WebIcon32: https://www.openra.net/images/icons/ra_32x32.png
WindowTitle: mod-windowtitle WindowTitle: mod-windowtitle
@@ -68,7 +68,7 @@ FileSystem: ContentInstallerFileSystem
MapFolders: MapFolders:
ra|maps: System ra|maps: System
~^SupportDir|maps/ra/release-20250330: User ~^SupportDir|maps/ra/release-20231010: User
Rules: Rules:
ra|rules/misc.yaml ra|rules/misc.yaml

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: mod-title
Version: release-20250330 Version: {DEV_VERSION}
Hidden: true Hidden: true
FileSystem: DefaultFileSystem FileSystem: DefaultFileSystem

View File

@@ -1,6 +1,6 @@
Metadata: Metadata:
Title: mod-title Title: Tiberian Sun
Version: release-20250330 Version: release-20231010
Website: https://www.openra.net Website: https://www.openra.net
WebIcon32: https://www.openra.net/images/icons/ts_32x32.png WebIcon32: https://www.openra.net/images/icons/ts_32x32.png
WindowTitle: mod-windowtitle WindowTitle: mod-windowtitle
@@ -44,7 +44,7 @@ FileSystem: ContentInstallerFileSystem
MapFolders: MapFolders:
ts|maps: System ts|maps: System
~^SupportDir|maps/ts/release-20250330: User ~^SupportDir|maps/ts/release-20231010: User
Rules: Rules:
ts|rules/ai.yaml ts|rules/ai.yaml