Integration Guide
Updated 9 hours agoIntegration Guide
Complete guide for integrating ZUI into your V Rising mod, including soft dependency patterns, reflection-based API access, and best practices.
📋 Table of Contents
- Integration Methods
- Soft Dependency (Recommended)
- Hard Dependency (Not Recommended)
- Understanding Client vs Server
- Complete Implementation
- Testing Your Integration
- Troubleshooting
Integration Methods
There are two ways to integrate ZUI into your mod:
| Method | Pros | Cons | Recommended |
|---|---|---|---|
| Soft Dependency | Works with/without ZUI, no crashes, max compatibility | Requires reflection, slightly more code | ✅ YES |
| Hard Dependency | Direct API access, cleaner code | Mod fails without ZUI, compatibility issues | ❌ NO |
Soft Dependency (Recommended)
Soft dependencies allow your mod to work whether ZUI is installed or not. This is the best practice for V Rising mods.
Why Soft Dependencies?
✅ Your mod always loads - Even if ZUI isn't installed
✅ No crashes - Gracefully handles missing ZUI
✅ Better compatibility - Works on servers without ZUI
✅ User friendly - Users don't need to install multiple mods
✅ Flexible - UI features are optional, not required
Basic Implementation
Here's the complete pattern for soft dependency integration:
using BepInEx;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using System;
using System.Linq;
using System.Reflection;
namespace YourMod
{
[BepInPlugin("com.yourname.yourmod", "Your Mod", "1.0.0")]
[BepInDependency("Zanakinz.ZUI", BepInDependency.DependencyFlags.SoftDependency)]
public class Plugin : BasePlugin
{
public static ManualLogSource LogInstance { get; private set; }
private static Type _zui;
public override void Load()
{
LogInstance = Log;
Log.LogInfo("Loading Your Mod...");
// Try to initialize ZUI
if (InitZUI())
{
Log.LogInfo("ZUI detected! Registering UI...");
RegisterUI();
}
else
{
Log.LogWarning("ZUI not found. UI features disabled.");
}
// Your mod's other initialization here
// This code runs whether ZUI is present or not
}
private bool InitZUI()
{
// Check if ZUI plugin is loaded
if (!IL2CPPChainloader.Instance.Plugins.ContainsKey("Zanakinz.ZUI"))
{
return false;
}
// Find ZUI assembly
var assembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.GetName().Name == "ZUI");
if (assembly == null)
{
return false;
}
// Get the ZUI API type
_zui = assembly.GetType("ZUI.API.ZUI");
return _zui != null;
}
private void Call(string methodName, params object[] args)
{
if (_zui == null) return;
// Find the method with matching name and parameter count
var method = _zui.GetMethods(BindingFlags.Public | BindingFlags.Static)
.FirstOrDefault(m => m.Name == methodName &&
m.GetParameters().Length == args.Length);
if (method != null)
{
method.Invoke(null, args);
}
else
{
LogInstance.LogError($"Could not find ZUI method '{methodName}' with {args.Length} parameters.");
}
}
private void RegisterUI()
{
// Set your plugin context
Call("SetPlugin", "Your Mod");
// Target main menu
Call("SetTargetWindow", "Main");
// Add UI elements
Call("AddCategory", "Features");
Call("AddButton", "Test", ".test");
LogInstance.LogInfo("UI registered successfully!");
}
}
}
How It Works
- BepInDependency with SoftDependency flag - Tells BepInEx this mod optionally uses ZUI
- InitZUI() - Checks if ZUI is loaded and gets the API type via reflection
- Call() helper method - Invokes ZUI methods dynamically
- Conditional registration - Only creates UI if ZUI is present
- Graceful fallback - Mod continues to work without ZUI
Hard Dependency (Not Recommended)
Hard dependencies require ZUI to be installed, or your mod won't load.
⚠️ Important Warning
ZUI is client-side while most V Rising mods are server-side. Mixing client and server dependencies causes:
- ❌ Mod fails to load on servers without ZUI
- ❌ Compatibility issues with other mods
- ❌ Load order problems
- ❌ Bad user experience (forced to install ZUI)
Only use hard dependencies if:
- Your mod is purely client-side
- You absolutely need ZUI for core functionality
- You understand the compatibility implications
Hard Dependency Implementation
Plugin.cs:
using BepInEx;
using BepInEx.Unity.IL2CPP;
using ZUI.API;
namespace YourMod
{
[BepInPlugin("com.yourname.yourmod", "Your Mod", "1.0.0")]
[BepInDependency("Zanakinz.ZUI", BepInDependency.DependencyFlags.HardDependency)]
public class Plugin : BasePlugin
{
public override void Load()
{
Log.LogInfo("Loading Your Mod...");
// Direct API access (no reflection needed)
ZUI.SetPlugin("Your Mod");
ZUI.SetTargetWindow("Main");
ZUI.AddCategory("Features");
ZUI.AddButton("Test", ".test");
Log.LogInfo("UI registered!");
}
}
}
YourMod.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<!-- Add ZUI as a compile-time reference -->
<Reference Include="ZUI">
<HintPath>path/to/ZUI.dll</HintPath>
<Private>false</Private>
</Reference>
<!-- Other references... -->
</ItemGroup>
</Project>
Drawbacks
- Users must install ZUI or mod crashes
- Server/client architecture conflicts
- Harder to distribute and maintain
- Less user-friendly
Recommendation: Use soft dependencies instead.
Understanding Client vs Server
This is critical for V Rising mod development.
ZUI is Client-Side
ZUI is a client-side UI framework. It runs on the player's game client and displays UI elements.
Client-side means:
- Runs on the player's computer
- Only affects that player's game
- Cannot be installed on dedicated servers
- Used for UI, visual effects, client data
Most V Rising Mods are Server-Side
Most gameplay mods are server-side and run on the dedicated server.
Server-side means:
- Runs on the game server
- Affects all players
- Controls game logic, data, rules
- Used for gameplay mechanics
The Problem with Mixing
When you add a client-side hard dependency to a server-side mod:
// This is problematic!
[BepInPlugin("com.yourname.servermod", "Server Mod", "1.0.0")]
[BepInDependency("Zanakinz.ZUI", BepInDependency.DependencyFlags.HardDependency)]
public class ServerMod : BasePlugin
{
// Server logic here
}
What happens:
- ❌ Mod won't load on dedicated servers (no ZUI installed)
- ❌ Server crashes or refuses to start
- ❌ All players lose server functionality
The Solution: Soft Dependencies
// This works!
[BepInPlugin("com.yourname.servermod", "Server Mod", "1.0.0")]
[BepInDependency("Zanakinz.ZUI", BepInDependency.DependencyFlags.SoftDependency)]
public class ServerMod : BasePlugin
{
public override void Load()
{
// Server logic always runs
InitializeServerFeatures();
// UI only loads if player has ZUI installed
if (InitZUI())
{
RegisterClientUI();
}
}
}
Result:
- ✅ Server runs without ZUI (server-side features work)
- ✅ Players with ZUI see UI (client-side enhancement)
- ✅ Players without ZUI still play (no UI, but functional)
- ✅ Maximum compatibility
Complete Implementation
Here's a production-ready implementation with all best practices:
Plugin.cs:
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using System;
using System.Linq;
using System.Reflection;
namespace YourMod
{
[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)]
[BepInDependency("Zanakinz.ZUI", BepInDependency.DependencyFlags.SoftDependency)]
public class Plugin : BasePlugin
{
public static ManualLogSource LogInstance { get; private set; }
private static Type _zuiType;
private static bool _zuiAvailable;
// Configuration
private ConfigEntry<bool> _enableUI;
public override void Load()
{
LogInstance = Log;
Log.LogInfo($"{MyPluginInfo.PLUGIN_NAME} v{MyPluginInfo.PLUGIN_VERSION} loading...");
// Load config
_enableUI = Config.Bind("UI", "EnableUI", true, "Enable ZUI integration");
// Initialize ZUI if available and enabled
_zuiAvailable = InitZUI();
if (_zuiAvailable && _enableUI.Value)
{
RegisterUI();
Log.LogInfo("ZUI integration enabled");
}
else if (!_zuiAvailable)
{
Log.LogInfo("ZUI not available - UI features disabled");
}
else
{
Log.LogInfo("ZUI integration disabled by config");
}
// Your mod's core functionality here
InitializeCore();
Log.LogInfo($"{MyPluginInfo.PLUGIN_NAME} loaded successfully");
}
private bool InitZUI()
{
try
{
// Check if ZUI plugin is loaded
if (!IL2CPPChainloader.Instance.Plugins.ContainsKey("Zanakinz.ZUI"))
{
return false;
}
// Find ZUI assembly
var assembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.GetName().Name == "ZUI");
if (assembly == null)
{
Log.LogWarning("ZUI assembly not found");
return false;
}
// Get ZUI API type
_zuiType = assembly.GetType("ZUI.API.ZUI");
if (_zuiType == null)
{
Log.LogWarning("ZUI.API.ZUI type not found");
return false;
}
return true;
}
catch (Exception ex)
{
Log.LogError($"Error initializing ZUI: {ex.Message}");
return false;
}
}
private void CallZUI(string methodName, params object[] args)
{
if (_zuiType == null) return;
try
{
var method = _zuiType.GetMethods(BindingFlags.Public | BindingFlags.Static)
.FirstOrDefault(m => m.Name == methodName &&
m.GetParameters().Length == args.Length);
if (method != null)
{
method.Invoke(null, args);
}
else
{
LogInstance.LogWarning($"ZUI method not found: {methodName}({args.Length} params)");
}
}
catch (Exception ex)
{
LogInstance.LogError($"Error calling ZUI.{methodName}: {ex.Message}");
}
}
private void RegisterUI()
{
try
{
CallZUI("SetPlugin", MyPluginInfo.PLUGIN_NAME);
CallZUI("SetTargetWindow", "Main");
CallZUI("AddCategory", "My Features");
CallZUI("AddButton", "Feature 1", ".feature1");
CallZUI("AddButton", "Feature 2", ".feature2");
// Optional: Custom window
RegisterCustomWindow();
}
catch (Exception ex)
{
LogInstance.LogError($"Error registering UI: {ex.Message}");
}
}
private void RegisterCustomWindow()
{
CallZUI("SetPlugin", MyPluginInfo.PLUGIN_NAME);
CallZUI("SetTargetWindow", "MyPanel");
CallZUI("SetUI", 600, 400);
CallZUI("SetTitle", $"<color=#4ECDC4>{MyPluginInfo.PLUGIN_NAME}</color>");
CallZUI("AddText", "Welcome!", 20f, 50f);
CallZUI("AddButton", "Action", ".action", 20f, 100f);
}
private void InitializeCore()
{
// Your mod's main functionality
// This runs whether ZUI is available or not
}
}
}
MyPluginInfo.cs:
namespace YourMod
{
public static class MyPluginInfo
{
public const string PLUGIN_GUID = "com.yourname.yourmod";
public const string PLUGIN_NAME = "Your Mod";
public const string PLUGIN_VERSION = "1.0.0";
}
}
Testing Your Integration
Test Scenarios
-
With ZUI Installed
- Load game
- Check BepInEx console for "ZUI integration enabled"
- Open ZUI main menu
- Verify your buttons appear
-
Without ZUI Installed
- Remove ZUI.dll
- Load game
- Check console for "ZUI not available"
- Verify mod still loads and functions
- No errors in console
-
ZUI Disabled in Config
- Set
EnableUI = falsein config - Load game
- Verify mod loads without UI
- Set
Common Test Cases
// Test: ZUI available
if (_zuiAvailable)
{
Log.LogInfo("✓ ZUI integration working");
}
// Test: ZUI not available
if (!_zuiAvailable)
{
Log.LogInfo("✓ Graceful fallback working");
}
// Test: Method calls don't crash
CallZUI("SetPlugin", "Test");
CallZUI("NonExistentMethod", "test"); // Should log warning, not crash
Troubleshooting
"ZUI not available" but ZUI is installed
Possible causes:
- ZUI loaded after your mod (load order issue)
- Wrong ZUI assembly name
- ZUI version incompatibility
Solution:
// Add more detailed logging
Log.LogInfo($"Plugins loaded: {string.Join(", ", IL2CPPChainloader.Instance.Plugins.Keys)}");
var zuiAssembly = AppDomain.CurrentDomain.GetAssemblies()
.FirstOrDefault(a => a.GetName().Name == "ZUI");
Log.LogInfo($"ZUI Assembly: {zuiAssembly?.FullName ?? "Not Found"}");
Methods not being called
Check:
- Method name spelling matches exactly
- Parameter count matches
- ZUI type is not null
Add logging:
private void CallZUI(string methodName, params object[] args)
{
Log.LogInfo($"Calling ZUI.{methodName} with {args.Length} args");
// ... rest of method
}
Compile errors with hard dependency
Error: The type or namespace name 'ZUI' could not be found
Solution: Add ZUI.dll reference to .csproj:
<Reference Include="ZUI">
<HintPath>path/to/ZUI.dll</HintPath>
<Private>false</Private>
</Reference>
Mod crashes without ZUI (hard dependency)
This is expected behavior with hard dependencies.
Solution: Switch to soft dependency pattern shown above.
Best Practices Summary
✅ DO:
- Use soft dependencies
- Add error handling
- Log initialization status
- Test with and without ZUI
- Make UI optional, not required
- Use descriptive method names
❌ DON'T:
- Use hard dependencies (unless purely client-side)
- Assume ZUI is always available
- Skip error handling
- Forget to check
_zuiType != null - Mix client/server dependencies
Related Pages
- Getting Started - Quick start guide
- API Reference - Complete API documentation
- Custom Windows - Creating custom UIs
- Examples & Tutorials - Practical examples
- Troubleshooting - Common issues
Ready to integrate? Start with the soft dependency pattern above and you'll be set!