266 lines
9.5 KiB
C#
266 lines
9.5 KiB
C#
using Jotunn.Managers;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
using static MxValheim.EventSystem.RandomUnique.SpawnManager;
|
|
|
|
namespace MxValheim.EventSystem.RandomUnique
|
|
{
|
|
internal class UniqueManager
|
|
{
|
|
public static void LoadAllTemplates()
|
|
{
|
|
string uniqueFolder = Path.Combine(MxValheimMod.internalDataPath, "UniqueEnemy");
|
|
|
|
if (!Directory.Exists(uniqueFolder))
|
|
{
|
|
Directory.CreateDirectory(uniqueFolder);
|
|
}
|
|
|
|
string[] jsonFiles = Directory.GetFiles(uniqueFolder, "*.json");
|
|
|
|
foreach (string filePath in jsonFiles)
|
|
{
|
|
try
|
|
{
|
|
string jsonContent = File.ReadAllText(filePath);
|
|
LoadEnemyFromJson(jsonContent);
|
|
Debug.Log($"Loaded custom enemy from: {Path.GetFileName(filePath)}");
|
|
}
|
|
catch (System.Exception ex)
|
|
{
|
|
Debug.LogError($"Failed to load {filePath}: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void LoadEnemyFromJson(string jsonContent)
|
|
{
|
|
var data = JsonConvert.DeserializeObject<EnemyTemplate>(jsonContent);
|
|
|
|
GameObject customEnemy = PrefabManager.Instance.CreateClonedPrefab(data.InternalName, data.PrefabToClone);
|
|
|
|
Character character = customEnemy.GetComponent<Character>();
|
|
if (character != null)
|
|
{
|
|
character.m_name = data.HoverName;
|
|
character.m_health = data.Health;
|
|
character.m_speed = data.Speed;
|
|
character.m_faction = Character.Faction.Boss;
|
|
}
|
|
|
|
customEnemy.transform.localScale = new Vector3(data.Scale, data.Scale, data.Scale);
|
|
|
|
PrefabManager.Instance.AddPrefab(customEnemy);
|
|
|
|
Debug.Log($"Successfully injected {data.InternalName} into Valheim!");
|
|
}
|
|
|
|
public static List<EnemyTemplate> LoadTemplatesFromFolder()
|
|
{
|
|
List<EnemyTemplate> loadedTemplates = new List<EnemyTemplate>();
|
|
|
|
string configFolder = Path.Combine(MxValheimMod.internalDataPath, "UniqueEnemy");
|
|
|
|
if (!Directory.Exists(configFolder))
|
|
{
|
|
Directory.CreateDirectory(configFolder);
|
|
return loadedTemplates;
|
|
}
|
|
|
|
string[] files = Directory.GetFiles(configFolder, "*.json");
|
|
|
|
foreach (string file in files)
|
|
{
|
|
try
|
|
{
|
|
string json = File.ReadAllText(file);
|
|
EnemyTemplate template = JsonConvert.DeserializeObject<EnemyTemplate>(json);
|
|
|
|
if (template != null)
|
|
{
|
|
loadedTemplates.Add(template);
|
|
Debug.Log($"Loaded template: {template.InternalName} from {Path.GetFileName(file)}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.Log($"Error loading JSON file {file}: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
return loadedTemplates;
|
|
}
|
|
|
|
public static void ApplyEquipment(GameObject customEnemy, EnemyTemplate data)
|
|
{
|
|
Humanoid humanoid = customEnemy.GetComponent<Humanoid>();
|
|
if (humanoid == null) return;
|
|
|
|
humanoid.m_defaultItems = new GameObject[0];
|
|
|
|
List<GameObject> equipmentList = new List<GameObject>();
|
|
|
|
void AddToGear(string prefabName)
|
|
{
|
|
if (string.IsNullOrEmpty(prefabName)) return;
|
|
GameObject item = ObjectDB.instance.GetItemPrefab(prefabName);
|
|
if (item != null) equipmentList.Add(item);
|
|
}
|
|
|
|
AddToGear(data.Equipment.RightHand);
|
|
AddToGear(data.Equipment.LeftHand);
|
|
AddToGear(data.Equipment.Chest);
|
|
AddToGear(data.Equipment.Legs);
|
|
AddToGear(data.Equipment.Back);
|
|
|
|
humanoid.m_defaultItems = equipmentList.ToArray();
|
|
}
|
|
|
|
public static void ApplyDropTable(GameObject customEnemy, EnemyTemplate data)
|
|
{
|
|
CharacterDrop dropComp = customEnemy.GetComponent<CharacterDrop>();
|
|
if (dropComp == null)
|
|
{
|
|
dropComp = customEnemy.AddComponent<CharacterDrop>();
|
|
}
|
|
|
|
dropComp.m_drops.Clear();
|
|
|
|
foreach (var dropInfo in data.DropTable)
|
|
{
|
|
GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(dropInfo.ItemName);
|
|
|
|
if (itemPrefab != null)
|
|
{
|
|
CharacterDrop.Drop newDrop = new CharacterDrop.Drop
|
|
{
|
|
m_prefab = itemPrefab,
|
|
m_amountMin = dropInfo.Min,
|
|
m_amountMax = dropInfo.Max,
|
|
m_chance = dropInfo.Chance,
|
|
m_onePerPlayer = dropInfo.OnePerPlayer
|
|
};
|
|
|
|
dropComp.m_drops.Add(newDrop);
|
|
}
|
|
}
|
|
}
|
|
|
|
public static void ApplyStats(GameObject customEnemy, EnemyTemplate data)
|
|
{
|
|
Character character = customEnemy.GetComponent<Character>();
|
|
if (character != null)
|
|
{
|
|
character.m_name = data.HoverName;
|
|
|
|
if (!string.IsNullOrEmpty(data.Faction) &&
|
|
Enum.TryParse(data.Faction, out Character.Faction factionEnum))
|
|
{
|
|
character.m_faction = factionEnum;
|
|
}
|
|
else
|
|
{
|
|
character.m_faction = Character.Faction.Undead;
|
|
}
|
|
|
|
typeof(Character).GetField("m_maxHealth", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
|
?.SetValue(character, data.Health);
|
|
character.m_health = data.Health;
|
|
|
|
typeof(Character).GetField("m_tamed", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
|
|
?.SetValue(character, false);
|
|
|
|
var tameable = customEnemy.GetComponent<Tameable>();
|
|
if (tameable != null)
|
|
{
|
|
UnityEngine.Object.DestroyImmediate(tameable);
|
|
}
|
|
|
|
var procreation = customEnemy.GetComponent<Procreation>();
|
|
if (procreation != null) UnityEngine.Object.DestroyImmediate(procreation);
|
|
|
|
character.m_speed = data.Speed;
|
|
character.m_runSpeed = data.Speed * 1.5f;
|
|
}
|
|
|
|
BaseAI ai = customEnemy.GetComponent<BaseAI>();
|
|
if (ai != null && character != null)
|
|
{
|
|
typeof(BaseAI).GetField("m_character", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(ai, character);
|
|
|
|
typeof(BaseAI).GetField("m_aggravated", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)?.SetValue(ai, true);
|
|
|
|
ai.m_viewRange = 50f;
|
|
}
|
|
|
|
Rigidbody rb = customEnemy.GetComponent<Rigidbody>();
|
|
if (rb != null)
|
|
{
|
|
rb.isKinematic = false;
|
|
rb.useGravity = true;
|
|
}
|
|
|
|
ZNetView nview = customEnemy.GetComponent<ZNetView>();
|
|
if (nview != null)
|
|
{
|
|
nview.m_type = ZDO.ObjectType.Default;
|
|
nview.m_syncInitialScale = true;
|
|
}
|
|
|
|
UnityEngine.AI.NavMeshAgent agent = customEnemy.GetComponent<UnityEngine.AI.NavMeshAgent>();
|
|
if (agent != null)
|
|
{
|
|
agent.enabled = true;
|
|
agent.updatePosition = true;
|
|
agent.updateRotation = true;
|
|
agent.stoppingDistance = 1.0f;
|
|
}
|
|
|
|
nview.GetZDO()?.Set("m_eventCreature", true);
|
|
|
|
customEnemy.transform.localScale = Vector3.one * data.Scale;
|
|
if (nview != null)
|
|
{
|
|
nview.SetLocalScale(customEnemy.transform.localScale);
|
|
}
|
|
}
|
|
|
|
public static void ApplyColorTint(GameObject customEnemy, EnemyTemplate data)
|
|
{
|
|
if (data.ColorTint == null) return;
|
|
|
|
// Convert JSON floats to a Unity Color object
|
|
Color customColor = new Color(data.ColorTint.r, data.ColorTint.g, data.ColorTint.b);
|
|
|
|
// Find all renderers (body, head, etc.)
|
|
var renderers = customEnemy.GetComponentsInChildren<Renderer>();
|
|
|
|
foreach (var renderer in renderers)
|
|
{
|
|
// We use 'material' (singular) to create a unique instance for THIS enemy
|
|
foreach (var mat in renderer.materials)
|
|
{
|
|
// '_Color' is the standard main tint property in most Valheim shaders
|
|
if (mat.HasProperty("_Color"))
|
|
{
|
|
mat.SetColor("_Color", customColor);
|
|
}
|
|
|
|
// Optional: If you want them to GLOW slightly, set the Emission
|
|
if (mat.HasProperty("_EmissionColor"))
|
|
{
|
|
mat.SetColor("_EmissionColor", customColor * 0.5f);
|
|
mat.EnableKeyword("_EMISSION");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|