From 5ac9d2c2f1e50f4ac64a9a661fd78f278b78dfb2 Mon Sep 17 00:00:00 2001 From: matjaeck <37185497+matjaeck@users.noreply.github.com> Date: Sat, 2 Nov 2019 10:39:00 +0100 Subject: [PATCH] Fix botmodules querying the Player actor before it is assigned. --- .../Traits/BotModules/BaseBuilderBotModule.cs | 15 +++++++++++---- .../Traits/BotModules/HarvesterBotModule.cs | 10 +++++++++- .../Traits/BotModules/McvManagerBotModule.cs | 13 ++++++++++--- .../Traits/BotModules/SquadManagerBotModule.cs | 13 ++++++++++--- .../Traits/BotModules/SupportPowerBotModule.cs | 10 +++++++++- .../Traits/BotModules/UnitBuilderBotModule.cs | 8 ++++++-- 6 files changed, 55 insertions(+), 14 deletions(-) diff --git a/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs index 7af6b28bb4..cacc6336a1 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/BaseBuilderBotModule.cs @@ -160,12 +160,19 @@ namespace OpenRA.Mods.Common.Traits player = self.Owner; } + protected override void Created(Actor self) + { + // Special case handling is required for the Player actor. + // Created is called before Player.PlayerActor is assigned, + // so we must query player traits from self, which refers + // for bot modules always to the Player actor. + playerPower = self.TraitOrDefault(); + playerResources = self.Trait(); + positionsUpdatedModules = self.TraitsImplementing().ToArray(); + } + protected override void TraitEnabled(Actor self) { - playerPower = player.PlayerActor.TraitOrDefault(); - playerResources = player.PlayerActor.Trait(); - positionsUpdatedModules = player.PlayerActor.TraitsImplementing().ToArray(); - var tileset = world.Map.Rules.TileSet; resourceTypeIndices = new BitArray(tileset.TerrainInfo.Length); // Big enough foreach (var t in world.Map.Rules.Actors["world"].TraitInfos()) diff --git a/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs index 7ba3c88543..3758b58946 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/HarvesterBotModule.cs @@ -76,9 +76,17 @@ namespace OpenRA.Mods.Common.Traits unitCannotBeOrdered = a => a.Owner != self.Owner || a.IsDead || !a.IsInWorld; } + protected override void Created(Actor self) + { + // Special case handling is required for the Player actor. + // Created is called before Player.PlayerActor is assigned, + // so we must query player traits from self, which refers + // for bot modules always to the Player actor. + requestUnitProduction = self.TraitsImplementing().ToArray(); + } + protected override void TraitEnabled(Actor self) { - requestUnitProduction = player.PlayerActor.TraitsImplementing().ToArray(); pathfinder = world.WorldActor.Trait(); domainIndex = world.WorldActor.Trait(); resLayer = world.WorldActor.TraitOrDefault(); diff --git a/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs index 065c050003..84c73e511d 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/McvManagerBotModule.cs @@ -80,11 +80,18 @@ namespace OpenRA.Mods.Common.Traits unitCannotBeOrdered = a => a.Owner != player || a.IsDead || !a.IsInWorld; } + protected override void Created(Actor self) + { + // Special case handling is required for the Player actor. + // Created is called before Player.PlayerActor is assigned, + // so we must query player traits from self, which refers + // for bot modules always to the Player actor. + notifyPositionsUpdated = self.TraitsImplementing().ToArray(); + requestUnitProduction = self.TraitsImplementing().ToArray(); + } + protected override void TraitEnabled(Actor self) { - notifyPositionsUpdated = player.PlayerActor.TraitsImplementing().ToArray(); - requestUnitProduction = player.PlayerActor.TraitsImplementing().ToArray(); - // Avoid all AIs reevaluating assignments on the same tick, randomize their initial evaluation delay. scanInterval = world.LocalRandom.Next(Info.ScanForNewMcvInterval, Info.ScanForNewMcvInterval * 2); } diff --git a/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs index 0b64cd2fe6..077d72764b 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/SquadManagerBotModule.cs @@ -126,11 +126,18 @@ namespace OpenRA.Mods.Common.Traits && !a.GetEnabledTargetTypes().IsEmpty; } + protected override void Created(Actor self) + { + // Special case handling is required for the Player actor. + // Created is called before Player.PlayerActor is assigned, + // so we must query player traits from self, which refers + // for bot modules always to the Player actor. + notifyPositionsUpdated = self.TraitsImplementing().ToArray(); + notifyIdleBaseUnits = self.TraitsImplementing().ToArray(); + } + protected override void TraitEnabled(Actor self) { - notifyPositionsUpdated = Player.PlayerActor.TraitsImplementing().ToArray(); - notifyIdleBaseUnits = Player.PlayerActor.TraitsImplementing().ToArray(); - // Avoid all AIs trying to rush in the same tick, randomize their initial rush a little. var smallFractionOfRushInterval = Info.RushInterval / 20; rushTicks = World.LocalRandom.Next(Info.RushInterval - smallFractionOfRushInterval, Info.RushInterval + smallFractionOfRushInterval); diff --git a/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs index ae217c882f..1cb4b38f97 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/SupportPowerBotModule.cs @@ -52,9 +52,17 @@ namespace OpenRA.Mods.Common.Traits player = self.Owner; } + protected override void Created(Actor self) + { + // Special case handling is required for the Player actor. + // Created is called before Player.PlayerActor is assigned, + // so we must query player traits from self, which refers + // for bot modules always to the Player actor. + supportPowerManager = self.Trait(); + } + protected override void TraitEnabled(Actor self) { - supportPowerManager = player.PlayerActor.Trait(); foreach (var decision in Info.Decisions) powerDecisions.Add(decision.OrderName, decision); } diff --git a/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs b/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs index 7417e72c01..7172a40f8f 100644 --- a/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs +++ b/OpenRA.Mods.Common/Traits/BotModules/UnitBuilderBotModule.cs @@ -60,9 +60,13 @@ namespace OpenRA.Mods.Common.Traits player = self.Owner; } - protected override void TraitEnabled(Actor self) + protected override void Created(Actor self) { - requestPause = player.PlayerActor.TraitsImplementing().ToArray(); + // Special case handling is required for the Player actor. + // Created is called before Player.PlayerActor is assigned, + // so we must query player traits from self, which refers + // for bot modules always to the Player actor. + requestPause = self.TraitsImplementing().ToArray(); } void IBotNotifyIdleBaseUnits.UpdatedIdleBaseUnits(List idleUnits)