diff --git a/BossHealthPlugin/BossBarStyle.cs b/BossHealthPlugin/BossBarStyle.cs index 39296fa..e05dc9c 100644 --- a/BossHealthPlugin/BossBarStyle.cs +++ b/BossHealthPlugin/BossBarStyle.cs @@ -5,9 +5,9 @@ namespace Skopje.BossHealth /// /// Look of the boss health bar. This is the file to edit. /// - /// Sprites are chosen by the name shown on an Image's Sprite field in the game. - /// Leave a name empty to copy the in-game XP progress bar sprite. - /// After changing a name, rebuild the plugin. + /// Sprites are chosen by the name shown on an Image's Sprite field in the game. + /// Leave a fill name empty to use a solid rectangle. + /// After changing a name, rebuild the plugin. /// public static class BossBarStyle { @@ -17,15 +17,17 @@ namespace Skopje.BossHealth public static readonly Color HealthColor = new Color(0.86f, 0.1f, 0.1f, 1f); public static readonly Color DelayColor = new Color(1f, 0.48f, 0.08f, 1f); + public static readonly Color ImmuneColor = new Color(0.62f, 0.62f, 0.62f, 1f); + public static readonly Color ImmuneDelayColor = new Color(0.4f, 0.4f, 0.4f, 1f); public static readonly Color BackgroundColor = new Color(0.04f, 0.04f, 0.04f, 0.8f); public static readonly Color LabelColor = Color.white; - // The white bar waits this long after the last hit, then drains toward the real health. + // The orange bar waits this long after the last hit, then drains toward the real health. public const float DelaySeconds = 0.6f; public const float DelayDrainPerSecond = 0.75f; public static readonly Vector2 BarSize = new Vector2(392f, 13f); - public const float TopClearance = 100f; + public const float TopClearance = 25f; public const float TrackPadding = 2f; public const float LabelHeight = 26f; public const float LabelFontSize = 20f; diff --git a/BossHealthPlugin/BossHealthPlugin.cs b/BossHealthPlugin/BossHealthPlugin.cs index deb77f6..14db63b 100644 --- a/BossHealthPlugin/BossHealthPlugin.cs +++ b/BossHealthPlugin/BossHealthPlugin.cs @@ -193,7 +193,7 @@ namespace Skopje.BossHealth { _nextReadTime = Time.unscaledTime + FightReadSeconds; if (_fights[0].StillGoing(out float ratio)) - Present(_fights[0].Name, ratio); + Present(_fights[0].Name, ratio, _fights[0].IsImmune()); } else { @@ -223,10 +223,10 @@ namespace Skopje.BossHealth } if (_fights[0].StillGoing(out float ratio)) - Present(_fights[0].Name, ratio); + Present(_fights[0].Name, ratio, _fights[0].IsImmune()); } - void Present(string bossName, float ratio) + void Present(string bossName, float ratio, bool immune) { EnsureBar(); if (!_hasSample || _bossName != bossName) @@ -255,9 +255,15 @@ namespace Skopje.BossHealth if (_label != null) _label.text = bossName; if (_healthImage != null) + { + _healthImage.color = immune ? BossBarStyle.ImmuneColor : BossBarStyle.HealthColor; _healthImage.fillAmount = _health; + } if (_delayImage != null) + { + _delayImage.color = immune ? BossBarStyle.ImmuneDelayColor : BossBarStyle.DelayColor; _delayImage.fillAmount = _delay; + } } void AnimateDelay() @@ -443,9 +449,8 @@ namespace Skopje.BossHealth { XpProgressBar xpBar = FindXpBar(); Image xpImage = xpBar != null ? xpBar.ProgressBar : null; - Sprite xpSprite = xpImage != null ? xpImage.sprite : null; - Sprite healthSprite = ResolveSprite(BossBarStyle.HealthSpriteName, xpSprite) ?? SolidSprite(); - Sprite delaySprite = ResolveSprite(BossBarStyle.DelaySpriteName, healthSprite) ?? healthSprite; + Sprite healthSprite = ResolveSprite(BossBarStyle.HealthSpriteName, null) ?? SolidSprite(); + Sprite delaySprite = ResolveSprite(BossBarStyle.DelaySpriteName, null) ?? healthSprite; Sprite backgroundSprite = ResolveSprite(BossBarStyle.BackgroundSpriteName, FrameSprite(xpImage, healthSprite)); _barRoot = new GameObject("BossHealthBar"); @@ -846,6 +851,18 @@ namespace Skopje.BossHealth return obj != null; } + static bool SafeDamageable(MetalskyBoss boss) + { + try + { + return boss.IsDamageable; + } + catch (Exception) + { + return true; + } + } + static bool SafeDead(MetalskyBoss boss) { try @@ -875,6 +892,7 @@ namespace Skopje.BossHealth public string Name; public abstract bool StillGoing(out float ratio); + public abstract bool IsImmune(); } sealed class AnaFight : Fight @@ -904,6 +922,11 @@ namespace Skopje.BossHealth return false; return TryRatio(_boss.EnemyControl, out ratio); } + + public override bool IsImmune() + { + return !IsTrue(_boss.IsVulnerable); + } } sealed class VesnaFight : Fight @@ -931,6 +954,11 @@ namespace Skopje.BossHealth return false; return TryRatio(_boss.EnemyControl, out ratio); } + + public override bool IsImmune() + { + return !IsTrue(_boss.Visibility); + } } sealed class MetalskyFight : Fight @@ -950,6 +978,11 @@ namespace Skopje.BossHealth return false; return TryRatio(_boss.PawnStatus, out ratio); } + + public override bool IsImmune() + { + return !SafeDamageable(_boss); + } } sealed class TeofanFight : Fight @@ -975,6 +1008,25 @@ namespace Skopje.BossHealth control = _brain.GetComponentInChildren(true); return TryRatio(control, out ratio); } + + public override bool IsImmune() + { + try + { + if (_brain.blockHelper != null && _brain.blockHelper.IsBlocking) + return true; + + TeofanBossState state = _brain.CurrentState; + return state == TeofanBossState.DissolveIn + || state == TeofanBossState.FallenInteract + || state == TeofanBossState.EndPhase + || state == TeofanBossState.Despawned; + } + catch (Exception) + { + return false; + } + } } } } diff --git a/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.dll b/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.dll index 388b28b..b921070 100644 Binary files a/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.dll and b/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.dll differ diff --git a/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.pdb b/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.pdb index 14a4ead..22ffce0 100644 Binary files a/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.pdb and b/BossHealthPlugin/bin/Release/net6.0/Skopje.BossHealth.pdb differ diff --git a/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfo.cs b/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfo.cs index 39f06f9..6ef20ca 100644 --- a/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfo.cs +++ b/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.BossHealth")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] [assembly: System.Reflection.AssemblyProductAttribute("Skopje.BossHealth")] [assembly: System.Reflection.AssemblyTitleAttribute("Skopje.BossHealth")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfoInputs.cache b/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfoInputs.cache index b0d2506..a150d82 100644 --- a/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfoInputs.cache +++ b/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.AssemblyInfoInputs.cache @@ -1 +1 @@ -0acf9d2f1a6c359332339552562b4ad3180ad1d45517bc93e22ec640b2c677b6 +abb2aafca8f9c38e16a185b614682f24e0da3a5492f3ed24b1aa588b0f35f2fc diff --git a/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.csproj.AssemblyReference.cache b/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.csproj.AssemblyReference.cache index 69b3c6f..1ce1eb6 100644 Binary files a/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.csproj.AssemblyReference.cache and b/BossHealthPlugin/obj/Release/net6.0/BossHealthPlugin.csproj.AssemblyReference.cache differ diff --git a/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.dll b/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.dll index 388b28b..b921070 100644 Binary files a/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.dll and b/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.dll differ diff --git a/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.pdb b/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.pdb index 14a4ead..22ffce0 100644 Binary files a/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.pdb and b/BossHealthPlugin/obj/Release/net6.0/Skopje.BossHealth.pdb differ diff --git a/BossHealthPlugin/obj/Release/net6.0/ref/Skopje.BossHealth.dll b/BossHealthPlugin/obj/Release/net6.0/ref/Skopje.BossHealth.dll index aa5efe0..367f5ab 100644 Binary files a/BossHealthPlugin/obj/Release/net6.0/ref/Skopje.BossHealth.dll and b/BossHealthPlugin/obj/Release/net6.0/ref/Skopje.BossHealth.dll differ diff --git a/BossHealthPlugin/obj/Release/net6.0/refint/Skopje.BossHealth.dll b/BossHealthPlugin/obj/Release/net6.0/refint/Skopje.BossHealth.dll index aa5efe0..367f5ab 100644 Binary files a/BossHealthPlugin/obj/Release/net6.0/refint/Skopje.BossHealth.dll and b/BossHealthPlugin/obj/Release/net6.0/refint/Skopje.BossHealth.dll differ diff --git a/CustomPlayerSkins/CustomPlayerSkinsPlugin.cs b/CustomPlayerSkins/CustomPlayerSkinsPlugin.cs new file mode 100644 index 0000000..cd94b9a --- /dev/null +++ b/CustomPlayerSkins/CustomPlayerSkinsPlugin.cs @@ -0,0 +1,438 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using BepInEx; +using BepInEx.Configuration; +using BepInEx.Logging; +using BepInEx.Unity.IL2CPP; +using HarmonyLib; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.InteropTypes.Arrays; +using Skopje.Modding; +using UnityEngine; + +namespace Skopje.CustomPlayerSkins +{ + [BepInPlugin(PluginGuid, PluginName, PluginVersion)] + public class CustomPlayerSkinsPlugin : BasePlugin + { + public const string PluginGuid = "com.skopje.customplayerskins"; + public const string PluginName = "Skopje Custom Player Skins"; + public const string PluginVersion = "1.0.0"; + + internal static ManualLogSource LogSource; + internal static ConfigEntry Enabled; + + static Harmony _harmony; + static Il2CppSystem.Action _onPlayerStarted; + + public override void Load() + { + LogSource = Log; + Enabled = Config.Bind("Skin", "Enabled", true, "Replace each player outfit with its own PNG in the CustomSkins folder next to this plugin."); + + _harmony = new Harmony(PluginGuid); + var refresh = AccessTools.Method(typeof(SkopjePlayer), "RefreshActiveModels"); + if (refresh == null) + LogSource.LogWarning("SkopjePlayer.RefreshActiveModels was not found. The skins are applied when a player spawns."); + else + _harmony.Patch(refresh, postfix: new HarmonyMethod(typeof(SkinPatches), nameof(SkinPatches.AfterRefreshModels))); + + _onPlayerStarted = DelegateSupport.ConvertDelegate>(new Action(SkinReplacer.ApplyPlayer)); + ModAPI.add_OnPlayerStartedClient(_onPlayerStarted); + + LogSource.LogInfo($"{PluginName} {PluginVersion} loaded. Edit the PNGs in CustomSkins: singleplayer, ranger, medic, engineer, and fighter (the Warrior class)."); + } + + public override bool Unload() + { + if (_harmony != null) + _harmony.UnpatchSelf(); + SkinReplacer.Restore(); + return true; + } + } + + static class SkinPatches + { + public static void AfterRefreshModels(SkopjePlayer __instance) + { + SkinReplacer.ApplyPlayer(__instance); + } + } + + static class SkinReplacer + { + sealed class Outfit + { + public string FileName; + public string DumpMaterial; + public string[] Materials; + public Texture2D Texture; + public DateTime WriteTimeUtc; + } + + // Fighter is the multiplayer class shown as Warrior on the player icons. + static readonly Outfit[] Outfits = + { + new Outfit + { + FileName = "singleplayer.png", + DumpMaterial = "MAT_Pioneer_Default_Clothes", + Materials = new[] { "MAT_Pioneer_Default_Clothes", "MAT_Pioneer_Default_Clothes_FP" }, + }, + new Outfit + { + FileName = "ranger.png", + DumpMaterial = "MAT_Pioneer_Ranger_Clothes", + Materials = new[] { "MAT_Pioneer_Ranger_Clothes", "MAT_Pioneer_Ranger_Clothes_FP" }, + }, + new Outfit + { + FileName = "medic.png", + DumpMaterial = "MAT_Pioneer_Medic_Clothes", + Materials = new[] { "MAT_Pioneer_Medic_Clothes", "MAT_Pioneer_Medic_Clothes_FP" }, + }, + new Outfit + { + FileName = "engineer.png", + DumpMaterial = "MAT_Pioneer_Engi_Clothes", + Materials = new[] { "MAT_Pioneer_Engi_Clothes", "MAT_Pioneer_Engi_Clothes_FP" }, + }, + new Outfit + { + FileName = "fighter.png", + DumpMaterial = "MAT_Pioneer_Fighter_Clothes", + Materials = new[] { "MAT_Pioneer_Fighter_Clothes", "MAT_Pioneer_Fighter_Clothes_FP" }, + }, + }; + + static readonly Dictionary _originals = new Dictionary(); + static float _nextFileCheck; + static bool _loggedMiss; + + public static void ApplyPlayer(SkopjePlayer player) + { + if (!CustomPlayerSkinsPlugin.Enabled.Value) + { + RevertMaterials(); + return; + } + if (!EnsureTextures()) + return; + + int applied = ApplyLoadedMaterials(); + if (player != null) + { + applied += ApplySkins(player.PlayerSkins); + applied += ApplyRenderer(player.FirstPersonRenderer); + applied += ApplyRenderer(player.ThirdPersonRenderer); + } + + if (applied == 0 && !_loggedMiss) + { + _loggedMiss = true; + CustomPlayerSkinsPlugin.LogSource.LogWarning("Custom skins are loaded, but the player clothes materials are not in memory yet."); + } + else if (applied > 0) + { + _loggedMiss = false; + CustomPlayerSkinsPlugin.LogSource.LogInfo($"Applied {applied} player clothes material{(applied == 1 ? "" : "s")} from CustomSkins."); + } + } + + public static void Restore() + { + RevertMaterials(); + _originals.Clear(); + for (int i = 0; i < Outfits.Length; i++) + { + if (Outfits[i].Texture == null) + continue; + UnityEngine.Object.Destroy(Outfits[i].Texture); + Outfits[i].Texture = null; + } + } + + static void RevertMaterials() + { + foreach (var pair in _originals) + { + var material = FindMaterial(pair.Key); + if (material != null) + material.SetTexture("_MainTex", pair.Value); + } + } + + static int ApplyLoadedMaterials() + { + int applied = 0; + var materials = Resources.FindObjectsOfTypeAll(); + for (int i = 0; i < materials.Length; i++) + applied += ApplyMaterial(materials[i]); + return applied; + } + + static int ApplySkins(Il2CppReferenceArray skins) + { + if (skins == null) + return 0; + int applied = 0; + for (int i = 0; i < skins.Length; i++) + { + PlayerSkin skin = skins[i]; + if (skin == null) + continue; + applied += ApplyMaterialArray(skin.FPMaterials); + applied += ApplyMaterialArray(skin.TPMaterials); + } + return applied; + } + + static int ApplyRenderer(Renderer renderer) + { + if (renderer == null) + return 0; + var materials = renderer.sharedMaterials; + if (materials == null) + return 0; + int applied = 0; + for (int i = 0; i < materials.Length; i++) + applied += ApplyMaterial(materials[i]); + return applied; + } + + static int ApplyMaterialArray(Il2CppReferenceArray materials) + { + if (materials == null) + return 0; + int applied = 0; + for (int i = 0; i < materials.Length; i++) + applied += ApplyMaterial(materials[i]); + return applied; + } + + static int ApplyMaterial(Material material) + { + if (material == null || !material.HasProperty("_MainTex")) + return 0; + Outfit outfit = FindOutfit(material.name); + if (outfit == null || outfit.Texture == null) + return 0; + + int id = material.GetInstanceID(); + if (!_originals.ContainsKey(id)) + { + var current = material.GetTexture("_MainTex"); + _originals[id] = current; + CopySampling(outfit.Texture, current); + } + + if (material.GetTexture("_MainTex") == outfit.Texture) + return 0; + + material.SetTexture("_MainTex", outfit.Texture); + return 1; + } + + static Outfit FindOutfit(string materialName) + { + if (string.IsNullOrEmpty(materialName)) + return null; + for (int i = 0; i < Outfits.Length; i++) + { + string[] names = Outfits[i].Materials; + for (int n = 0; n < names.Length; n++) + { + string expected = names[n]; + if (materialName == expected || materialName.StartsWith(expected + " (", StringComparison.Ordinal)) + return Outfits[i]; + } + } + return null; + } + + static void CopySampling(Texture2D target, Texture source) + { + if (target == null || source == null) + return; + target.wrapMode = source.wrapMode; + target.filterMode = source.filterMode; + target.anisoLevel = source.anisoLevel; + } + + static Material FindMaterial(int instanceId) + { + var materials = Resources.FindObjectsOfTypeAll(); + for (int i = 0; i < materials.Length; i++) + { + Material material = materials[i]; + if (material != null && material.GetInstanceID() == instanceId) + return material; + } + return null; + } + + static bool EnsureTextures() + { + if (AnyLoaded() && Time.unscaledTime < _nextFileCheck) + return true; + _nextFileCheck = Time.unscaledTime + 1f; + + string directory = SkinsDirectory(); + int ready = 0; + for (int i = 0; i < Outfits.Length; i++) + { + if (EnsureOutfit(Outfits[i], directory)) + ready++; + } + + if (ready == 0) + { + CustomPlayerSkinsPlugin.LogSource.LogWarning("No outfit PNGs are ready in " + directory); + return false; + } + return true; + } + + static bool AnyLoaded() + { + for (int i = 0; i < Outfits.Length; i++) + { + if (Outfits[i].Texture != null) + return true; + } + return false; + } + + static bool EnsureOutfit(Outfit outfit, string directory) + { + string path = Path.Combine(directory, outfit.FileName); + if (!File.Exists(path)) + { + if (!TryDumpSample(outfit, path)) + return outfit.Texture != null; + } + + DateTime writeTime; + try { writeTime = File.GetLastWriteTimeUtc(path); } + catch (Exception ex) + { + CustomPlayerSkinsPlugin.LogSource.LogError("Could not read " + outfit.FileName + ": " + ex.Message); + return outfit.Texture != null; + } + + if (outfit.Texture != null && outfit.WriteTimeUtc == writeTime) + return true; + + byte[] bytes; + try { bytes = File.ReadAllBytes(path); } + catch (Exception ex) + { + CustomPlayerSkinsPlugin.LogSource.LogError("Could not read " + outfit.FileName + ": " + ex.Message); + return outfit.Texture != null; + } + + var texture = new Texture2D(2, 2, TextureFormat.RGBA32, true); + texture.name = "SkopjeCustomSkin_" + Path.GetFileNameWithoutExtension(outfit.FileName); + texture.hideFlags = HideFlags.HideAndDontSave; + if (!ImageConversion.LoadImage(texture, bytes)) + { + UnityEngine.Object.Destroy(texture); + CustomPlayerSkinsPlugin.LogSource.LogError(outfit.FileName + " is not a readable image: " + path); + return outfit.Texture != null; + } + + if (outfit.Texture != null) + UnityEngine.Object.Destroy(outfit.Texture); + outfit.Texture = texture; + outfit.WriteTimeUtc = writeTime; + _loggedMiss = false; + CustomPlayerSkinsPlugin.LogSource.LogInfo($"Loaded {outfit.FileName} ({texture.width}x{texture.height})"); + return true; + } + + static bool TryDumpSample(Outfit outfit, string path) + { + Texture source = null; + var materials = Resources.FindObjectsOfTypeAll(); + for (int i = 0; i < materials.Length && source == null; i++) + { + Material material = materials[i]; + if (material == null || material.name != outfit.DumpMaterial) + continue; + if (!material.HasProperty("_MainTex")) + continue; + Texture current = material.GetTexture("_MainTex"); + if (_originals.TryGetValue(material.GetInstanceID(), out Texture original)) + current = original; + source = current; + } + if (source == null) + return false; + + byte[] png = EncodePng(source); + if (png == null || png.Length == 0) + return false; + + try + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + File.WriteAllBytes(path, png); + CustomPlayerSkinsPlugin.LogSource.LogInfo("Dumped " + outfit.FileName + " from the game into CustomSkins."); + return true; + } + catch (Exception ex) + { + CustomPlayerSkinsPlugin.LogSource.LogError("Could not write " + outfit.FileName + ": " + ex.Message); + return false; + } + } + + static byte[] EncodePng(Texture source) + { + var readable = source as Texture2D; + bool temporary = false; + RenderTexture rt = null; + RenderTexture previous = RenderTexture.active; + try + { + if (readable == null || !readable.isReadable) + { + rt = RenderTexture.GetTemporary(source.width, source.height, 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB); + Graphics.Blit(source, rt); + RenderTexture.active = rt; + readable = new Texture2D(source.width, source.height, TextureFormat.RGBA32, false); + readable.ReadPixels(new Rect(0, 0, source.width, source.height), 0, 0); + readable.Apply(); + temporary = true; + } + + var encoded = ImageConversion.EncodeToPNG(readable); + if (encoded == null) + return null; + var bytes = new byte[encoded.Length]; + for (int i = 0; i < encoded.Length; i++) + bytes[i] = encoded[i]; + return bytes; + } + finally + { + RenderTexture.active = previous; + if (rt != null) + RenderTexture.ReleaseTemporary(rt); + if (temporary && readable != null) + UnityEngine.Object.Destroy(readable); + } + } + + static string SkinsDirectory() + { + string dllDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + if (!string.IsNullOrEmpty(dllDir)) + return Path.Combine(dllDir, "CustomSkins"); + return Path.Combine(Paths.PluginPath, "CustomSkins"); + } + } +} diff --git a/CustomPlayerSkins/CustomPlayerSkinsPlugin.csproj b/CustomPlayerSkins/CustomPlayerSkinsPlugin.csproj new file mode 100644 index 0000000..3867a27 --- /dev/null +++ b/CustomPlayerSkins/CustomPlayerSkinsPlugin.csproj @@ -0,0 +1,60 @@ + + + net6.0 + latest + disable + disable + true + Skopje.CustomPlayerSkins + Skopje.CustomPlayerSkins + true + D:\SteamLibrary\steamapps\common\Skopje83 + + + + + $(GameDir)\BepInEx\core\0Harmony.dll + false + + + $(GameDir)\BepInEx\core\BepInEx.Core.dll + false + + + $(GameDir)\BepInEx\core\BepInEx.Unity.IL2CPP.dll + false + + + $(GameDir)\BepInEx\core\Il2CppInterop.Runtime.dll + false + + + $(GameDir)\BepInEx\interop\Il2Cppmscorlib.dll + false + + + $(GameDir)\BepInEx\interop\SkopjeAssembly.dll + false + + + $(GameDir)\BepInEx\interop\FishNet.Runtime.dll + false + + + $(GameDir)\BepInEx\interop\Archon.SwissArmyLib.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.CoreModule.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.ImageConversionModule.dll + false + + + + + + + diff --git a/CustomPlayerSkins/CustomSkins/engineer.png b/CustomPlayerSkins/CustomSkins/engineer.png new file mode 100644 index 0000000..6666a90 Binary files /dev/null and b/CustomPlayerSkins/CustomSkins/engineer.png differ diff --git a/CustomPlayerSkins/CustomSkins/fighter.png b/CustomPlayerSkins/CustomSkins/fighter.png new file mode 100644 index 0000000..61dff42 Binary files /dev/null and b/CustomPlayerSkins/CustomSkins/fighter.png differ diff --git a/CustomPlayerSkins/CustomSkins/medic.png b/CustomPlayerSkins/CustomSkins/medic.png new file mode 100644 index 0000000..f2de69c Binary files /dev/null and b/CustomPlayerSkins/CustomSkins/medic.png differ diff --git a/CustomPlayerSkins/CustomSkins/ranger.png b/CustomPlayerSkins/CustomSkins/ranger.png new file mode 100644 index 0000000..410e766 Binary files /dev/null and b/CustomPlayerSkins/CustomSkins/ranger.png differ diff --git a/CustomPlayerSkins/CustomSkins/singleplayer.png b/CustomPlayerSkins/CustomSkins/singleplayer.png new file mode 100644 index 0000000..2ce4b0c Binary files /dev/null and b/CustomPlayerSkins/CustomSkins/singleplayer.png differ diff --git a/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/engineer.png b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/engineer.png new file mode 100644 index 0000000..6666a90 Binary files /dev/null and b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/engineer.png differ diff --git a/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/fighter.png b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/fighter.png new file mode 100644 index 0000000..61dff42 Binary files /dev/null and b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/fighter.png differ diff --git a/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/medic.png b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/medic.png new file mode 100644 index 0000000..f2de69c Binary files /dev/null and b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/medic.png differ diff --git a/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/ranger.png b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/ranger.png new file mode 100644 index 0000000..410e766 Binary files /dev/null and b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/ranger.png differ diff --git a/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/singleplayer.png b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/singleplayer.png new file mode 100644 index 0000000..2ce4b0c Binary files /dev/null and b/CustomPlayerSkins/bin/Release/net6.0/CustomSkins/singleplayer.png differ diff --git a/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.deps.json b/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.deps.json new file mode 100644 index 0000000..0f540b7 --- /dev/null +++ b/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "Skopje.CustomPlayerSkins/1.0.0": { + "runtime": { + "Skopje.CustomPlayerSkins.dll": {} + } + } + } + }, + "libraries": { + "Skopje.CustomPlayerSkins/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.dll b/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.dll new file mode 100644 index 0000000..cc0bb23 Binary files /dev/null and b/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.dll differ diff --git a/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.pdb b/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.pdb new file mode 100644 index 0000000..09c7ee2 Binary files /dev/null and b/CustomPlayerSkins/bin/Release/net6.0/Skopje.CustomPlayerSkins.pdb differ diff --git a/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.dgspec.json b/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.dgspec.json new file mode 100644 index 0000000..918967d --- /dev/null +++ b/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.dgspec.json @@ -0,0 +1,85 @@ +{ + "format": 1, + "restore": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\CustomPlayerSkinsPlugin.csproj": {} + }, + "projects": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\CustomPlayerSkinsPlugin.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\CustomPlayerSkinsPlugin.csproj", + "projectName": "Skopje.CustomPlayerSkins", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\CustomPlayerSkinsPlugin.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[6.0.36, 6.0.36]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.g.props b/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.g.props new file mode 100644 index 0000000..ba0d2cb --- /dev/null +++ b/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + PackageReference + 7.0.0 + + + + + \ No newline at end of file diff --git a/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.g.targets b/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/CustomPlayerSkins/obj/CustomPlayerSkinsPlugin.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/CustomPlayerSkins/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/CustomPlayerSkins/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..ed92695 --- /dev/null +++ b/CustomPlayerSkins/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] diff --git a/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.AssemblyInfo.cs b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.AssemblyInfo.cs new file mode 100644 index 0000000..00d17b7 --- /dev/null +++ b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.CustomPlayerSkins")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] +[assembly: System.Reflection.AssemblyProductAttribute("Skopje.CustomPlayerSkins")] +[assembly: System.Reflection.AssemblyTitleAttribute("Skopje.CustomPlayerSkins")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.AssemblyInfoInputs.cache b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.AssemblyInfoInputs.cache new file mode 100644 index 0000000..c224ac7 --- /dev/null +++ b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +2039bc0988efa0867d36e92385b47db55a3abd9b1b79233f9907b9909d2a0097 diff --git a/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.GeneratedMSBuildEditorConfig.editorconfig b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..4c04389 --- /dev/null +++ b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,18 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property.EntryPointFilePath = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Skopje.CustomPlayerSkins +build_property.ProjectDir = c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 6.0 +build_property.EnableCodeStyleSeverity = diff --git a/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.assets.cache b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.assets.cache new file mode 100644 index 0000000..87adbd1 Binary files /dev/null and b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.assets.cache differ diff --git a/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.AssemblyReference.cache b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.AssemblyReference.cache new file mode 100644 index 0000000..1f4a1a0 Binary files /dev/null and b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.AssemblyReference.cache differ diff --git a/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.CoreCompileInputs.cache b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..cc36eae --- /dev/null +++ b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +6c1139a480f7b2b40bb2ca9a6182e2472a2688fad5f37ff82d5b23ba614cabb0 diff --git a/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.FileListAbsolute.txt b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..1b57119 --- /dev/null +++ b/CustomPlayerSkins/obj/Release/net6.0/CustomPlayerSkinsPlugin.csproj.FileListAbsolute.txt @@ -0,0 +1,17 @@ +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\CustomPlayerSkinsPlugin.csproj.AssemblyReference.cache +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\CustomPlayerSkinsPlugin.GeneratedMSBuildEditorConfig.editorconfig +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\CustomPlayerSkinsPlugin.AssemblyInfoInputs.cache +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\CustomPlayerSkinsPlugin.AssemblyInfo.cs +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\CustomPlayerSkinsPlugin.csproj.CoreCompileInputs.cache +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\Skopje.CustomPlayerSkins.dll +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\refint\Skopje.CustomPlayerSkins.dll +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\Skopje.CustomPlayerSkins.pdb +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\Skopje.CustomPlayerSkins.deps.json +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\Skopje.CustomPlayerSkins.dll +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\Skopje.CustomPlayerSkins.pdb +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\obj\Release\net6.0\ref\Skopje.CustomPlayerSkins.dll +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\CustomSkins\engineer.png +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\CustomSkins\fighter.png +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\CustomSkins\medic.png +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\CustomSkins\ranger.png +c:\Users\andre\Desktop\SkopjeMods\CustomPlayerSkins\bin\Release\net6.0\CustomSkins\singleplayer.png diff --git a/CustomPlayerSkins/obj/Release/net6.0/Skopje.CustomPlayerSkins.dll b/CustomPlayerSkins/obj/Release/net6.0/Skopje.CustomPlayerSkins.dll new file mode 100644 index 0000000..cc0bb23 Binary files /dev/null and b/CustomPlayerSkins/obj/Release/net6.0/Skopje.CustomPlayerSkins.dll differ diff --git a/CustomPlayerSkins/obj/Release/net6.0/Skopje.CustomPlayerSkins.pdb b/CustomPlayerSkins/obj/Release/net6.0/Skopje.CustomPlayerSkins.pdb new file mode 100644 index 0000000..09c7ee2 Binary files /dev/null and b/CustomPlayerSkins/obj/Release/net6.0/Skopje.CustomPlayerSkins.pdb differ diff --git a/CustomPlayerSkins/obj/Release/net6.0/ref/Skopje.CustomPlayerSkins.dll b/CustomPlayerSkins/obj/Release/net6.0/ref/Skopje.CustomPlayerSkins.dll new file mode 100644 index 0000000..8d7e450 Binary files /dev/null and b/CustomPlayerSkins/obj/Release/net6.0/ref/Skopje.CustomPlayerSkins.dll differ diff --git a/CustomPlayerSkins/obj/Release/net6.0/refint/Skopje.CustomPlayerSkins.dll b/CustomPlayerSkins/obj/Release/net6.0/refint/Skopje.CustomPlayerSkins.dll new file mode 100644 index 0000000..8d7e450 Binary files /dev/null and b/CustomPlayerSkins/obj/Release/net6.0/refint/Skopje.CustomPlayerSkins.dll differ diff --git a/CustomPlayerSkins/obj/project.assets.json b/CustomPlayerSkins/obj/project.assets.json new file mode 100644 index 0000000..a067448 --- /dev/null +++ b/CustomPlayerSkins/obj/project.assets.json @@ -0,0 +1,90 @@ +{ + "version": 4, + "targets": { + "net6.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net6.0": [] + }, + "packageFolders": { + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\CustomPlayerSkinsPlugin.csproj", + "projectName": "Skopje.CustomPlayerSkins", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\CustomPlayerSkinsPlugin.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[6.0.36, 6.0.36]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/CustomPlayerSkins/obj/project.nuget.cache b/CustomPlayerSkins/obj/project.nuget.cache new file mode 100644 index 0000000..b8e0839 --- /dev/null +++ b/CustomPlayerSkins/obj/project.nuget.cache @@ -0,0 +1,12 @@ +{ + "version": 2, + "dgSpecHash": "7IEzcjI0wFM=", + "success": true, + "projectFilePath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\CustomPlayerSkins\\CustomPlayerSkinsPlugin.csproj", + "expectedPackageFiles": [ + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.netcore.app.ref\\6.0.36\\microsoft.netcore.app.ref.6.0.36.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.windowsdesktop.app.ref\\6.0.36\\microsoft.windowsdesktop.app.ref.6.0.36.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.aspnetcore.app.ref\\6.0.36\\microsoft.aspnetcore.app.ref.6.0.36.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/DamageNumbers/DamageNumbersPlugin.cs b/DamageNumbers/DamageNumbersPlugin.cs index 369fdf8..cff397f 100644 --- a/DamageNumbers/DamageNumbersPlugin.cs +++ b/DamageNumbers/DamageNumbersPlugin.cs @@ -25,6 +25,8 @@ namespace Skopje.DamageNumbers internal static ConfigEntry OnlyYourDamage; internal static ConfigEntry Lifetime; internal static ConfigEntry Size; + internal static ConfigEntry ValueMultiplier; + internal static ConfigEntry CritTextAbove; static Harmony _harmony; static SkopjePlayer _localPlayer; @@ -51,6 +53,8 @@ namespace Skopje.DamageNumbers OnlyYourDamage = Config.Bind("Display", "OnlyYourDamage", true, "Only show hits dealt by your pawn. Hits with no owner still show."); Lifetime = Config.Bind("Display", "Lifetime", 0.8f, "Seconds each number stays on screen."); Size = Config.Bind("Display", "Size", 1f, "Size multiplier."); + ValueMultiplier = Config.Bind("Display", "ValueMultiplier", 1f, "Extra multiplier on the displayed number. The built-in scale stays in place."); + CritTextAbove = Config.Bind("Display", "CritTextAbove", 100, "Show the CRIT label when the displayed number is greater than this."); ClassInjector.RegisterTypeInIl2Cpp(); @@ -181,8 +185,9 @@ namespace Skopje.DamageNumbers part = enemy.lastDamagedPart.Value; bool crit = IsCrit(part); - int shown = ShownDamage(raw, crit); - DamageTier.Apply(shown, out Color color, out float tierScale); + float displayScale = DisplayScale(crit); + int shown = ShownDamage(raw, displayScale); + DamageTier.Apply(shown, displayScale, out Color color, out float tierScale); float punch = PunchFor(rawAmount, crit, type) * tierScale; pos += new Vector3( UnityEngine.Random.Range(-0.22f, 0.22f), @@ -280,11 +285,26 @@ namespace Skopje.DamageNumbers // Real hits in this game are often 1, 2, or 3. Scale them up so the popup // still tracks the hit, but reads like a chunky score. Crits are doubled. - static int ShownDamage(float raw, bool crit) + static float DisplayScale(bool crit) + { + float extra = 1f; + if (ValueMultiplier != null && !float.IsNaN(ValueMultiplier.Value) && !float.IsInfinity(ValueMultiplier.Value)) + extra = ValueMultiplier.Value; + return (crit ? 200f : 100f) * extra; + } + + static int ShownDamage(float raw, float displayScale) { - float scale = crit ? 200f : 100f; float roll = UnityEngine.Random.Range(0.94f, 1.06f); - return Mathf.Max(1, Mathf.RoundToInt(raw * scale * roll)); + return Mathf.Max(1, Mathf.RoundToInt(raw * displayScale * roll)); + } + + internal static bool ShowCritText(int shown, bool crit) + { + if (!crit) + return false; + int above = CritTextAbove != null ? CritTextAbove.Value : 100; + return shown > above; } static bool Claim(EnemyControlAStar enemy, int amount, Vector3 pos) @@ -416,7 +436,7 @@ namespace Skopje.DamageNumbers Tilt = UnityEngine.Random.Range(crit ? -18f : -14f, crit ? 18f : 14f), Amount = amount, Color = color, - Text = crit ? "CRIT\n" + amount : amount.ToString() + Text = DamageNumbersPlugin.ShowCritText(amount, crit) ? "CRIT\n" + amount : amount.ToString() }; Measure(display._numbers[slot].Text, out display._numbers[slot].Lines, out display._numbers[slot].Longest); } @@ -607,9 +627,13 @@ namespace Skopje.DamageNumbers static readonly Color LightOrange = new Color(1f, 0.74f, 0.38f, 1f); static readonly Color Orange = new Color(1f, 0.48f, 0.08f, 1f); - public static void Apply(int amount, out Color color, out float sizeScale) + public static void Apply(int amount, float displayScale, out Color color, out float sizeScale) { - if (amount >= 50) + int yellow = Band(25, displayScale); + int lightOrange = Band(40, displayScale); + int orange = Band(50, displayScale); + + if (amount >= orange) { color = Orange; sizeScale = 1.15f; @@ -617,12 +641,17 @@ namespace Skopje.DamageNumbers } sizeScale = 1f; - if (amount >= 40) + if (amount >= lightOrange) color = LightOrange; - else if (amount >= 25) + else if (amount >= yellow) color = LightYellow; else color = White; } + + static int Band(int baseValue, float displayScale) + { + return Mathf.Max(1, Mathf.RoundToInt(baseValue * displayScale)); + } } } diff --git a/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.dll b/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.dll index 9574fba..0613b1f 100644 Binary files a/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.dll and b/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.dll differ diff --git a/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.pdb b/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.pdb index 066284a..4fc0e7f 100644 Binary files a/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.pdb and b/DamageNumbers/bin/Release/net6.0/Skopje.DamageNumbers.pdb differ diff --git a/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfo.cs b/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfo.cs index 66d0f42..32eb50d 100644 --- a/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfo.cs +++ b/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.DamageNumbers")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] [assembly: System.Reflection.AssemblyProductAttribute("Skopje.DamageNumbers")] [assembly: System.Reflection.AssemblyTitleAttribute("Skopje.DamageNumbers")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfoInputs.cache b/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfoInputs.cache index 9954ebc..dbf7e50 100644 --- a/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfoInputs.cache +++ b/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.AssemblyInfoInputs.cache @@ -1 +1 @@ -a6bbf0f8cbba65e2618b81c6321ac40b204cddd43585a4acfc7f7e5c36244fcc +dde6890729b61f58e466ea7b10c19cab8ad8b0c2df507a60a79c69f9ac5267e5 diff --git a/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.csproj.AssemblyReference.cache b/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.csproj.AssemblyReference.cache index 1a4a5d3..e4d6795 100644 Binary files a/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.csproj.AssemblyReference.cache and b/DamageNumbers/obj/Release/net6.0/DamageNumbersPlugin.csproj.AssemblyReference.cache differ diff --git a/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.dll b/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.dll index 9574fba..0613b1f 100644 Binary files a/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.dll and b/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.dll differ diff --git a/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.pdb b/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.pdb index 066284a..4fc0e7f 100644 Binary files a/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.pdb and b/DamageNumbers/obj/Release/net6.0/Skopje.DamageNumbers.pdb differ diff --git a/DamageNumbers/obj/Release/net6.0/ref/Skopje.DamageNumbers.dll b/DamageNumbers/obj/Release/net6.0/ref/Skopje.DamageNumbers.dll index 14e2ff6..850c2a1 100644 Binary files a/DamageNumbers/obj/Release/net6.0/ref/Skopje.DamageNumbers.dll and b/DamageNumbers/obj/Release/net6.0/ref/Skopje.DamageNumbers.dll differ diff --git a/DamageNumbers/obj/Release/net6.0/refint/Skopje.DamageNumbers.dll b/DamageNumbers/obj/Release/net6.0/refint/Skopje.DamageNumbers.dll index 14e2ff6..850c2a1 100644 Binary files a/DamageNumbers/obj/Release/net6.0/refint/Skopje.DamageNumbers.dll and b/DamageNumbers/obj/Release/net6.0/refint/Skopje.DamageNumbers.dll differ diff --git a/DomRadio/DomRadioPlugin.cs b/DomRadio/DomRadioPlugin.cs new file mode 100644 index 0000000..c07573c --- /dev/null +++ b/DomRadio/DomRadioPlugin.cs @@ -0,0 +1,735 @@ +using System; +using System.Collections.Generic; +using System.IO; +using BepInEx; +using BepInEx.Configuration; +using BepInEx.Logging; +using BepInEx.Unity.IL2CPP; +using FMODUnity; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.Injection; +using Il2CppInterop.Runtime.InteropTypes.Arrays; +using Skopje.Modding; +using UnityEngine; + +namespace Skopje.DomRadio +{ + [BepInPlugin(PluginGuid, PluginName, PluginVersion)] + public class DomRadioPlugin : BasePlugin + { + public const string PluginGuid = "com.skopje.domradio"; + public const string PluginName = "Skopje Dom Radio"; + public const string PluginVersion = "1.0.0"; + + internal static ManualLogSource LogSource; + + internal static ConfigEntry Toggle; + internal static ConfigEntry NextTrack; + internal static ConfigEntry PreviousTrack; + internal static ConfigEntry Shuffle; + internal static ConfigEntry MuteGameMusic; + internal static ConfigEntry MusicBusFilter; + internal static ConfigEntry Folder; + internal static ConfigEntry ShowNowPlaying; + + internal static SkopjePlayer LocalPlayer; + + static GameObject _host; + static Il2CppSystem.Action _onPlayerStarted; + static Il2CppSystem.Action _onPlayerStopped; + + public override void Load() + { + LogSource = Log; + Toggle = Config.Bind("Radio", "Toggle", KeyCode.F8, "Turn the radio on or off."); + NextTrack = Config.Bind("Radio", "NextTrack", KeyCode.F10, "Skip to the next file."); + PreviousTrack = Config.Bind("Radio", "PreviousTrack", KeyCode.F9, "Go back to the previous file."); + Shuffle = Config.Bind("Radio", "Shuffle", false, "Play the folder in a random order. Off plays files by name."); + MuteGameMusic = Config.Bind("Radio", "MuteGameMusic", true, "While the radio is on, mute the game's music buses. That includes the Dom bus track. Sound effects stay on."); + MusicBusFilter = Config.Bind("Radio", "MusicBusFilter", "Music", "Mute FMOD buses whose path contains this text. Music covers the Dom bus home track."); + Folder = Config.Bind("Radio", "Folder", "", "Folder of .mp3 and .wav files. Leave empty to use BepInEx/plugins/DomRadio/Music."); + ShowNowPlaying = Config.Bind("Radio", "ShowNowPlaying", true, "Show the current file name while the radio is on."); + + ClassInjector.RegisterTypeInIl2Cpp(); + + try + { + Directory.CreateDirectory(MusicDirectory); + } + catch (Exception ex) + { + Log.LogWarning("Could not create the music folder: " + ex.Message); + } + + _onPlayerStarted = DelegateSupport.ConvertDelegate>(new Action(OnPlayerStarted)); + _onPlayerStopped = DelegateSupport.ConvertDelegate>(new Action(OnPlayerStopped)); + ModAPI.add_OnPlayerStartedClient(_onPlayerStarted); + ModAPI.add_OnPlayerStoppedClient(_onPlayerStopped); + + _host = new GameObject("SkopjeDomRadio"); + UnityEngine.Object.DontDestroyOnLoad(_host); + _host.hideFlags = HideFlags.HideAndDontSave; + _host.AddComponent(); + + Log.LogInfo($"{PluginName} {PluginVersion} loaded. Put .mp3 and .wav files in {MusicDirectory}. Toggle {Toggle.Value}, next {NextTrack.Value}, previous {PreviousTrack.Value}."); + } + + public override bool Unload() + { + if (DomRadioPlayer.Instance != null) + DomRadioPlayer.Instance.TurnOff(false); + GameMusic.Release(); + LocalPlayer = null; + if (_onPlayerStarted != null) + ModAPI.remove_OnPlayerStartedClient(_onPlayerStarted); + if (_onPlayerStopped != null) + ModAPI.remove_OnPlayerStoppedClient(_onPlayerStopped); + if (_host != null) + { + UnityEngine.Object.Destroy(_host); + _host = null; + } + + return true; + } + + internal static string MusicDirectory + { + get + { + string custom = Folder == null ? null : Folder.Value; + if (!string.IsNullOrWhiteSpace(custom)) + return custom; + return Path.Combine(Paths.PluginPath, "DomRadio", "Music"); + } + } + + static void OnPlayerStarted(SkopjePlayer player) + { + if (player != null && player.IsOwner) + LocalPlayer = player; + } + + static void OnPlayerStopped(SkopjePlayer player) + { + if (LocalPlayer == player) + LocalPlayer = null; + } + + internal static SkopjePlayer FindLocalPlayer() + { + if (LocalPlayer != null) + return LocalPlayer; + + var players = UnityEngine.Object.FindObjectsOfType(); + if (players == null) + return null; + + for (int i = 0; i < players.Length; i++) + { + SkopjePlayer player = players[i]; + if (player != null && player.IsOwner) + { + LocalPlayer = player; + return player; + } + } + + return null; + } + + internal static float MusicLevel() + { + try + { + OptionsManager manager = OptionsManager.Instance; + if (manager == null || manager.OptionsData == null) + return 1f; + + return Unit(manager.OptionsData.MasterVolume) * Unit(manager.OptionsData.MusicVolume); + } + catch (Exception) + { + return 1f; + } + } + + static float Unit(float value) + { + if (value > 1f) + value *= 0.01f; + return Mathf.Clamp01(value); + } + } + + public class DomRadioPlayer : MonoBehaviour + { + const float MissedPlaySeconds = 2f; + + public static DomRadioPlayer Instance { get; private set; } + + readonly List _tracks = new List(); + FMOD.Sound _sound; + FMOD.Channel _channel; + bool _hasSound; + int _index; + int _failures; + bool _on; + bool _suspended; + bool _skipPending; + bool _heardPlayback; + bool _loggedEmpty; + float _playDeadline; + string _nowPlaying = string.Empty; + string _notice = string.Empty; + float _noticeUntil; + GUIStyle _label; + Texture2D _backdrop; + int _styleHeight; + + public DomRadioPlayer(IntPtr pointer) : base(pointer) + { + } + + void Awake() + { + Instance = this; + } + + void OnDestroy() + { + TurnOff(false); + if (_backdrop != null) + Destroy(_backdrop); + if (Instance == this) + Instance = null; + } + + void Update() + { + bool inside = InDom(); + if (Pressed(DomRadioPlugin.Toggle.Value)) + { + if (_on) + TurnOff(true); + else if (inside) + TurnOn(); + else + Notify("Radio only plays in the Dom", 2f); + } + + if (!_on) + return; + + if (!inside) + { + if (!_suspended) + Suspend(); + return; + } + + if (_suspended) + Resume(); + + if (Pressed(DomRadioPlugin.NextTrack.Value)) + Advance(1); + else if (Pressed(DomRadioPlugin.PreviousTrack.Value)) + Advance(-1); + + PumpLoad(); + // Mute the Dom track only while one of our files is actually audible. + if (DomRadioPlugin.MuteGameMusic.Value && IsAudible()) + GameMusic.Hold(); + else if (!DomRadioPlugin.MuteGameMusic.Value) + GameMusic.Release(); + } + + void OnGUI() + { + if (Event.current == null || Event.current.type != EventType.Repaint || GUI.skin == null) + return; + + EnsureStyle(); + const float width = 640f; + const float height = 36f; + float textWidth = width - _label.padding.left - _label.padding.right; + + string text = null; + if (_on && !_suspended && DomRadioPlugin.ShowNowPlaying.Value && !string.IsNullOrEmpty(_nowPlaying)) + text = Fit(_nowPlaying, textWidth); + else if (Time.unscaledTime <= _noticeUntil && !string.IsNullOrEmpty(_notice)) + text = Fit(_notice, textWidth); + if (text == null) + return; + + var rect = new Rect((Screen.width - width) * 0.5f, Screen.height - 96f, width, height); + Color previous = GUI.color; + GUI.color = new Color(0f, 0f, 0f, 0.62f); + GUI.DrawTexture(rect, _backdrop); + GUI.color = previous; + GUI.Label(rect, text, _label); + } + + public void TurnOn() + { + ReloadTracks(); + if (_tracks.Count == 0) + { + if (!_loggedEmpty) + { + _loggedEmpty = true; + DomRadioPlugin.LogSource.LogInfo("Radio disabled. No .mp3 or .wav files in " + DomRadioPlugin.MusicDirectory + ". Dom music will keep playing."); + } + + return; + } + + _loggedEmpty = false; + _on = true; + _failures = 0; + _index = 0; + _nowPlaying = TrackLabel(_tracks[0]); + try + { + PlayFile(_tracks[0]); + } + catch (Exception ex) + { + DomRadioPlugin.LogSource.LogWarning("Could not start the radio: " + ex.Message); + TurnOff(false); + DomRadioPlugin.LogSource.LogInfo("Radio disabled. Dom music restored."); + return; + } + + DomRadioPlugin.LogSource.LogInfo("Radio on. " + _tracks.Count + " file(s) in " + DomRadioPlugin.MusicDirectory); + } + + public void TurnOff(bool announce) + { + _on = false; + _suspended = false; + _skipPending = false; + _heardPlayback = false; + _nowPlaying = string.Empty; + StopSound(); + GameMusic.Release(); + if (announce) + { + Notify("Radio off", 2f); + DomRadioPlugin.LogSource.LogInfo("Radio off. Dom music restored."); + } + } + + void Advance(int direction) + { + if (_tracks.Count == 0) + { + TurnOff(true); + return; + } + + int next = _index + direction; + if (next >= _tracks.Count) + next = 0; + else if (next < 0) + next = _tracks.Count - 1; + + _index = next; + _nowPlaying = TrackLabel(_tracks[_index]); + PlayFile(_tracks[_index]); + } + + void ReloadTracks() + { + _tracks.Clear(); + string folder = DomRadioPlugin.MusicDirectory; + if (!Directory.Exists(folder)) + { + try + { + Directory.CreateDirectory(folder); + } + catch (Exception ex) + { + DomRadioPlugin.LogSource.LogWarning("Could not create the music folder: " + ex.Message); + return; + } + } + + string[] files; + try + { + files = Directory.GetFiles(folder); + } + catch (Exception ex) + { + DomRadioPlugin.LogSource.LogWarning("Could not read the music folder: " + ex.Message); + return; + } + + for (int i = 0; i < files.Length; i++) + { + string extension = Path.GetExtension(files[i]); + if (extension.Equals(".mp3", StringComparison.OrdinalIgnoreCase) || extension.Equals(".wav", StringComparison.OrdinalIgnoreCase)) + _tracks.Add(files[i]); + } + + _tracks.Sort(StringComparer.OrdinalIgnoreCase); + if (DomRadioPlugin.Shuffle.Value) + ShuffleTracks(); + } + + void ShuffleTracks() + { + var random = new System.Random(); + for (int i = _tracks.Count - 1; i > 0; i--) + { + int swap = random.Next(i + 1); + string file = _tracks[i]; + _tracks[i] = _tracks[swap]; + _tracks[swap] = file; + } + } + + void PlayFile(string path) + { + StopSound(); + _heardPlayback = false; + _nowPlaying = TrackLabel(path); + if (!RuntimeManager.IsInitialized) + { + DomRadioPlugin.LogSource.LogWarning("Audio system is not ready yet."); + _skipPending = true; + return; + } + + FMOD.System core = RuntimeManager.CoreSystem; + if (!core.hasHandle()) + { + DomRadioPlugin.LogSource.LogWarning("Audio system is not ready yet."); + _skipPending = true; + return; + } + + FMOD.MODE mode = FMOD.MODE.CREATESTREAM | FMOD.MODE._2D | FMOD.MODE.LOOP_OFF; + FMOD.Sound sound; + FMOD.RESULT result = core.createSound(path, mode, out sound); + if (result != FMOD.RESULT.OK || !sound.hasHandle()) + { + DomRadioPlugin.LogSource.LogWarning("Could not open " + Path.GetFileName(path) + " (" + result + ")."); + _skipPending = true; + return; + } + + FMOD.ChannelGroup master; + core.getMasterChannelGroup(out master); + FMOD.Channel channel; + result = core.playSound(sound, master, false, out channel); + if (result != FMOD.RESULT.OK || !channel.hasHandle()) + { + sound.release(); + DomRadioPlugin.LogSource.LogWarning("Could not play " + Path.GetFileName(path) + " (" + result + ")."); + _skipPending = true; + return; + } + + channel.setVolume(DomRadioPlugin.MusicLevel()); + _sound = sound; + _channel = channel; + _hasSound = true; + _playDeadline = Time.unscaledTime + MissedPlaySeconds; + } + + void PumpLoad() + { + if (_skipPending) + { + _skipPending = false; + OnTrackFailed(); + return; + } + + if (!_hasSound) + return; + + if (IsAudible()) + { + _heardPlayback = true; + _failures = 0; + _channel.setVolume(DomRadioPlugin.MusicLevel()); + return; + } + + if (_heardPlayback || Time.unscaledTime >= _playDeadline) + Advance(1); + } + + bool IsAudible() + { + if (!_hasSound || !_channel.hasHandle()) + return false; + bool playing = false; + return _channel.isPlaying(out playing) == FMOD.RESULT.OK && playing; + } + + void OnTrackFailed() + { + _failures++; + if (_tracks.Count == 0 || _failures >= _tracks.Count) + { + TurnOff(false); + DomRadioPlugin.LogSource.LogInfo("Radio disabled. No playable files in " + DomRadioPlugin.MusicDirectory + ". Dom music restored."); + return; + } + + Advance(1); + } + + void StopSound() + { + if (_hasSound && _channel.hasHandle()) + _channel.stop(); + if (_hasSound && _sound.hasHandle()) + _sound.release(); + _hasSound = false; + } + + void Notify(string text, float seconds) + { + _notice = text ?? string.Empty; + _noticeUntil = Time.unscaledTime + seconds; + } + + static bool _loggedInput; + + static bool Pressed(KeyCode key) + { + if (key == KeyCode.None) + return false; + try + { + return Input.GetKeyDown(key); + } + catch (Exception ex) + { + if (!_loggedInput) + { + _loggedInput = true; + DomRadioPlugin.LogSource.LogWarning("Keyboard input is unavailable: " + ex.Message); + } + + return false; + } + } + + bool InDom() + { + SkopjePlayer player = DomRadioPlugin.FindLocalPlayer(); + if (player == null) + return false; + + try + { + return player.InsideVehicle != null; + } + catch (Exception) + { + DomRadioPlugin.LocalPlayer = null; + return false; + } + } + + void Suspend() + { + _suspended = true; + if (_hasSound && _channel.hasHandle()) + _channel.setPaused(true); + GameMusic.Release(); + } + + void Resume() + { + _suspended = false; + if (_hasSound && _channel.hasHandle()) + { + _channel.setPaused(false); + _channel.setVolume(DomRadioPlugin.MusicLevel()); + return; + } + + if (_index >= 0 && _index < _tracks.Count) + PlayFile(_tracks[_index]); + } + + string Fit(string text, float width) + { + if (string.IsNullOrEmpty(text) || _label.CalcSize(new GUIContent(text)).x <= width) + return text; + + const string ellipsis = "..."; + int low = 0; + int high = text.Length; + while (low < high) + { + int mid = (low + high + 1) / 2; + string candidate = text.Substring(0, mid).TrimEnd() + ellipsis; + if (_label.CalcSize(new GUIContent(candidate)).x <= width) + low = mid; + else + high = mid - 1; + } + + if (low <= 0) + return ellipsis; + return text.Substring(0, low).TrimEnd() + ellipsis; + } + + static string TrackLabel(string path) + { + return "Radio — " + Path.GetFileNameWithoutExtension(path); + } + + void EnsureStyle() + { + if (_backdrop == null) + { + _backdrop = new Texture2D(1, 1); + _backdrop.SetPixel(0, 0, Color.white); + _backdrop.Apply(); + } + + if (_label != null && _styleHeight == Screen.height) + return; + + _styleHeight = Screen.height; + _label = new GUIStyle(GUI.skin.label); + _label.alignment = TextAnchor.MiddleCenter; + _label.wordWrap = false; + _label.clipping = TextClipping.Clip; + _label.padding = new RectOffset(12, 12, 0, 0); + _label.fontSize = Mathf.Clamp(Mathf.RoundToInt(Screen.height * 0.018f), 14, 28); + _label.normal.textColor = Color.white; + } + } + + // The Dom bus soundtrack is event:/Music/Bus/Home, on the game's Music buses. + // Muting those buses leaves the events running, so the track returns when the radio turns off. + static class GameMusic + { + sealed class HeldBus + { + public FMOD.Studio.Bus Bus; + public bool WasMuted; + } + + static readonly List _held = new List(); + static bool _loggedMiss; + static float _nextDiscover; + + public static void Hold() + { + if (!DomRadioPlugin.MuteGameMusic.Value) + return; + if (!RuntimeManager.IsInitialized) + return; + + if (_held.Count == 0 && Time.unscaledTime >= _nextDiscover) + { + _nextDiscover = Time.unscaledTime + 1f; + Discover(); + } + + int valid = 0; + for (int i = 0; i < _held.Count; i++) + { + FMOD.Studio.Bus bus = _held[i].Bus; + if (!bus.isValid()) + continue; + valid++; + bus.setMute(true); + } + + // Banks reload with a new level. Drop dead handles so the next pass can find the music buses again. + if (_held.Count > 0 && valid == 0) + { + _held.Clear(); + _nextDiscover = 0f; + } + } + + public static void Release() + { + for (int i = 0; i < _held.Count; i++) + { + FMOD.Studio.Bus bus = _held[i].Bus; + if (bus.isValid()) + bus.setMute(_held[i].WasMuted); + } + + _held.Clear(); + _loggedMiss = false; + _nextDiscover = 0f; + } + + static void Discover() + { + try + { + var studio = RuntimeManager.StudioSystem; + if (!studio.isValid()) + return; + + Il2CppStructArray banks = null; + if (studio.getBankList(out banks) != FMOD.RESULT.OK || banks == null || banks.Length == 0) + return; + + string filter = DomRadioPlugin.MusicBusFilter.Value ?? string.Empty; + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + var others = new List(); + for (int i = 0; i < banks.Length; i++) + { + FMOD.Studio.Bank bank = banks[i]; + if (!bank.isValid()) + continue; + + Il2CppStructArray buses = null; + if (bank.getBusList(out buses) != FMOD.RESULT.OK || buses == null) + continue; + + for (int b = 0; b < buses.Length; b++) + { + FMOD.Studio.Bus bus = buses[b]; + if (!bus.isValid()) + continue; + + string path = null; + if (bus.getPath(out path) != FMOD.RESULT.OK || string.IsNullOrEmpty(path)) + continue; + if (!seen.Add(path)) + continue; + if (filter.Length == 0 || path.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0) + { + others.Add(path); + continue; + } + + bool wasMuted = false; + bus.getMute(out wasMuted); + _held.Add(new HeldBus { Bus = bus, WasMuted = wasMuted }); + DomRadioPlugin.LogSource.LogInfo("Muting " + path); + } + } + + if (_held.Count == 0 && !_loggedMiss) + { + _loggedMiss = true; + DomRadioPlugin.LogSource.LogWarning("No music bus matched \"" + filter + "\". Dom music will keep playing. Buses: " + string.Join(", ", others)); + } + } + catch (Exception ex) + { + DomRadioPlugin.LogSource.LogWarning("Could not find the music buses: " + ex.Message); + } + } + } +} diff --git a/DomRadio/DomRadioPlugin.csproj b/DomRadio/DomRadioPlugin.csproj new file mode 100644 index 0000000..7ae9717 --- /dev/null +++ b/DomRadio/DomRadioPlugin.csproj @@ -0,0 +1,64 @@ + + + net6.0 + latest + disable + disable + true + Skopje.DomRadio + Skopje.DomRadio + true + D:\SteamLibrary\steamapps\common\Skopje83 + + + + + $(GameDir)\BepInEx\core\BepInEx.Core.dll + false + + + $(GameDir)\BepInEx\core\BepInEx.Unity.IL2CPP.dll + false + + + $(GameDir)\BepInEx\core\Il2CppInterop.Runtime.dll + false + + + $(GameDir)\BepInEx\interop\Il2Cppmscorlib.dll + false + + + $(GameDir)\BepInEx\interop\SkopjeAssembly.dll + false + + + $(GameDir)\BepInEx\interop\FishNet.Runtime.dll + false + + + $(GameDir)\BepInEx\interop\Archon.SwissArmyLib.dll + false + + + $(GameDir)\BepInEx\interop\FMODUnity.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.CoreModule.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.IMGUIModule.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.TextRenderingModule.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.InputLegacyModule.dll + false + + + diff --git a/DomRadio/bin/Release/net6.0/Skopje.DomRadio.deps.json b/DomRadio/bin/Release/net6.0/Skopje.DomRadio.deps.json new file mode 100644 index 0000000..f3df0bc --- /dev/null +++ b/DomRadio/bin/Release/net6.0/Skopje.DomRadio.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "Skopje.DomRadio/1.0.0": { + "runtime": { + "Skopje.DomRadio.dll": {} + } + } + } + }, + "libraries": { + "Skopje.DomRadio/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/DomRadio/bin/Release/net6.0/Skopje.DomRadio.dll b/DomRadio/bin/Release/net6.0/Skopje.DomRadio.dll new file mode 100644 index 0000000..2a78d0f Binary files /dev/null and b/DomRadio/bin/Release/net6.0/Skopje.DomRadio.dll differ diff --git a/DomRadio/bin/Release/net6.0/Skopje.DomRadio.pdb b/DomRadio/bin/Release/net6.0/Skopje.DomRadio.pdb new file mode 100644 index 0000000..2089194 Binary files /dev/null and b/DomRadio/bin/Release/net6.0/Skopje.DomRadio.pdb differ diff --git a/DomRadio/obj/DomRadioPlugin.csproj.nuget.dgspec.json b/DomRadio/obj/DomRadioPlugin.csproj.nuget.dgspec.json new file mode 100644 index 0000000..b9bb7ca --- /dev/null +++ b/DomRadio/obj/DomRadioPlugin.csproj.nuget.dgspec.json @@ -0,0 +1,85 @@ +{ + "format": 1, + "restore": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj": {} + }, + "projects": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj", + "projectName": "Skopje.DomRadio", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[6.0.36, 6.0.36]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/DomRadio/obj/DomRadioPlugin.csproj.nuget.g.props b/DomRadio/obj/DomRadioPlugin.csproj.nuget.g.props new file mode 100644 index 0000000..ba0d2cb --- /dev/null +++ b/DomRadio/obj/DomRadioPlugin.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + PackageReference + 7.0.0 + + + + + \ No newline at end of file diff --git a/DomRadio/obj/DomRadioPlugin.csproj.nuget.g.targets b/DomRadio/obj/DomRadioPlugin.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/DomRadio/obj/DomRadioPlugin.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/DomRadio/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/DomRadio/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..ed92695 --- /dev/null +++ b/DomRadio/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] diff --git a/DomRadio/obj/Release/net6.0/DomRadioPlugin.AssemblyInfo.cs b/DomRadio/obj/Release/net6.0/DomRadioPlugin.AssemblyInfo.cs new file mode 100644 index 0000000..dace733 --- /dev/null +++ b/DomRadio/obj/Release/net6.0/DomRadioPlugin.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.DomRadio")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] +[assembly: System.Reflection.AssemblyProductAttribute("Skopje.DomRadio")] +[assembly: System.Reflection.AssemblyTitleAttribute("Skopje.DomRadio")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/DomRadio/obj/Release/net6.0/DomRadioPlugin.AssemblyInfoInputs.cache b/DomRadio/obj/Release/net6.0/DomRadioPlugin.AssemblyInfoInputs.cache new file mode 100644 index 0000000..c598668 --- /dev/null +++ b/DomRadio/obj/Release/net6.0/DomRadioPlugin.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +fb5aa0eaad5177616647c1fd58891f07eda98dfbaa1c7f1588f2c8bfe53d1402 diff --git a/DomRadio/obj/Release/net6.0/DomRadioPlugin.GeneratedMSBuildEditorConfig.editorconfig b/DomRadio/obj/Release/net6.0/DomRadioPlugin.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..8389d14 --- /dev/null +++ b/DomRadio/obj/Release/net6.0/DomRadioPlugin.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,18 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property.EntryPointFilePath = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Skopje.DomRadio +build_property.ProjectDir = c:\Users\andre\Desktop\SkopjeMods\DomRadio\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 6.0 +build_property.EnableCodeStyleSeverity = diff --git a/DomRadio/obj/Release/net6.0/DomRadioPlugin.assets.cache b/DomRadio/obj/Release/net6.0/DomRadioPlugin.assets.cache new file mode 100644 index 0000000..ddab172 Binary files /dev/null and b/DomRadio/obj/Release/net6.0/DomRadioPlugin.assets.cache differ diff --git a/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.AssemblyReference.cache b/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.AssemblyReference.cache new file mode 100644 index 0000000..aad68d4 Binary files /dev/null and b/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.AssemblyReference.cache differ diff --git a/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.CoreCompileInputs.cache b/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..e7e2c06 --- /dev/null +++ b/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +081092add6543b8dcb5ec27e0ed95920f8750f6a3a0b82e5686acb95102220e9 diff --git a/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.FileListAbsolute.txt b/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..b41f788 --- /dev/null +++ b/DomRadio/obj/Release/net6.0/DomRadioPlugin.csproj.FileListAbsolute.txt @@ -0,0 +1,12 @@ +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.csproj.AssemblyReference.cache +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.GeneratedMSBuildEditorConfig.editorconfig +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.AssemblyInfoInputs.cache +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.AssemblyInfo.cs +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\DomRadioPlugin.csproj.CoreCompileInputs.cache +c:\Users\andre\Desktop\SkopjeMods\DomRadio\bin\Release\net6.0\Skopje.DomRadio.deps.json +c:\Users\andre\Desktop\SkopjeMods\DomRadio\bin\Release\net6.0\Skopje.DomRadio.dll +c:\Users\andre\Desktop\SkopjeMods\DomRadio\bin\Release\net6.0\Skopje.DomRadio.pdb +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\Skopje.DomRadio.dll +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\refint\Skopje.DomRadio.dll +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\Skopje.DomRadio.pdb +c:\Users\andre\Desktop\SkopjeMods\DomRadio\obj\Release\net6.0\ref\Skopje.DomRadio.dll diff --git a/DomRadio/obj/Release/net6.0/Skopje.DomRadio.dll b/DomRadio/obj/Release/net6.0/Skopje.DomRadio.dll new file mode 100644 index 0000000..2a78d0f Binary files /dev/null and b/DomRadio/obj/Release/net6.0/Skopje.DomRadio.dll differ diff --git a/DomRadio/obj/Release/net6.0/Skopje.DomRadio.pdb b/DomRadio/obj/Release/net6.0/Skopje.DomRadio.pdb new file mode 100644 index 0000000..2089194 Binary files /dev/null and b/DomRadio/obj/Release/net6.0/Skopje.DomRadio.pdb differ diff --git a/DomRadio/obj/Release/net6.0/ref/Skopje.DomRadio.dll b/DomRadio/obj/Release/net6.0/ref/Skopje.DomRadio.dll new file mode 100644 index 0000000..8f422b3 Binary files /dev/null and b/DomRadio/obj/Release/net6.0/ref/Skopje.DomRadio.dll differ diff --git a/DomRadio/obj/Release/net6.0/refint/Skopje.DomRadio.dll b/DomRadio/obj/Release/net6.0/refint/Skopje.DomRadio.dll new file mode 100644 index 0000000..8f422b3 Binary files /dev/null and b/DomRadio/obj/Release/net6.0/refint/Skopje.DomRadio.dll differ diff --git a/DomRadio/obj/project.assets.json b/DomRadio/obj/project.assets.json new file mode 100644 index 0000000..2094ac5 --- /dev/null +++ b/DomRadio/obj/project.assets.json @@ -0,0 +1,90 @@ +{ + "version": 4, + "targets": { + "net6.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net6.0": [] + }, + "packageFolders": { + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj", + "projectName": "Skopje.DomRadio", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[6.0.36, 6.0.36]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/DomRadio/obj/project.nuget.cache b/DomRadio/obj/project.nuget.cache new file mode 100644 index 0000000..32c0ab8 --- /dev/null +++ b/DomRadio/obj/project.nuget.cache @@ -0,0 +1,12 @@ +{ + "version": 2, + "dgSpecHash": "3mbnNdPiqio=", + "success": true, + "projectFilePath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\DomRadio\\DomRadioPlugin.csproj", + "expectedPackageFiles": [ + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.netcore.app.ref\\6.0.36\\microsoft.netcore.app.ref.6.0.36.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.windowsdesktop.app.ref\\6.0.36\\microsoft.windowsdesktop.app.ref.6.0.36.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.aspnetcore.app.ref\\6.0.36\\microsoft.aspnetcore.app.ref.6.0.36.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/Minimap/MinimapPlugin.cs b/Minimap/MinimapPlugin.cs new file mode 100644 index 0000000..438cb0f --- /dev/null +++ b/Minimap/MinimapPlugin.cs @@ -0,0 +1,1037 @@ +using System; +using System.Collections.Generic; +using BepInEx; +using BepInEx.Configuration; +using BepInEx.Logging; +using BepInEx.Unity.IL2CPP; +using Doozy.Engine.UI; +using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.Injection; +using Skopje.Modding; +using UnityEngine; +using UnityEngine.UI; + +namespace Skopje.Minimap +{ + [BepInPlugin(PluginGuid, PluginName, PluginVersion)] + public class MinimapPlugin : BasePlugin + { + public const string PluginGuid = "com.skopje.minimap"; + public const string PluginName = "Skopje Minimap"; + public const string PluginVersion = "1.0.0"; + + internal static ManualLogSource LogSource; + + internal static ConfigEntry Enabled; + internal static ConfigEntry Size; + internal static ConfigEntry ViewRadius; + internal static ConfigEntry Gap; + internal static ConfigEntry ShowMarkers; + internal static ConfigEntry MarkerSize; + + internal static SkopjePlayer LocalPlayer; + + // Il2Cpp delegates are collected if nothing managed keeps them alive. + static Il2CppSystem.Action _onClientStarted; + static Il2CppSystem.Action _onClientStopped; + static Il2CppSystem.Action _onPlayerStarted; + static Il2CppSystem.Action _onPlayerStopped; + + public override void Load() + { + LogSource = Log; + Enabled = Config.Bind("Minimap", "Enabled", true, "Show the minimap under the clock."); + Size = Config.Bind("Minimap", "Size", 256f, new ConfigDescription( + "Width and height of the minimap, in the same units as the rest of the HUD.", + new AcceptableValueRange(96f, 512f))); + ViewRadius = Config.Bind("Minimap", "ViewRadius", 100f, new ConfigDescription( + "Meters from the player to the edge of the minimap.", + new AcceptableValueRange(25f, 600f))); + Gap = Config.Bind("Minimap", "Gap", 6f, new ConfigDescription( + "Space between the bottom of the clock and the top of the minimap.", + new AcceptableValueRange(0f, 80f))); + ShowMarkers = Config.Bind("Minimap", "ShowMarkers", true, "Show the same map icons the full map uses, when they are inside the view."); + MarkerSize = Config.Bind("Minimap", "MarkerSize", 16f, new ConfigDescription( + "Icon size on the minimap.", + new AcceptableValueRange(8f, 40f))); + + ClassInjector.RegisterTypeInIl2Cpp(); + + _onClientStarted = ToIl2Cpp(new System.Action(OnClientStarted)); + _onClientStopped = ToIl2Cpp(new System.Action(OnClientStopped)); + _onPlayerStarted = ToIl2Cpp(new System.Action(OnPlayerStarted)); + _onPlayerStopped = ToIl2Cpp(new System.Action(OnPlayerStopped)); + + ModAPI.add_OnClientStarted(_onClientStarted); + ModAPI.add_OnClientStopped(_onClientStopped); + ModAPI.add_OnPlayerStartedClient(_onPlayerStarted); + ModAPI.add_OnPlayerStoppedClient(_onPlayerStopped); + + LogSource.LogInfo($"{PluginName} {PluginVersion} loaded. Config: {Config.ConfigFilePath}"); + } + + public override bool Unload() + { + LocalPlayer = null; + if (MinimapDisplay.Instance != null) + UnityEngine.Object.Destroy(MinimapDisplay.Instance.gameObject); + return true; + } + + static void OnClientStarted() + { + if (MinimapDisplay.Instance != null) + return; + + var host = new GameObject("SkopjeMinimap"); + UnityEngine.Object.DontDestroyOnLoad(host); + host.AddComponent(); + LogSource.LogInfo("Minimap display created."); + } + + static void OnClientStopped() + { + LocalPlayer = null; + if (MinimapDisplay.Instance != null) + UnityEngine.Object.Destroy(MinimapDisplay.Instance.gameObject); + } + + static void OnPlayerStarted(SkopjePlayer player) + { + if (player != null && player.IsOwner) + LocalPlayer = player; + } + + static void OnPlayerStopped(SkopjePlayer player) + { + if (LocalPlayer == player) + LocalPlayer = null; + } + + internal static SkopjePlayer FindLocalPlayer() + { + if (LocalPlayer != null) + return LocalPlayer; + + var players = UnityEngine.Object.FindObjectsOfType(); + if (players == null) + return null; + + SkopjePlayer solo = null; + int count = 0; + for (int i = 0; i < players.Length; i++) + { + SkopjePlayer player = players[i]; + if (player == null) + continue; + count++; + solo = player; + if (player.IsOwner) + { + LocalPlayer = player; + return player; + } + } + + if (count == 1) + { + LocalPlayer = solo; + return solo; + } + + return null; + } + + static Il2CppSystem.Action ToIl2Cpp(System.Action action) + { + return DelegateSupport.ConvertDelegate(action); + } + + static Il2CppSystem.Action ToIl2Cpp(System.Action action) + { + return DelegateSupport.ConvertDelegate>(action); + } + } + + public class MinimapDisplay : MonoBehaviour + { + const float Border = 2f; + const int MaxMarkers = 40; + const float SampleMeters = 20f; + + public static MinimapDisplay Instance { get; private set; } + + TimeDisplay _time; + UIView _hud; + MapControls _map; + LevelBounds _bounds; + Image _source; + Sprite _mapSprite; + + RectTransform _root; + RectTransform _window; + RectTransform _content; + RectTransform _mapRect; + Image _mapImage; + RectTransform _markersRoot; + RectTransform _heading; + + bool _useTopDown = true; + Vector2 _fallbackSize; + bool _laidOut; + bool _loggedReady; + bool _loggedTick; + bool _loggedWait; + float _nextSearch; + float _nextMarkerScan; + int _errorLogs; + + readonly List _slots = new List(); + readonly List _nearby = new List(); + readonly List _nearbyDist = new List(); + readonly Vector3[] _corners = new Vector3[4]; + + static Sprite _arrowSprite; + static Sprite _dotSprite; + + public MinimapDisplay(IntPtr pointer) : base(pointer) + { + } + + void Awake() + { + Instance = this; + } + + void OnDestroy() + { + if (_root != null) + Destroy(_root.gameObject); + if (Instance == this) + Instance = null; + } + + void Update() + { + try + { + Tick(); + } + catch (Exception ex) + { + if (_errorLogs < 3) + { + _errorLogs++; + MinimapPlugin.LogSource.LogWarning("Minimap update failed: " + ex.Message); + } + } + } + + void Tick() + { + if (!_loggedTick) + { + _loggedTick = true; + MinimapPlugin.LogSource.LogInfo("Minimap ticking."); + } + + if (!MinimapPlugin.Enabled.Value) + { + if (_root != null) + _root.gameObject.SetActive(false); + return; + } + + float now = Time.unscaledTime; + bool hudMissing = _hud == null || !_hud.gameObject.activeInHierarchy; + if ((_time == null || hudMissing || _mapSprite == null || _bounds == null) && now >= _nextSearch) + { + _nextSearch = now + 1.5f; + ResolveSources(); + } + + bool hudOn = _hud != null && _hud.gameObject.activeInHierarchy; + if (!hudOn) + { + if (_root != null) + _root.gameObject.SetActive(false); + if (!_loggedWait && now > 8f) + { + _loggedWait = true; + MinimapPlugin.LogSource.LogInfo("Minimap hidden: the in-game HUD is not active."); + } + return; + } + + EnsureWidget(); + if (_root == null) + return; + + if (!_root.gameObject.activeSelf) + _root.gameObject.SetActive(true); + + PlaceUnderTimer(); + + SkopjePlayer player = MinimapPlugin.FindLocalPlayer(); + if (_mapSprite == null || _bounds == null) + { + if (!_loggedWait && now > 8f) + { + _loggedWait = true; + MinimapPlugin.LogSource.LogInfo( + "Minimap frame is showing. Map image found: " + (_mapSprite != null) + ". Level bounds found: " + (_bounds != null) + "."); + } + return; + } + + if (!_laidOut || _mapImage.sprite != _mapSprite) + LayoutMap(); + + if (player != null && !Follow(player)) + ShowWholeMap(player); + else if (player == null) + ShowWholeMap(null); + + if (player != null && MinimapPlugin.ShowMarkers.Value) + { + if (now >= _nextMarkerScan) + { + _nextMarkerScan = now + 0.75f; + RescanMarkers(player); + } + MoveMarkers(); + } + else if (_slots.Count > 0) + { + HideMarkers(); + } + } + + void ResolveSources() + { + if (_time == null) + _time = PickTimer(); + if (_hud == null || !_hud.gameObject.activeInHierarchy) + { + UIView found = FindIngameView(); + if (found != null) + _hud = found; + } + if (_mapSprite == null) + { + _map = PickMap(); + _source = _map != null ? FindMapGraphic(_map) : null; + if (_source != null) + _mapSprite = _source.sprite; + if (_mapSprite == null) + _mapSprite = FindLooseMapSprite(); + _laidOut = false; + } + if (_bounds == null) + _bounds = PickBounds(); + } + + void EnsureWidget() + { + if (_root != null) + return; + + RectTransform parent = _hud.transform as RectTransform; + if (parent == null) + return; + + int layer = parent.gameObject.layer; + _root = CreateRect("Minimap", parent, layer); + _root.anchorMin = _root.anchorMax = new Vector2(0f, 1f); + _root.pivot = new Vector2(0f, 1f); + + Image border = CreateImage("Border", _root, DotSprite(), new Color(0.95f, 0.93f, 0.86f, 0.95f)); + Stretch(border.rectTransform, 0f); + + _window = CreateRect("Window", _root, layer); + Stretch(_window, Border); + _window.gameObject.AddComponent(); + + Image backdrop = CreateImage("Backdrop", _window, DotSprite(), new Color(0.07f, 0.09f, 0.08f, 0.94f)); + Stretch(backdrop.rectTransform, 0f); + + _content = CreateRect("Content", _window, layer); + _content.anchorMin = _content.anchorMax = new Vector2(0.5f, 0.5f); + _content.pivot = Vector2.zero; + _content.anchoredPosition = Vector2.zero; + + _mapImage = CreateImage("Map", _content, _mapSprite, Color.white); + _mapRect = _mapImage.rectTransform; + _mapRect.anchorMin = _mapRect.anchorMax = Vector2.zero; + _mapRect.pivot = new Vector2(0.5f, 0.5f); + + _markersRoot = CreateRect("Markers", _window, layer); + Stretch(_markersRoot, 0f); + + _heading = CreateRect("Heading", _window, layer); + _heading.anchorMin = _heading.anchorMax = new Vector2(0.5f, 0.5f); + _heading.pivot = new Vector2(0.5f, 0.5f); + _heading.anchoredPosition = Vector2.zero; + _heading.sizeDelta = Vector2.zero; + + Image shadow = CreateImage("ArrowShadow", _heading, ArrowSprite(), new Color(0f, 0f, 0f, 0.9f)); + shadow.rectTransform.anchorMin = shadow.rectTransform.anchorMax = new Vector2(0.5f, 0.5f); + shadow.rectTransform.sizeDelta = new Vector2(22f, 22f); + Image arrow = CreateImage("Arrow", _heading, ArrowSprite(), Color.white); + arrow.rectTransform.anchorMin = arrow.rectTransform.anchorMax = new Vector2(0.5f, 0.5f); + arrow.rectTransform.sizeDelta = new Vector2(15f, 15f); + + _root.SetAsLastSibling(); + _laidOut = false; + MinimapPlugin.LogSource.LogInfo("Minimap parented to '" + parent.name + "'."); + } + + void LayoutMap() + { + if (_mapSprite == null) + return; + + _mapImage.sprite = _mapSprite; + _mapImage.color = Color.white; + _mapImage.type = Image.Type.Simple; + _mapImage.preserveAspect = false; + + Vector2 bl = new Vector2(0f, 0f); + Vector2 tr = new Vector2(1f, 1f); + _useTopDown = _bounds != null; + if (_bounds != null) + { + try + { + bl = _bounds.GetTopDownPositionFrom01(new Vector2(0f, 0f)); + tr = _bounds.GetTopDownPositionFrom01(new Vector2(1f, 1f)); + } + catch (Exception) + { + _useTopDown = false; + } + } + + float span = Mathf.Max(Mathf.Abs(tr.x - bl.x), Mathf.Abs(tr.y - bl.y)); + if (!_useTopDown || span < 0.0001f || float.IsNaN(span)) + { + _useTopDown = false; + Rect spriteRect = _mapSprite.rect; + _fallbackSize = new Vector2(Mathf.Max(spriteRect.width, 1f), Mathf.Max(spriteRect.height, 1f)); + _mapRect.anchoredPosition = _fallbackSize * 0.5f; + _mapRect.sizeDelta = _fallbackSize; + _mapRect.localScale = Vector3.one; + } + else + { + _mapRect.anchoredPosition = (bl + tr) * 0.5f; + _mapRect.sizeDelta = new Vector2(Mathf.Abs(tr.x - bl.x), Mathf.Abs(tr.y - bl.y)); + _mapRect.localScale = new Vector3(tr.x < bl.x ? -1f : 1f, tr.y < bl.y ? -1f : 1f, 1f); + } + + _laidOut = true; + if (!_loggedReady) + { + _loggedReady = true; + MinimapPlugin.LogSource.LogInfo("Minimap using sprite '" + _mapSprite.name + "'."); + } + } + + void PlaceUnderTimer() + { + RectTransform parent = _hud.transform as RectTransform; + if (parent == null) + return; + + if (_root.parent != parent) + { + _root.SetParent(parent, false); + AdoptLayer(_root, parent.gameObject.layer); + _root.SetAsLastSibling(); + } + + float size = Mathf.Clamp(MinimapPlugin.Size.Value, 96f, 512f); + _root.anchorMin = _root.anchorMax = new Vector2(0f, 1f); + _root.pivot = new Vector2(0f, 1f); + _root.localScale = Vector3.one; + _root.sizeDelta = new Vector2(size, size); + + float x = 16f; + float y = -72f - MinimapPlugin.Gap.Value; + RectTransform clock = ClockRect(); + if (clock != null) + { + clock.GetWorldCorners(_corners); + Vector3 bottomLeft = _corners[0]; + Vector3 down = _corners[0] - _corners[1]; + float paneHeight = down.magnitude; + float clockHeight = Mathf.Abs(clock.rect.height); + if (clockHeight < 1f) + clockHeight = Mathf.Abs(clock.sizeDelta.y); + if (paneHeight > 0.5f && clockHeight >= 1f) + { + bottomLeft += down / paneHeight * (paneHeight * (MinimapPlugin.Gap.Value / clockHeight)); + Rect parentRect = parent.rect; + Vector3 local = parent.InverseTransformPoint(bottomLeft); + x = local.x - parentRect.xMin; + y = local.y - parentRect.yMax; + if (float.IsNaN(x) || float.IsNaN(y) || Mathf.Abs(x) > 4000f || Mathf.Abs(y) > 4000f) + { + x = 16f; + y = -72f - MinimapPlugin.Gap.Value; + } + } + } + + _root.anchoredPosition = new Vector2(x, y); + } + + RectTransform ClockRect() + { + if (_time == null || _time.TimePane == null) + return null; + return _time.TimePane; + } + + bool Follow(SkopjePlayer player) + { + Vector3 pos = player.transform.position; + Vector2 here = ToMap(pos); + Vector2 east = ToMap(pos + Vector3.right * SampleMeters) - here; + Vector2 north = ToMap(pos + Vector3.forward * SampleMeters) - here; + float ppm = east.magnitude / SampleMeters; + if (ppm < 0.0000001f) + ppm = north.magnitude / SampleMeters; + if (ppm < 0.0000001f || float.IsNaN(ppm) || float.IsInfinity(ppm)) + return false; + + float inner = Mathf.Max(16f, _root.sizeDelta.x - Border * 2f); + float radius = Mathf.Clamp(MinimapPlugin.ViewRadius.Value, 25f, 600f); + float zoom = (inner * 0.5f) / (radius * ppm); + if (float.IsNaN(zoom) || float.IsInfinity(zoom)) + return false; + + _content.anchoredPosition = -here * zoom; + _content.localScale = new Vector3(zoom, zoom, 1f); + _heading.anchoredPosition = Vector2.zero; + + Vector3 forward = player.transform.forward; + Vector2 mapForward = east * forward.x + north * forward.z; + if (mapForward.sqrMagnitude > 0.000001f) + { + float degrees = Mathf.Atan2(mapForward.x, mapForward.y) * Mathf.Rad2Deg; + _heading.localRotation = Quaternion.Euler(0f, 0f, -degrees); + } + + _playerMap = here; + _zoom = zoom; + return true; + } + + void ShowWholeMap(SkopjePlayer player) + { + if (_mapRect == null) + return; + + Vector2 size = _mapRect.sizeDelta; + float inner = Mathf.Max(16f, _root.sizeDelta.x - Border * 2f); + float zoom = inner / Mathf.Max(Mathf.Max(size.x, size.y), 1f); + Vector2 center = _mapRect.anchoredPosition; + _content.anchoredPosition = -center * zoom; + _content.localScale = new Vector3(zoom, zoom, 1f); + _playerMap = center; + _zoom = zoom; + + if (player == null || _bounds == null) + { + _heading.anchoredPosition = Vector2.zero; + return; + } + + try + { + Vector2 here = ToMap(player.transform.position); + _heading.anchoredPosition = (here - center) * zoom; + } + catch (Exception) + { + _heading.anchoredPosition = Vector2.zero; + } + } + + Vector2 _playerMap; + float _zoom = 1f; + + Vector2 ToMap(Vector3 world) + { + Vector2 uv = _bounds.GetLevelObjectPosition01(world); + if (!_useTopDown) + return new Vector2(uv.x * _fallbackSize.x, uv.y * _fallbackSize.y); + return _bounds.GetTopDownPositionFrom01(uv); + } + + void RescanMarkers(SkopjePlayer player) + { + _nearby.Clear(); + _nearbyDist.Clear(); + + float radius = Mathf.Clamp(MinimapPlugin.ViewRadius.Value, 25f, 600f) * 1.25f; + float limitSq = radius * radius; + Vector3 origin = player.transform.position; + + var indicators = Resources.FindObjectsOfTypeAll(); + for (int i = 0; i < indicators.Length; i++) + { + MapIndicator indicator = indicators[i]; + if (!IsSceneObject(indicator) || !indicator.gameObject.activeInHierarchy) + continue; + if (IsLocalPlayerMarker(indicator, player)) + continue; + + Vector3 delta = indicator.transform.position - origin; + delta.y = 0f; + float distSq = delta.sqrMagnitude; + if (distSq > limitSq) + continue; + + InsertNearest(indicator, distSq); + } + + int generation = Time.frameCount; + float markerSize = Mathf.Clamp(MinimapPlugin.MarkerSize.Value, 8f, 40f); + for (int i = 0; i < _nearby.Count; i++) + { + MapIndicator indicator = _nearby[i]; + MarkerSlot slot = SlotFor(indicator.GetInstanceID()); + slot.Indicator = indicator; + slot.Generation = generation; + slot.Rect.gameObject.SetActive(true); + + Sprite icon = null; + try + { + icon = indicator.GetIcon(); + } + catch (Exception) + { + icon = null; + } + + slot.Image.sprite = icon != null ? icon : DotSprite(); + slot.Image.color = icon != null ? indicator.Color : new Color(1f, 0.82f, 0.25f, 1f); + if (slot.Image.color.a < 0.05f) + slot.Image.color = icon != null ? Color.white : new Color(1f, 0.82f, 0.25f, 1f); + + float scale = 1f; + try + { + if (indicator.Scale > 0.05f) + scale = Mathf.Clamp(indicator.Scale, 0.4f, 2.5f); + } + catch (Exception) + { + scale = 1f; + } + + slot.Rect.sizeDelta = Vector2.one * (markerSize * scale); + } + + for (int i = 0; i < _slots.Count; i++) + { + if (_slots[i].Generation != generation) + _slots[i].Rect.gameObject.SetActive(false); + } + } + + void InsertNearest(MapIndicator indicator, float distSq) + { + int index = _nearby.Count; + for (int i = 0; i < _nearby.Count; i++) + { + if (distSq < _nearbyDist[i]) + { + index = i; + break; + } + } + + if (index >= MaxMarkers) + return; + + _nearby.Insert(index, indicator); + _nearbyDist.Insert(index, distSq); + if (_nearby.Count > MaxMarkers) + { + _nearby.RemoveAt(_nearby.Count - 1); + _nearbyDist.RemoveAt(_nearbyDist.Count - 1); + } + } + + void MoveMarkers() + { + float limit = (_root.sizeDelta.x - Border * 2f) * 0.5f + 8f; + for (int i = 0; i < _slots.Count; i++) + { + MarkerSlot slot = _slots[i]; + if (!slot.Rect.gameObject.activeSelf) + continue; + if (slot.Indicator == null) + { + slot.Rect.gameObject.SetActive(false); + continue; + } + + Vector2 point = ToMap(slot.Indicator.transform.position); + Vector2 local = (point - _playerMap) * _zoom; + if (Mathf.Abs(local.x) > limit || Mathf.Abs(local.y) > limit) + { + slot.Image.enabled = false; + continue; + } + + slot.Image.enabled = true; + slot.Rect.anchoredPosition = local; + } + } + + void HideMarkers() + { + for (int i = 0; i < _slots.Count; i++) + _slots[i].Rect.gameObject.SetActive(false); + } + + MarkerSlot SlotFor(int id) + { + for (int i = 0; i < _slots.Count; i++) + { + if (_slots[i].Id == id) + return _slots[i]; + } + + var rect = CreateRect("Marker", _markersRoot, _markersRoot.gameObject.layer); + rect.anchorMin = rect.anchorMax = new Vector2(0.5f, 0.5f); + rect.pivot = new Vector2(0.5f, 0.5f); + rect.sizeDelta = Vector2.one * 16f; + + Image image = rect.gameObject.AddComponent(); + image.raycastTarget = false; + image.maskable = true; + image.preserveAspect = true; + + var slot = new MarkerSlot + { + Id = id, + Rect = rect, + Image = image + }; + _slots.Add(slot); + return slot; + } + + static bool IsLocalPlayerMarker(MapIndicator indicator, SkopjePlayer player) + { + if (indicator.transform == player.transform || indicator.transform.IsChildOf(player.transform)) + return true; + + try + { + PlayerMapIndicator playerMarker = indicator.GetComponent(); + return playerMarker != null && playerMarker.Player != null && playerMarker.Player.IsOwner; + } + catch (Exception) + { + return false; + } + } + + static UIView FindIngameView() + { + var views = Resources.FindObjectsOfTypeAll(); + UIView inactive = null; + for (int i = 0; i < views.Length; i++) + { + UIView view = views[i]; + if (!IsSceneObject(view) || !IsIngameView(view)) + continue; + if (view.gameObject.activeInHierarchy) + return view; + inactive ??= view; + } + + return inactive; + } + + static bool IsIngameView(UIView view) + { + string objectName = view.name; + if (objectName == "View - Ingame" || objectName == "View - Ingam") + return true; + + try + { + string viewName = view.ViewName; + return viewName == "Ingame" || viewName == "Ingam"; + } + catch (Exception) + { + return false; + } + } + + static Sprite FindLooseMapSprite() + { + var sprites = Resources.FindObjectsOfTypeAll(); + Sprite best = null; + float bestArea = 256f * 256f; + for (int i = 0; i < sprites.Length; i++) + { + Sprite sprite = sprites[i]; + if (sprite == null) + continue; + string name = sprite.name; + if (name.IndexOf("map", StringComparison.OrdinalIgnoreCase) < 0) + continue; + if (name.IndexOf("icon", StringComparison.OrdinalIgnoreCase) >= 0 || name.IndexOf("pin", StringComparison.OrdinalIgnoreCase) >= 0) + continue; + + Rect rect = sprite.rect; + float area = rect.width * rect.height; + if (area > bestArea) + { + best = sprite; + bestArea = area; + } + } + + return best; + } + + static TimeDisplay PickTimer() + { + var displays = Resources.FindObjectsOfTypeAll(); + TimeDisplay fallback = null; + for (int i = 0; i < displays.Length; i++) + { + TimeDisplay display = displays[i]; + if (!IsSceneObject(display) || display.TimePane == null) + continue; + if (display.gameObject.activeInHierarchy) + return display; + fallback ??= display; + } + + return fallback; + } + + static MapControls PickMap() + { + var maps = Resources.FindObjectsOfTypeAll(); + MapControls fallback = null; + for (int i = 0; i < maps.Length; i++) + { + MapControls map = maps[i]; + if (!IsSceneObject(map) || FindMapGraphic(map) == null) + continue; + if (map.gameObject.activeInHierarchy) + return map; + fallback ??= map; + } + + return fallback; + } + + static Image FindMapGraphic(MapControls map) + { + if (map == null) + return null; + + if (map.MapBg != null && map.MapBg.sprite != null && map.MapBg.sprite.rect.width >= 128f) + return map.MapBg; + + Image best = map.MapBg != null && map.MapBg.sprite != null ? map.MapBg : null; + float bestArea = SpriteArea(best); + if (map.MapTransform != null) + Consider(map.MapTransform, ref best, ref bestArea); + + var extras = map.FallbackMapTransforms; + if (extras != null) + { + for (int i = 0; i < extras.Length; i++) + { + if (extras[i] != null) + Consider(extras[i], ref best, ref bestArea); + } + } + + return best; + } + + static void Consider(Transform root, ref Image best, ref float bestArea) + { + var images = root.GetComponentsInChildren(true); + for (int i = 0; i < images.Length; i++) + { + float area = SpriteArea(images[i]); + if (area > bestArea) + { + best = images[i]; + bestArea = area; + } + } + } + + static float SpriteArea(Image image) + { + if (image == null || image.sprite == null) + return 0f; + Rect rect = image.sprite.rect; + return rect.width * rect.height; + } + + static LevelBounds PickBounds() + { + var all = Resources.FindObjectsOfTypeAll(); + LevelBounds best = null; + float bestArea = -1f; + for (int i = 0; i < all.Length; i++) + { + LevelBounds bounds = all[i]; + if (!IsSceneObject(bounds)) + continue; + + float area = 0f; + try + { + BoxCollider box = bounds.BoxCollider; + if (box != null) + { + Vector3 size = box.bounds.size; + area = Mathf.Abs(size.x * size.z); + } + } + catch (Exception) + { + area = 0f; + } + + if (area > bestArea) + { + bestArea = area; + best = bounds; + } + } + + return best; + } + + static bool IsSceneObject(Component component) + { + return component != null && component.gameObject.scene.IsValid(); + } + + static RectTransform CreateRect(string name, Transform parent, int layer) + { + var go = new GameObject(name); + go.layer = layer; + RectTransform rect = go.AddComponent(); + rect.SetParent(parent, false); + rect.localScale = Vector3.one; + rect.localRotation = Quaternion.identity; + return rect; + } + + static Image CreateImage(string name, Transform parent, Sprite sprite, Color color) + { + RectTransform rect = CreateRect(name, parent, parent.gameObject.layer); + Image image = rect.gameObject.AddComponent(); + image.sprite = sprite; + image.color = color; + image.raycastTarget = false; + image.maskable = true; + return image; + } + + static void Stretch(RectTransform rect, float inset) + { + rect.anchorMin = Vector2.zero; + rect.anchorMax = Vector2.one; + rect.pivot = new Vector2(0.5f, 0.5f); + rect.offsetMin = new Vector2(inset, inset); + rect.offsetMax = new Vector2(-inset, -inset); + rect.localScale = Vector3.one; + } + + static void AdoptLayer(Transform target, int layer) + { + target.gameObject.layer = layer; + for (int i = 0; i < target.childCount; i++) + AdoptLayer(target.GetChild(i), layer); + } + + static Sprite DotSprite() + { + if (_dotSprite != null) + return _dotSprite; + + var texture = new Texture2D(1, 1, TextureFormat.RGBA32, false); + texture.name = "MinimapDot"; + texture.SetPixel(0, 0, Color.white); + texture.Apply(); + texture.hideFlags = HideFlags.HideAndDontSave; + _dotSprite = Sprite.Create(texture, new Rect(0f, 0f, 1f, 1f), new Vector2(0.5f, 0.5f), 1f); + _dotSprite.hideFlags = HideFlags.HideAndDontSave; + return _dotSprite; + } + + static Sprite ArrowSprite() + { + if (_arrowSprite != null) + return _arrowSprite; + + const int n = 32; + var texture = new Texture2D(n, n, TextureFormat.RGBA32, false); + texture.name = "MinimapArrow"; + texture.filterMode = FilterMode.Bilinear; + texture.wrapMode = TextureWrapMode.Clamp; + var clear = new Color(1f, 1f, 1f, 0f); + Vector2 a = new Vector2(15.5f, 29.5f); + Vector2 b = new Vector2(4f, 8.5f); + Vector2 c = new Vector2(27f, 8.5f); + for (int y = 0; y < n; y++) + { + for (int x = 0; x < n; x++) + texture.SetPixel(x, y, PointInTriangle(new Vector2(x + 0.5f, y + 0.5f), a, b, c) ? Color.white : clear); + } + + texture.Apply(); + texture.hideFlags = HideFlags.HideAndDontSave; + _arrowSprite = Sprite.Create(texture, new Rect(0f, 0f, n, n), new Vector2(0.5f, 0.5f), n); + _arrowSprite.hideFlags = HideFlags.HideAndDontSave; + return _arrowSprite; + } + + static bool PointInTriangle(Vector2 p, Vector2 a, Vector2 b, Vector2 c) + { + float d1 = Sign(p, a, b); + float d2 = Sign(p, b, c); + float d3 = Sign(p, c, a); + bool hasNeg = d1 < 0f || d2 < 0f || d3 < 0f; + bool hasPos = d1 > 0f || d2 > 0f || d3 > 0f; + return !(hasNeg && hasPos); + } + + static float Sign(Vector2 p, Vector2 a, Vector2 b) + { + return (p.x - b.x) * (a.y - b.y) - (a.x - b.x) * (p.y - b.y); + } + + sealed class MarkerSlot + { + public int Id; + public int Generation; + public MapIndicator Indicator; + public RectTransform Rect; + public Image Image; + } + } +} diff --git a/Minimap/MinimapPlugin.csproj b/Minimap/MinimapPlugin.csproj new file mode 100644 index 0000000..3da1773 --- /dev/null +++ b/Minimap/MinimapPlugin.csproj @@ -0,0 +1,60 @@ + + + net6.0 + latest + disable + disable + true + Skopje.Minimap + Skopje.Minimap + true + D:\SteamLibrary\steamapps\common\Skopje83 + + + + + $(GameDir)\BepInEx\core\BepInEx.Core.dll + false + + + $(GameDir)\BepInEx\core\BepInEx.Unity.IL2CPP.dll + false + + + $(GameDir)\BepInEx\core\Il2CppInterop.Runtime.dll + false + + + $(GameDir)\BepInEx\interop\Il2Cppmscorlib.dll + false + + + $(GameDir)\BepInEx\interop\SkopjeAssembly.dll + false + + + $(GameDir)\BepInEx\interop\FishNet.Runtime.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.CoreModule.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.UI.dll + false + + + $(GameDir)\BepInEx\interop\DoozyEngineAssembly.dll + false + + + $(GameDir)\BepInEx\interop\UnityEngine.PhysicsModule.dll + false + + + $(GameDir)\BepInEx\interop\Archon.SwissArmyLib.dll + false + + + diff --git a/Minimap/bin/Release/net6.0/Skopje.Minimap.deps.json b/Minimap/bin/Release/net6.0/Skopje.Minimap.deps.json new file mode 100644 index 0000000..7f263df --- /dev/null +++ b/Minimap/bin/Release/net6.0/Skopje.Minimap.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "Skopje.Minimap/1.0.0": { + "runtime": { + "Skopje.Minimap.dll": {} + } + } + } + }, + "libraries": { + "Skopje.Minimap/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/Minimap/bin/Release/net6.0/Skopje.Minimap.dll b/Minimap/bin/Release/net6.0/Skopje.Minimap.dll new file mode 100644 index 0000000..6f37307 Binary files /dev/null and b/Minimap/bin/Release/net6.0/Skopje.Minimap.dll differ diff --git a/Minimap/bin/Release/net6.0/Skopje.Minimap.pdb b/Minimap/bin/Release/net6.0/Skopje.Minimap.pdb new file mode 100644 index 0000000..3ddc752 Binary files /dev/null and b/Minimap/bin/Release/net6.0/Skopje.Minimap.pdb differ diff --git a/Minimap/obj/MinimapPlugin.csproj.nuget.dgspec.json b/Minimap/obj/MinimapPlugin.csproj.nuget.dgspec.json new file mode 100644 index 0000000..422958e --- /dev/null +++ b/Minimap/obj/MinimapPlugin.csproj.nuget.dgspec.json @@ -0,0 +1,85 @@ +{ + "format": 1, + "restore": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\MinimapPlugin.csproj": {} + }, + "projects": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\MinimapPlugin.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\MinimapPlugin.csproj", + "projectName": "Skopje.Minimap", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\MinimapPlugin.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[6.0.36, 6.0.36]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/Minimap/obj/MinimapPlugin.csproj.nuget.g.props b/Minimap/obj/MinimapPlugin.csproj.nuget.g.props new file mode 100644 index 0000000..ba0d2cb --- /dev/null +++ b/Minimap/obj/MinimapPlugin.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + PackageReference + 7.0.0 + + + + + \ No newline at end of file diff --git a/Minimap/obj/MinimapPlugin.csproj.nuget.g.targets b/Minimap/obj/MinimapPlugin.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/Minimap/obj/MinimapPlugin.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Minimap/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/Minimap/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..ed92695 --- /dev/null +++ b/Minimap/obj/Release/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] diff --git a/Minimap/obj/Release/net6.0/MinimapPlugin.AssemblyInfo.cs b/Minimap/obj/Release/net6.0/MinimapPlugin.AssemblyInfo.cs new file mode 100644 index 0000000..9674ae3 --- /dev/null +++ b/Minimap/obj/Release/net6.0/MinimapPlugin.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.Minimap")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] +[assembly: System.Reflection.AssemblyProductAttribute("Skopje.Minimap")] +[assembly: System.Reflection.AssemblyTitleAttribute("Skopje.Minimap")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/Minimap/obj/Release/net6.0/MinimapPlugin.AssemblyInfoInputs.cache b/Minimap/obj/Release/net6.0/MinimapPlugin.AssemblyInfoInputs.cache new file mode 100644 index 0000000..9401367 --- /dev/null +++ b/Minimap/obj/Release/net6.0/MinimapPlugin.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +76a35bd1005e7595549b8f53ede6d7fe291948c74a3299c2ccd64bca53d35f29 diff --git a/Minimap/obj/Release/net6.0/MinimapPlugin.GeneratedMSBuildEditorConfig.editorconfig b/Minimap/obj/Release/net6.0/MinimapPlugin.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..7a29a74 --- /dev/null +++ b/Minimap/obj/Release/net6.0/MinimapPlugin.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,18 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property.EntryPointFilePath = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = Skopje.Minimap +build_property.ProjectDir = c:\Users\andre\Desktop\SkopjeMods\Minimap\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 6.0 +build_property.EnableCodeStyleSeverity = diff --git a/Minimap/obj/Release/net6.0/MinimapPlugin.assets.cache b/Minimap/obj/Release/net6.0/MinimapPlugin.assets.cache new file mode 100644 index 0000000..fa32f5d Binary files /dev/null and b/Minimap/obj/Release/net6.0/MinimapPlugin.assets.cache differ diff --git a/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.AssemblyReference.cache b/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.AssemblyReference.cache new file mode 100644 index 0000000..ca6262e Binary files /dev/null and b/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.AssemblyReference.cache differ diff --git a/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.CoreCompileInputs.cache b/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..1dcff41 --- /dev/null +++ b/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +d64656e1d47566a242332baae27415b1f54265daad457ca67758136236ded997 diff --git a/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.FileListAbsolute.txt b/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..74c34cc --- /dev/null +++ b/Minimap/obj/Release/net6.0/MinimapPlugin.csproj.FileListAbsolute.txt @@ -0,0 +1,12 @@ +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\MinimapPlugin.csproj.AssemblyReference.cache +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\MinimapPlugin.GeneratedMSBuildEditorConfig.editorconfig +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\MinimapPlugin.AssemblyInfoInputs.cache +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\MinimapPlugin.AssemblyInfo.cs +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\MinimapPlugin.csproj.CoreCompileInputs.cache +c:\Users\andre\Desktop\SkopjeMods\Minimap\bin\Release\net6.0\Skopje.Minimap.deps.json +c:\Users\andre\Desktop\SkopjeMods\Minimap\bin\Release\net6.0\Skopje.Minimap.dll +c:\Users\andre\Desktop\SkopjeMods\Minimap\bin\Release\net6.0\Skopje.Minimap.pdb +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\Skopje.Minimap.dll +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\refint\Skopje.Minimap.dll +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\Skopje.Minimap.pdb +c:\Users\andre\Desktop\SkopjeMods\Minimap\obj\Release\net6.0\ref\Skopje.Minimap.dll diff --git a/Minimap/obj/Release/net6.0/Skopje.Minimap.dll b/Minimap/obj/Release/net6.0/Skopje.Minimap.dll new file mode 100644 index 0000000..6f37307 Binary files /dev/null and b/Minimap/obj/Release/net6.0/Skopje.Minimap.dll differ diff --git a/Minimap/obj/Release/net6.0/Skopje.Minimap.pdb b/Minimap/obj/Release/net6.0/Skopje.Minimap.pdb new file mode 100644 index 0000000..3ddc752 Binary files /dev/null and b/Minimap/obj/Release/net6.0/Skopje.Minimap.pdb differ diff --git a/Minimap/obj/Release/net6.0/ref/Skopje.Minimap.dll b/Minimap/obj/Release/net6.0/ref/Skopje.Minimap.dll new file mode 100644 index 0000000..aa6b76c Binary files /dev/null and b/Minimap/obj/Release/net6.0/ref/Skopje.Minimap.dll differ diff --git a/Minimap/obj/Release/net6.0/refint/Skopje.Minimap.dll b/Minimap/obj/Release/net6.0/refint/Skopje.Minimap.dll new file mode 100644 index 0000000..aa6b76c Binary files /dev/null and b/Minimap/obj/Release/net6.0/refint/Skopje.Minimap.dll differ diff --git a/Minimap/obj/project.assets.json b/Minimap/obj/project.assets.json new file mode 100644 index 0000000..b10e2f7 --- /dev/null +++ b/Minimap/obj/project.assets.json @@ -0,0 +1,90 @@ +{ + "version": 4, + "targets": { + "net6.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net6.0": [] + }, + "packageFolders": { + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\MinimapPlugin.csproj", + "projectName": "Skopje.Minimap", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\MinimapPlugin.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net6.0": { + "framework": "net6.0", + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.36, 6.0.36]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[6.0.36, 6.0.36]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301\\RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/Minimap/obj/project.nuget.cache b/Minimap/obj/project.nuget.cache new file mode 100644 index 0000000..c3789b8 --- /dev/null +++ b/Minimap/obj/project.nuget.cache @@ -0,0 +1,12 @@ +{ + "version": 2, + "dgSpecHash": "fEqRFu6N7Gw=", + "success": true, + "projectFilePath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\Minimap\\MinimapPlugin.csproj", + "expectedPackageFiles": [ + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.netcore.app.ref\\6.0.36\\microsoft.netcore.app.ref.6.0.36.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.windowsdesktop.app.ref\\6.0.36\\microsoft.windowsdesktop.app.ref.6.0.36.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.aspnetcore.app.ref\\6.0.36\\microsoft.aspnetcore.app.ref.6.0.36.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/README.md b/README.md index 5498cbc..bbf1b90 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,18 @@ Mods for Skopje 83 using BepInEx IL2CPP. +## Instructions to install mods + +1. Download BepInEx 6 IL2CPP +https://builds.bepinex.dev/projects/bepinex_be + +Version: Artifact 789 +File: BepInEx-Unity.IL2CPP-win-x64-6.0.0-be.789+6cea286.zip + +2. Launch game once to initialize BepInEx classes and folders + +3. Drop mods in plugins and config where needed + ## Mods | Mod | Description | Version | Status | @@ -10,3 +22,6 @@ Mods for Skopje 83 using BepInEx IL2CPP. | Boss Health | On-screen health bar for the current boss. | 1.0.0 | ![Working](https://img.shields.io/badge/Working-16a34a?style=flat-square) | | Horde | Multiplies enemy counts, health, and damage, globally or per zone. | 1.0.0 | ![Working](https://img.shields.io/badge/Working-16a34a?style=flat-square) | | Third Person | Over-the-shoulder camera that can orbit around the player. | 1.0.0 | ![Broken](https://img.shields.io/badge/Broken-dc2626?style=flat-square) | +| Custom Player Skins | Replaces each outfit from its own PNG in `CustomSkins`: singleplayer, ranger, medic, engineer, and fighter. | 1.0.0 | ![Untested](https://img.shields.io/badge/Untested-ca8a04?style=flat-square) | +| Minimap | Small map under the clock, using the in-game map. | 1.0.0 | ![Broken](https://img.shields.io/badge/Broken-dc2626?style=flat-square) | +| DOM Radio | Plays your mp3 and wav files inside the Dom, and mutes its music while the radio is on. | 1.0.0 | ![Working](https://img.shields.io/badge/Working-16a34a?style=flat-square) | diff --git a/ThirdPerson/ThirdPersonPlugin.cs b/ThirdPerson/ThirdPersonPlugin.cs index 0d4f4f1..6ed14ae 100644 --- a/ThirdPerson/ThirdPersonPlugin.cs +++ b/ThirdPerson/ThirdPersonPlugin.cs @@ -4,12 +4,12 @@ using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using BepInEx.Unity.IL2CPP; -using Cinemachine; using HarmonyLib; using Il2CppInterop.Runtime; using Il2CppInterop.Runtime.Injection; using Skopje.Modding; using UnityEngine; +using UnityEngine.Rendering; namespace Skopje.ThirdPerson { @@ -18,7 +18,7 @@ namespace Skopje.ThirdPerson { public const string PluginGuid = "com.skopje.thirdperson"; public const string PluginName = "Skopje Third Person"; - public const string PluginVersion = "1.0.0"; + public const string PluginVersion = "1.2.0"; internal static ManualLogSource LogSource; @@ -46,12 +46,12 @@ namespace Skopje.ThirdPerson LogSource = Log; Enabled = Config.Bind("Camera", "Enabled", true, "Over-the-shoulder camera on the right. The body keeps its own facing so the camera can orbit around to the face."); FaceMovement = Config.Bind("Camera", "FaceMovement", false, "Turn the body toward the direction you move. Leave this off to keep the body still while the camera orbits."); - Distance = Config.Bind("Camera", "Distance", 2.7f, "Meters behind the aim axis."); - Shoulder = Config.Bind("Camera", "Shoulder", 0.62f, "Meters to the right of the aim axis."); - Height = Config.Bind("Camera", "Height", 0.22f, "Meters above the pivot."); - PivotHeight = Config.Bind("Camera", "PivotHeight", 1.25f, "Orbit height above the feet, before crouch."); - AdsDistance = Config.Bind("Camera", "AdsDistance", 1.55f, "Distance while aiming down sights."); - AdsShoulder = Config.Bind("Camera", "AdsShoulder", 0.4f, "Right offset while aiming down sights."); + Distance = Config.Bind("Camera", "Distance", 3.6f, "Meters behind the eyes."); + Shoulder = Config.Bind("Camera", "Shoulder", 1.05f, "Meters to the right of the eyes. Kept even when a wall shortens the boom."); + Height = Config.Bind("Camera", "Height", 0.4f, "Meters above the eyes."); + PivotHeight = Config.Bind("Camera", "PivotHeight", 1.25f, "Unused. The view is offset from the eye camera so interiors stay aligned."); + AdsDistance = Config.Bind("Camera", "AdsDistance", 2.1f, "Distance while aiming down sights."); + AdsShoulder = Config.Bind("Camera", "AdsShoulder", 0.75f, "Right offset while aiming down sights."); FovBonus = Config.Bind("Camera", "FovBonus", 8f, "Extra field of view. Drops to zero while aiming."); AimDistance = Config.Bind("Camera", "AimDistance", 80f, "Crosshair trace length when nothing is under the reticle."); @@ -73,9 +73,11 @@ namespace Skopje.ThirdPerson _driverHost.AddComponent(); _harmony = new Harmony(PluginGuid); - Patch(AccessTools.Method(typeof(SkopjeFPSCamera), "LateUpdate"), nameof(ThirdPersonPatches.AfterCamera)); - Patch(AccessTools.Method(typeof(CinemachineBrain), "LateUpdate"), nameof(ThirdPersonPatches.AfterBrain)); + Patch(AccessTools.Method(typeof(RenderPipelineManager), "BeginCameraRendering"), nameof(ThirdPersonPatches.AfterBeginCamera)); + Patch(AccessTools.Method(typeof(RenderPipelineManager), "EndCameraRendering"), nameof(ThirdPersonPatches.AfterEndCamera)); Patch(AccessTools.Method(typeof(SkopjeCharacterController), "UpdateRotation"), nameof(ThirdPersonPatches.AfterBodyRotation), nameof(ThirdPersonPatches.BeforeBodyRotation)); + PatchInteract(AccessTools.Method(typeof(InteractController), "Update")); + PatchInteract(AccessTools.Method(typeof(InteractController), "LateUpdate")); LogSource.LogInfo($"{PluginName} {PluginVersion} loaded. Config: {Config.ConfigFilePath}"); } @@ -94,6 +96,21 @@ namespace Skopje.ThirdPerson return true; } + static void PatchInteract(MethodInfo method) + { + if (method == null) + { + LogSource.LogWarning("Third person hook was not found: InteractController"); + return; + } + + _harmony.Patch( + method, + prefix: new HarmonyMethod(typeof(ThirdPersonPatches), nameof(ThirdPersonPatches.BeforeInteract)), + postfix: new HarmonyMethod(typeof(ThirdPersonPatches), nameof(ThirdPersonPatches.AfterInteract)), + finalizer: new HarmonyMethod(typeof(ThirdPersonPatches), nameof(ThirdPersonPatches.RestoreInteract))); + } + static void Patch(MethodInfo method, string postfix, string prefix = null) { if (method == null) @@ -121,14 +138,14 @@ namespace Skopje.ThirdPerson public static class ThirdPersonPatches { - public static void AfterCamera(SkopjeFPSCamera __instance) + public static void AfterBeginCamera(ScriptableRenderContext context, Camera camera) { - ThirdPersonRig.Apply(__instance); + ThirdPersonRig.PushView(camera); } - public static void AfterBrain() + public static void AfterEndCamera(ScriptableRenderContext context, Camera camera) { - ThirdPersonRig.Apply(ThirdPersonRig.LocalCamera); + ThirdPersonRig.PopView(camera); } public static void BeforeBodyRotation(SkopjeCharacterController __instance, ref Quaternion currentRotation) @@ -141,5 +158,21 @@ namespace Skopje.ThirdPerson { ThirdPersonRig.HoldBodyFacing(__instance, ref currentRotation, deltaTime); } + + public static void BeforeInteract() + { + ThirdPersonRig.HideBodiesFromInteract(); + } + + public static void AfterInteract() + { + ThirdPersonRig.RestoreInteractLayers(); + } + + public static Exception RestoreInteract(Exception __exception) + { + ThirdPersonRig.RestoreInteractLayers(); + return __exception; + } } } diff --git a/ThirdPerson/ThirdPersonRig.cs b/ThirdPerson/ThirdPersonRig.cs index 658b969..c66e2a8 100644 --- a/ThirdPerson/ThirdPersonRig.cs +++ b/ThirdPerson/ThirdPersonRig.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using UnityEngine; +using UnityEngine.Rendering; namespace Skopje.ThirdPerson { @@ -13,7 +14,7 @@ namespace Skopje.ThirdPerson void LateUpdate() { - ThirdPersonRig.Apply(ThirdPersonRig.LocalCamera); + ThirdPersonRig.PrepareView(); } } @@ -22,32 +23,50 @@ namespace Skopje.ThirdPerson const float MoveThreshold = 0.2f; const float ExternalTurn = 35f; - static readonly List Hidden = new List(); + static readonly List BodyRenderers = new List(); + static readonly List ArmRenderers = new List(); + static readonly List ShadowOnly = new List(); + static readonly List InteractColliders = new List(); + static readonly List InteractLayers = new List(); static readonly RaycastHit[] Hits = new RaycastHit[24]; - internal static SkopjeFPSCamera LocalCamera; - static SkopjePlayer _player; static bool _holding; static bool _hasFacing; static Quaternion _facing; static Quaternion _incomingFacing; static bool _hasIncoming; - static bool _hasLook; - static Quaternion _look = Quaternion.identity; - static bool _hasPlacement; - static Vector3 _placedPos; - static float _baseFov; static float _boom = 2.7f; static float _ads; static bool _capturedIk; static bool _aimWasEnabled; static bool _lookWasEnabled; - static bool _followWasEnabled; - static bool _disabledFollow; static float _nextScan; static int _errors; static bool _logged; + static int _viewId; + static bool _hasView; + static Vector3 _viewPos; + static Quaternion _viewRot; + static float _viewFov; + static bool _pushed; + static Vector3 _savedPos; + static Quaternion _savedRot; + static float _savedFov; + static bool _maskSaved; + static int _savedMask; + static int _bodyLayers; + static GameObject _thirdRoot; + static Vector3 _thirdScale; + static bool _scaledThird; + static bool _control; + static IntPtr _controllerPtr; + static Camera _viewCamera; + static Vector3 _movePlanar; + static float _turnSharpness; + static int _interactMask = -1; + static bool _layersShifted; + static float _nextColliderScan; public static void OnClientStarted() { @@ -57,7 +76,6 @@ namespace Skopje.ThirdPerson { Release(); _player = null; - LocalCamera = null; } public static void OnPlayerStarted(SkopjePlayer player) @@ -72,7 +90,6 @@ namespace Skopje.ThirdPerson { Release(); _player = null; - LocalCamera = null; } } @@ -80,12 +97,12 @@ namespace Skopje.ThirdPerson { Release(); _player = null; - LocalCamera = null; } public static void TickBody() { - if (!CanControl(_player)) + RefreshControl(); + if (!_control) { if (_holding) Release(); @@ -94,30 +111,14 @@ namespace Skopje.ThirdPerson try { - HoldPresentation(_player); - } - catch (Exception ex) - { - Fail(ex); - } - } - - public static void Apply(SkopjeFPSCamera fps) - { - if (fps == null || !CanControl(fps.Player)) - return; - - Camera cam = fps.mainCamera != null ? fps.mainCamera : Camera.main; - if (cam == null) - return; - - LocalCamera = fps; - if (_player == null) - _player = fps.Player; - - try - { - Place(fps, cam); + CacheInteractMask(); + if (Time.unscaledTime >= _nextColliderScan) + { + _nextColliderScan = Time.unscaledTime + 0.5f; + CacheInteractColliders(); + } + + Present(_player, null); } catch (Exception ex) { @@ -125,9 +126,10 @@ namespace Skopje.ThirdPerson } } + // UpdateRotation runs inside an IL2CPP call. Touching IsOwner from here re-enters the runtime and crashes the process. public static void RememberBody(SkopjeCharacterController controller, Quaternion currentRotation) { - if (!CanControl(controller != null ? controller.Player : null)) + if (!_control || controller is null || controller.Pointer != _controllerPtr) { _hasIncoming = false; return; @@ -139,25 +141,18 @@ namespace Skopje.ThirdPerson public static void HoldBodyFacing(SkopjeCharacterController controller, ref Quaternion currentRotation, float deltaTime) { - if (!_hasIncoming || controller == null || !CanControl(controller.Player)) + if (!_hasIncoming || !_control || controller is null || controller.Pointer != _controllerPtr) return; Quaternion held = _hasFacing ? _facing : _incomingFacing; if (!_hasFacing || Quaternion.Angle(held, _incomingFacing) > ExternalTurn) held = _incomingFacing; - if (ThirdPersonPlugin.FaceMovement.Value) + if (ThirdPersonPlugin.FaceMovement.Value && _movePlanar.sqrMagnitude > MoveThreshold * MoveThreshold) { - Vector3 move = controller.moveInputVector; - move.y = 0f; - if (move.sqrMagnitude > MoveThreshold * MoveThreshold) - { - float sharp = controller.OrientationSharpness; - if (sharp < 0.01f) - sharp = 12f; - float blend = 1f - Mathf.Exp(-sharp * Mathf.Max(0f, deltaTime)); - held = Quaternion.Slerp(held, Quaternion.LookRotation(move.normalized, Vector3.up), blend); - } + float sharp = _turnSharpness > 0.01f ? _turnSharpness : 12f; + float blend = 1f - Mathf.Exp(-sharp * Mathf.Max(0f, deltaTime)); + held = Quaternion.Slerp(held, Quaternion.LookRotation(_movePlanar.normalized, Vector3.up), blend); } _facing = FlatYaw(held); @@ -165,68 +160,119 @@ namespace Skopje.ThirdPerson currentRotation = _facing; } - static void Place(SkopjeFPSCamera fps, Camera cam) + static void RefreshControl() { - Quaternion look = ReadLook(fps, cam); - _look = look; - _hasLook = true; + _control = false; + _controllerPtr = IntPtr.Zero; + if (!CanControl(_player)) + return; - bool fresh = !_hasPlacement || (cam.transform.position - _placedPos).sqrMagnitude > 0.0004f; - if (fresh) - _baseFov = cam.fieldOfView; + SkopjeCharacterController body = _player.SkopjeCharacterController; + SkopjeFPSCamera camera = _player.SkopjeFPSCamera; + if (body is null || camera is null || body.Pointer == IntPtr.Zero || camera.Pointer == IntPtr.Zero) + return; - float adsTarget = fps.adsMode ? 1f : 0f; - _ads = Mathf.MoveTowards(_ads, adsTarget, Time.deltaTime / 0.12f); + _controllerPtr = body.Pointer; + _movePlanar = body.moveInputVector; + _movePlanar.y = 0f; + _turnSharpness = body.OrientationSharpness; + _control = true; + } - float distance = Mathf.Lerp(Clamp(ThirdPersonPlugin.Distance.Value, 0.8f, 8f), Clamp(ThirdPersonPlugin.AdsDistance.Value, 0.6f, 6f), _ads); - float shoulder = Mathf.Lerp(Clamp(ThirdPersonPlugin.Shoulder.Value, 0f, 2f), Clamp(ThirdPersonPlugin.AdsShoulder.Value, 0f, 1.5f), _ads); - float height = Clamp(ThirdPersonPlugin.Height.Value, -1f, 2f); - float boom = new Vector3(shoulder, height, -distance).magnitude; - if (!_hasPlacement) - _boom = boom; - _boom = Mathf.Lerp(_boom, boom, 1f - Mathf.Exp(-16f * Time.deltaTime)); - - Vector3 pivot = Pivot(fps.Player); - Vector3 offset = look * new Vector3(shoulder, height, -distance); - if (offset.sqrMagnitude < 0.0001f) - offset = look * Vector3.back; - Vector3 dir = offset.normalized; - float allowed = PullIn(fps.Player, pivot, dir, _boom); - Vector3 camPos = pivot + dir * allowed; - - Vector3 aim = AimPoint(fps.Player, pivot, look * Vector3.forward); - Vector3 toAim = aim - camPos; - Vector3 up = look * Vector3.up; - if (toAim.sqrMagnitude < 0.0001f || Mathf.Abs(Vector3.Dot(toAim.normalized, up.normalized)) > 0.995f) - cam.transform.rotation = look; - else - cam.transform.rotation = Quaternion.LookRotation(toAim, up); - - cam.transform.position = camPos; - cam.fieldOfView = _baseFov + Clamp(ThirdPersonPlugin.FovBonus.Value, 0f, 40f) * (1f - _ads); - _placedPos = camPos; - _hasPlacement = true; - KeepBodyYaw(fps.Player); - - if (!_logged) + public static void PrepareView() + { + if (_pushed && _viewCamera != null) { - _logged = true; - ThirdPersonPlugin.LogSource.LogInfo("Right-shoulder camera is active. The body does not turn with the mouse."); + _viewCamera.transform.SetPositionAndRotation(_savedPos, _savedRot); + _viewCamera.fieldOfView = _savedFov; + _pushed = false; + } + + _hasView = false; + _viewId = 0; + if (!_control || _player is null) + return; + + SkopjeFPSCamera fps = _player.SkopjeFPSCamera; + if (fps is null) + return; + + Camera cam = fps.mainCamera != null ? fps.mainCamera : Camera.main; + if (cam == null) + return; + + try + { + // Offset from the live eye camera. Offset interiors move that camera, not the root position. + Quaternion look = ReadLook(fps, cam); + Vector3 eye = cam.transform.position; + float adsTarget = fps.adsMode ? 1f : 0f; + _ads = Mathf.MoveTowards(_ads, adsTarget, Time.deltaTime / 0.12f); + + float distance = Mathf.Lerp(Clamp(ThirdPersonPlugin.Distance.Value, 0.8f, 8f), Clamp(ThirdPersonPlugin.AdsDistance.Value, 0.6f, 6f), _ads); + float shoulder = Mathf.Lerp(Clamp(ThirdPersonPlugin.Shoulder.Value, 0f, 2.5f), Clamp(ThirdPersonPlugin.AdsShoulder.Value, 0f, 2f), _ads); + float height = Clamp(ThirdPersonPlugin.Height.Value, -1f, 2f); + if (_boom <= 0.01f) + _boom = distance; + _boom = Mathf.Lerp(_boom, distance, 1f - Mathf.Exp(-16f * Time.deltaTime)); + + Vector3 side = eye + look * new Vector3(shoulder, height, 0f); + Vector3 back = look * Vector3.back; + float allowed = PullIn(_player, side, back, _boom); + Vector3 camPos = side + back * allowed; + Vector3 aim = AimPoint(_player, eye, look * Vector3.forward); + Vector3 toAim = aim - camPos; + Vector3 up = look * Vector3.up; + + _viewPos = camPos; + _viewFov = cam.fieldOfView + Clamp(ThirdPersonPlugin.FovBonus.Value, 0f, 40f) * (1f - _ads); + if (toAim.sqrMagnitude < 0.0001f || up.sqrMagnitude < 0.0001f || Mathf.Abs(Vector3.Dot(toAim.normalized, up.normalized)) > 0.995f) + _viewRot = look; + else + _viewRot = Quaternion.LookRotation(toAim, up); + + _viewId = cam.GetInstanceID(); + _viewCamera = cam; + _hasView = true; + Present(_player, cam); + + if (!_logged) + { + _logged = true; + ThirdPersonPlugin.LogSource.LogInfo("Right-shoulder view is active. World streaming still uses the eye camera."); + } + } + catch (Exception ex) + { + Fail(ex); } } - static void KeepBodyYaw(SkopjePlayer player) + // Render-only. The gameplay camera stays on the eyes so chunk streaming does not follow the shoulder. + public static void PushView(Camera camera) { - if (!_hasFacing || player == null) + if (!_hasView || camera == null || camera.GetInstanceID() != _viewId || _pushed) return; - Transform body = player.transform; - Vector3 up = body.up; - Vector3 forward = Vector3.ProjectOnPlane(_facing * Vector3.forward, up); - if (forward.sqrMagnitude < 0.0001f) + _savedPos = camera.transform.position; + _savedRot = camera.transform.rotation; + _savedFov = camera.fieldOfView; + camera.transform.SetPositionAndRotation(_viewPos, _viewRot); + camera.fieldOfView = _viewFov; + if (_maskSaved) + camera.cullingMask |= _bodyLayers; + RevealCached(); + _pushed = true; + } + + public static void PopView(Camera camera) + { + if (!_pushed || camera == null || camera.GetInstanceID() != _viewId) return; - body.rotation = Quaternion.LookRotation(forward.normalized, up); + camera.transform.SetPositionAndRotation(_savedPos, _savedRot); + camera.fieldOfView = _savedFov; + _pushed = false; } static Quaternion ReadLook(SkopjeFPSCamera fps, Camera cam) @@ -235,8 +281,6 @@ namespace Skopje.ThirdPerson return fps.VCamera.transform.rotation; if (fps.SocketTransform != null && fps.SocketTransform != cam.transform) return fps.SocketTransform.rotation; - if (_hasLook && _hasPlacement && (cam.transform.position - _placedPos).sqrMagnitude < 0.0004f) - return _look; return cam.transform.rotation; } @@ -296,15 +340,24 @@ namespace Skopje.ThirdPerson return best; } - static void HoldPresentation(SkopjePlayer player) + static void Present(SkopjePlayer player, Camera cam) { GameObject third = player.ThirdPerson; - if (third != null && !third.activeSelf) - third.SetActive(true); + if (third != null) + { + if (!third.activeSelf) + third.SetActive(true); + if (!_scaledThird && third.transform.localScale.sqrMagnitude < 0.0001f) + { + _thirdScale = third.transform.localScale; + third.transform.localScale = Vector3.one; + _scaledThird = true; + _thirdRoot = third; + } + } - GameObject pack = player.ThirdPersonBackpackParent; - if (pack != null && !pack.activeSelf) - pack.SetActive(true); + if (player.ThirdPersonBackpackParent != null && !player.ThirdPersonBackpackParent.activeSelf) + player.ThirdPersonBackpackParent.SetActive(true); var anim = player.TPAnimationController; if (anim != null) @@ -322,56 +375,69 @@ namespace Skopje.ThirdPerson anim.LookAtMotor.enabled = false; } - var follow = player.ThirdPersonFollowCam; - if (follow != null && follow.Look != null && follow.Look.enabled) - { - _followWasEnabled = true; - follow.Look.enabled = false; - _disabledFollow = true; - } - if (Time.unscaledTime >= _nextScan) { _nextScan = Time.unscaledTime + 0.25f; - RebuildHidden(player); + CacheVisuals(player); } - for (int i = 0; i < Hidden.Count; i++) - { - if (Hidden[i] != null) - Hidden[i].forceRenderingOff = true; - } + RevealCached(); + if (cam != null) + IncludeBodyLayers(cam); _holding = true; } - static void RebuildHidden(SkopjePlayer player) + static void CacheVisuals(SkopjePlayer player) { - var next = new List(); + RestoreArms(); + BodyRenderers.Clear(); + ArmRenderers.Clear(); + _bodyLayers = 0; + Transform third = player.ThirdPerson != null ? player.ThirdPerson.transform : null; - Collect(player.FirstPerson, third, next); - - var weapons = player.WeaponsController; - if (weapons != null) + if (player.ThirdPersonRenderer != null) + AddBody(player.ThirdPersonRenderer); + if (third != null) { - if (weapons.Socket != null) - Collect(weapons.Socket.gameObject, third, next); - if (weapons.ThrowSocket != null) - Collect(weapons.ThrowSocket.gameObject, third, next); + Renderer[] found = third.GetComponentsInChildren(true); + for (int i = 0; i < found.Length; i++) + AddBody(found[i]); } - for (int i = 0; i < Hidden.Count; i++) + if (player.SkopjeCharacterController != null && player.SkopjeCharacterController.MeshRoot != null) { - Renderer old = Hidden[i]; - if (old != null && !next.Contains(old)) - old.forceRenderingOff = false; + Renderer[] found = player.SkopjeCharacterController.MeshRoot.GetComponentsInChildren(true); + for (int i = 0; i < found.Length; i++) + { + Renderer renderer = found[i]; + if (renderer == null) + continue; + if (third != null && (renderer.transform == third || renderer.transform.IsChildOf(third))) + AddBody(renderer); + else if (player.FirstPerson == null || !renderer.transform.IsChildOf(player.FirstPerson.transform)) + AddBody(renderer); + } } - Hidden.Clear(); - Hidden.AddRange(next); + CollectArms(player.FirstPerson, third); } - static void Collect(GameObject root, Transform thirdPerson, List into) + static void AddBody(Renderer renderer) + { + if (renderer == null || BodyRenderers.Contains(renderer)) + return; + + BodyRenderers.Add(renderer); + _bodyLayers |= 1 << renderer.gameObject.layer; + if (renderer.shadowCastingMode == ShadowCastingMode.ShadowsOnly && !ShadowOnly.Contains(renderer)) + { + ShadowOnly.Add(renderer); + renderer.shadowCastingMode = ShadowCastingMode.On; + } + } + + static void CollectArms(GameObject root, Transform thirdPerson) { if (root == null) return; @@ -382,24 +448,181 @@ namespace Skopje.ThirdPerson for (int i = 0; i < found.Length; i++) { Renderer renderer = found[i]; - if (renderer == null) + if (renderer == null || BodyRenderers.Contains(renderer) || ArmRenderers.Contains(renderer)) continue; if (thirdPerson != null && renderer.transform.IsChildOf(thirdPerson)) continue; - if (!into.Contains(renderer)) - into.Add(renderer); + ArmRenderers.Add(renderer); + } + } + + static void RevealCached() + { + if (_thirdRoot != null && !_thirdRoot.activeSelf) + _thirdRoot.SetActive(true); + + for (int i = 0; i < BodyRenderers.Count; i++) + { + Renderer renderer = BodyRenderers[i]; + if (renderer == null) + continue; + renderer.forceRenderingOff = false; + renderer.enabled = true; + if (renderer is SkinnedMeshRenderer skin) + skin.updateWhenOffscreen = true; + } + + for (int i = 0; i < ArmRenderers.Count; i++) + { + if (ArmRenderers[i] != null) + ArmRenderers[i].forceRenderingOff = true; + } + } + + static void IncludeBodyLayers(Camera cam) + { + if (_bodyLayers == 0) + return; + if (!_maskSaved) + { + _savedMask = cam.cullingMask; + _maskSaved = true; + } + + cam.cullingMask |= _bodyLayers; + } + + public static void HideBodiesFromInteract() + { + RestoreInteractLayers(); + if (_interactMask == 0 || InteractColliders.Count == 0) + return; + + int free = 2; + if ((_interactMask & (1 << free)) != 0) + { + free = -1; + for (int layer = 8; layer < 32; layer++) + { + if ((_interactMask & (1 << layer)) == 0) + { + free = layer; + break; + } + } + } + + if (free < 0) + return; + + for (int i = 0; i < InteractColliders.Count; i++) + { + Collider collider = InteractColliders[i]; + if (collider == null) + { + InteractLayers.Add(0); + continue; + } + + int layer = collider.gameObject.layer; + InteractLayers.Add(layer); + if ((_interactMask & (1 << layer)) != 0) + collider.gameObject.layer = free; + } + + _layersShifted = true; + } + + public static void RestoreInteractLayers() + { + if (!_layersShifted) + return; + + for (int i = InteractColliders.Count - 1; i >= 0; i--) + { + Collider collider = InteractColliders[i]; + if (collider != null && i < InteractLayers.Count) + collider.gameObject.layer = InteractLayers[i]; + } + + InteractLayers.Clear(); + _layersShifted = false; + } + + static void CacheInteractMask() + { + InteractController interact = _player.InteractController; + if (interact == null) + { + _interactMask = 0; + return; + } + + _interactMask = interact.BlockingLayers.value | interact.InteractLayers.value; + } + + static void CacheInteractColliders() + { + if (_layersShifted) + return; + + InteractColliders.Clear(); + SkopjePlayer[] players = UnityEngine.Object.FindObjectsOfType(); + for (int i = 0; i < players.Length; i++) + AddPlayerColliders(players[i]); + } + + static void AddPlayerColliders(SkopjePlayer player) + { + if (player == null || player.ThirdPerson == null) + return; + + Collider owner = player.OwnerCollider; + Collider[] found = player.ThirdPerson.GetComponentsInChildren(true); + for (int i = 0; i < found.Length; i++) + { + Collider collider = found[i]; + if (collider == null || collider.isTrigger || collider == owner || InteractColliders.Contains(collider)) + continue; + InteractColliders.Add(collider); + } + } + + static void RestoreArms() + { + for (int i = 0; i < ArmRenderers.Count; i++) + { + if (ArmRenderers[i] != null) + ArmRenderers[i].forceRenderingOff = false; } } static void Release() { - for (int i = 0; i < Hidden.Count; i++) + if (_pushed && _viewCamera != null) { - if (Hidden[i] != null) - Hidden[i].forceRenderingOff = false; + _viewCamera.transform.SetPositionAndRotation(_savedPos, _savedRot); + _viewCamera.fieldOfView = _savedFov; } - Hidden.Clear(); + if (_maskSaved && _viewCamera != null) + _viewCamera.cullingMask = _savedMask; + + for (int i = 0; i < ShadowOnly.Count; i++) + { + if (ShadowOnly[i] != null) + ShadowOnly[i].shadowCastingMode = ShadowCastingMode.ShadowsOnly; + } + + if (_scaledThird && _thirdRoot != null) + _thirdRoot.transform.localScale = _thirdScale; + + RestoreInteractLayers(); + InteractColliders.Clear(); + RestoreArms(); + BodyRenderers.Clear(); + ArmRenderers.Clear(); + ShadowOnly.Clear(); if (_player != null) { @@ -412,9 +635,6 @@ namespace Skopje.ThirdPerson anim.LookAtMotor.enabled = _lookWasEnabled; } - if (_disabledFollow && _player.ThirdPersonFollowCam != null && _player.ThirdPersonFollowCam.Look != null) - _player.ThirdPersonFollowCam.Look.enabled = _followWasEnabled; - try { _player.RefreshActiveModels(); @@ -426,14 +646,20 @@ namespace Skopje.ThirdPerson } _capturedIk = false; - _disabledFollow = false; _holding = false; _hasFacing = false; _hasIncoming = false; - _hasPlacement = false; - _hasLook = false; _ads = 0f; _logged = false; + _control = false; + _controllerPtr = IntPtr.Zero; + _hasView = false; + _pushed = false; + _maskSaved = false; + _scaledThird = false; + _thirdRoot = null; + _viewCamera = null; + _bodyLayers = 0; } static bool CanControl(SkopjePlayer player) diff --git a/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.dll b/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.dll index 3d95e43..8ae93fb 100644 Binary files a/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.dll and b/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.dll differ diff --git a/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.pdb b/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.pdb index 8c09b11..872d883 100644 Binary files a/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.pdb and b/ThirdPerson/bin/Release/net6.0/Skopje.ThirdPerson.pdb differ diff --git a/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.dll b/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.dll index 3d95e43..8ae93fb 100644 Binary files a/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.dll and b/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.dll differ diff --git a/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.pdb b/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.pdb index 8c09b11..872d883 100644 Binary files a/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.pdb and b/ThirdPerson/obj/Release/net6.0/Skopje.ThirdPerson.pdb differ diff --git a/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfo.cs b/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfo.cs index f81db69..fa3f346 100644 --- a/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfo.cs +++ b/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("Skopje.ThirdPerson")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] [assembly: System.Reflection.AssemblyProductAttribute("Skopje.ThirdPerson")] [assembly: System.Reflection.AssemblyTitleAttribute("Skopje.ThirdPerson")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfoInputs.cache b/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfoInputs.cache index d37f276..d72cd09 100644 --- a/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfoInputs.cache +++ b/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.AssemblyInfoInputs.cache @@ -1 +1 @@ -8ec25d9c2fd66f388ffb60470d85e452afd95523e8f8b9133f1a26f62c293384 +bc8b2b18196c3acb4bcc9f717e44bd539bfb6c46a1061eb8c275c7da7f6dfc9f diff --git a/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.csproj.AssemblyReference.cache b/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.csproj.AssemblyReference.cache index 47e5d12..e6bf606 100644 Binary files a/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.csproj.AssemblyReference.cache and b/ThirdPerson/obj/Release/net6.0/ThirdPersonPlugin.csproj.AssemblyReference.cache differ diff --git a/ThirdPerson/obj/Release/net6.0/ref/Skopje.ThirdPerson.dll b/ThirdPerson/obj/Release/net6.0/ref/Skopje.ThirdPerson.dll index d1edbd8..0bf7c2e 100644 Binary files a/ThirdPerson/obj/Release/net6.0/ref/Skopje.ThirdPerson.dll and b/ThirdPerson/obj/Release/net6.0/ref/Skopje.ThirdPerson.dll differ diff --git a/ThirdPerson/obj/Release/net6.0/refint/Skopje.ThirdPerson.dll b/ThirdPerson/obj/Release/net6.0/refint/Skopje.ThirdPerson.dll index d1edbd8..0bf7c2e 100644 Binary files a/ThirdPerson/obj/Release/net6.0/refint/Skopje.ThirdPerson.dll and b/ThirdPerson/obj/Release/net6.0/refint/Skopje.ThirdPerson.dll differ diff --git a/_fix/DumpMap/DumpMap.csproj b/_fix/DumpMap/DumpMap.csproj new file mode 100644 index 0000000..d5c37af --- /dev/null +++ b/_fix/DumpMap/DumpMap.csproj @@ -0,0 +1,11 @@ + + + Exe + net8.0 + enable + disable + + + + + diff --git a/_fix/DumpMap/Program.cs b/_fix/DumpMap/Program.cs new file mode 100644 index 0000000..eb46d53 --- /dev/null +++ b/_fix/DumpMap/Program.cs @@ -0,0 +1,48 @@ +using System.Reflection; + +var interop = @"D:\SteamLibrary\steamapps\common\Skopje83\BepInEx\interop"; +var core = @"D:\SteamLibrary\steamapps\common\Skopje83\BepInEx\core"; +var runtime = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory(); +var paths = new List(); +paths.AddRange(Directory.GetFiles(interop, "*.dll")); +paths.AddRange(Directory.GetFiles(core, "*.dll")); +paths.AddRange(Directory.GetFiles(runtime, "*.dll")); +using var mlc = new MetadataLoadContext(new PathAssemblyResolver(paths)); + +var names = new HashSet(args); +var skopje = mlc.LoadFromAssemblyPath(Path.Combine(interop, "SkopjeAssembly.dll")); +foreach (var type in skopje.GetTypes()) +{ + if (!names.Contains(type.Name)) + continue; + Console.WriteLine("TYPE " + type.FullName + " : " + type.BaseType?.FullName); + var flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly; + foreach (var p in type.GetProperties(flags)) + Console.WriteLine(" P " + Format(p.PropertyType) + " " + p.Name); + foreach (var f in type.GetFields(flags)) + { + if (f.Name.StartsWith("Native")) continue; + Console.WriteLine(" F " + Format(f.FieldType) + " " + f.Name); + } + foreach (var m in type.GetMethods(flags)) + { + if (m.Name.StartsWith("get_") || m.Name.StartsWith("set_") || m.Name.Contains("Native")) continue; + var parms = string.Join(", ", m.GetParameters().Select(p => Format(p.ParameterType) + " " + p.Name)); + Console.WriteLine(" M " + Format(m.ReturnType) + " " + m.Name + "(" + parms + ")"); + } +} + +static string Format(Type t) +{ + if (t == null) return "?"; + if (t.IsGenericType) + { + var def = t.Name; + var tick = def.IndexOf('`'); + if (tick >= 0) def = def.Substring(0, tick); + return def + "<" + string.Join(", ", t.GetGenericArguments().Select(Format)) + ">"; + } + if (t.IsArray) + return Format(t.GetElementType()) + "[]"; + return t.Name; +} diff --git a/_fix/DumpMap/bin/Release/net8.0/DumpMap.deps.json b/_fix/DumpMap/bin/Release/net8.0/DumpMap.deps.json new file mode 100644 index 0000000..da6ce63 --- /dev/null +++ b/_fix/DumpMap/bin/Release/net8.0/DumpMap.deps.json @@ -0,0 +1,41 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v8.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v8.0": { + "DumpMap/1.0.0": { + "dependencies": { + "System.Reflection.MetadataLoadContext": "8.0.0" + }, + "runtime": { + "DumpMap.dll": {} + } + }, + "System.Reflection.MetadataLoadContext/8.0.0": { + "runtime": { + "lib/net8.0/System.Reflection.MetadataLoadContext.dll": { + "assemblyVersion": "8.0.0.0", + "fileVersion": "8.0.23.53103" + } + } + } + } + }, + "libraries": { + "DumpMap/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + }, + "System.Reflection.MetadataLoadContext/8.0.0": { + "type": "package", + "serviceable": true, + "sha512": "sha512-SZxrQ4sQYnIcdwiO3G/lHZopbPYQ2lW0ioT4JezgccWUrKaKbHLJbAGZaDfkYjWcta1pWssAo3MOXLsR0ie4tQ==", + "path": "system.reflection.metadataloadcontext/8.0.0", + "hashPath": "system.reflection.metadataloadcontext.8.0.0.nupkg.sha512" + } + } +} \ No newline at end of file diff --git a/_fix/DumpMap/bin/Release/net8.0/DumpMap.dll b/_fix/DumpMap/bin/Release/net8.0/DumpMap.dll new file mode 100644 index 0000000..1c55246 Binary files /dev/null and b/_fix/DumpMap/bin/Release/net8.0/DumpMap.dll differ diff --git a/_fix/DumpMap/bin/Release/net8.0/DumpMap.exe b/_fix/DumpMap/bin/Release/net8.0/DumpMap.exe new file mode 100644 index 0000000..f80c68b Binary files /dev/null and b/_fix/DumpMap/bin/Release/net8.0/DumpMap.exe differ diff --git a/_fix/DumpMap/bin/Release/net8.0/DumpMap.pdb b/_fix/DumpMap/bin/Release/net8.0/DumpMap.pdb new file mode 100644 index 0000000..9ff80b2 Binary files /dev/null and b/_fix/DumpMap/bin/Release/net8.0/DumpMap.pdb differ diff --git a/_fix/DumpMap/bin/Release/net8.0/DumpMap.runtimeconfig.json b/_fix/DumpMap/bin/Release/net8.0/DumpMap.runtimeconfig.json new file mode 100644 index 0000000..d784515 --- /dev/null +++ b/_fix/DumpMap/bin/Release/net8.0/DumpMap.runtimeconfig.json @@ -0,0 +1,13 @@ +{ + "runtimeOptions": { + "tfm": "net8.0", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "8.0.0" + }, + "configProperties": { + "System.Reflection.Metadata.MetadataUpdater.IsSupported": false, + "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false + } + } +} \ No newline at end of file diff --git a/_fix/DumpMap/bin/Release/net8.0/System.Reflection.MetadataLoadContext.dll b/_fix/DumpMap/bin/Release/net8.0/System.Reflection.MetadataLoadContext.dll new file mode 100644 index 0000000..a54bbed Binary files /dev/null and b/_fix/DumpMap/bin/Release/net8.0/System.Reflection.MetadataLoadContext.dll differ diff --git a/_fix/DumpMap/obj/DumpMap.csproj.nuget.dgspec.json b/_fix/DumpMap/obj/DumpMap.csproj.nuget.dgspec.json new file mode 100644 index 0000000..8ac2257 --- /dev/null +++ b/_fix/DumpMap/obj/DumpMap.csproj.nuget.dgspec.json @@ -0,0 +1,95 @@ +{ + "format": 1, + "restore": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\DumpMap.csproj": {} + }, + "projects": { + "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\DumpMap.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\DumpMap.csproj", + "projectName": "DumpMap", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\DumpMap.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "framework": "net8.0", + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net8.0": { + "framework": "net8.0", + "targetAlias": "net8.0", + "dependencies": { + "System.Reflection.MetadataLoadContext": { + "target": "Package", + "version": "[8.0.0, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[8.0.28, 8.0.28]" + }, + { + "name": "Microsoft.NETCore.App.Host.win-x64", + "version": "[8.0.28, 8.0.28]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[8.0.28, 8.0.28]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[8.0.28, 8.0.28]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/_fix/DumpMap/obj/DumpMap.csproj.nuget.g.props b/_fix/DumpMap/obj/DumpMap.csproj.nuget.g.props new file mode 100644 index 0000000..ba0d2cb --- /dev/null +++ b/_fix/DumpMap/obj/DumpMap.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + $(UserProfile)\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + C:\Users\andre\AppData\Local\Temp\cursor-sandbox-cache\a0404811fc6e51c4c5761fd11591789f\nuget + PackageReference + 7.0.0 + + + + + \ No newline at end of file diff --git a/_fix/DumpMap/obj/DumpMap.csproj.nuget.g.targets b/_fix/DumpMap/obj/DumpMap.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/_fix/DumpMap/obj/DumpMap.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/_fix/DumpMap/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs b/_fix/DumpMap/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs new file mode 100644 index 0000000..2217181 --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/.NETCoreApp,Version=v8.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v8.0", FrameworkDisplayName = ".NET 8.0")] diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.AssemblyInfo.cs b/_fix/DumpMap/obj/Release/net8.0/DumpMap.AssemblyInfo.cs new file mode 100644 index 0000000..18eb210 --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/DumpMap.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("DumpMap")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] +[assembly: System.Reflection.AssemblyProductAttribute("DumpMap")] +[assembly: System.Reflection.AssemblyTitleAttribute("DumpMap")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.AssemblyInfoInputs.cache b/_fix/DumpMap/obj/Release/net8.0/DumpMap.AssemblyInfoInputs.cache new file mode 100644 index 0000000..6cdfbae --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/DumpMap.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +ae0c48002f62f98b7adc5e902b1de30eecca72e82060a4b80499e2417e90a658 diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.GeneratedMSBuildEditorConfig.editorconfig b/_fix/DumpMap/obj/Release/net8.0/DumpMap.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..9b47015 --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/DumpMap.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,18 @@ +is_global = true +build_property.TargetFramework = net8.0 +build_property.TargetFrameworkIdentifier = .NETCoreApp +build_property.TargetFrameworkVersion = v8.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = +build_property.EntryPointFilePath = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = DumpMap +build_property.ProjectDir = c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = +build_property.EffectiveAnalysisLevelStyle = 8.0 +build_property.EnableCodeStyleSeverity = diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.GlobalUsings.g.cs b/_fix/DumpMap/obj/Release/net8.0/DumpMap.GlobalUsings.g.cs new file mode 100644 index 0000000..d12bcbc --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/DumpMap.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using System; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Net.Http; +global using System.Threading; +global using System.Threading.Tasks; diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.assets.cache b/_fix/DumpMap/obj/Release/net8.0/DumpMap.assets.cache new file mode 100644 index 0000000..fad49f3 Binary files /dev/null and b/_fix/DumpMap/obj/Release/net8.0/DumpMap.assets.cache differ diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.AssemblyReference.cache b/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.AssemblyReference.cache new file mode 100644 index 0000000..457a0ec Binary files /dev/null and b/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.AssemblyReference.cache differ diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.CoreCompileInputs.cache b/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..5c102b5 --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +4d4771ea8f8d3cf3aeed797e4bf4b6713531421023b94150e57e7de4c9154a1e diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.FileListAbsolute.txt b/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..ca31af3 --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.FileListAbsolute.txt @@ -0,0 +1,17 @@ +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\bin\Release\net8.0\DumpMap.exe +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\bin\Release\net8.0\DumpMap.deps.json +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\bin\Release\net8.0\DumpMap.runtimeconfig.json +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\bin\Release\net8.0\DumpMap.dll +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\bin\Release\net8.0\DumpMap.pdb +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.GeneratedMSBuildEditorConfig.editorconfig +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.AssemblyInfoInputs.cache +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.AssemblyInfo.cs +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.csproj.CoreCompileInputs.cache +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.dll +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\refint\DumpMap.dll +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.pdb +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.genruntimeconfig.cache +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\ref\DumpMap.dll +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\bin\Release\net8.0\System.Reflection.MetadataLoadContext.dll +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.csproj.AssemblyReference.cache +c:\Users\andre\Desktop\SkopjeMods\_fix\DumpMap\obj\Release\net8.0\DumpMap.csproj.Up2Date diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.Up2Date b/_fix/DumpMap/obj/Release/net8.0/DumpMap.csproj.Up2Date new file mode 100644 index 0000000..e69de29 diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.dll b/_fix/DumpMap/obj/Release/net8.0/DumpMap.dll new file mode 100644 index 0000000..1c55246 Binary files /dev/null and b/_fix/DumpMap/obj/Release/net8.0/DumpMap.dll differ diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.genruntimeconfig.cache b/_fix/DumpMap/obj/Release/net8.0/DumpMap.genruntimeconfig.cache new file mode 100644 index 0000000..5093584 --- /dev/null +++ b/_fix/DumpMap/obj/Release/net8.0/DumpMap.genruntimeconfig.cache @@ -0,0 +1 @@ +02342370508c732cc9f2de508ae0c01444ce9fa716191aa93a72245efb2157e2 diff --git a/_fix/DumpMap/obj/Release/net8.0/DumpMap.pdb b/_fix/DumpMap/obj/Release/net8.0/DumpMap.pdb new file mode 100644 index 0000000..9ff80b2 Binary files /dev/null and b/_fix/DumpMap/obj/Release/net8.0/DumpMap.pdb differ diff --git a/_fix/DumpMap/obj/Release/net8.0/apphost.exe b/_fix/DumpMap/obj/Release/net8.0/apphost.exe new file mode 100644 index 0000000..f80c68b Binary files /dev/null and b/_fix/DumpMap/obj/Release/net8.0/apphost.exe differ diff --git a/_fix/DumpMap/obj/Release/net8.0/ref/DumpMap.dll b/_fix/DumpMap/obj/Release/net8.0/ref/DumpMap.dll new file mode 100644 index 0000000..510fded Binary files /dev/null and b/_fix/DumpMap/obj/Release/net8.0/ref/DumpMap.dll differ diff --git a/_fix/DumpMap/obj/Release/net8.0/refint/DumpMap.dll b/_fix/DumpMap/obj/Release/net8.0/refint/DumpMap.dll new file mode 100644 index 0000000..510fded Binary files /dev/null and b/_fix/DumpMap/obj/Release/net8.0/refint/DumpMap.dll differ diff --git a/_fix/DumpMap/obj/project.assets.json b/_fix/DumpMap/obj/project.assets.json new file mode 100644 index 0000000..b5edfc9 --- /dev/null +++ b/_fix/DumpMap/obj/project.assets.json @@ -0,0 +1,249 @@ +{ + "version": 4, + "targets": { + "net8.0": { + "System.Collections.Immutable/8.0.0": { + "type": "package", + "compile": { + "lib/net8.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.Collections.Immutable.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.Reflection.Metadata/8.0.0": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "8.0.0" + }, + "compile": { + "lib/net8.0/System.Reflection.Metadata.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.Reflection.Metadata.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + }, + "System.Reflection.MetadataLoadContext/8.0.0": { + "type": "package", + "dependencies": { + "System.Collections.Immutable": "8.0.0", + "System.Reflection.Metadata": "8.0.0" + }, + "compile": { + "lib/net8.0/System.Reflection.MetadataLoadContext.dll": { + "related": ".xml" + } + }, + "runtime": { + "lib/net8.0/System.Reflection.MetadataLoadContext.dll": { + "related": ".xml" + } + }, + "build": { + "buildTransitive/net6.0/_._": {} + } + } + } + }, + "libraries": { + "System.Collections.Immutable/8.0.0": { + "sha512": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg==", + "type": "package", + "path": "system.collections.immutable/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Collections.Immutable.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Collections.Immutable.targets", + "lib/net462/System.Collections.Immutable.dll", + "lib/net462/System.Collections.Immutable.xml", + "lib/net6.0/System.Collections.Immutable.dll", + "lib/net6.0/System.Collections.Immutable.xml", + "lib/net7.0/System.Collections.Immutable.dll", + "lib/net7.0/System.Collections.Immutable.xml", + "lib/net8.0/System.Collections.Immutable.dll", + "lib/net8.0/System.Collections.Immutable.xml", + "lib/netstandard2.0/System.Collections.Immutable.dll", + "lib/netstandard2.0/System.Collections.Immutable.xml", + "system.collections.immutable.8.0.0.nupkg.sha512", + "system.collections.immutable.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Reflection.Metadata/8.0.0": { + "sha512": "ptvgrFh7PvWI8bcVqG5rsA/weWM09EnthFHR5SCnS6IN+P4mj6rE1lBDC4U8HL9/57htKAqy4KQ3bBj84cfYyQ==", + "type": "package", + "path": "system.reflection.metadata/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Reflection.Metadata.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Reflection.Metadata.targets", + "lib/net462/System.Reflection.Metadata.dll", + "lib/net462/System.Reflection.Metadata.xml", + "lib/net6.0/System.Reflection.Metadata.dll", + "lib/net6.0/System.Reflection.Metadata.xml", + "lib/net7.0/System.Reflection.Metadata.dll", + "lib/net7.0/System.Reflection.Metadata.xml", + "lib/net8.0/System.Reflection.Metadata.dll", + "lib/net8.0/System.Reflection.Metadata.xml", + "lib/netstandard2.0/System.Reflection.Metadata.dll", + "lib/netstandard2.0/System.Reflection.Metadata.xml", + "system.reflection.metadata.8.0.0.nupkg.sha512", + "system.reflection.metadata.nuspec", + "useSharedDesignerContext.txt" + ] + }, + "System.Reflection.MetadataLoadContext/8.0.0": { + "sha512": "SZxrQ4sQYnIcdwiO3G/lHZopbPYQ2lW0ioT4JezgccWUrKaKbHLJbAGZaDfkYjWcta1pWssAo3MOXLsR0ie4tQ==", + "type": "package", + "path": "system.reflection.metadataloadcontext/8.0.0", + "files": [ + ".nupkg.metadata", + ".signature.p7s", + "Icon.png", + "LICENSE.TXT", + "PACKAGE.md", + "THIRD-PARTY-NOTICES.TXT", + "buildTransitive/net461/System.Reflection.MetadataLoadContext.targets", + "buildTransitive/net462/_._", + "buildTransitive/net6.0/_._", + "buildTransitive/netcoreapp2.0/System.Reflection.MetadataLoadContext.targets", + "lib/net462/System.Reflection.MetadataLoadContext.dll", + "lib/net462/System.Reflection.MetadataLoadContext.xml", + "lib/net6.0/System.Reflection.MetadataLoadContext.dll", + "lib/net6.0/System.Reflection.MetadataLoadContext.xml", + "lib/net7.0/System.Reflection.MetadataLoadContext.dll", + "lib/net7.0/System.Reflection.MetadataLoadContext.xml", + "lib/net8.0/System.Reflection.MetadataLoadContext.dll", + "lib/net8.0/System.Reflection.MetadataLoadContext.xml", + "lib/netstandard2.0/System.Reflection.MetadataLoadContext.dll", + "lib/netstandard2.0/System.Reflection.MetadataLoadContext.xml", + "system.reflection.metadataloadcontext.8.0.0.nupkg.sha512", + "system.reflection.metadataloadcontext.nuspec", + "useSharedDesignerContext.txt" + ] + } + }, + "projectFileDependencyGroups": { + "net8.0": [ + "System.Reflection.MetadataLoadContext >= 8.0.0" + ] + }, + "packageFolders": { + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\DumpMap.csproj", + "projectName": "DumpMap", + "projectPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\DumpMap.csproj", + "packagesPath": "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget", + "outputPath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\obj\\", + "projectStyle": "PackageReference", + "configFilePaths": [ + "C:\\Users\\andre\\AppData\\Roaming\\NuGet\\NuGet.Config", + "C:\\Program Files (x86)\\NuGet\\Config\\Microsoft.VisualStudio.Offline.config" + ], + "originalTargetFrameworks": [ + "net8.0" + ], + "sources": { + "C:\\Program Files (x86)\\Microsoft SDKs\\NuGetPackages\\": {}, + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net8.0": { + "framework": "net8.0", + "targetAlias": "net8.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + }, + "restoreAuditProperties": { + "enableAudit": "true", + "auditLevel": "low", + "auditMode": "direct" + }, + "SdkAnalysisLevel": "10.0.300" + }, + "frameworks": { + "net8.0": { + "framework": "net8.0", + "targetAlias": "net8.0", + "dependencies": { + "System.Reflection.MetadataLoadContext": { + "target": "Package", + "version": "[8.0.0, )" + } + }, + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[8.0.28, 8.0.28]" + }, + { + "name": "Microsoft.NETCore.App.Host.win-x64", + "version": "[8.0.28, 8.0.28]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[8.0.28, 8.0.28]" + }, + { + "name": "Microsoft.WindowsDesktop.App.Ref", + "version": "[8.0.28, 8.0.28]" + } + ], + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "C:\\Program Files\\dotnet\\sdk\\10.0.301/PortableRuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/_fix/DumpMap/obj/project.nuget.cache b/_fix/DumpMap/obj/project.nuget.cache new file mode 100644 index 0000000..4dfd0f6 --- /dev/null +++ b/_fix/DumpMap/obj/project.nuget.cache @@ -0,0 +1,16 @@ +{ + "version": 2, + "dgSpecHash": "e2CJM3ZSKiM=", + "success": true, + "projectFilePath": "c:\\Users\\andre\\Desktop\\SkopjeMods\\_fix\\DumpMap\\DumpMap.csproj", + "expectedPackageFiles": [ + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\system.collections.immutable\\8.0.0\\system.collections.immutable.8.0.0.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\system.reflection.metadata\\8.0.0\\system.reflection.metadata.8.0.0.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\system.reflection.metadataloadcontext\\8.0.0\\system.reflection.metadataloadcontext.8.0.0.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.netcore.app.ref\\8.0.28\\microsoft.netcore.app.ref.8.0.28.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.windowsdesktop.app.ref\\8.0.28\\microsoft.windowsdesktop.app.ref.8.0.28.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.aspnetcore.app.ref\\8.0.28\\microsoft.aspnetcore.app.ref.8.0.28.nupkg.sha512", + "C:\\Users\\andre\\AppData\\Local\\Temp\\cursor-sandbox-cache\\a0404811fc6e51c4c5761fd11591789f\\nuget\\microsoft.netcore.app.host.win-x64\\8.0.28\\microsoft.netcore.app.host.win-x64.8.0.28.nupkg.sha512" + ], + "logs": [] +} \ No newline at end of file diff --git a/_fix/DumpUi/Program.cs b/_fix/DumpUi/Program.cs index 8d791ad..bbacb0f 100644 --- a/_fix/DumpUi/Program.cs +++ b/_fix/DumpUi/Program.cs @@ -31,10 +31,21 @@ void Dump(string file, string typeName) static string EnumNames(Type t) => string.Join(",", t.GetEnumNames()); var skopje = mlc.LoadFromAssemblyPath(Path.Combine(interop, "SkopjeAssembly.dll")); +string[] names = { "EnemyBlockHelper", "NotDamageable", "IDamageable" }; foreach (var type in skopje.GetTypes()) { - if (type.Name != "CompassViewController" && type.Name != "CompassView") continue; - Console.WriteLine("TYPE " + type.FullName + " : " + type.BaseType?.FullName); - foreach (var p in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) + if (!names.Contains(type.Name)) continue; + Console.WriteLine("TYPE " + type.Name); + if (type.IsEnum) + { + Console.WriteLine(" " + string.Join(", ", type.GetEnumNames())); + continue; + } + foreach (var p in type.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) Console.WriteLine(" P " + p.PropertyType.Name + " " + p.Name); + foreach (var m in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)) + { + if (m.IsSpecialName) continue; + Console.WriteLine(" M " + m.ReturnType.Name + " " + m.Name); + } } diff --git a/_fix/DumpUi/bin/Release/net8.0/DumpUi.dll b/_fix/DumpUi/bin/Release/net8.0/DumpUi.dll index 81d65b5..d337b91 100644 Binary files a/_fix/DumpUi/bin/Release/net8.0/DumpUi.dll and b/_fix/DumpUi/bin/Release/net8.0/DumpUi.dll differ diff --git a/_fix/DumpUi/bin/Release/net8.0/DumpUi.exe b/_fix/DumpUi/bin/Release/net8.0/DumpUi.exe index 773a7ae..44e63c5 100644 Binary files a/_fix/DumpUi/bin/Release/net8.0/DumpUi.exe and b/_fix/DumpUi/bin/Release/net8.0/DumpUi.exe differ diff --git a/_fix/DumpUi/bin/Release/net8.0/DumpUi.pdb b/_fix/DumpUi/bin/Release/net8.0/DumpUi.pdb index d3722dd..e6ab26b 100644 Binary files a/_fix/DumpUi/bin/Release/net8.0/DumpUi.pdb and b/_fix/DumpUi/bin/Release/net8.0/DumpUi.pdb differ diff --git a/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfo.cs b/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfo.cs index a6eab44..3e8dda8 100644 --- a/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfo.cs +++ b/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfo.cs @@ -13,7 +13,7 @@ using System.Reflection; [assembly: System.Reflection.AssemblyCompanyAttribute("DumpUi")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Release")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] -[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+9f4f8bf5235790c04718d7ca24b0f3f76e93b270")] [assembly: System.Reflection.AssemblyProductAttribute("DumpUi")] [assembly: System.Reflection.AssemblyTitleAttribute("DumpUi")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] diff --git a/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfoInputs.cache b/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfoInputs.cache index 933b0a3..33cc44e 100644 --- a/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfoInputs.cache +++ b/_fix/DumpUi/obj/Release/net8.0/DumpUi.AssemblyInfoInputs.cache @@ -1 +1 @@ -1bd7648d90d9d85fede4b666912953baba06df98a1e74e7105064e3c5fcbaae0 +f37b9f7c232818ed923a9fb9b7b83a33eb2edde4f75ff4178f075a26424253c5 diff --git a/_fix/DumpUi/obj/Release/net8.0/DumpUi.dll b/_fix/DumpUi/obj/Release/net8.0/DumpUi.dll index 81d65b5..d337b91 100644 Binary files a/_fix/DumpUi/obj/Release/net8.0/DumpUi.dll and b/_fix/DumpUi/obj/Release/net8.0/DumpUi.dll differ diff --git a/_fix/DumpUi/obj/Release/net8.0/DumpUi.pdb b/_fix/DumpUi/obj/Release/net8.0/DumpUi.pdb index d3722dd..e6ab26b 100644 Binary files a/_fix/DumpUi/obj/Release/net8.0/DumpUi.pdb and b/_fix/DumpUi/obj/Release/net8.0/DumpUi.pdb differ diff --git a/_fix/DumpUi/obj/Release/net8.0/apphost.exe b/_fix/DumpUi/obj/Release/net8.0/apphost.exe index 773a7ae..44e63c5 100644 Binary files a/_fix/DumpUi/obj/Release/net8.0/apphost.exe and b/_fix/DumpUi/obj/Release/net8.0/apphost.exe differ diff --git a/_fix/DumpUi/obj/Release/net8.0/ref/DumpUi.dll b/_fix/DumpUi/obj/Release/net8.0/ref/DumpUi.dll index 2c5fa42..8cf3719 100644 Binary files a/_fix/DumpUi/obj/Release/net8.0/ref/DumpUi.dll and b/_fix/DumpUi/obj/Release/net8.0/ref/DumpUi.dll differ diff --git a/_fix/DumpUi/obj/Release/net8.0/refint/DumpUi.dll b/_fix/DumpUi/obj/Release/net8.0/refint/DumpUi.dll index 2c5fa42..8cf3719 100644 Binary files a/_fix/DumpUi/obj/Release/net8.0/refint/DumpUi.dll and b/_fix/DumpUi/obj/Release/net8.0/refint/DumpUi.dll differ