diff --git a/RLBotCS/ManagerTools/MatchStarter.cs b/RLBotCS/ManagerTools/MatchStarter.cs index e8934bd..2b963a9 100644 --- a/RLBotCS/ManagerTools/MatchStarter.cs +++ b/RLBotCS/ManagerTools/MatchStarter.cs @@ -428,12 +428,7 @@ private bool SpawnCars(MatchConfigurationT matchConfig, bool force = false) { case PlayerClass.CustomBot: bridge.TryWrite( - new SpawnBot( - playerConfig, - BotSkill.Custom, - (uint)(i - indexOffset), - true - ) + new SpawnBot(playerConfig, BotSkill.Custom, (uint)(i - indexOffset)) ); break; @@ -451,7 +446,7 @@ private bool SpawnCars(MatchConfigurationT matchConfig, bool force = false) }; bridge.TryWrite( - new SpawnBot(playerConfig, skillEnum, (uint)(i - indexOffset), false) + new SpawnBot(playerConfig, skillEnum, (uint)(i - indexOffset)) ); break; diff --git a/RLBotCS/Server/BridgeMessage/SpawnBot.cs b/RLBotCS/Server/BridgeMessage/SpawnBot.cs index a4d30b5..38e429e 100644 --- a/RLBotCS/Server/BridgeMessage/SpawnBot.cs +++ b/RLBotCS/Server/BridgeMessage/SpawnBot.cs @@ -6,12 +6,8 @@ namespace RLBotCS.Server.BridgeMessage; -record SpawnBot( - PlayerConfigurationT Config, - BotSkill Skill, - uint DesiredIndex, - bool IsCustomBot -) : IBridgeMessage +record SpawnBot(PlayerConfigurationT Config, BotSkill Skill, uint DesiredIndex) + : IBridgeMessage { public void HandleMessage(BridgeContext context) { @@ -41,7 +37,7 @@ public void HandleMessage(BridgeContext context) CommandId = commandId, SpawnId = Config.SpawnId, DesiredPlayerIndex = DesiredIndex, - IsCustomBot = IsCustomBot, + IsCustomBot = Skill == BotSkill.Custom, IsBot = true, } ); diff --git a/RLBotCS/Server/BridgeMessage/StateSetLoadout.cs b/RLBotCS/Server/BridgeMessage/StateSetLoadout.cs new file mode 100644 index 0000000..40395a9 --- /dev/null +++ b/RLBotCS/Server/BridgeMessage/StateSetLoadout.cs @@ -0,0 +1,58 @@ +using Bridge.Models.Command; +using Bridge.Models.Message; +using Bridge.State; +using Microsoft.Extensions.Logging; +using rlbot.flat; +using RLBotCS.Conversion; + +namespace RLBotCS.Server.BridgeMessage; + +record StateSetLoadout(PlayerLoadoutT Loadout, uint Index) : IBridgeMessage +{ + public void HandleMessage(BridgeContext context) + { + PlayerMetadata? meta = context + .GameState.PlayerMapping.GetKnownPlayers() + .FirstOrDefault(kp => Index == kp.PlayerIndex); + if (meta == null) + return; + + // todo: Psyonix bot support - + // requires additional work to figure out the proper BotSkill + if (!meta.IsCustomBot) + { + context.Logger.LogWarning( + "Player {0} is not controlled by RLBot, cannot set loadout.", + meta.PlayerIndex + ); + return; + } + + context.MatchCommandSender.AddDespawnCommand(meta.ActorId); + + Loadout.LoadoutPaint ??= new LoadoutPaintT(); + + var player = context.GameState.GameCars[meta.PlayerIndex]; + Loadout loadout = FlatToModel.ToLoadout(Loadout, player.Team); + + ushort commandId = context.MatchCommandSender.AddBotSpawnCommand( + player.Name, + (int)player.Team, + BotSkill.Custom, + loadout + ); + + context.GameState.PlayerMapping.AddPendingSpawn( + new SpawnTracker + { + CommandId = commandId, + SpawnId = meta.SpawnId, + DesiredPlayerIndex = meta.PlayerIndex, + IsCustomBot = true, + IsBot = true, + } + ); + + context.MatchCommandSender.Send(); + } +} diff --git a/RLBotCS/Server/FlatBuffersServer.cs b/RLBotCS/Server/FlatBuffersServer.cs index 9f601f0..2504d37 100644 --- a/RLBotCS/Server/FlatBuffersServer.cs +++ b/RLBotCS/Server/FlatBuffersServer.cs @@ -59,9 +59,9 @@ private void AddSession(TcpClient client) session.Cleanup(); } }); - sessionThread.Start(); _context.Sessions.Add(clientId, (sessionChannel.Writer, sessionThread, 0)); + sessionThread.Start(); } private async Task HandleIncomingMessages() diff --git a/RLBotCS/Server/FlatBuffersSession.cs b/RLBotCS/Server/FlatBuffersSession.cs index 6fe642e..3ddd266 100644 --- a/RLBotCS/Server/FlatBuffersSession.cs +++ b/RLBotCS/Server/FlatBuffersSession.cs @@ -108,7 +108,7 @@ private async Task ParseClientMessage(TypedPayload message) case DataType.ConnectionSettings when !_connectionEstablished: var readyMsg = ConnectionSettings.GetRootAsConnectionSettings(byteBuffer); - _agentId = readyMsg.AgentId; + _agentId = readyMsg.AgentId ?? ""; _wantsBallPredictions = readyMsg.WantsBallPredictions; _wantsComms = readyMsg.WantsComms; _closeBetweenMatches = readyMsg.CloseBetweenMatches; @@ -135,26 +135,37 @@ await _rlbotServer.WriteAsync( var setLoadout = SetLoadout.GetRootAsSetLoadout(byteBuffer).UnPack(); - // ensure the provided index is a bot we control, - // and map the index to the spawn id - PlayerIdPair? maybeIdPair = _playerIdPairs.FirstOrDefault(idPair => - idPair.Index == setLoadout.Index - ); - - if (maybeIdPair is { } pair) + if (_isReady) { - await _rlbotServer.WriteAsync( - new SpawnLoadout(setLoadout.Loadout, pair.SpawnId) + // state setting is enabled, + // allow setting the loadout of any bots post-init + await _bridge.WriteAsync( + new StateSetLoadout(setLoadout.Loadout, setLoadout.Index) ); } else { - var owned = string.Join(", ", _playerIdPairs.Select(p => p.Index)); - Logger.LogWarning( - $"Client sent loadout unowned player" - + $"(index(es) owned: {owned}," - + $"index got: {setLoadout.Index})" + // ensure the provided index is a bot we control, + // and map the index to the spawn id + PlayerIdPair? maybeIdPair = _playerIdPairs.FirstOrDefault(idPair => + idPair.Index == setLoadout.Index ); + + if (maybeIdPair is { } pair) + { + await _rlbotServer.WriteAsync( + new SpawnLoadout(setLoadout.Loadout, pair.SpawnId) + ); + } + else + { + var owned = string.Join(", ", _playerIdPairs.Select(p => p.Index)); + Logger.LogWarning( + $"Client tried to set loadout of player it does not own " + + $"(index(es) owned: {owned}," + + $" got: {setLoadout.Index})" + ); + } } break; @@ -201,16 +212,17 @@ await _rlbotServer.WriteAsync( // ensure the provided index is a bot we control if ( - !_playerIdPairs.Any(playerInfo => + !_stateSettingIsEnabled + && !_playerIdPairs.Any(playerInfo => playerInfo.Index == playerInputMsg.PlayerIndex ) ) { var owned = string.Join(", ", _playerIdPairs.Select(p => p.Index)); Logger.LogWarning( - $"Client sent player input unowned player" - + $"(index(es) owned: {owned}," - + $"index got: {playerInputMsg.PlayerIndex})" + $"Client tried to set loadout of player it does not own" + + $" (index(es) owned: {owned}," + + $" got: {playerInputMsg.PlayerIndex})" ); break; } diff --git a/RLBotCS/lib/Bridge.dll b/RLBotCS/lib/Bridge.dll index 2817557..e44442a 100644 Binary files a/RLBotCS/lib/Bridge.dll and b/RLBotCS/lib/Bridge.dll differ