In Progress [e1.1.1]Crash when player agent is controlled by AI and issued an order to stop using siege machine.

Users who are viewing this thread

This bug causes crash in siege battle when using some mods such as RTS Camera .
But it also can be reproduced without using any mods.
Reproduce steps:
  • Enable cheat mode. Start the game without using any third-party mods.
  • Enter custom battle, choose siege battle and add a ballista (or any siege weapon) for attacker.
  • Adjust attacker army size to 1, then starts.
  • Begin assault directly.
  • Press ctrl + f5 to let AI control the player.
  • Before the player agent reaches the siege weapon, press F1 on the siege weapon to let the agent stop using the siege weapon.
  • Then crash happens.
The reason is that in Formation.LeaveDetachment, it excludes main agent (!IsMainAgent) rather than excludes agent that is controlled by player (Controller == Player). It's inconsistent with Agent.CanBeAssignedForScriptedMovement, in which agents can be attached to siege weapon if it is controlled by AI.
After player controller is switched to AI, it will be attached to available siege weapons. But when the formation it belongs to stops to use the siege weapon, the agent is not removed from the siege weapon and attached to the formation again because Formation.LeaveDetachment filters out main agent.

Fix:
  • The fix is simple: just replace "!IsMainAgent" in Formation.LeaveDetachment with "IsAIControlled" but it's in official code and hard to be replaced by modders so it can only be accomplished by TaleWorlds.
Though this bug can only be triggered in cheat mode or using mods, it should not cost too much effort for TaleWorlds to fix this problem: just to replace a single word. So please don't ignore this problem.
 
Last edited:
Hello, thank you for your find and input. I have informed the devs about the issue and i am sure it will be fixed in no time.
 
this method can be patched with harmony if you don't want to wait for tw… I will do it if the fix is as simple as you describe
 
this literally took me two seconds to fix, hire me tw? I will fix more :3

I don't think that TaleWorlds should fix this problem instantly but they promised to "fix it in no time".
Does "in no time" mean longer than a month? I would provide a work-around if I knew that.
 
Last edited:
this literally took me two seconds to fix, hire me tw? I will fix more :3

By the way I decompiled the patch you made and find that there're some errors in your patch. Anyway I used harmony to fix it and will release it in next release of my mod. Thanks for your code to demonstrate how to use harmony!
 
Last edited:
I don't think that TaleWorlds should fix this problem instantly but they promised to "fix it in no time".
Does "in no time" mean longer than a month? I would provide a work-around if I knew that.
what do you mean?
 
By the way I decompiled the patch you made and find that there're some errors in your patch. Anyway I used harmony to fix it and will release it in next release of my mod. Thanks for your code to demonstrate how to use harmony!
and the error is? if you use the patch in your mod just please give credit to me. No need to decompile my mod, i released the visual studio project and uploaded to nexus. FYI, I uploaded the 1.0.0 version and forgot to delete the exclamation point so 1.0.1 should not have errors and i changed exactly what you said to change in your post.

edit: now i uploaded 1.0.2 because i left a dependency (BannerLib) in the submodule.xml when i copied the xml text from another mod. Removed that entry.
 
Last edited:
and the error is? if you use the patch in your mod just please give credit to me. No need to decompile my mod, i released the visual studio project and uploaded to nexus. FYI, I uploaded the 1.0.0 version and forgot to delete the exclamation point so 1.0.1 should not have errors and i changed exactly what you said to change in your post.

edit: now i uploaded 1.0.2 because i left a dependency (BannerLib) in the submodule.xml when i copied the xml text from another mod. Removed that entry.
I didn't use harmony before so I used your code as a fast tutorial. In your code "detachmentManager" is defined but not used. The first argument of the last call to Invoke should be "detachmentManager" rather than "detachment". I fixed it in my mod. Of course I will give credit to you.
 
Last edited:
oh oops, I accidently must have did that too quickly and when I tabbed, intellisense chose the IDetachment parameter instead of the detachmentManager which I had intended. Thanks for pointing that out. :smile:

Updated my code to...
Code:
static bool Prefix(Formation __instance, List<IDetachment> ____detachments, IDetachment detachment)
{
    BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
    MethodInfo attachUnitMethod = typeof(Formation).GetMethod("AttachUnit", flags);//THIS HAD AN ERROR, USED WRONG TYPE
    foreach (Agent agent in detachment.Agents.Where(a => a.Formation == __instance && a.IsAIControlled).ToList())
    {
        detachment.RemoveAgent(agent);
        attachUnitMethod.Invoke(__instance, new object[] { agent });
    }
    ____detachments.Remove(detachment);
    DetachmentManager detachmentManager = (DetachmentManager)typeof(Team).GetProperty("DetachmentManager", flags).GetValue(__instance.Team);
    MethodInfo onFormationLeaveDetachmentMethod = typeof(DetachmentManager).GetMethod("OnFormationLeaveDetachment", flags);
    onFormationLeaveDetachmentMethod.Invoke(detachmentManager, new object[] { __instance, detachment });//THIS HAD ERROR, USED WRONG OBJECT
    return false;
}
 
Last edited:
oh oops, I accidently must have did that too quickly and when I tabbed, intellisense chose the IDetachment parameter instead of the detachmentManager which I had intended. Thanks for pointing that out. :smile:

Updated my code to...
Code:
        static bool Prefix(Formation __instance, List<IDetachment> ____detachments, IDetachment detachment)
{
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance;
MethodInfo attachUnitMethod = typeof(Formation).GetMethod("AttachUnit", flags);
foreach (Agent agent in detachment.Agents.Where(a => a.Formation == __instance && a.IsAIControlled).ToList())
{
detachment.RemoveAgent(agent);
attachUnitMethod.Invoke(__instance, new object[] { agent });
}
            ____detachments.Remove(detachment);
            DetachmentManager detachmentManager = (DetachmentManager)typeof(Team).GetProperty("DetachmentManager", flags).GetValue(__instance.Team);
MethodInfo onFormationLeaveDetachmentMethod = typeof(DetachmentManager).GetMethod("OnFormationLeaveDetachment", flags);
onFormationLeaveDetachmentMethod.Invoke(detachmentManager, new object[] { __instance, detachment });
return false;
        }
Thanks for solving this problem and share the code. I really appreciate your help. Thank you so much!
 
Back
Top Bottom