fieryhenry / tbcml

A python library designed to make modding The Battle Cats easier, more automated, and more powerful
MIT License
7 stars 3 forks source link
battle-cats hacking modding

TBCML

The Battle Cats Modding Library (TBCML) is a python library designed to make modding The Battle Cats easier, more automated, and more powerful.

Because the package is a library and you will need to have programming experience if you want to use it effectively.

Most features are not documented yet and many may not work properly atm.

Credits

Functionality

Note that most of these features are a work in progress and may not work properly.

Note that the scripting functionality is very limited, especially in later game versions (> 8.4.0) as function and class names have been stripped from the binary.

Discord: https://discord.gg/DvmMgvn5ZB (The server is the same one which is used for save editing as I haven't made a modding specific one yet)

I've spent so much time working on this project because I've changed my mind on what this library should do and how to structure it, but due to all of the re-writes, it really doesn't look like it. So I would really appricate it if you considered donating to my kofi:

ko-fi

wakatime

Getting Started

Installation

To install on android see Install on Android

From source (recommended)

git clone https://github.com/fieryhenry/tbcml.git
cd tbcml
pip install -r requirements_scripting.txt
pip install -e .

You don't need to install the requirements_scripting.txt if you don't want to use the scripting features.

From pypi

pip install tbcml

If you want scripting (frida scripting or libnative patching), you will also need to install tbcml[scripting]

pip install tbcml[scripting]

Basic Usage

You can obviously do more advanced things with this library, but this is just a basic example of how to use it.

I don't have time to create a bunch of examples and the documentation is not finished, so you'll probably have to read the source code to figure out how to do more advanced things.

Create script.py

import tbcml

class BasicCustomForm(tbcml.CatForm):
    """For better organization, these classes could be defined in
    another / separate files and then imported.

    See game_data/cat_base/cats.py for documetation of cats
    """

    def __init__(self):
        super().__init__(form_type=tbcml.CatFormType.FIRST, name="Cool Cat")

        # you can either set properties in the constructor as shown above, or
        # like this:

        self.description = ["First line!", "Second Line!", "Third description line!"]

        # note that if you use .read() it will overwrite any previously defined
        # values, so you may not be able to put the values in the constructor
        # if you want to use .read()

class BasicCustomCat(tbcml.Cat):
    def __init__(self):
        super().__init__(cat_id=0)

        first_form = BasicCustomForm()
        self.set_form(first_form)

loader = tbcml.ModLoader(
    "en", "12.3.0"
)  # these can be changed for the version you want
loader.initialize_apk()

apk = loader.get_apk()

mod = tbcml.Mod(
    name="Test Mod",
    authors="fieryhenry",  # can be a list of authors e.g ["person 1", "person 2"]
    short_description="Test Description",
)

cat = BasicCustomCat()
mod.add_modification(cat)

mod.save("test.zip") # save the mod to a zip file (optional)

apk.set_app_name("The Battle Cats Basic Mod")

# package name should be different to base game if you want your modded app
# to not replace the normal app.
apk.set_package_name("jp.co.ponos.battlecats.basicmod")

# set open_path to True if you want to open the containg folder of the modded apk
loader.apply(mod, open_path=False)

print(apk.final_pkg_path)

If apktool isn't supported for your achitecture, you can set use_apktool=False when creating the apk object / initializing the loader. This will just extract the apk like a zip file and then repackage it like a zip file.

However, this does not decode the resources, so you will not be able to modify stuff such as the app name, package name, or other resources. You can still modify the game data though. In the future, I may add support for decoding and encoding resources without apktool.

loader.initialize_apk(use_apktool=False)

If you want to modify a different langauge and you are using an en apk, you can change the language when you initialize the loader. Valid langs are "fr", "it", "de", "es", and "th".

loader.initialize_apk(lang="fr")

If you don't want to use inheritance, then you can structure the code like this:

...
cat = tbcml.Cat(cat_id=0)
form = tbcml.CatForm(form_type=tbcml.CatFormType.FIRST, name="Cool Cat")
form.description = ["First line!", "Second Line!", "Third description line!"]
cat.set_form(form)
mod.add_modification(cat)
...

If you want to do disable script modding (e.g for security reasons), you will need to set allowed_script_mods to False when creating the apk object / initializing the loader

loader.initialize_apk(allowed_script_mods=False)

If you have a large mod, you may want to compile the modifications into raw game files so that it is faster to load the mod (Also useful when debugging). You can do this by running the following code:

target = tbcml.CompilationTarget(
    target_country_codes="en", target_game_versions="12.3.0"
)
mod.compile_modifications(loader.get_game_packs(), existing_target=target)

Note that at the moment, this does not merge changes from multiple mods, so if 2 mods have changes to the same file, only the changes from the last mod will be used.

The target_country_codes is a list of country codes (e.g "en,jp,kr,tw") or you can put a ! in front of the country code to exclude it (e.g !jp). You can put a * to match any country code.

The target_game_versions is a list of game versions seperated by a comma, (e.g "11.3.0,12.3.0") you can put a ! in front of the game version to exclude it (e.g !11.3.0). You can put a * to match any game version. You can also use the > and < operators to match any version greater than or less than the specified version (and >= and <=).

There is some basic support for iOS ipa files:

loader = tbcml.ModLoader("en", "12.3.0")

# you need to specify the path to the ipa as it can't be downloaded
loader.initialize_ipa(ipa="path/to/ipa")

ipa = loader.get_ipa()

# ... rest of the code is the same

Run the script

Windows

py script.py

Everything else

python3 script.py

You can then install the apk on your device. If the apk fails to install, you may need to uninstall the previous version first.

Install on Android

Documentation (Not Finished)

For examples see examples.md. Note that some may need the latest commit to work (see install from source)

https://tbcml-docs.readthedocs.io/en/latest/