Friday Night Funkin' Cookbook
Friday Night Funkin' CookbookExpertCompiling Scripts

Compiling Scripts

Reading time: 3 minutes

cautionCaution

This feature is a W.I.P, and might not even make it into the game! As such this article is simply a quick and fast tutorial, and not a full article!

To use CPPIA and compile your .cppia files, our current convention revolves around keeping your .hx source files (for cppia compliation in your scripts), inside of the cppia-src directory in the root of your mod. So one script might look like your-mod/cppia-src/my-mod/package/HelloCppia.hx

In that file it also might look like:

// your-mod/cppia-src/my-mod/package/HelloCppia.hx

package mymod.package;

import funkin.modding.module.Module;
import funkin.modding.events.ScriptEvent;

class HelloCppia extends Module
{
    public function new()
    {
        super('HelloCppia', 1000);
    }

    override public function onCreate(event:ScriptEvent):Void
    {
        super.onCreate(event);
        
        trace("Why hello there.");
    }
}

Inside of the game source, look into scripts/cppia/ you will see two build files. Two for different platforms (windows and unix based systems). Use the one for your platform and give it a directory like this: ./build_cppia.ps1 --sdk ./funkin-cppia-sdk ./funkin-source ./my-mod/scripts/cppia-src/ ./my-mod/scripts/MyMod.cppia

You require the full source of the game (IE: ./funkin-source), and an SDK (IE: ./funkin-cppia-sdk). This sdk can be obtained through a build script, or more likely given by the game itself in a download somewhere (check the PR)

You also need all of the libraries installed, and of course - the haxe build system.

For this you can follow the compiling the game guide

After that you give a directory where you have all of your script files you give it an output (your mod can contain multiple .cppia files if you have multiple folders of scripts needing cppia). Your scripts will be compiled into that one compiled binary.

If all goes well, you should have a compiled .cppia file you can include anywhere in your mod. The game should automatically load it.

Version stamping

Each CPPIA file is stamped with the game version they are built with, and while we aren't stamping the commit hash (so technically if changes were present) - you could in theory try to access something that doesn't exist, but the SDK says it does (or vice versa). Luckily this should be handled by an error handler, with a stack trace.

Should mostly be stable enough for you to use.

Debug information

By default the script compiles with debug information (believe it or not, helps with debugging). Without this, script execeptions cannot determine stack traces.

To disable debug information use --no-debug

Other arguments

You can also specify:

A platform:

`--target windows`

A configuration:

`--config debug` (this is for what the *game* is targeted towards)

Targeting Platforms

To target a specific platform in a script, prepend a platform name to the extenstion like so: MyMod.windows.cppia

Please consult this table for which files take precedent over what on each platform:

WindowsLinuxMacosAndroidIOS
MyMod.windows.cppiaMyMod.linux.cppiaMyMod.macos.cppiaMyMod.android.cppiaMyMod.ios.cppia
MyMod.desktop.cppia< - - - -< - - - -MyMod.mobile.cppia< - - - -
MyMod.cppia< - - - -< - - - -< - - - -< - - - -

Accessing scripts at runtime

To access scripts that aren't guarenteed to be ran (like platform specifics), you can use the CppiaScripts class like so:


// MyMod.windows.cppia

class MyModWindows
{
    public static function nativeThing(x:Int):Void { /* windows-only code */ }
    public function nativeThingClass():Void {
        trace('Hello natives!');
    }
}

// Some cppia script file like MyMod.cppia

import funkin.modding.CppiaScripts;

// ... 


if (CppiaScripts.exists('MyModWindows'))
{
    CppiaScripts.call('MyModWindows', 'nativeThing', [42]); // static function call
    var helper:Dynamic = CppiaScripts.create('MyModWindows', []); // create instance
    helper.nativeThingClass();
}

// ...

Static types but no dynamic typing

Unfourtunately cppia is static typed, so it only checks against types at compile time. Meaning if you were to try typing against another CPPIA file it would not work. Hence using dynamic at the top there.

The only real way to get typing working is by using Typedefs (like so):

typedef WindowsHelper =
{
    function nativeThingClass():Void;
}

var helper:WindowsHelper = cast CppiaScripts.create('MyModWindows', []);
if (helper != null) helper.nativeThingClass();

Although this typedef would have to be local to the script, and carrying that across different .cppia files might be tricky!

HScript interactions with CPPIA

CPPIA can be used as a library for HScript. All HScript code can access CPPIA functions as they are loaded first.

You can just import classes like you would normally:

// CoolCppiaFile.cppia

package coolpackage;

class ThisIsSoCool
{
    public function CoolPeopleOnly()
    {
        trace('Woah...');
    }
}

// CoolConsumer.hxc

import coolpackage.ThisIsSoCool;
import funkin.modding.module.Module;

class CoolConsumer extends Module
{
    public function new() {
        super('CoolConsumer');
    }

    public override function onCreate(ev:ScriptEvent):Void
    {
        var cool = new ThisIsSoCool();
        cool.CoolPeopleOnly();
    }
}

Contributors:
Kade-gtihub
Last modified:
Created:
Category:  Expert
Tags: