diff --git a/RLBotCS/Main.cs b/RLBotCS/Main.cs
index f1e2f76..e06296e 100644
--- a/RLBotCS/Main.cs
+++ b/RLBotCS/Main.cs
@@ -10,7 +10,7 @@
if (args.Length > 0 && args[0] == "--version")
{
Console.WriteLine(
- "RLBotServer v5.beta.7.10\n"
+ "RLBotServer v5.0.0-rc.1\n"
+ $"Bridge {BridgeVersion.Version}\n"
+ "@ https://www.rlbot.org & https://github.com/RLBot/core"
);
diff --git a/RLBotCS/ManagerTools/ConfigValidator.cs b/RLBotCS/ManagerTools/ConfigValidator.cs
index ce198e8..e0f9a20 100644
--- a/RLBotCS/ManagerTools/ConfigValidator.cs
+++ b/RLBotCS/ManagerTools/ConfigValidator.cs
@@ -18,7 +18,7 @@ public static class ConfigValidator
/// If the config is invalid, the reasons are logged.
///
/// Whether the given match is valid and can be started without issues.
- public static bool Validate(MatchConfigurationT config)
+ public static bool Validate(MatchConfigurationT config, bool surpressWarnings = false)
{
bool valid = true;
PsyonixLoadouts.Reset();
@@ -48,8 +48,11 @@ public static bool Validate(MatchConfigurationT config)
config.PlayerConfigurations ??= new();
config.ScriptConfigurations ??= new();
- valid = ValidatePlayers(ctx, config.PlayerConfigurations) && valid;
- valid = ValidateScripts(ctx, config.ScriptConfigurations) && valid;
+ Dictionary agentIdTracker = new();
+ valid =
+ ValidatePlayers(ctx, config.PlayerConfigurations, agentIdTracker, surpressWarnings)
+ && valid;
+ valid = ValidateScripts(ctx, config.ScriptConfigurations, agentIdTracker) && valid;
Logger.LogDebug(valid ? "Match config is valid." : "Match config is invalid!");
return valid;
@@ -57,7 +60,9 @@ public static bool Validate(MatchConfigurationT config)
private static bool ValidatePlayers(
ConfigContextTracker ctx,
- List players
+ List players,
+ Dictionary agentIdTracker,
+ bool surpressWarnings
)
{
bool valid = true;
@@ -99,6 +104,46 @@ List players
bot.Loadout.LoadoutPaint ??= new();
player.PlayerId = $"{bot.AgentId}/{player.Team}/{i}".GetHashCode();
+
+ // Dont validate agent id for bots that will be manually started
+ if (!surpressWarnings && !string.IsNullOrEmpty(bot.RunCommand))
+ {
+ // Reduce user confusion around how agent ids should be used
+ // Same bot == same agent id, different bot == different agent id
+ // This is not a hard requirement, so we just log a warning
+ // We check for "same bot" by comparing RootDir and RunCommand
+ if (agentIdTracker.TryGetValue(bot.AgentId, out var existing))
+ {
+ if (
+ existing.rootDir != bot.RootDir
+ || existing.runCmd != bot.RunCommand
+ )
+ {
+ string errorStr;
+
+ if (existing.rootDir != bot.RootDir)
+ {
+ errorStr =
+ existing.runCmd != bot.RunCommand
+ ? "RootDirs and RunCommands"
+ : "RootDirs";
+ }
+ else
+ {
+ errorStr = "RunCommands";
+ }
+
+ Logger.LogWarning(
+ $"Potential agent ID conflict: \"{bot.AgentId}\" is used by multiple bots with different {errorStr}.\n"
+ + "Agent configs using the same ID may get used interchangeably. Agents that behave differently should have unique IDs."
+ );
+ }
+ }
+ else
+ {
+ agentIdTracker[bot.AgentId] = (bot.RootDir, bot.RunCommand);
+ }
+ }
break;
case PsyonixBotT bot:
string skill = bot.BotSkill switch
@@ -168,7 +213,8 @@ List players
private static bool ValidateScripts(
ConfigContextTracker ctx,
- List scripts
+ List scripts,
+ Dictionary agentIdTracker
)
{
bool valid = true;
@@ -192,6 +238,19 @@ List scripts
script.RunCommand ??= "";
script.RootDir ??= "";
script.ScriptId = $"{script.AgentId}/{Team.Scripts}/{i}".GetHashCode();
+
+ if (agentIdTracker.TryGetValue(script.AgentId, out var existing))
+ {
+ Logger.LogError(
+ $"{ctx.ToStringWithEnd(Fields.AgentAgentId)} \"{script.AgentId}\" is already in use. "
+ + "Each script must have a unique agent ID."
+ );
+ valid = false;
+ }
+ else
+ {
+ agentIdTracker[script.AgentId] = (script.RootDir, script.RunCommand);
+ }
}
return valid;
diff --git a/RLBotCS/Server/ServerMessage/StartMatch.cs b/RLBotCS/Server/ServerMessage/StartMatch.cs
index 361cf9d..94c068f 100644
--- a/RLBotCS/Server/ServerMessage/StartMatch.cs
+++ b/RLBotCS/Server/ServerMessage/StartMatch.cs
@@ -9,7 +9,7 @@ readonly struct StartMatch(MatchConfigurationT MatchConfig) : IServerMessage
{
public ServerAction Execute(ServerContext context)
{
- Debug.Assert(ConfigValidator.Validate(MatchConfig));
+ Debug.Assert(ConfigValidator.Validate(MatchConfig, true));
context.Bridge.TryWrite(new ClearRenders());