Creating a Modding API for a Unity Game

So, I’m making a Game using Unity, and I want it to be moddable. So Modders will create a new C# Class Library Project, reference my Game’s and Unity’s .DLL files located in *_Data/Managed for Mono Games and create new Items, and Enemies, then compile to a .dll and put it in the Mods Folder (AutoGenned by the Game) Which will then be loaded by the Game.
My only problem is that my Items are created like this:

using UnityEngine;

namespace items
{  
    [CreateAssetMenu(fileName = "NewItem", menuName = "Inventory/Item")]
    public class Item : ScriptableObject
    {
        public string ItemName;
        public Sprite Icon;
        public bool IsStackable;

        public virtual void Use(Vector3 pos)
        {
            
        }
    }
}

And Enemies are

using DefaultNamespace;
using UnityEngine;

namespace enemey
{
    [CreateAssetMenu(fileName = "NewEnemy", menuName = "Enemies/EnemyData")]
    public class EnemyData : ScriptableObject
    {
        public string EnemyName;
        public float MaxHealth;
        public float MoveSpeed;
        public float Damage;
        public GameObject EnemyPrefab; // optional, for spawning

        public virtual void Attack(IDamageable player)
        {
            var beh = player;
            beh.TakeDamage(Damage);
        }
    }
}
using DefaultNamespace;
using UnityEngine;

namespace enemey
{ 
    public class Enemy : MonoBehaviour, IDamageable
    { 
        public EnemyData data; // assign in inspector
        
        private Transform playerTransform;
        private IDamageable damageable;
        
        private float currentHealth; 
        void Start() 
        { 
            playerTransform = GameObject.FindGameObjectWithTag("Player")?.transform;
            damageable = GameObject.FindGameObjectWithTag("Player")?.GetComponent<IDamageable>();
            currentHealth = data.MaxHealth;
        }

        void Update()
        {
            // Example simple AI: follow player
            if (playerTransform != null)
            {
                Vector3 dir = (playerTransform.position - transform.position).normalized;
                transform.position += dir * data.MoveSpeed * Time.deltaTime;
            }

            if (Vector3.Distance(playerTransform.position, transform.position) <= 0.1f)
            {
                data.Attack(damageable);
            }
        }

        public void TakeDamage(float amount)
        {
            currentHealth -= amount;
            if (currentHealth <= 0)
            {
                Die();
            }
        }

        void Die()
        {
            // Drop loot, play animation, destroy object
            Destroy(gameObject);
        }
    }
}

And I don’t know how Modders will create their own.

First, modding discussions are verboten on this forum. See terms of service for more details.

Second, all games are inherently moddable to one extent or another.

Third, the most-moddable game is one that you simply do open-source, then anyone can download it and modify it as much as they want.

Finally, paging @CodeSmile for commentary on using LUA in place of C# to achieve text-level modding.

They can’t create their own ScriptableObject assets without the Unity editor.

Exposing the entire C# API surface isn’t modding. It’s a recipe for disaster. It may even violate Unity’s TOS by providing users the ability to use something “like Unity” (the referencing Unity DLLs part) but without actually using Unity. Probably depends on how far you plan on taking this.

But you definitely don’t want any “grieving” mods to appear which use YOUR game and THEIR mod to steal or destroy a user’s data by allowing them to execute code on the user’s machine without them installing anything but a “mod”. Or they could make use of the Unity APIs that - perhaps - connects to your already-embedded cloud services and cause you a fat service bill or the app taken off the store due to abuse (scripted traffic to harrass or blackmail you). This should not be taken lightly!

For modding to work in a meaningful way you need to load the game’s moddable data in an engine-agnostic format (json, lua).

To ensure modders only modify what you specify as moddable, you have to install a sandbox environment.

You can either expose the moddable API to a scripting language like Lua, or you provide a C# API that loads an external DLL from a directory and scans it for types implementing a common base type or interface. Then you use Activator.CreateInstance() to instantiate these types, and any data and API they need should be passed into a Initialize(ModApi api, ModData data) method for modder’s scripts to consume.

Modders will NOT reference the game’s Unity DLLs. Instead, you provide the parts of the Unity and game’s APIs that you want to give modders access to. This means you will have to provide custom wrappers for Unity types like Vector3, Sprite and so forth. That part you provide as open source for modders to include in their C# project. Using a scripting language makes this a whole lot easier.

Knowledgeable users could still find a way into your game engine, but then you wouldn’t be liable anymore - unless they manage to do so through gross negligence on your part.

Worth noting: I know there are modding tools using C# that allow you to directly modify anything in the game - but these are hacks by the community. This is not how developer-sanctioned modding works due to the inherent risks for fraud, grief, theft and legal liability.

Beep. Beep. Page received. :slight_smile: