Mod Scripting: Difference between revisions

From Ardenfall Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
 
(One intermediate revision by the same user not shown)
Line 2: Line 2:
Essentially every mod needs a Mod Root class definition. This is your hook into the mod activation and deactivation events, as well as additional hooks.
Essentially every mod needs a Mod Root class definition. This is your hook into the mod activation and deactivation events, as well as additional hooks.


Your mod root class can be anywhere in the mod folder within a .cs file, but I'd suggest putting it in YourModDirectory/Scripts/mod.cs.
Your mod root class can be anywhere in the mod's Scripts folder within a .cs file.


There are two main methods you probably want to override:
There are two main methods you probably want to override:
Line 37: Line 37:
By default, mods do not save custom data. But you can do it!  
By default, mods do not save custom data. But you can do it!  


Use the interface ISaveMod on your ModRoot script, and implement the following methods:
Override the following methods:


void CreateState(): Run when a new game is made, or when the mod is loaded for a save for the first time. Use this to initialize a default state.
void CreateState(): Run when a new game is made, or when the mod is loaded for a save for the first time. Use this to initialize a default state.
Line 53: Line 53:
namespace ExampleSaveMod  
namespace ExampleSaveMod  
{
{
public class ExampleSaveMod : ModRoot, ISaveMod,
public class ExampleSaveMod : ModRoot
{
{
private float randomNumber;
private float randomNumber;
Line 69: Line 69:
}
}
        void ISaveMod.CreateState()
public override void CreateState()
{
{
randomNumber = UnityEngine.Random.value;
randomNumber = UnityEngine.Random.value;
Line 75: Line 75:


         //Save state. You can save it as json or any format, it just needs to be a string.
         //Save state. You can save it as json or any format, it just needs to be a string.
        string ISaveMod.SaveState()
public override string SaveState()
{
{
var state = new ExampleModSaveState()  
var state = new ExampleModSaveState()  
Line 86: Line 86:


         //Load the state as a string.
         //Load the state as a string.
        void ISaveMod.LoadState(string jsonState)  
public override void LoadState(string jsonState)  
{
{
var state = JsonUtility.FromJson<ExampleModSaveState>(jsonState);
var state = JsonUtility.FromJson<ExampleModSaveState>(jsonState);
Line 112: Line 112:


If you ever run into needing a certain asset in the lookup table, throw me (joshcamas) a message on discord.
If you ever run into needing a certain asset in the lookup table, throw me (joshcamas) a message on discord.
Be careful when modifying assets in particular - users expect to be able to disable mods easily, and if you wreck an asset and disabling mods doesn't undo it, players may be unhappy.


Non scripting methods to create/modify assets is planned in the future.
Non scripting methods to create/modify assets is planned in the future.


<u>''Example of creating a new asset and registering it to the lookup table''</u>
''Example of creating a new asset and registering it to the lookup table''


TODO
TODO
Line 131: Line 128:


TODO
TODO
'''NOTE:''' If a mod spawns or modifies a record, and then the user disables the mod, this record will still exist in old save files. No immediate solutions for this, since players should expect odd things to happen when disabling mods and then loading an old save.
=== Mod Version Patching ===
TODO: Add built in Mod Version Patching Support
=== Mod Settings ===
TODO: Add Mod settings support.


=== A note on Hot Reloading / Refreshing ===
=== A note on Hot Reloading / Refreshing ===
Ardenfall's modding systems supports hot reloading. That is to say, reloading the mod without restarting the game.  
Ardenfall's modding systems supports hot reloading. That is to say, reloading the mod without restarting the game.  


The mod user can always turn your mod on and off in the main menu, and you should ensure your mods correctly clean up during this state, otherwise it will cause problems for your users.
The mod user can always turn your mod on and off in the main menu, and you should ensure your mods correctly clean up during this state, otherwise it will cause problems for your users. However, users should expect weird things to occur on old save files that used to have the mod, of course.


As a mod developer, you can also turn your mod on and off / refresh it while actually playing the game. You don't officially need support for this (no one will know) but making your mod work in this circumstance as much as possible is great from a developmental standpoint - you can super quickly work on your mods without worries.
As a mod developer, you can also turn your mod on and off / refresh it while actually playing the game. You don't officially need support for this (no one will know) but making your mod work in this circumstance as much as possible is great from a developmental standpoint - you can super quickly work on your mods without needing to restart the application, or even maybe not reloading the save file sometimes.

Latest revision as of 21:08, 21 May 2026

Mod Root

Essentially every mod needs a Mod Root class definition. This is your hook into the mod activation and deactivation events, as well as additional hooks.

Your mod root class can be anywhere in the mod's Scripts folder within a .cs file.

There are two main methods you probably want to override:

Initialize(string id): Called when the mod is initialized. This happens on boot (if the mod is active), or whenever the mod is activated.

Uninitialize(string id): Called when the mod is uninitialized. This happens whenever the mod is deactivated.

Barebones Example:

using Ardenfall;
using UnityEngine;
using System;

namespace ExampleMod 
{	
	public class ExampleMod : ModRoot
	{
		public override void Initialize(string id)
		{
			base.Initialize(id);
			Debug.Log("Loaded Example Mod! WOW!");
		}
        
		public override void Uninitialize()
		{
			base.Uninitialize();
			Debug.Log("Unloaded Example Mod! WOW!");
		}
	}
}

Mod Saving

By default, mods do not save custom data. But you can do it!

Override the following methods:

void CreateState(): Run when a new game is made, or when the mod is loaded for a save for the first time. Use this to initialize a default state.

void LoadState(string state): Load your state from previously saved data.

string SaveState(): Save your state to a string.

If you want to serialize data, you can use JsonUtility, or whatever other serializer you get your hands on, as long as its a string.

Example of a mod that saves state.

using Ardenfall;
using UnityEngine;
using System;

namespace ExampleSaveMod 
{	
	public class ExampleSaveMod : ModRoot
	{
		private float randomNumber;
			
		public override void Initialize(string id)
		{
			base.Initialize(id);
			Debug.Log("Loaded Example Mod! WOW!");
		}
        
		public override void Uninitialize()
		{
			base.Uninitialize();
			Debug.Log("Unloaded Example Mod! WOW!");
		}
		
		public override void CreateState()
		{
			randomNumber = UnityEngine.Random.value;
		}

        //Save state. You can save it as json or any format, it just needs to be a string.
		public override string SaveState()
		{
			var state = new ExampleModSaveState() 
			{
				randomNumber = randomNumber
			};

			return JsonUtility.ToJson(state);
		}

        //Load the state as a string.
		public override void LoadState(string jsonState) 
		{
			var state = JsonUtility.FromJson<ExampleModSaveState>(jsonState);
			randomNumber = state.randomNumber;
			Debug.Log(randomNumber);
		}
	}

	[System.Serializable]
	public class ExampleModSaveState 
	{
		public float randomNumber;
	}
}

Debugging Mods

TODO (IMGUI Debugging)

TODO (Graph Debugging)

Lookup Table Registration

To register or modify assets, you can hook into the lookup table initialization step.

The Lookup Table is a big list of assets that is commonly used in the engine, tied to an id. Beyond modding, it's used by the save system - any asset that is referenced in the save file (such as an item in the inventory) must be registered to the lookup table. The lookup table does not contain EVERY asset, however.

If you ever run into needing a certain asset in the lookup table, throw me (joshcamas) a message on discord.

Non scripting methods to create/modify assets is planned in the future.

Example of creating a new asset and registering it to the lookup table

TODO


Lookup Table Tools

TODO

Records Registration

You may also want to create Records with your mods. Records are objects in the world that can be accessed / manipulated at any time. The most common Record is the CharacterRecord, but there are others.

TODO

NOTE: If a mod spawns or modifies a record, and then the user disables the mod, this record will still exist in old save files. No immediate solutions for this, since players should expect odd things to happen when disabling mods and then loading an old save.

Mod Version Patching

TODO: Add built in Mod Version Patching Support

Mod Settings

TODO: Add Mod settings support.

A note on Hot Reloading / Refreshing

Ardenfall's modding systems supports hot reloading. That is to say, reloading the mod without restarting the game.

The mod user can always turn your mod on and off in the main menu, and you should ensure your mods correctly clean up during this state, otherwise it will cause problems for your users. However, users should expect weird things to occur on old save files that used to have the mod, of course.

As a mod developer, you can also turn your mod on and off / refresh it while actually playing the game. You don't officially need support for this (no one will know) but making your mod work in this circumstance as much as possible is great from a developmental standpoint - you can super quickly work on your mods without needing to restart the application, or even maybe not reloading the save file sometimes.