diff --git a/src/Loader.cs b/src/Loader.cs index f68f8f4..bdf79a2 100644 --- a/src/Loader.cs +++ b/src/Loader.cs @@ -61,14 +61,10 @@ public static class Loader { if (duringEnumCacheCreation) { - UnitData.Type unitPrefabType = UnitData.Type.Scout; if (token["prefab"] != null) { - string prefabId = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(token["prefab"]!.ToString()); - if (Enum.TryParse(prefabId, out UnitData.Type parsedType)) - unitPrefabType = parsedType; + Registry.prefabNames.Add((int)(UnitData.Type)Registry.autoidx, CultureInfo.CurrentCulture.TextInfo.ToTitleCase(token["prefab"]!.ToString())); } - PrefabManager.units.TryAdd((int)(UnitData.Type)Registry.autoidx, PrefabManager.units[(int)unitPrefabType]); } else { @@ -458,6 +454,119 @@ public static void LoadAudioFile(Mod mod, Mod.File file) // TODO: issue #71 } + public static void LoadPrefabInfoFile(Mod mod, Mod.File file) + { + try + { + var prefab = JsonSerializer.Deserialize(file.bytes, new JsonSerializerOptions + { + Converters = { new Vector2Json() }, + PropertyNameCaseInsensitive = true, + }); + if (prefab == null || prefab.type != Visual.PrefabType.Unit) + return; + + var baseUnit = PrefabManager.GetPrefab(UnitData.Type.Warrior, TribeData.Type.Imperius, SkinType.Default); + if (baseUnit == null) + return; + + var unitInstance = GameObject.Instantiate(baseUnit); + if (unitInstance == null) + return; + + var spriteContainer = unitInstance.transform.GetChild(0); + var material = ClearExistingPartsAndExtractMaterial(spriteContainer); + + var visualParts = ApplyVisualParts(prefab.visualParts, spriteContainer, material); + + var svr = unitInstance.GetComponent(); + svr.visualParts = visualParts.ToArray(); + + GameObject.DontDestroyOnLoad(unitInstance.gameObject); + Registry.unitPrefabs.Add(prefab, unitInstance.GetComponent()); + + Plugin.logger.LogInfo($"Registered prefab info from {mod.id} mod"); + } + catch (Exception e) + { + Plugin.logger.LogError($"Error on loading prefab info from {mod.id} mod: {e.Message}"); + } + } + + private static Material? ClearExistingPartsAndExtractMaterial(Transform spriteContainer) + { + Material? material = null; + for (int i = 0; i < spriteContainer.childCount; i++) + { + var child = spriteContainer.GetChild(i); + if (child.gameObject.name == "Head") + { + var renderer = child.GetComponent(); + if (renderer != null) + material = renderer.material; + } + GameObject.Destroy(child.gameObject); + } + return material; + } + + private static List ApplyVisualParts( + List partInfos, + Transform spriteContainer, + Material? material) + { + List parts = new(); + + foreach (var info in partInfos) + { + parts.Add(CreateVisualPart(info, spriteContainer, material)); + } + + return parts; + } + + private static SkinVisualsReference.VisualPart CreateVisualPart( + Visual.VisualPartInfo info, + Transform parent, + Material? material) + { + var visualPartObj = new GameObject(info.gameObjectName); + visualPartObj.transform.SetParent(parent); + visualPartObj.transform.position = info.coordinates; + visualPartObj.transform.localScale = info.scale; + visualPartObj.transform.rotation = Quaternion.Euler(0f, 0f, info.rotation); + + var outlineObj = new GameObject("Outline"); + outlineObj.transform.SetParent(visualPartObj.transform); + outlineObj.transform.position = info.coordinates; + outlineObj.transform.localScale = info.scale; + outlineObj.transform.rotation = Quaternion.Euler(0f, 0f, info.rotation); + + var visualPart = new SkinVisualsReference.VisualPart + { + DefaultSpriteName = info.baseName, + visualPart = visualPartObj, + outline = outlineObj, + tintable = info.tintable + }; + + var renderer = visualPartObj.AddComponent(); + renderer.material = material; + renderer.sortingLayerName = "Units"; + renderer.sortingOrder = info.tintable ? 0 : 1; + + visualPart.renderer = new SkinVisualsReference.RendererUnion { spriteRenderer = renderer }; + + var outlineRenderer = outlineObj.AddComponent(); + outlineRenderer.material = material; + outlineRenderer.sortingLayerName = "Units"; + outlineRenderer.sortingOrder = -1; + + visualPart.outlineRenderer = new SkinVisualsReference.RendererUnion { spriteRenderer = outlineRenderer }; + + return visualPart; + } + public static void LoadGameLogicDataPatch(Mod mod, JObject gld, JObject patch) { try diff --git a/src/Managers/Main.cs b/src/Managers/Main.cs index db9ab38..68892ed 100644 --- a/src/Managers/Main.cs +++ b/src/Managers/Main.cs @@ -32,6 +32,28 @@ private static void GameLogicData_Parse(GameLogicData __instance, JObject rootOb if (!fullyInitialized) { Load(rootObject); + foreach (System.Collections.Generic.KeyValuePair item in Registry.prefabNames) + { + UnitData.Type unitPrefabType = UnitData.Type.Scout; + string prefabId = item.Value; + if (Enum.TryParse(prefabId, out UnitData.Type parsedType)) + { + unitPrefabType = parsedType; + PrefabManager.units.TryAdd(item.Key, PrefabManager.units[(int)unitPrefabType]); + } + else + { + KeyValuePair prefabInfo = Registry.unitPrefabs.FirstOrDefault(kv => kv.Key.name == prefabId); + if (!EqualityComparer.Default.Equals(prefabInfo.Key, default)) + { + PrefabManager.units.TryAdd(item.Key, prefabInfo.Value); + } + else + { + PrefabManager.units.TryAdd(item.Key, PrefabManager.units[(int)unitPrefabType]); + } + } + } foreach (Visual.SkinInfo skin in Registry.skinInfo) { if (skin.skinData != null) @@ -286,6 +308,15 @@ private static void StartTurnAction_Execute(StartTurnAction __instance, GameStat } } + [HarmonyPrefix] + [HarmonyPatch(typeof(Unit), nameof(Unit.CreateUnit))] + private static bool Unit_CreateUnit(Unit __instance, UnitData unitData, TribeData.Type tribe, SkinType unitSkin) + { + Unit unit = PrefabManager.GetPrefab(unitData.type, tribe, unitSkin); + if (unit == null) Console.Write("THIS FUCKING SHIT IS NULL WHAT THE FUCK"); + return true; + } + internal static void Init() { stopwatch.Start(); @@ -359,6 +390,14 @@ internal static void Load(JObject gameLogicdata) ); continue; } + if (Regex.IsMatch(Path.GetFileName(file.name), @"^prefab(_.*)?\.json$")) + { + Loader.LoadPrefabInfoFile( + mod, + file + ); + continue; + } switch (Path.GetExtension(file.name)) { diff --git a/src/Managers/Visual.cs b/src/Managers/Visual.cs index 96b3350..e816f0b 100644 --- a/src/Managers/Visual.cs +++ b/src/Managers/Visual.cs @@ -37,6 +37,22 @@ public record SkinInfo(int idx, string id, SkinData? skinData); private static bool firstTimeOpeningPreview = true; private static UnitData.Type currentUnitTypeUI = UnitData.Type.None; private static TribeData.Type attackerTribe = TribeData.Type.None; + public enum PrefabType + { + Unit, + Improvement, + Resource + } + public record PrefabInfo(PrefabType type, string name, List visualParts); + public record VisualPartInfo( + string gameObjectName, + string baseName, + float rotation = 0f, + Vector2 coordinates = new Vector2(), + Vector2 scale = new Vector2(), + bool tintable = false + ); + private static bool enableOutlines = false; #region General @@ -105,6 +121,30 @@ private static void SpriteAtlasManager_DoSpriteLookup(ref SpriteAtlasManager.Spr #endregion #region Units + // lobotomy + + [HarmonyPrefix] + [HarmonyPatch(typeof(InteractionBar), nameof(InteractionBar.Show))] + private static bool InteractionBar_Show(InteractionBar __instance, bool instant, bool force) + { + enableOutlines = true; + return true; + } + + [HarmonyPrefix] + [HarmonyPatch(typeof(UISpriteDuplicator), nameof(UISpriteDuplicator.CreateImage), typeof(SpriteRenderer), typeof(Transform), typeof(Transform), typeof(float), typeof(Vector2), typeof(bool))] + private static bool UISpriteDuplicator_CreateImage(SpriteRenderer spriteRenderer, Transform source, Transform destination, float scale, Vector2 offset, bool forceFullAlpha) + { + return !(spriteRenderer.sortingOrder == -1 && !enableOutlines); + } + + [HarmonyPostfix] + [HarmonyPatch(typeof(InteractionBar), nameof(InteractionBar.Show))] + private static void InteractionBar_Show_Postfix(InteractionBar __instance, bool instant, bool force) + { + enableOutlines = false; + } + [HarmonyPrefix] [HarmonyPatch(typeof(UIUnitRenderer), nameof(UIUnitRenderer.CreateUnit))] private static bool UIUnitRenderer_CreateUnit_Prefix(UIUnitRenderer __instance) diff --git a/src/Registry.cs b/src/Registry.cs index 3861034..207d225 100644 --- a/src/Registry.cs +++ b/src/Registry.cs @@ -14,6 +14,10 @@ public static class Registry internal static Dictionary mods = new(); public static Dictionary tribePreviews = new(); public static Dictionary spriteInfos = new(); + public static Dictionary prefabNames = new(); + public static Dictionary unitPrefabs = new(); + public static Dictionary resourcePrefabs = new(); + public static Dictionary improvementsPrefabs = new(); public static Dictionary assetBundles = new(); public static List customTribes = new(); public static List skinInfo = new();