e1.6.0-v1.2.7 Modding Changes

Users who are viewing this thread

With a friend, we are working on a mod in which we would like to let the player place barricades at the during or at the beginning of a battle.
If I'm right, the navmesh is not dynamic in Bannerlord. Which mines it can't be done with the current game. Could taleworlds add this possiblity for modders to moddify the navemash after the load of the scene ?

Example of what we want to do:

nice idea
 
EncyclopediaHeroPageVM.InformationText. EncyclopediaHeroPageVM is the DataSource of the hero encyclopedia page.


Apart from using third party UI extending libraries made by other modders to add your own custom widget in the xml, you can create your own xml for EncyclopediaHeroPage.xml or EncyclopediaSettlementPage.xml and use your custom widget that way. Using your own xml would mean overwriting the existing ones(both TW and modder made).


One of the ways:
  • Create a EncyclopediaSettlementPage.xml in "\{YOUR_MODULE}\GUI\Prefabs\"
  • Add your custom widget in the xml.
    • You can create a new class derived from TaleWorlds.GauntletUI.Widget(or any other widget type) and use that in your xml.
    • The system will find that widget in your assembly when the game loads your xml and sees that widget in the xml.
  • In that custom widget, set a textwidget to your TimesSieged value.
  • Set UIConfig.DoNotUseGeneratedPrefabs to true.(So that the game will use your xml instead of the generated code)

So I have gotten custom widgets to work, but the bigger problem I'm running into is that I seemingly don't have any way to access the underlying viewmodel stuff or for the widget to understand the larger UI context. For my encyclopedia widget, it has no idea what encyclopedia page is open or which settlement is being viewed, for instance, so I can't see how to display the correct data. The widget is only passed the UI context containing brushes and stuff, but i don't see any way to figure out which encyclopedia page the player is currently viewing or specific info like which settlement's page is open. Hopefully there is some way to do this without using Harmony which I have been able to avoid up until now.
 
So I have gotten custom widgets to work, but the bigger problem I'm running into is that I seemingly don't have any way to access the underlying viewmodel stuff or for the widget to understand the larger UI context. For my encyclopedia widget, it has no idea what encyclopedia page is open or which settlement is being viewed, for instance, so I can't see how to display the correct data. The widget is only passed the UI context containing brushes and stuff, but i don't see any way to figure out which encyclopedia page the player is currently viewing or specific info like which settlement's page is open. Hopefully there is some way to do this without using Harmony which I have been able to avoid up until now.
Our datasource(ViewModel) and View(Gauntlet/Widgets) are de-coupled. That means the two systems only "know" each other through abstraction. Meaning widget can't use the TaleWorlds.CampaignSystem.Settlements.Settlement type. But your View/Widget code doesn't need to adhere to that architecture.

You can get MapScreen.Instance.EncyclopediaScreenManager as GauntletMapEncyclopediaView and get _encyclopediaData through reflection. Then EncyclopediaData._activeDatasource with reflection. Type check _activeDataSource to EncyclopediaSettlementPageVM. If not null, get EncyclopediaSettlementPageVM._settlement member. Should be doable without Harmony.
 
Our datasource(ViewModel) and View(Gauntlet/Widgets) are de-coupled. That means the two systems only "know" each other through abstraction. Meaning widget can't use the TaleWorlds.CampaignSystem.Settlements.Settlement type. But your View/Widget code doesn't need to adhere to that architecture.

You can get MapScreen.Instance.EncyclopediaScreenManager as GauntletMapEncyclopediaView and get _encyclopediaData through reflection. Then EncyclopediaData._activeDatasource with reflection. Type check _activeDataSource to EncyclopediaSettlementPageVM. If not null, get EncyclopediaSettlementPageVM._settlement member. Should be doable without Harmony.
Okay thanks a lot. Didn't know it was possible for me to do that. That's exactly what I needed.
 
Last edited:
Hi, I got a question. I was translating mods created by others by string XML file before 1.8.0 patch and it was all good. But after the patch, its not working anymore. anyone knows why and how to make it happen?
 
Hi, I got a question. I was translating mods created by others by string XML file before 1.8.0 patch and it was all good. But after the patch, its not working anymore. anyone knows why and how to make it happen?
Would need some more details than that - how are you implementing it?
 
Would need some more details than that - how are you implementing it?
For example, the most recent work of mine was the translation of EnhancedSmithing mod, met the author in nexus. he created std_module_strings_xml under the directory "EnhancedSmithing\ModuleData\Languages\" and I translated it, and put it in "\Mount & Blade II Bannerlord\Modules\EnhancedSmithing\ModuleData\Languages\TR\std_module_strings_xml.xml" and it doesnt work. I can post the code inside the file but not in here in public forum maybe
 
Hi, I got a question. I was translating mods created by others by string XML file before 1.8.0 patch and it was all good. But after the patch, its not working anymore. anyone knows why and how to make it happen?
  • Language files are now referenced in language folders in the "language_data.xml" (they were previously automatically searched for and added).
Can you check if that's the problem?
 
About using IMapEntity. I'd like to dynamically create some things on the map for the player to sometimes randomly access. I have gotten them to appear on map but interaction of any kind seems to be missing.

var entity = new TestMapEntity(); var partyVis = new TestIPartyVisual(); partyVis.partyVisualPrefabToGenerateFrom = "tutorial_training_field"; partyVis.OnStartup(null); // this basically just gets a game entity with GameEntity.Instantiate() for "tutorial_training_field" and adds the entity to MapScreen.VisualsOfEntities entity.PartyVisual = partyVis; entity.PartyVisual.StrategicEntity.SetLocalPosition(Hero.MainHero.GetPosition()); entity.InteractionPosition = partyVis.StrategicEntity.GlobalPosition.AsVec2;

Successfully places the partyvisual part right under the player on the map, but I'm pretty sure something is missing with the MapEntity because its methods (which I have implemented) like OnHover and on click are never called and the field I created on the map has no interaction or presence on the map. My PartyVisual probably works because I added it to VisualsOfEntities, and probably I need to add the mapentity to something as well. Checking other objects in the game, for their IMapEntity they seem to directly rely on MobileParty or Settlement, using CampaignObjectManager to add their entities to MobileParties or Settlements, which are read only lists I can't access, so I'm really not sure where to go with IMapEntity from here.
 
About using IMapEntity. I'd like to dynamically create some things on the map for the player to sometimes randomly access. I have gotten them to appear on map but interaction of any kind seems to be missing.

var entity = new TestMapEntity(); var partyVis = new TestIPartyVisual(); partyVis.partyVisualPrefabToGenerateFrom = "tutorial_training_field"; partyVis.OnStartup(null); // this basically just gets a game entity with GameEntity.Instantiate() for "tutorial_training_field" and adds the entity to MapScreen.VisualsOfEntities entity.PartyVisual = partyVis; entity.PartyVisual.StrategicEntity.SetLocalPosition(Hero.MainHero.GetPosition()); entity.InteractionPosition = partyVis.StrategicEntity.GlobalPosition.AsVec2;

Successfully places the partyvisual part right under the player on the map, but I'm pretty sure something is missing with the MapEntity because its methods (which I have implemented) like OnHover and on click are never called and the field I created on the map has no interaction or presence on the map. My PartyVisual probably works because I added it to VisualsOfEntities, and probably I need to add the mapentity to something as well. Checking other objects in the game, for their IMapEntity they seem to directly rely on MobileParty or Settlement, using CampaignObjectManager to add their entities to MobileParties or Settlements, which are read only lists I can't access, so I'm really not sure where to go with IMapEntity from here.

Do you have IPartyVisual.GetMapEntity() function implemented?
 
Yes, i put in some basic implementation for each interface method for testing.
public IMapEntity GetMapEntity() { Util.InfoPrint("Something called GetMapEntity()"); return _mapEntity; }
Nothing seems to be calling this either. Actually, none of my PartyVisuals methods seem to be being called at all, even Tick(). Maybe I haven't set up the entity returned from GameEntity.Instantiate() correctly?
public void OnStartup(PartyBase party) { Util.InfoPrint("IPartyVisual startup called."); _mapScene = ((MapScene)Campaign.Current.MapSceneWrapper).Scene; StrategicEntity = GameEntity.Instantiate(_mapScene, partyVisualPrefabToGenerateFrom, true); StrategicEntity.SetReadyToRender(true); if (!MapScreen.VisualsOfEntities.ContainsKey(StrategicEntity)) { MapScreen.VisualsOfEntities.Add(StrategicEntity, this); } }

If possible any example with basic functionality of IMapEntity working would be enough to figure the rest out on our own.
 
Last edited:
  • Language files are now referenced in language folders in the "language_data.xml" (they were previously automatically searched for and added).
Can you check if that's the problem?
I confirm, that's the root cause.
We have to create a "language_data.xml" for each language and list any xml file which contains the translated strings.
 
Thank you for your request. We'll look into this.
In addition, the DestructableComponent class should get two methods to externally raise the OnDestroyed and OnHitTaken events, since C# doesn't allow raising events from a subclass directly. Without such methods, we wouldn't be able to raise the events from our override OnHit methods.
 

1.9.0 Changes​

Greetings!

Patch e1.9.0 comes with more modding-related changes. Here they are!
  • Changed Official node in SubModule.xml to ModuleType that has possible values of "Official", "OfficialOptional" and "Community". The default value is “Community”.
  • Increased the number of bones defined in monsters.xml to extend modding support of the animation system.
  • Hero.SetSkillValue() function is now public. Modders can now directly change the hero skill value.
  • Added a "Quick Save Scene" option to the editor.
  • Decreased the road generation minimum width value to 0.1 meters.
    • In response to the community report by @NPC99 on the modding discord.
  • The volunteer upgrade tier cap is now calculated from a model, allowing modders to change the value to their needs.
  • Unsealed and removed internals from some combat related classes and methods.
  • Removed the unused GameMenuSelectionBehavior.
  • Fixed a visual bug in relation to tree_far trees.
    • In response to the community report by @Bullero on the modding discord.
  • Fixed a crash that occurred on load if an issue behavior had been removed from the game.
  • Adjusted the algorithm responsible for resizing the helmets to correctly fit the different head shapes, removing the bug that caused helmets to be too large.
    • Was pointed out by many community members, including @KingKilo.
  • Increased the theoretical limit for concurrent players on a custom server to around 1000.
    • In response to the community request by the closed custom servers group.
Our modding documentation has moved to a new address (which has SSL enabled) - https://moddocs.bannerlord.com/ We have also published new pages on it to accompany our recent Custom Servers release:
We continue to work on other modding-related features/issues:

Thank you again for all your feedback and suggestions. If you have any questions or would like to make further requests, please discuss them below (or HERE).
 
cool, but when decal paths gonna be fixed? They doesnt work even on native maps, not even on modded ones.

Also what is with tree color customisation, would it be ever possible to change colors of tree trunk and foliage separately?
 
While removing internals, could you please look into this as well? It would make modding menus a lot easier without really affecting your modding standards.Even if you don't remove the internals there, letting us pass a related object would help.
 
@Dejan
Would it be possible to remove the "IsBanditFaction" check condition in the FactionManager class?
All the methods allowing to manage the relation between the factions have this check condition which result in the following:
It is impossible to set the hero faction neutral with any bandit faction.
C#:
        // Token: 0x06000AA1 RID: 2721 RVA: 0x00037308 File Offset: 0x00035508
        public static void DeclareAlliance(IFaction faction1, IFaction faction2)
        {
            if (faction1 != faction2 && !faction1.IsBanditFaction && !faction2.IsBanditFaction)
            {
                FactionManager.SetStance(faction1, faction2, StanceType.Neutral);
            }
        }

        // Token: 0x06000AA2 RID: 2722 RVA: 0x00037327 File Offset: 0x00035527
        public static void DeclareWar(IFaction faction1, IFaction faction2, bool isAtConstantWar = false)
        {
            if (faction1 != faction2 && !faction1.IsBanditFaction && !faction2.IsBanditFaction)
            {
                FactionManager.SetStance(faction1, faction2, StanceType.War).IsAtConstantWar = isAtConstantWar;
            }
        }

        // Token: 0x06000AA3 RID: 2723 RVA: 0x0003734B File Offset: 0x0003554B
        public static void SetNeutral(IFaction faction1, IFaction faction2)
        {
            if (faction1 != faction2 && !faction1.IsBanditFaction && !faction2.IsBanditFaction)
            {
                FactionManager.Instance.GetStanceLinkInternal(faction1, faction2).StanceType = StanceType.Neutral;
            }
        }

I understand it is a default stance you want to keep for the native game.
But in my case I would like to allow the player clan to at least become "neutral" with the bandits.
Maybe you could add a method that could be called by modders?
C#:
        public static void SetNeutralForModders(IFaction faction1, IFaction faction2)
        {
            if (faction1 != faction2)
            {
                FactionManager.Instance.GetStanceLinkInternal(faction1, faction2).StanceType = StanceType.Neutral;
            }
        }
 
@Dejan
I have a small request too, if someone even care at all now.
In the village class there is a property "tradebound" that is supposed to be updated from time to time in the game and is purely economic. But first the game is really buggy on this and secondly i just want to change the behavior to something different, so two good reason to let people access it, but of course if the property is public, the set method is internal.

Code:
public Settlement TradeBound
        {
            get
            {
                if (!this._bound.IsTown)
                {
                    return this._tradeBound;
                }
                return this._bound;
            }
            internal set      // <-------------------------------------------------- this here
            {
                if (this._tradeBound != value && !this._bound.IsTown)
                {
                    Settlement tradeBound = this._tradeBound;
                    if (tradeBound != null)
                    {
                        tradeBound.Town.RemoveTradeBoundVillageInternal(this);
                    }
                    this._tradeBound = value;
                    Settlement tradeBound2 = this._tradeBound;
                    if (tradeBound2 == null)
                    {
                        return;
                    }
                    tradeBound2.Town.SetTradeBoundVillageInternal(this);
                }
            }
        }

I don't remember who said internal should be purely removed from the code and i tend to agree more and more. If it can have someuse for classes, this kind of ... Is just here to annoy and spit at the face of modders. It's like saying "Yeah we wanted to make it private, but if we did we couldn't make the game work, it was above our skills. So we made it internal cause we know it should be public but it's funnier to see you struggle with reflection to have it working, because we are so much better than you AHAHAH".

So yes please, can you remove this internal? And many others that truly have no sense either? And no it's not good coding practice, it's the exact opposite.
Thank you for your time if you read this.
 

v1.1.0 Changes​

Greetings!

Patch v1.1.0 came to Beta last week. Here are the modding-related changes that came with it (apologies for posting with delay).
  • Improved scene checker code (editor side) in order to detect various spawn path placement problems.
  • The map camera implementation was separated from the map screen code for easier modding.
    • In response to the community request by Jansen via the modding discord.
  • A new attribute is_moving was added to the monster usage system. It allows specifying different actions in moving or stationary situations.
  • Enabled the ability to give banner tableaus to armor pieces. This change adds native support for armor pieces to have banner textures. It works the same way as shields, banner bearer items etc.
  • Fixed a bug that caused issues with asset importing if there were two modules with the same id.
  • Fixed SpCultures default xml to throw warnings when it has no cultures defined.
  • Animation clips can now be searched by their flags in the resource viewer.
  • Increased the ModifiedDamage compression info limits from 500 to 2000 and clamped the out of limit damage numbers to the min/max values.
  • AddGameMenu and GetGameMenu are now public.
  • Game menu options can work with related objects.
  • Fixed a crash that happens if the main hero talks with a hero that does not have any proper conversation lines. Now he/she says a default conversation line if proper dialog lines were not added.
We continue to work on other modding-related features/issues:
Thank you again for all your feedback and suggestions. If you have any questions or would like to make further requests, please discuss them below (or HERE).
 
Back
Top Bottom