-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bug: fix heroes having equipment of last battle on campaign map
For instance, naked lords in a siege attack were then naked on the campaign map.
- Loading branch information
Showing
7 changed files
with
248 additions
and
137 deletions.
There are no files selected for viewing
90 changes: 90 additions & 0 deletions
90
...xpandedTemplate.Integration/SetSpawnEquipment/MissionLogic/EquipmentSetterMissionLogic.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using System.Collections.Generic; | ||
using Bannerlord.ExpandedTemplate.Domain.EquipmentPool; | ||
using Bannerlord.ExpandedTemplate.Integration.SetSpawnEquipment.MissionLogic.EquipmentSetters; | ||
using SandBox.Missions.MissionLogics; | ||
using TaleWorlds.CampaignSystem; | ||
using TaleWorlds.Core; | ||
using TaleWorlds.MountAndBlade; | ||
|
||
namespace Bannerlord.ExpandedTemplate.Integration.SetSpawnEquipment.MissionLogic; | ||
|
||
public class EquipmentSetterMissionLogic : TaleWorlds.MountAndBlade.MissionLogic | ||
{ | ||
private readonly HeroEquipmentSetter _heroEquipmentSetter; | ||
private readonly TroopEquipmentPoolSetter _troopEquipmentPoolSetter; | ||
private readonly IGetEquipmentPool _getEquipmentPool; | ||
private readonly CharacterEquipmentRosterReference _characterEquipmentRosterReference; | ||
|
||
private readonly Dictionary<string, MBEquipmentRoster> _nativeTroopEquipmentRosters = new(); | ||
private readonly Dictionary<string, Equipment> _nativeHeroEquipment = new(); | ||
|
||
public EquipmentSetterMissionLogic(HeroEquipmentSetter heroEquipmentSetter, | ||
TroopEquipmentPoolSetter troopEquipmentPoolSetter, IGetEquipmentPool getEquipmentPool, | ||
CharacterEquipmentRosterReference characterEquipmentRosterReference) | ||
{ | ||
_heroEquipmentSetter = heroEquipmentSetter; | ||
_troopEquipmentPoolSetter = troopEquipmentPoolSetter; | ||
_getEquipmentPool = getEquipmentPool; | ||
_characterEquipmentRosterReference = characterEquipmentRosterReference; | ||
} | ||
|
||
public override void OnBehaviorInitialize() | ||
{ | ||
base.OnBehaviorInitialize(); | ||
|
||
_nativeTroopEquipmentRosters.Clear(); | ||
_nativeHeroEquipment.Clear(); | ||
} | ||
|
||
public override void OnAgentCreated(Agent agent) | ||
{ | ||
MBEquipmentRoster? agentEquipmentRoster = | ||
_characterEquipmentRosterReference.GetEquipmentRoster(agent.Character); | ||
|
||
if (agentEquipmentRoster is null) return; | ||
if (!CanOverrideEquipment(agent)) return; | ||
|
||
base.OnAgentCreated(agent); | ||
|
||
string id = agent.Character.StringId; | ||
if (agent.Character is CharacterObject characterObject) | ||
id = characterObject.OriginalCharacter?.StringId ?? id; | ||
|
||
var equipmentPool = _getEquipmentPool.GetTroopEquipmentPool(id); | ||
if (equipmentPool.IsEmpty()) | ||
equipmentPool = _getEquipmentPool.GetTroopEquipmentPool(agentEquipmentRoster.StringId); | ||
|
||
if (agent.IsHero) | ||
{ | ||
_nativeHeroEquipment[agent.Character.StringId] = agent.Character.Equipment.Clone(); | ||
_heroEquipmentSetter.SetEquipmentFromEquipmentPool(agent, equipmentPool); | ||
} | ||
else | ||
{ | ||
_nativeTroopEquipmentRosters[agent.Character.StringId] = agentEquipmentRoster; | ||
_troopEquipmentPoolSetter.SetEquipmentPool(agent, equipmentPool); | ||
} | ||
} | ||
|
||
public override void OnAgentBuild(Agent agent, Banner banner) | ||
{ | ||
if (!CanOverrideEquipment(agent)) return; | ||
|
||
base.OnAgentBuild(agent, banner); | ||
|
||
if (agent.IsHero) | ||
_heroEquipmentSetter.SetEquipment(agent, _nativeHeroEquipment[agent.Character.StringId]); | ||
else | ||
_troopEquipmentPoolSetter.SetEquipmentPool(agent, | ||
_nativeTroopEquipmentRosters[agent.Character.StringId]); | ||
} | ||
|
||
private static bool CanOverrideEquipment(IAgent agent) | ||
{ | ||
return (Mission.Current?.GetMissionBehavior<MissionAgentHandler>() is not null || | ||
Mission.Current?.GetMissionBehavior<IMissionAgentSpawnLogic>() is not null) && | ||
agent?.Character is not null && | ||
!(Clan.PlayerClan?.Heroes?.Exists( | ||
hero => hero?.StringId is not null && agent?.Character?.StringId == hero.StringId) ?? true); | ||
} | ||
} |
46 changes: 46 additions & 0 deletions
46
...tion/SetSpawnEquipment/MissionLogic/EquipmentSetters/CharacterEquipmentRosterReference.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
using System.Reflection; | ||
using Bannerlord.ExpandedTemplate.Domain.Logging.Port; | ||
using TaleWorlds.Core; | ||
|
||
namespace Bannerlord.ExpandedTemplate.Integration.SetSpawnEquipment.MissionLogic.EquipmentSetters; | ||
|
||
public class CharacterEquipmentRosterReference | ||
{ | ||
private static readonly FieldInfo? EquipmentRosterField = | ||
typeof(BasicCharacterObject).GetField("_equipmentRoster", BindingFlags.NonPublic | BindingFlags.Instance)!; | ||
|
||
public CharacterEquipmentRosterReference(ILoggerFactory loggerFactory) | ||
{ | ||
ILogger logger = loggerFactory.CreateLogger<CharacterEquipmentRosterReference>(); | ||
|
||
if (EquipmentRosterField is null || EquipmentRosterField.FieldType != typeof(MBEquipmentRoster)) | ||
logger.Error( | ||
"BasicCharacterObject's _mbEquipmentRoster field could not be found preventing equipment pool override"); | ||
} | ||
|
||
/// <summary> | ||
/// Returns the equipment roster reference of a characterObject | ||
/// </summary> | ||
/// <param name="characterObject"></param> | ||
/// <returns> | ||
/// the internal MBEquipmentRoster object from the characterObject object or | ||
/// null if the characterObject is null or if the under the hood reflection implementation fails due to | ||
/// a game update) | ||
/// </returns> | ||
public MBEquipmentRoster? GetEquipmentRoster(BasicCharacterObject characterObject) | ||
{ | ||
if (characterObject is null) return null; | ||
return (MBEquipmentRoster?)EquipmentRosterField?.GetValue(characterObject); | ||
} | ||
|
||
/// <summary> | ||
/// Sets the equipment roster reference of a characterObject | ||
/// </summary> | ||
/// <param name="characterObject"></param> | ||
/// <param name="mbEquipmentRoster"></param> | ||
public void SetEquipmentRoster(BasicCharacterObject characterObject, MBEquipmentRoster mbEquipmentRoster) | ||
{ | ||
if (characterObject is null) return; | ||
EquipmentRosterField?.SetValue(characterObject, mbEquipmentRoster); | ||
} | ||
} |
59 changes: 59 additions & 0 deletions
59
...mplate.Integration/SetSpawnEquipment/MissionLogic/EquipmentSetters/HeroEquipmentSetter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
using Bannerlord.ExpandedTemplate.Domain.EquipmentPool; | ||
using Bannerlord.ExpandedTemplate.Domain.EquipmentPool.Model; | ||
using Bannerlord.ExpandedTemplate.Domain.Logging.Port; | ||
using Bannerlord.ExpandedTemplate.Integration.SetSpawnEquipment.EquipmentPools.Mappers; | ||
using TaleWorlds.Core; | ||
using Equipment = TaleWorlds.Core.Equipment; | ||
|
||
namespace Bannerlord.ExpandedTemplate.Integration.SetSpawnEquipment.MissionLogic.EquipmentSetters; | ||
|
||
public class HeroEquipmentSetter | ||
{ | ||
private readonly IGetEquipment _getEquipment; | ||
private readonly EquipmentMapper _equipmentMapper; | ||
private readonly CharacterEquipmentRosterReference _characterEquipmentRosterReference; | ||
private readonly ILogger _logger; | ||
|
||
public HeroEquipmentSetter(IGetEquipment getEquipment, EquipmentMapper equipmentMapper, | ||
CharacterEquipmentRosterReference characterEquipmentRosterReference, ILoggerFactory loggerFactory) | ||
{ | ||
_getEquipment = getEquipment; | ||
_equipmentMapper = equipmentMapper; | ||
_characterEquipmentRosterReference = characterEquipmentRosterReference; | ||
_logger = loggerFactory.CreateLogger<HeroEquipmentSetter>(); | ||
} | ||
|
||
public void SetEquipmentFromEquipmentPool(IAgent agent, EquipmentPool equipmentPool) | ||
{ | ||
MBEquipmentRoster? agentEquipmentRoster = | ||
_characterEquipmentRosterReference.GetEquipmentRoster(agent.Character); | ||
|
||
if (agentEquipmentRoster is null) return; | ||
|
||
var equipment = _getEquipment.GetEquipmentFromEquipmentPool(equipmentPool); | ||
if (equipment is null) | ||
SetEquipment(agent, new Equipment()); | ||
else | ||
SetEquipment(agent, | ||
_equipmentMapper.Map(equipment, agentEquipmentRoster)); | ||
} | ||
|
||
public void SetEquipment(IAgent agent, Equipment? equipment) | ||
{ | ||
if (agent?.Character?.Equipment is null) | ||
{ | ||
_logger.Error( | ||
"Expected a hero Agent to have a non-nullable Character field with a non-nullable Equipment field"); | ||
return; | ||
} | ||
|
||
if (equipment is null) | ||
{ | ||
_logger.Error( | ||
$"Could find any equipment for ${agent.Character.StringId}"); | ||
return; | ||
} | ||
|
||
agent.Character.Equipment.FillFrom(equipment); | ||
} | ||
} |
37 changes: 37 additions & 0 deletions
37
...e.Integration/SetSpawnEquipment/MissionLogic/EquipmentSetters/TroopEquipmentPoolSetter.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
using Bannerlord.ExpandedTemplate.Domain.EquipmentPool.Model; | ||
using Bannerlord.ExpandedTemplate.Integration.SetSpawnEquipment.EquipmentPools.Mappers; | ||
using TaleWorlds.Core; | ||
|
||
namespace Bannerlord.ExpandedTemplate.Integration.SetSpawnEquipment.MissionLogic.EquipmentSetters; | ||
|
||
public class TroopEquipmentPoolSetter | ||
{ | ||
private readonly EquipmentPoolsMapper _equipmentPoolsMapper; | ||
private readonly CharacterEquipmentRosterReference _characterEquipmentRosterReference; | ||
|
||
public TroopEquipmentPoolSetter(EquipmentPoolsMapper equipmentPoolsMapper, | ||
CharacterEquipmentRosterReference characterEquipmentRosterReference) | ||
|
||
{ | ||
_equipmentPoolsMapper = equipmentPoolsMapper; | ||
_characterEquipmentRosterReference = characterEquipmentRosterReference; | ||
} | ||
|
||
public void SetEquipmentPool(IAgent agent, EquipmentPool equipmentPool) | ||
{ | ||
if (agent?.Character is null) return; | ||
|
||
MBEquipmentRoster? agentEquipmentRoster = | ||
_characterEquipmentRosterReference.GetEquipmentRoster(agent.Character); | ||
|
||
if (agentEquipmentRoster is null) return; | ||
|
||
SetEquipmentPool(agent, _equipmentPoolsMapper.MapEquipmentPool(equipmentPool, agentEquipmentRoster)); | ||
} | ||
|
||
public void SetEquipmentPool(IAgent agent, MBEquipmentRoster equipmentRoster) | ||
{ | ||
if (agent?.Character is null) return; | ||
_characterEquipmentRosterReference.SetEquipmentRoster(agent.Character, equipmentRoster); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
127 changes: 0 additions & 127 deletions
127
...dedTemplate.Integration/SetSpawnEquipment/MissionLogic/MissionSpawnEquipmentPoolSetter.cs
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.