[SaveEditor] WarBender - savegame editor [released/1.0.4]

Users who are viewing this thread

int19h

Recruit
WarBender is a save game editor for Mount & Blade: Warband.

DOWNLOAD

Features:
  • Allows editing all the data in the save: factions, troops, parties, items...
  • User-friendly editing of troop skills and item modifiers
  • Multi-window interface to see and edit objects side by side
  • Bulk editing (select and edit multiple objects at once)
  • Quick search by name or ID
  • Supports all modules
  • Rich slot metadata provided out of the box for Native
  • Slot metadata is extensible via XML to enable it for other modules
  • Displays sizes in bytes of game objects as stored in the save file
  • Backed by a reusable .NET library with a public API

41222663-6fc53c0c-6d1c-11e8-8633-881255787187.png


41221901-5eba35b8-6d1a-11e8-84d1-2b8f0b0f5eb0.png


As far as module support goes, it can edit any M&B save, but it only "knows" names and types of faction, party, troop etc slots for Native. So for Native, you get the kind of experience that you can see on the second screenshot; it will even show different slots for objects of the same type where appropriate (e.g. village-specific slots only for villages, or marriage-related slots only for kingdom lords and ladies).

If you load a save from a different module, you get an option of assuming the same slots as Native (might give incorrect representation), or assuming nothing and just showing them as raw numbers. However, users (or module authors!) can also provide the description of slots for their module as an XML file, and the app can then load and use those. This is how such XML looks for Native. There's no docs other than the file itself for the time being - more on this will be coming in the future.

 
MnbSaveGameEditor was very useful back when I was playing/testing/Dev mods, so nice to see a new project that is also open source.

For testing mods a suggestion is that you include a tutorial on how to extract (print) values from globals, specific slots (like troop X, slot Y), specific values (like quest state), and so on. That is the sort of thingy that can help debug quicker. Remember most modders don't know any Python.

On working with different modules: tutorial on how to setup the globals and slots constants, so you can have like VC or Floris savegame displaying the correct names (which are not the same as in Native shorter list).

Eventually moderators will move this to the tools section, so no worries there.

Cheers

 
Modding is done with MBScript, so most modders don't need to learn even basic Python. So even a simple concept like a loop will look strange and thus the need for a simple, but step by step, tutorial.

Do keep in mind that modding is on a low phase now, with few mods under development. We are not in 2011 or 2014 anymore, so there won't be that many coders that could use your tool. That said I would think the common use will be to open a save, find some value (flag), edit and save (similar to the older tool), using the GUI (player friendly), so anything you can do to make this process less tech will be a bonus.

Cheers
 
int19h said:
Not sure if this is the right place to post about it; please let me know if it's not!

I have two projects that I've been working on for a while, and I'm getting to the point where it's time to release something and ask for help testing it.

WarBender is a GUI editor that lets you load saved games, edit them, dump them as XML (and load it back), and eventually write them back. It lets you view or edit multiple objects at a time or side by side.

40268587-4ffe4ebc-5b25-11e8-8513-9502c0ce31c3.png


To give it a try, download it from here:
https://github.com/int19h/WarBender/releases/tag/0.1.0

(This should be considered a pre-release of beta quality at this point. Expect bugs! Back up your saves before you run it.)

WarBend is a Python library that backs the GUI in WarBender. If you know Python, this lets you do complicated queries and bulk edit operations on the object graph stored in the save. Example:
Python:
from warbend.game.mount_and_blade.native import *
game = load('sg00.sav')

player = game.troops['player']
companions = game.troops['companions']
lords = game.troops['lords']
kings = game.troops['kings']

# All companions ...
for troop in companions:
    # ... are very strong.
    troop.attributes['strength'] = 20
    # ... have maxed-out skills.
    troop.skills[:] = [10] * len(troop.skills)
    # ... have a masterwork long arming sword.
    troop.equipped_items['item_1'].item_kind_id = ID_items.itm_sword_medieval_d_long
    troop.equipped_items['item_1'].modifiers = module_items.imod_masterwork

# All lords ...
for troop in lords:
    # ... have upstanding personality.
    troop.slots['lord_reputation_type'] = module_constants.lrep_upstanding
    # ... love the player.
    troop.slots['troop_player_relation'] = 100
    # ... hate all kings.
    for other in kings:
        troop.slots[other] = -100

save(game, 'sg01.sav')
There are no releases for WarBend, but you can git clone or download the source from GitHub, and there's a bunch of stuff to play with in samples. I strongly recommend using PyPy rather than stock Python, due to significant performance difference (PyPy is ~3 times faster for this workload - and we're talking seconds here, not milliseconds).
Something that I'm specifically looking feedback on are other uses of the library, beyond the GUI editor. In theory, this can be used to e.g. upgrade saves between different versions of modules, or convert saves from one module system to another. It might also come in handy to debug your module system, but my experience with modding proper is very limited, so I'm not sure.

The incompatability of save games after a module update needs a better work-around. Assuming no item/entity is deleted or renamed in an upgrade, could an old saved game be automatically upgraded where the modder responsible for the upgrade provided module_constants.py and all ID files for the older and newer versions of his module as data inputs for your programs?
 
The incompatability of save games after a module update needs a better work-around. Assuming no item/entity is deleted or renamed in an upgrade, could an old saved game be automatically upgraded where the modder responsible for the upgrade provided module_constants.py and all ID files for the older and newer versions of his module as data inputs for your programs?

I might be confused about what exactly the incompatibility entails (really only ever ran into it with M&B upgrades, where the save format itself used to change - a long time ago). If all items are the same, is the problem basically just newly added items (locations, factions, troops, ...) not being present in the old save? Or are we talking about ID remapping? Also, are there any concerns wrt slots?

Adding missing stuff from the module system into the save can be done, but not always trivial for everything, because of all the dependencies between different structures in places - e.g. if you add a new faction, then size of the "relations" array for every faction also changes. So the conversion script would need to patch those as well. I'm not sure if there really are any other special cases like that though. But mostly it sounds like taking the data from various tables in .py files, and using it to drive the library.

 
Oh, and one question while I'm at it. Where does "dont_load_regular_troop_inventories" come from? I know it's in module.ini in the end, but does that gets generated as part of module build process?
 
That said I would think the common use will be to open a save, find some value (flag), edit and save (similar to the older tool), using the GUI (player friendly), so anything you can do to make this process less tech will be a bonus.

Ironically, the reason why I started working on this is because the other editor didn't have convenient batch edits to do things like "let's see what happens when all lords are upstanding and love the marshal" :smile:

Finding the flag is interesting. I'm thinking if the ability to search nodes in the tree might come in handy. The catch is that it uses internal IDs mostly, not names that players normally see. So you get something like "kingdom_1_lord"  instead of "King Harlaus" etc. The names aren't actually present in the save at all unless the entity was renamed (where it's even possible at all, like with troops). But they can be loaded from module_troops, of course - just means that the needs to be a little bit more smarts about what to get from where.
 
int19h said:
The incompatability of save games after a module update needs a better work-around. Assuming no item/entity is deleted or renamed in an upgrade, could an old saved game be automatically upgraded where the modder responsible for the upgrade provided module_constants.py and all ID files for the older and newer versions of his module as data inputs for your programs?

I might be confused about what exactly the incompatibility entails (really only ever ran into it with M&B upgrades, where the save format itself used to change - a long time ago). If all items are the same, is the problem basically just newly added items (locations, factions, troops, ...) not being present in the old save? Or are we talking about ID remapping? Also, are there any concerns wrt slots?

Adding missing stuff from the module system into the save can be done, but not always trivial for everything, because of all the dependencies between different structures in places - e.g. if you add a new faction, then size of the "relations" array for every faction also changes. So the conversion script would need to patch those as well. I'm not sure if there really are any other special cases like that though. But mostly it sounds like taking the data from various tables in .py files, and using it to drive the library.

I wasn’t envisaging anything as significant as a new faction. M&B converts everything into numbers. So related items/entities are best grouped together to facilitate loop checks - try for range from polearm1 to polearmsend. Inserting a new item into such a list makes saves incompatible as ID files are simple sequence lists, which are regenerated on each compile - every item/entity after a new insert is recompiled with an enum one larger than the previous version. Adding new items to the end of files avoids this problem but makes loop checks etc, problematic. All I was envisaging was ID remapping from a comparison of the ID files plus an adjustment for new slots based on a comparison of the old and new module_constants.py files. Thinking about it, the second part will be pointless without default values to populate any new slots - so that part is probably impractical.

PS an old duscussion on save compatibility:
kalarhan said:
NPC99 said:
I've looked at Warband's save game structure to try to understand what changes break save game compatibility and where placeholders might be useful (assuming the number of related slots aren't changed).

1. Global variables - only the number appears to be held, suggesting placeholders could work with some dummy code to avoid unused warnings.
2. Triggers & Simple triggers - placeholders appear impractical as the timer details are held in the save game file.
3. Quests - uncertain if placeholders would be of any value - details held may only be populated once a quest is initiated.
4. Info pages - I doubt these change often enough to worry about.
5. Sites/Scenes - placeholders with dummy sco files appear possible, but I'm uncertain whether they would prove useful for new towns or castles due to the numbers required.
6. Factions - placeholders appear possible (with some way to change saved relationships), but pointless as existing factions would have already carved up the saved map
7. Party templates - placeholders appear possible.
8. Parties - placeholders appear to only be practical for static parties where the initial position can be predicted as this will be fixed in the saved game file.
9. Troops - troop placeholders may avoid breaking a saved game, but seem pointless as the skills, proficiencies, level, equipment etc. appear to be fixed in the saved game to that specified in the dummy placeholder, which will be wrong when such troops are subsequently spawned.
10. Items - item placeholders appear possible provided their item flags can be predicted/pre-set

Unless I'm missing something, placeholders might avoid game crashes, but can't allow the new troop/item to feature properly in an old game. How do other mods build save game compatibility into their upgrades?

being awhile since I cared about savegame compatibility, but to add to your list above. In general you can't add stuff in the middle, unless you have a placeholder, and some files will crash if you add anything new (like a new trigger).

1) you need to copy the variables.txt from your folder before doing a new compilation. This way it will keep the same order for old variables, and it will add new ones at the bottom of the list. If you don't, it will create a new list on alphabetic order. As the savegame uses that order (and not the name) to read the globals, any change will mess with your game.

2) triggers need to be kept on the same ID (order). You can use placeholders at the end of the file with a short timer like 24hours, and re-use them in the future. When you change the timer, it will eventually update the savegame (in this case, within 24 hours)
  a alternative is to use generic triggers (0, 1, 6, ... hours) and call scripts from them. Put those scripts inside try_block so any condition you have won't affect the others. If your new code is not performance heavy, you won't notice any lag or issues.

Code:
(24, 0, 0, [
   ],[

  (try_begin),
    (eq, condtion_test, 1),
    (call_script, "script_stuff_for_this_condition"),
  (try_end),

  (try_begin),
    (eq, condition_test2, 1),
    ....
])

3) you need to keep the ID. VC had a problem with this, so if you check their code you will notice several blank quests used in their code. A clean way to use placeholder is to replace the name with a custom variable on your code
  instead of using "qst_blank_quest_30", you could use a constant QUEST_MAYOR_STONE on dialogs, scripts, etc

5 8 ) remember to update any slots for towns, etc
    also depending on what you add, only new saves will see them (like VC and the new locations for RE edition)

6) you could add new areas to the map, etc, and make it compatible with old saves.

9) problematic for sure, altho you can update a troop with code (some of the stats), so you would need to plan ahead. I am not sure which operations you would have for F&S tho.

See trigger below (VC code) for a example of the things they had to do to keep updating old files.
Code:
    #game load trigger(165)
    (ti_on_switch_to_map, [

in general to keep saving compatility is more of a hassle than its worth. You shouldn't worry about it while on heavy development (instead create quick code and templates for testing), and later one if you have a big update just call it a new version (1.0 to 2.0) and break the saves  :mrgreen:. VC had/has to keep them working, a modder doesn't have that restriction.
 
int19h said:
Oh, and one question while I'm at it. Where does "dont_load_regular_troop_inventories" come from? I know it's in module.ini in the end, but does that gets generated as part of module build process?

Module.ini doesn't interfere with modsys. It is loaded directly by the game engine, like the other .txt files, and the flags logic is hardcoded inside the .exe code.
 
Looks very promising. Any chance you could let it present more details? For example, the troop flags are just shown as a couple of digits. It would be good to know which troop flags are present (for instance tf_male/tf_female/other "gender" /tf_hero/tf_inactive/tf_guarantee_XXX etc. Having those flags shown with their respective value would really help.
 
While we're at it, here are some non-obvious features in the editor.

To enable multiple selection in the tree, use the button right below it on the status bar to show selection checkboxes.

The arrow in the top right corner of the property editor (under Close button in the screenshot above) opens the same selection in a separate editor pop-out window. Every such pop-out tracks its selection separately, and does not follow whatever is selected in the tree. This lets you open different objects and compare or edit them side by side.

When multiple selection is enabled, or when objects are opened in a pop-out, there's a list of objects opened in the property editor, at the bottom. Those are clickable, and will select the corresponding node in the tree. They can also be middle-clicked to remove them from that pop-out, and there's a button to remove all of them.

You can drag tree nodes, and drop them onto property editors, to add them to selection that's being edited by that particular property editor. You can also drag an object from one pop-out, and drop it onto another.  This lets you use pop-outs to easily track objects from different parts of the tree when you need to quickly switch back and forth between them (by clicking the object names in the list at the bottom of the pop-out).

When multiple objects are selected, the property editor will only show properties with the same name (or, for arrays, items with the same index and name) that exist for both objects. For matching properties, value is only shown if it is the same for all selected objects, otherwise it's blank. However, you can still edit it even when blank, and the new value will then be applied to all selected objects. So e.g. you can select all companions, and edit some skill to be 10 for all of them, even if they had different values for it.

Note that if you select multiple objects that have no properties/items in common (say, a faction and a troop), you will get a blank property editor, by design.
 
So, I decided to do another take on another take with this.

The original design was somewhat problematic, because I didn't properly understand what belongs to the game itself, and what belongs to the modules. The choice to use Python was also wrong in retrospect - it makes it easier to reuse constants from the module system, but the performance was atrocious, and the app needs Python to do anything. I didn't really make the library with UI in mind, and it shows.

Anyway, here's take two - it's a rewrite pretty much from scratch. This time, it's all .NET, so it's much faster (as in, load a save in under a second). Most of the stuff it needs to know about the module, it reads directly from .txt files. Module-specific stuff like slots that's not stored in the final module representation is described by XML that looks like this, and lets you do some fairly powerful stuff, like defining different slots for different objects (e.g. slot_village_state only makes sense for villages, while ladies and lords have different relationship slots); I think I got everything I could glean from the scripts for Native there. Without XML for the module, or if you use the wrong one, you'll just get wrong slot names and/or types where they don't match.

The UI is reworked quite a bit to make it more uniform, too - now it's an MDI app with tabs. The biggest change from the old one, though, is fast text search.

Download here

41222663-6fc53c0c-6d1c-11e8-8633-881255787187.png


41221901-5eba35b8-6d1a-11e8-84d1-2b8f0b0f5eb0.png


(I reused the repo name on GitHub; if anyone still cares about the old one for whatever reason, it's at https://github.com/int19h/WarBender1).
 
the tool is growing quite nicely, well done.

A few suggestions:

1) Update your OP (original post, the first in this thread) with the latest info, including screenshots and download link. People will download the old/wrong one as they tend to check just that hehe
  -> moderators will soon move this thread to the tool section as well, so a clear OP helps a lot

2) Include a short tutorial on how to add support to other modules. The files to edit, how to find them, etc. A simple thingy like the .xml file is actually on this XXXX.xmmx file (as most people will not connect them to the same thingy).

3) Include any future plans (if any), a note about the tool stability, etc,

4) A clear note about if people can include profiles to their modules now (you wont add changes that would break their .xml config files)

5) Update your thread title. Something that catches the eye and helps with search function. Example: "[Tool][SaveEditor]Warbender - save game editor [Released/1.0]"
 
Thanks, all good advice! I've updated the post with new links and screenshots.

I'll need some more time to sit down and write some decent docs for .wmmx XML authoring (for the curious, .wmmx stands for WarBender Module Metadata XML). Probably starting with some comments in the file itself, since the way I'd expect it to be done for most modules is by taking Native.wmmx and changing as necessary.

On the subject of XML format stability - maintaining it would be easy, but I think it would be worthwhile to get some feedback on the format, and how well it works to describe real-world modules, so that I can make any necessary breaking changes before committing to stability long term. I'm fairly confident that what's there works fine for Native, and hopefully that also translates to others... but just to be sure.
 
int19h said:
some feedback on the format

I will put on my list to create a profile for VC, likely on this weekend (my free time is taken by World Cup this week hehe, too many good games to watch).

Cheers
 
kalarhan said:
I will put on my list to create a profile for VC, likely on this weekend (my free time is taken by World Cup this week hehe, too many good games to watch).

Awesome!

I've added some comments to the .wmmx file to explain what's going on there. There's also py2wmmx.py, which is used to generate those slot definitions from module_constants.py (it can't just spit out .wmmx automagically, but it takes care of the most tedious part of authoring it) - this now has a comment explaining how to use it, as well.

The new 1.0.1 release includes those updated files, and a few small changes and fixes that have accumulated since the first release.
 
Back
Top Bottom