Background
I created a rudimentary mod kit for the game Battle Brothers that allows editing the encrypted Squirrel scripts (.cnut files) within the game. Since almost the entire game is implemented in script, this allows tremendous flexibility for modding. It started when I wanted to know which character backgrounds were best to hire in a "value for money" sense. There was a spreadsheet that the community had painstakingly created over the years based on hundreds of manual tests showing the typical stat ranges of various backgrounds, but it was invalidated by the Beasts & Exploration DLC which rebalanced various parts of the game. I wished I could just take a look at how characters are generated, but like many people trying to peek under the hood I soon saw that the scripts are shipped only in a compiled form, and not only that but they appear to be corrupted or encrypted.
Accessing the files
Before we can start messing with the game data files, we first have to know where they are. If your Battle Brothers installation directory is bbros, then the data files are stored within bbros/data/. Within that directory you'll see files named like data_001.dat. These are actually .zip files, and if you rename it to data_001.zip you'll be able to open it. Images, sound effects, etc., are not encrypted, so you can examine them. (Don't be tempted to modify them inside the .zip file, though. See below for how to make changes.) The scripts are the .cnut files, but if you open them they just look like garbage.
Encryption and decryption
The "corruption" in the compiled scripts is actually an unusual encryption algorithm that encrypts only bits and pieces of the files, making them look like normal compiled scripts at a glance, but preventing them from actually working if you try to run or examine them. After painstakingly reverse engineering parts of the game, I was able to decipher the encryption algorithm. I spent quite a long time discovering how it worked and then a while longer translating the cryptic instructions into C code that I could run. Only after I was done did I realize that one of the constants in the algorithm is well-known, and that the core cipher is XXTEA.
But like I said, only parts of the file are encrypted. The encryption algorithm is unusual in that the format of a Battle Brothers encrypted .cnut file cannot be described in a stand-alone way since it's intimately tied to the internal implementation details of the Squirrel script engine. Specifically, the Squirrel API calls to parse a compiled script take a reader callback function, which gets called with a buffer and a number of requested bytes, and the function is supposed to read those bytes from the application's storage. Basically, it's a byte-oriented stream interface. Now, where it gets tricky is that the game only decrypts runs of 8 or more bytes requested through that stream interface, and it doesn't keep any state between invocations. If the Squirrel engine changed to break one read into two, or to combine two reads into one, or even just changed the size of any encrypted read, the file format would effectively change. So, to be safe, you should use the same version of Squirrel as the game. At the time of writing, this is 3.0.4, but I've also tested with 3.0.7. Also, only multiples of 4 bytes are encrypted, so a 15-byte read has the first 12 bytes encrypted and the last 3 bytes unencrypted.
So, without further ado, here's how you'd go about decrypting a Battle Brothers .cnut file:
// the standard XXTEA block cipher algorithm #define DELTA 0x9e3779b9 #define MX(p) (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (key[((p)&3)^e] ^ z))) void decrypt(uint32_t *values, uint32_t count, const uint32_t key[4]) { uint32_t rounds = 6 + 52/count, sum = rounds*DELTA, y = values[0], z; do { uint32_t e = (sum >> 2) & 3; for (uint32_t p = count-1; p; p--) { z = values[p-1]; y = values[p] -= MX(p); } z = values[count-1]; y = values[0] -= MX(0); sum -= DELTA; } while (--rounds); } // the key used by Battle Brothers static uint32_t bbkey[4] = { 238473842, 20047425, 14005, 978629342 }; // the Squirrel reader function SQInteger read_encrypted(SQUserPointer file, SQUserPointer buffer, SQInteger length) { length = file_read(file, buffer, length); // read the data from the file if (length >= 8) decrypt((uint32_t*)buffer, length / sizeof(uint32_t), bbkey); return length; } ... sq_readclosure(vm, read_encrypted, file);
To encrypt a file, you can't simply do the analogous approach of using a writer callback function to encrypt all blocks of 8+ bytes, since the Squirrel writer doesn't invoke the callback for the same offsets and lengths as the reader, which is needed for the two to match. (And even if they did match, there's no guarantee that it would stay that way.) So, I implemented encryption using a reader function as well, so you read the file that you want to encrypt, and as a byproduct of reading it the file gets encrypted.
void encrypt(uint32_t *values, uint32_t count, const uint32_t key[4]) { uint32_t rounds = 6 + 52/count, sum = 0, y, z = values[count-1]; do { sum += DELTA; uint32_t e = (sum >> 2) & 3, p; for (p = 0; p < count-1; p++) { y = values[p+1]; z = values[p] += MX(p); } y = values[0]; z = values[count-1] += MX(p); } while (--rounds); } SQInteger read_and_encrypt(SQUserPointer file, SQUserPointer buffer, SQInteger length) { length = file_read(file, buffer, length); // read the data from the file if (length >= 8) { // encrypt the file in place. you could also write the changes to a separate file encrypt((uint32_t*)buffer, length / sizeof(uint32_t), bbkey); // encrypt the data file_seek(file, -length, SEEK_CUR); // seek back to the start of the block file_write(buffer, length); // write the encrypted bytes back to the file file_flush(file); // some C file APIs require a flush when switching from write to read // decrypt the data again so we don't return garbage to Squirrel decrypt((uint32_t*)buffer, length / sizeof(uint32_t), bbkey); } return length; }
Decompiling a script
Now we can decrypt a script file, but it's still in compiled form, so we can't easily edit it. To decompile it, I recommend using NutCracker. I actually don't like that decompiler, because the output is incorrect. It has numerous bugs, some of which I've fixed, and is more verbose than it needs to be. It also doesn't preserve all the information from the .cnut file, so if you decompile a file with NutCracker and then recompile it, the result will not be the same as the original. It still seems to work when loaded into the game, though.
Because of those problems, I wanted to write my own decompiler. I'm sure I can create a better one than NutCracker, but my free time is limited so I probably won't do so unless there's a real demand. The problems above are not fatal, since Battle Brothers is capable of loading plain-text scripts (for the most part) and most scripts decompile correctly. A few scripts don't, though, so be careful.
Anyway, here's an example of how to use NutCracker to decompile a script. By default it prints the script to the console, so you simply redirect the output to a file. (The NutCracker author doesn't distribute binaries for the decompiler, but a binary is included in my mod kit.) From a command-line:
nutcracker decrypted.cnut >decrypted.nut
Getting a modified script loaded by the game
Lets say you decompile scripts/items/weapons/knife.cnut, which starts like this:
this.knife <- this.inherit("scripts/items/weapons/weapon", { m = {}, function create() { this.weapon.create(); this.m.ID = "weapon.knife"; this.m.Name = "Knife"; this.m.Description = "A short knife, not made for combat."; this.m.Categories = "Dagger, One-Handed"; ...
Just for a test, you change "not" to "totally" within the description. Now how to get the modification back into the game? The most convenient way is to just use the plain-text script. For many scripts (including this one), the game will prioritize a plain-text script named "foo.nut" over a compiled script named "foo.cnut" in the same directory, so you could drop the plain-text script into the directory with the .cnut file. But to be sure you can recompile the .nut file using the standard Squirrel compiler (sq.exe) into a .cnut file and then reencrypt it using the mod kit.
You could simply insert the file into the data_001.dat archive, but that's a bad idea, because your modification may cause file corruption if the game is patched, and any game update would undo your changes. We want the game to load the base data and your modified version. Thankfully, the game uses the PhysFS filesystem abstraction library, and configures it in such a way that the game will load files from subdirectories of the data directory as well as files from the .dat archives. So you could actually place your modified knife.nut (or knife.cnut) file in bbros/data/scripts/items/weapons/ and it will take precedence over knife.cnut from the data_001.dat archive. This is good for testing, but is not a good solution for mods in general because it makes it hard to combine multiple mods. (Their files would be all mixed together.)
A better way is to simply package your mod into its own .dat file. Since the .dat files are really .zip files, just create a .zip file with the scripts/items/weapons/knife.nut file inside and place it in the bbros/data/ directory along with data_001.dat. (It's not necessary to use the .dat extension.) The important thing here is that mods get loaded after the base data, and I believe this happens based on the file name. Since 'm' sorts after 'd', naming the archive "mod_knife.zip" hopefully ensures that it gets loaded after the file named "data_001.dat". If order among mods is important (to resolve some conflicts), you could tweak the names to get the right ordering.
Coding guidelines for better mods
Now we can mod the game, but mods created as above will not play well together either with other mods or with future official updates. The reason is that you are overwriting entire files rather than just tweaking the bits you want to change. If an official update changes the file, your copy won't have the update unless you recreate your mod based on the latest official version. And, two mods that update the same file will overwrite each other's changes even if the changes don't conflict. So, we need a way to express the changes relevant to us without duplicating the rest of the file. Consider the following script.
local super = this.knife.create; this.knife.create = function() { super(); this.m.Description = "A short knife, totally made for combat."; }
Something like this would allow us to change just the description while keeping the rest of the knife code the same, and we could put this script into its own file rather than overwriting the base knife file. The difficult part is getting this code loaded at the right time. By placing your file in a folder named !mod_mymod you can make a script load before most others, and by placing it in a folder named ~mod_mymod you can make it load after most others, but neither of those work in this case. That said, I did create a small mod called "modding script hooks" that allows something like this:
::mods_hookNewObject("items/weapons/knife", function(obj) { obj.m.Description = "A short knife, totally made for combat."; });
On a side note, any sizeable mod will have to deal with official updates. You wouldn't want to redo your mod from scratch after each official update, nor would you want to continue to use outdated script files in your mod. The solution here is to set up version control. Extract the game data, decompile the scripts, and put it into a Mercurial or Git repository. Create a branch for the mod and edit your mod in the new branch. After each official update, switch back to the main branch, extract and decompile the game data again, and check in any changes. Then merge the changes into your mod branch. This way you keep your mod up to date with official changes without having to redo it from scratch. Also, the repository should of course just be on your local disk. Don't go putting all the game files up on GitHub. This also helps if you need to merge multiple mods together due to conflicts.
The mod kit
I packaged together a few tools into a very basic mod kit to get people started modifying the scripts for Battle Brothers. See the README.txt file within the package for details.
Download: bbros.zip (874kb) Version 9 - released February 12, 2019
Changelog
- Version 1, January 20, 2019 - Initial release
- Version 2, January 21, 2019 - Attempted to fix a serious bug in NutCracker. I'm not sure if the fix is correct. Hopefully the author will make an official fix.
- Version 3, January 22, 2019 - Attempted to fix another bug in NutCracker.
- Version 4, January 23, 2019 - Attempted to fix another serious bug in NutCracker.
- Version 5, January 26, 2019 - Added a program (bbrusher) that can unpack and repack the game's sprite sheets
- Version 6, January 27, 2019 - Fixed two more serious bugs in NutCracker
- Version 7, January 28, 2019 - Expanded the types of sprites that can be added with bbrusher. (Should be all types now.) Made Nutcracker's floating point output prettier. Added a masscompile.bat tool.
- Version 8, February 3, 2019 - Fixed four more serious bugs in NutCracker
- Version 9, February 12, 2019 - Improved Nutcracker's handling of non-ANSI strings by using UTF-8
Postscript
So in the end, I got my updated character backgrounds spreadsheet. :-) I wrote a program to scan the script files and make a spreadsheet out of it. I guess that's mission accomplished!
Comments
you hab changed the construct of the universe for generations to come.
However you have wrote instructions at a high-level skilled programmers voice.
Are you able to dumb down the words in the Battle Brothers mod kit for us without the proper training?
Thank you and still can't believe you mod Sid Meiers Pirates game one of my favorites.
Wish we can get attacked by pirate hunters a full fledge fleet like maybe 1-3 ships trying to sink you or something.
On those lines with Pirates! I remember I was once working on a mod to allow you to have up to 4 ships in combat. (The enemy could also have up to 4 ships.) I never finished it but it would have been interesting...
http://www.hookedonpirates.com/forums/viewtopic.php?t=6771
Then there's this craziness:
http://www.hookedonpirates.com/forums/viewtopic.php?p=91296#91296
Fun times. :-)
There's already some support you could latch on to, since the game has different head, body, and sound sets for the different races, and also for subsets like "old men", "smart men", "tidy men", "untidy men", etc. Women could just be another race or perhaps a different subset of humans. You also wouldn't have to lose any of male art by overwriting it. It could be in addition.
Anyway, I'm looking forward to seeing what you can make. :-)
bbsq.exe -d orc_trophy_item.cnut a.nut
File a.nut had error the index 'std_stream' does not exist
Any idea how to get it working? Btw you are incredible for getting this done. Thank you
I'll be able to do so much with the knowledge you've posted here, although those bugs you've found in the decompiler are like landmines in the path of any large mod. This is more progress than any modder has made before you.
Many won't be able to follow in your footesteps though, so if you're willing to do more work on this I'm happy to offer whatever support i can to help you. The complexity of this solution greatly limits how many modders will able to try it out.
I have heard many people say they would pay for mod support on this game, including myself. We can get a patreon or crowd funding campaign going if you're interested. I would personally be willing to pay your hourly rate directly to work on this if it got us to a single UI mod tool, or even a better decompiler
bbsq.exe -d orc_trophy_item.cnut
nutcracker orc_trophy_item.cnut >orc_trophy_item.nut
Note that since you already ran bbsq.exe it's already been decrypted. Running bbsq.exe a second time will corrupt it. So you'd best start with a fresh copy of the .cnut file.
I think I fixed the major bug I found in NutCracker, so I hope we are good to go. There are other bugs, though... I hope the author patches them, or else I might have to do it.
I'm not sure what you mean by a "UI mod tool". Theoretically you can do everything with the mod kit I posted, but I realize it can be a pain to edit scripts and HTML and CSS by hand. I suppose one could create a UI tool to let people edit simple things like item stats and character backgrounds. That wouldn't be hard. But any serious mod will probably have to proceed by writing code...
Thank you very much for these mod tools. This is fantastic. Already knee deep into the code with some ideas I've always wanted to do.
Again, greatly appreciated!
Any chance you have been able to get the log file statements in the scripts to print out to file? So far no luck.
first of all Thx a bunch for all the effort you put into this. Finally seeing some mod support was hell of a good news for me today ;)
I tried to follow your Guide to get into all this but unfortunally it didnt work out for me.
I became kind of stuck on point 4 of your suggested workflow in the Readme.txt.
I have all the ".nut" files ready in clear text by using the "Massdecompiler.bat" and for a simple testing purpose i just wanted to creat a modiefied "knife.nut" and change the description of the knife just as you have stated it in your example.
I modified the knife.nut file and placed it in my installation folder that looks now like this:
<InstallationFolder>\Data\scripts\items\weapons\knife.nut
The actually file that i used for the test is this:
https://nofile.io/f/jPU3UFEfo1r/knife.nut
Problem is, when i start a new game, im stuck in the loading screen. Waited 10min+ but nothing. No error massege visible. It just wont load the game.
I tried a different approach by packing the folder into an zip archive named data_005.dat but in this state the game wont even launch at all.
Im running the 1.2.0.25 GOG version of the game with Beats&Exploration DLC installed if this matters but i think i clearly miss somthing here.
Any kind of help would be much appriciated.
im desperete to get starting on that stuff. ;)
But for now saying Thx again and keep up the great work !
If the NutCracker author doesn't fix it soon, I will fix it myself.
Also I have some questions: lots of scripts start with a list (or tuple?) named "m" to define some constants. For example:
this.asset_manager <- {
m = {
Stash = null,
OverflowItems = [],
CampaignID = 0,
Name = "Battle Brothers",
Banner = "banner_01",
BannerID = 1,
Look = 1,
...
How can I modify those values other than making a copy of the entire file?
Thanks a lot for your time and critical insights.
As for how to modify them without making a copy of the entire file, see my example for the knife above. If you can get it to load at the right time, you can modify them without copying the file.
this.asset_manager.m.Name = "Battle Dudes"";
When I compile an edited .nut file and then decompile the resulting .cnut file I notice there are a few issues. Besides the floating point one, it throws away iterator increments
- for( local i = 0; i != this.Const.Attributes.COUNT; i = ++i )
+ for( local i = 0; i != this.Const.Attributes.COUNT; i = i )^M
im not that much of a coder myself but i think i see what the problem was here.
im from germany and this is absolutly not the first time i ran into problems with the "," and "." seperators when it comes to modding stuff so thanks for your explanation.
I also testet your Version 3 of the ModKit and as far as i can tell everything works like a charm now ;)
Guess i can now stop to hunt down and correct those floats manually in every script i wish to modify. That makes life a little easier over here :)
You might be interested to see one of the developers positive response to the mod-kit.
https://www.reddit.com/r/BattleBrothers/comments/ainxfh/i_asked_the_battle_brothers_devs_what_they/
Now, is it actually changing the logic or just changing the style? What is "lost" in your example? You said it moves the update to the end of the loop, which might be okay.
for(local i=0; i<10; i++) { body; }
for(local i=0; i<10; i = i) { body; i++; }
These are equivalent, as long as 'body' doesn't have a "break" or "continue" statement in it.
Anyway, please contact me by email and give me an example.
Any help or should I resign myself to the fact an unofficial modkit for a Windows only game isn't going to be running on Linux?
"bbsq -d whatever.cnut" doesn't do nothing. It decrypts the file. It simply doesn't print anything in the success case. "Error: accessing not valid stack variable" from NutCracker indicates that the .cnut file is corrupt, either because you didn't decrypt it, or because you decrypted it multiple times, or something like that.
Try starting with a fresh .cnut file taken from the game's data file, and run these commands:
bbsq -d foo.cnut
nutcracker foo.cnut
It should work.
As for getting the mod kit running natively on GNU, it is entirely possible. The source code is included, but you'll have to compile it. bbsq and sq should compile without much difficulty. Follow the instructions from the Squirrel project. bbrusher is a .NET executable so you can run it directly under Mono without recompilation. The two .bat files could be replaced with bash scripts.
::mods_hookNewObject("entity/tactical/player", function(o) {
o.getHiringTalents = function()
//copy the code from original mod
});
::mods_hookNewObjectOnce("ui/global/data_helper", function(o) {
o.convertEntityHireInformationToUIData = function( _entity )
//copy the code from original mod
});
However the games says: Script Error
the index 'getHiringTalents' does not exist
Could you tell me what's the problems in my code? Thanks a lot.
Thank you for all the hard work on this!
What do you use to compress the modified scripts after editing and encrypting them again? I have not been able to get anything to work in the game. I even tried compressing a mod I made no changes to, just extracted the files and then compressed them again, and the mod won't work.
Any help is greatly appreciated!
cd C:\Users\Besitzer\Desktop\bbros\bin
followed by:
bbrusher unpack C:\Users\Besitzer\Desktop\data_001\gfx\ui.brush
and its telling me that the "ui.brush" cant be found
im aiming at the ui.png sprite sheet - cant figure out why its not working even with the manual
bbrusher unpack C:\Users\Besitzer\Desktop\data_001\brushes\ui.brush
Do you have any idea what's the possible reason for such behavior? Thanks.
Here is how I used the hook:
local setStartValuesEx = function( _backgrounds, _addTraits = true )
{
//copy the original function here but set maxTraits = 2
}
::mods_hookClass("entity/tactical/player",
function(o) { ::mods_override(o, "setStartValuesEx", setStartValuesEx); });
function start( _event )
{
local roster = this.World.getTemporaryRoster();
_event.m.Assassin = roster.create("scripts/entity/tactical/player");
_event.m.Assassin.setStartValuesEx([
"assassin_background"
]);
this.Characters.push(_event.m.Assassin.getImagePath());
}
It is actually pretty similiar to the code that generates bros in town, which is defined in scripts\entity\world\settlement.nut and listed as below:
while (maxRecruits > current.len())
{
local bro = roster.create("scripts/entity/tactical/player");
bro.setStartValuesEx(draftList);
current.push(bro);
}
Personally I can hardly see what's the difference between those two. Also, by adding a debug line to write some warnings in log, it seems that the script I made (in previous post) is actually not executed when the event is triggered.
Recently, I found that the masscomplie.bat makes an error whenever I try to complie (the original 1.3.0.25 ver) event/dlc2/location/kraken_cult_enter_event.nut and event/dlc2/location/witchhut_destroyed_event.nut.
Could you check whether it is a bug or not?
Thanks!
Could you allow us to integrate your 'Weighted Talent' Mod to the legend Mod? I tried to make one myself but it turns out buggy and I cannot fix it.
I'm running into an issue with trying to unpack sprites using bbrusher. Every time I try unpacking the entity_#.brush files I receive an error stating "ArgumentException - Parameter is not valid." I've tried unzipping the .brush file from the dat file, I've tried unpacking it from the dat file itself, I've tried specifying a directory to unpack to, and nothing seems to be working.
Any ideas on what might be going on? Thanks!
I'm running into an issue with a mod i made, i really don't know why this "Script Error the index 'isStacking' does not exist" kept appearing.
Maybe you could give me some advice to fix this.thanks!
C:\Users\Admin\Desktop\Modkit\bin>bbrusher unpack C:\Users\Admin\Desktop\Brushes\entity_6.brush
I receive an error stating "ArgumentException - Parameter is not valid." every time
Can you help me to solve this? Thanks!
D:\code\bbros>bbrusher unpack data\brushes\entity_6.brush
Opening gfx/entity_6.png...
entity\bodies\southern\bust_body_southern_01.png
entity\bodies\southern\bust_body_southern_01_damaged.png
entity\bodies\southern\bust_body_southern_01_dead.png
...
What is the structure of your files? Do you have the gfx\entity_6.png file in the appropriate place?
Thank you for making such amazing tools.
I tried it and found it very useful for understanding this game.
But I hit a crash when I copied skills.nut to BBGame\data\scripts\skills folder, even remain it unchanged.
The crash dialog said "ID mismatch while deserializing script data."
How to solve it? Does it mean I cannot change some of scripts? I can change files in senarios and it works well.
This could be a very stupid question but I want to seek some light from you.
Thanks!
In the last version of BB (.47) I can't decompile cultist_origin_vs_old_gods_event, it always causes "Error: bad conversion" no matter how many times I re-run the decompiler.
In the past I had a similar issue with one of Legends files until it turned out that that file contained the following symbol: ’ - which looks like an apostrophe but isn't and as soon as it was replaced, the filed started decompiling properly. So maybe the issue with cultist_origin_vs_old_gods_event is similar.
Also I frequently have completely random "Error: bad conversion" errors: like, roughly speaking, I run the decompiler for 100 files 10 times and every time it bugs out 1-2-3 different files.
Is there any random code in the decompiler? like, some random bruteforcing or something? if so, it may have an error somewhere.
Anyway, that was just a minor bug report, and thank you for the modding tools!
That said, I don't think there is any random aspect to the decompiler. In all the other cases when I've seen people report such "random" decompilation failures it's been because they have messed up the encryption. It's possible to decrypt twice or encrypt twice or fail to decrypt and get things messed up.
Sorry that I don't have any immediate fixes for you.
-- Adam
Regarding random corrupted files - let me explain the situation again.
For example, I download the new Legends build, unpack it and run the following command: massdecompile.bat H:\legends_scripts\scripts\events
Say, the events folder has 200 files.
1st launch - files #10, #44 and #156 are broken, everything else decompiled properly.
2nd launch - files #27, #91 and #199 are broken, everything else decompiled properly (including those that failed to decompile on the first try).
3rd launch - files #37, #57, #87 and #107 are broken, everything else decompiled properly.
Etc.
Every time I rune massdecompile.bat on the exact same large enough folder, a few files inevitably break and every time it's completely random different files. And every time files that broke before decompile without issues (with the exception of permanently bugged files like cultist_origin_vs_old_gods_event.cnut, ofc).
So in the end I have to decompile the whole Legends archive in small portions - small enough to only trigger 1-2 broken files, then I search for all cnuts in this subfolder, delete them all except for the ones that still need to be decompiled to fix broken files, run the decompiler again and only then move on to the next subfolder.
Does no-one else have this issue?
The error that appears in the cmd for each broken file is the following: "File ~tmp.cnut had error the index "std_stream" does not exist".
As for that cultist file - thank you for the offer, but no, I'm neither good enough to understand assembly code nor do I really need that file. It was just a bug report in case you decide to take a look at it and patch the decompiler.
As for the cultist file, in my previous message I did describe how it can be decompiled successfully, just in case you do want to look inside.
Thank you for the nice tools. You seem quite proficient at Squirrel scripting. I was trying to find a way to interact with other processes from Squirrel as it is in Battle Brothers.
Usually in Squirrel you have the file class to read/write to files. Also there is the system(cmd) function to start another process. Unfortunately, in Battle Brothers they seem to be missing.
Do you know any way for two-way communication with external processes?
The Squirrel system in Battle Brothers is restricted. As you noticed, it is missing the I/O and process libraries, etc. I can think of a couple ways to achieve two-way communication with another process, but not nice ones.
First, modify the Battle Brothers executable to add new features. I imagine the executable doesn't change very often and pretty much all recent changes are implemented in Squirrel script, so an .exe patch might be stable for a while, but it's still a complicated task to create.
Second, establish a shared-memory communication channel based on a Squirrel array. For example, if you create an array and fill the first few elements with a signature that another process can find by scanning through the memory space, you can find the storage for that array. Then, the processes can communicate by reading and writing the elements of the array according to some protocol. That said, there are some dangers and/or difficulties, depending on whether Squirrel has a garbage collector that can move memory around. (If not, this could be pretty reliable.)
in your "masscompile.bat",
just one more "&" like:
sq -o "%%~dpnf.cnut" -c "%%f" && bbsq -e "%%~dpnf.cnut
but not:
sq -o "%%~dpnf.cnut" -c "%%f" & bbsq -e "%%~dpnf.cnut
then maybe it will run rightly...
i guess since i search some advice about "how to run order after another only when the first order run successfully" on the internet.
Amazing bit of kit! Thank you very much for your efforts.
I followed your instructions above to rewrite the batch scripts as bash scripts and was able to run everything nicely using wine on Gnu/Linux.
Thank you for making such great tools.I'm sorry I only discovered this tool now.I just learned how to create mods. When I repackaged the brush file, the console reported an error of "unauthorizedaccessexception access to the path is denied". I tried to give all permissions to the folder in the security tab, but this error still occurred.
May I ask how to solve this problem? Thank you very much for your help.
C:\Nerv\Game\Battle Brothers v1.5.0.15\download\bbros\bin>bbrusher pack huoshou_2.brush C:\Nerv\Game\Battle Brothers v1.5.0.15\download\bbros\bin\huoshou_1
Usage: bbrusher unpack [<options>] <file.brush> [<outputDirectory>]
Unpacks all sprites from the image referenced by file.brush into the given
output directory. If the output directory is not specified, it will be named
based on the brush file and created in the current directory.
Usage: bbrusher pack [<options>] <file.brush> <inputDirectory>
Packs all PNG images from the input directory into a sprite sheet and
creates the file.brush file describing the sprite sheet. The input directory
must contain an appropriate sprites.xml metadata file describing the images.
Options:
--gfxPath <directory>
Specifies the name of the directory where the sprite sheet image should
loaded from or written to. If omitted, the parent of the directory
containing the brush file will be used.
C:\Nerv\Game\Battle Brothers v1.5.0.15\download\bbros\bin\huoshou_1
But because of the spaces, it is being interpreted as three arguments: "C:\Nerv\Game\Battle", "Brothers", and "v1.5.0.15\download\bbros\bin\huoshou_1".
In general, command-line arguments are separated with spaces. If you have an argument with spaces in it, that argument needs to be quoted to let the shell know that it is just one argument and not multiple arguments. (This is not specific to bbrusher, but is a general feature of command lines.)
In short, you need to write this:
bbrusher pack huoshou_2.brush "C:\Nerv\Game\Battle Brothers v1.5.0.15\download\bbros\bin\huoshou_1"
I hope that helps.
-- Adam
Do I pack them into XYZ.brush with "pack [<options>] <file.brush> <inputDirectory>"?
Will that create a huge entity_0.png sprite sheet in GFX folder or do I need to create/edit those manually?
Thanks
Both give the same error:
Opening gfx/<file>.png...
ERROR: ArgumentException - Parameter is not valid.
https://imgur.com/a/0V4ElvO
Tried official game files and mod brush files, same error. I'm giving up for now. Got the massdecompile.bat to work just fine so ¯\_(ツ)_/¯
function getTooltip()
{
local result = this.helmet.getTooltip();
result.push({
id = 6,
type = "text",
icon = "ui/icons/vision.png",
text = "Allows the wearer to see at night and negates any penalties due to nighttime."
});
return result;
It always crashes on me. Is it because of the 'local'? Functions like this one are very common, so figuring out how to substitute the text in it would be excellent. I'm also curious if I should write all the hooks for every item in one .nut file.
Sorry if this is a dumb problem, this is my first time modding and not even GPT could help me. Thanks