Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions assets/content/cookbook/Expert/06.ScriptMerging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
[tags]: / "expert,hscript"

# Merging Scripts

Sometimes, a custom behavior would be locked behind a specific condition in a script found by either the base game or a dependency mod. While there is an option of replacing the script file with yours or using another script for the specific case needed, it is less of a hassle to use the `_merge` folder to combine the behaviors.
This article will guide you over using the `_merge` folder and annotations to inject script data.

Start by creating a file in your mod's `_merge` folder that matches the script you're overriding. For example, if you intend to merge into the `assets/scripts/players/backcards/backcard-bf.hxc` file, you should create a file `mods/mymod/_merge/scripts/players/backcards/backcard-bf.hxc`, which will contain HScript to be merged into the base script.

## Merging Packages
If you wrote a package in your merge script, it will not get carried over to the base script, as it causes classes from that file to require different imports to be used in other scripts.

## Merging Imports and Usings
Every import and using in your merge script will automatically get carried over to the base script, even if the import/using for the class already exists there.

## Merging Classes
There are three possible ways of merging a class with the base script, all of which requiring different annotations to be put on top of the class.
- `@:merge_add` - Adds the class into the script file, if one with the same name isn't provided already.
- `@:merge_override` - Overrides the class from the script file with the same name. If one doesn't exist, it will add the class from the merge file onto the base file.
- `@:merge_combine` - Injects the fields from the merge file's class onto the base class with the same name. If one doesn't exist, it will add the class from the merge file onto the base file.

By using the metadata for combining, you would have to specify how the class fields should get merged. There are three options for this, all requiring a different annotation on top.
- `@:merge_add` - Adds the fields from the merge class onto the base class, if one with the same name isn't provided already.
- `@:merge_override` - Overrides the class field with the same name from the base class. If one doesn't exist, it will add the field onto the base class.
- `@:merge_insert(index)` - Adds the function's logic at the `index` position of the base class function with the same name.

> [!NOTE]
> If multiple of the merge annotations are provided, it takes the first one by priority. The priority goes as follows, from highest priority to lowest: Combine > Insert > Add > Override.

As an example, if the base class is this:
```haxe
class Test
{
var foo:Int = 5;

function func()
{
trace("Running function 'func'.");

return 1;
}
}
```

You can merge into the class' fields by doing the following:
```haxe
// Tell the system that we should merge the fields of this class with the fields of the base class "Test"
@:merge_combine
class Test
{
// Tell the system to add this field to the base class
@:merge_add
var foo2:Bool = true;

// Tell the system to override the "foo" field with the one from this class
@:merge_override
var foo:Int = 4;

// Tell the system to insert the function content of this function in the middle of the base class' function with the same name
// It should be after the trace, but before the final return, hence the index being 1
@:merge_insert(1)
function func()
{
if (foo == 4) return 2;
}
}
```

The resulting class will look something like this:
```haxe
class Test
{
var foo:Int = 4;
var foo2:Bool = true;

function func()
{
trace("Running function 'func'.");

if (foo == 4) return 2;

return 1;
}
}
```

## Merging Enums
In comparison to classes, enums can only be merged using the `@:merge_add` and `@:merge_override` annotations, with the same conditions as with classes. It is not possible to merge individual enum fields.

## Merging Typedefs
Similarly to enums, typedefs can also only be merged using the `@:merge_add` and `@:merge_override` annotations. Since they can redirect to things other than anonymous structures, merging individual anonymous structure fields is not possible.

## Merging Interfaces
Likewise, interface merging only allows for annotations `@:merge_add` and `@:merge_override`.

> Author: [KoloInDaCrib](https://github.com/KoloInDaCrib)
Loading