Suggestion General division by 0 at TroopUpgradeTracker.CalculateReadyToUpgradeSafe()

Users who are viewing this thread

So I am modding some troops and wanted to try and extend the amount of tiers but in doing this, alongside other modders, I have come across the issue in the title.
IggTWSz.png
 

MRay

Developer
Have you changed PartyTroopUpgradeModel by any chance? If I read the code correctly, this is happening because upgrade cost is 0xp for a troop. This would be considered a bug during our development so crash is preferable in these cases(Having 0xp required for upgrading)

But still, we can fix this. In the meantime you can give at least 1xp required for upgrading.

Also, I don't see the connection with TroopUpgradeTracker.CalculateReadyToUpgradeSafe() with this callstack. But the same issue(0xp required) might be causing the crash there 🤷‍♂️
 
Have you changed PartyTroopUpgradeModel by any chance? If I read the code correctly, this is happening because upgrade cost is 0xp for a troop. This would be considered a bug during our development so crash is preferable in these cases(Having 0xp required for upgrading)

But still, we can fix this. In the meantime you can give at least 1xp required for upgrading.

Also, I don't see the connection with TroopUpgradeTracker.CalculateReadyToUpgradeSafe() with this callstack. But the same issue(0xp required) might be causing the crash there 🤷‍♂️
that could be what it is
I'll have a look
 
After some analyzing, I found that the method causing the exception is DefaultPartyTroopUpgradeModel.GetXpCostForUpgrade().

I think the solution would be to not have a 0xp cost for upgrading a troop to the same tier. It makes sense because if the upgrade cost was 0xp, the player could keep upgrading the same troop endlessly.
 

svelok

Sergeant
Cause of this is expanding beyond 7 tiers. GetXpCostForUpgrade contains a loop that starts at the upgrading unit's tier + 1, and runs until that number is greater than the upgrade target's tier. But CharacterHelper.GetCharacterTier (aka CharacterObject.Tier) caps out at 7. If you have eg tier 8 units, then the loop to upgrade the tier 7 unit gets set to 7 + 1 = 8, and the (t:cool: upgrade target is returned as t7, and so the for-loop never runs because it checks if 8 <= 7 and skips.

So GetXpCostForUpgrade returns the default value of 0, which causes the downstream division by 0 crash in the UI. Workaround for modders who want >7 tiers would be to make a custom PartyTroopUpgradeModel. Fixes this crash specifically, could be other stuff that breaks with t8+ units, but this specific one isn't a roadblock
 
Actually a better solution would be to patch CharacterHelper.GetCharacterTier and change 7 to the highest troop tier in your mod.

So if for example your highest troop tier is 10, you would patch it like so:

C#:
[HarmonyPatch(typeof(CharacterHelper), "GetCharacterTier")]
public static bool Prefix(CharacterObject character, ref int __result)
{
    if (character.IsHero)
    {
        __result = 0;
    }
    __result = Math.Min(Math.Max(MathF.Ceiling(((float)character.Level - 5f) / 5f), 0), 10);
    return false;
}
 
I'am having this crash, is it related?
  1. at TaleWorlds.CampaignSystem.TroopUpgradeTracker.CalculateReadyToUpgradeSafe(TroopRosterElement& el, PartyBase owner)
  2. at TaleWorlds.CampaignSystem.TroopUpgradeTracker.AddTrackedTroop(PartyBase party, CharacterObject character)
  3. at SandBox.BattleAgentLogic.OnAgentBuild(Agent agent, Banner banner)
  4. at TaleWorlds.MountAndBlade.Mission.SpawnAgent_Patch1(Mission this, AgentBuildData agentBuildData, Boolean spawnFromAgentVisuals, Int32 formationTroopCount)
  5. at TaleWorlds.MountAndBlade.Mission.SpawnTroop(IAgentOriginBase troopOrigin, Boolean isPlayerSide, Boolean hasFormation, Boolean spawnWithHorse, Boolean isReinforcement, Boolean enforceSpawningOnInitialPoint, Int32 formationTroopCount, Int32 formationTroopIndex, Boolean isAlarmed, Boolean wieldInitialWeapons, Boolean forceDismounted, Nullable`1 initialPosition, Nullable`1 initialDirection, String specialActionSet)
  6. at TaleWorlds.MountAndBlade.MissionAgentSpawnLogic.MissionSide.SpawnTroops(Int32 number, Boolean isReinforcement, Boolean enforceSpawningOnInitialPoint)
  7. at TaleWorlds.MountAndBlade.MissionAgentSpawnLogic.CheckInitialSpawns()
  8. at TaleWorlds.MountAndBlade.SiegeMissionController.SetupTeam(Team team)
  9. at TaleWorlds.MountAndBlade.SiegeMissionController.SetupTeams()
  10. at TaleWorlds.MountAndBlade.SiegeMissionController.OnMissionTick(Single dt)
  11. at TaleWorlds.MountAndBlade.Mission.OnTick(Single dt, Single realDt, Boolean updateCamera)
  12. at TaleWorlds.MountAndBlade.MissionState.TickMission(Single realDt)
  13. at TaleWorlds.MountAndBlade.MissionState.OnTick(Single realDt)
  14. at TaleWorlds.Core.GameStateManager.OnTick(Single dt)
  15. at TaleWorlds.Core.Game.OnTick(Single dt)
  16. at TaleWorlds.Core.GameManagerBase.OnTick(Single dt)
  17. at TaleWorlds.MountAndBlade.Module.OnApplicationTick_Patch1(Module this, Single dt)
  18. at TaleWorlds.DotNet.Managed.ApplicationTick_Patch1(Single dt)
this is my modlist

Can anyone help?
 
Does it also throw "Attempted to divide by 0"? What were you doing when the crash occurred?
Joining a battle with of about 1000 troops, the same crash occurs on auto resolve and trying to play the battle. Although sometimes I were able to fight till reinforcements from the allied army spawn(800 battle size allows me to join the battle before crash, but game crashes anyway on reinforcements spawning). Last time I fixed this issue by deleting some looters upgrade paths.
 
Joining a battle with of about 1000 troops, the same crash occurs on auto resolve and trying to play the battle. Although sometimes I were able to fight till reinforcements from the allied army spawn(800 battle size allows me to join the battle before crash, but game crashes anyway on reinforcements spawning). Last time I fixed this issue by deleting some looters upgrade paths.
You will have to patch CharacterHelper.GetCharacterTier() to match your number of troop tiers.
 
Top Bottom