diff --git a/.gitignore b/.gitignore index 9491a2f..00972f2 100644 --- a/.gitignore +++ b/.gitignore @@ -360,4 +360,8 @@ MigrationBackup/ .ionide/ # Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file +FodyWeavers.xsd + +# git merge +*.orig +*.bak diff --git a/ColorCycler/About/About.xml b/ColorCycler/About/About.xml new file mode 100644 index 0000000..081310a --- /dev/null +++ b/ColorCycler/About/About.xml @@ -0,0 +1,10 @@ + + + Color Cycler + Elmotrix + 1.200000.00 + Cycles colors on spray cans with mouse wheel + + paint + + \ No newline at end of file diff --git a/ColorCycler/About/Preview.png b/ColorCycler/About/Preview.png new file mode 100644 index 0000000..a74ec24 Binary files /dev/null and b/ColorCycler/About/Preview.png differ diff --git a/ColorCycler/About/bepinex b/ColorCycler/About/bepinex new file mode 100644 index 0000000..e69de29 diff --git a/ColorCycler/About/thumb.png b/ColorCycler/About/thumb.png new file mode 100644 index 0000000..6d11a2b Binary files /dev/null and b/ColorCycler/About/thumb.png differ diff --git a/ColorCycler/BepInEx.cs b/ColorCycler/BepInEx.cs index b10bea3..e267fca 100644 --- a/ColorCycler/BepInEx.cs +++ b/ColorCycler/BepInEx.cs @@ -1,6 +1,6 @@ -using HarmonyLib; +using BepInEx.Logging; +using HarmonyLib; using System; -using UnityEngine; namespace ColorCycler { @@ -10,24 +10,39 @@ public class ColorCyclerBep : BepInEx.BaseUnityPlugin { public const string pluginGuid = "net.elmo.stationeers.ColorCycler"; public const string pluginName = "ColorCycler"; - public const string pluginVersion = "1.1.0"; - public static void Log(string line) + public const string pluginVersion = "1.2.0"; + + private Harmony _harmony; + + internal static new ManualLogSource Logger; + internal static ColorCyclerConfig Settings; + + public ColorCyclerBep() { - Debug.Log("[" + pluginName + "]: " + line); + Settings ??= new ColorCyclerConfig(Config); } + void Awake() { + Logger = base.Logger; try { - var harmony = new Harmony(pluginGuid); - harmony.PatchAll(); - Log("Patch succeeded"); + _harmony = new Harmony(pluginGuid); + _harmony.PatchAll(); + Logger.LogInfo("Patch succeeded"); } catch (Exception e) { - Log("Patch Failed"); - Log(e.ToString()); + Logger.LogFatal("Patch Failed"); + Logger.LogFatal(e); } + Logger.LogMessage($"{nameof(Settings.ShouldCreatePollution)}: {Settings.ShouldCreatePollution}"); + Logger.LogMessage($"{nameof(Settings.InfinitePaint)}: {Settings.InfinitePaint}"); + } + + private void OnDestroy() + { + _harmony.UnpatchSelf(); } } #endregion diff --git a/ColorCycler/ColorCycler.csproj b/ColorCycler/ColorCycler.csproj index e9f824a..feeff91 100644 --- a/ColorCycler/ColorCycler.csproj +++ b/ColorCycler/ColorCycler.csproj @@ -12,49 +12,51 @@ v4.7.2 512 true + latest true full false - bin\Debug\ + bin\Debug\ColorCycler DEBUG;TRACE prompt 4 - pdbonly + embedded true - bin\Release\ + bin\Release\ColorCycler TRACE prompt 4 + true - + D:\SteamLibrary\steamapps\common\Stationeers\BepInEx\core\0Harmony.dll - + D:\SteamLibrary\steamapps\common\Stationeers\rocketstation_Data\Managed\Assembly-CSharp.dll - + D:\SteamLibrary\steamapps\common\Stationeers\BepInEx\core\BepInEx.dll - - - - - - - - - + + + + + + + + + D:\SteamLibrary\steamapps\common\Stationeers\rocketstation_Data\Managed\UnityEngine.dll - + D:\SteamLibrary\steamapps\common\Stationeers\rocketstation_Data\Managed\UnityEngine.CoreModule.dll - + False D:\SteamLibrary\steamapps\common\Stationeers\rocketstation_Data\Managed\UnityEngine.PhysicsModule.dll @@ -63,7 +65,24 @@ + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + PreserveNewest + + \ No newline at end of file diff --git a/ColorCycler/ColorCyclerConfig.cs b/ColorCycler/ColorCyclerConfig.cs new file mode 100644 index 0000000..5aa7f4d --- /dev/null +++ b/ColorCycler/ColorCyclerConfig.cs @@ -0,0 +1,39 @@ +using BepInEx.Configuration; +using System; + +namespace ColorCycler +{ + internal class ColorCyclerConfig + { + private ConfigEntry _shouldCreatePollutionEntry; + private ConfigEntry _infinitePaint; + + public bool ShouldCreatePollution => _shouldCreatePollutionEntry.Value; + public bool InfinitePaint => _infinitePaint.Value; + + public ColorCyclerConfig(ConfigFile config) + { + _shouldCreatePollutionEntry = config.Bind( + "ColorCycler", + nameof(ShouldCreatePollution), + false, + "Should spray cans create pollution?" + ); + _infinitePaint = config.Bind( + "ColorCycler", + nameof(InfinitePaint), + true, + "Should spray cans have infinite uses?" + ); + + config.ConfigReloaded += OnConfigReloaded; + } + + private void OnConfigReloaded(object sender, EventArgs e) + { + ColorCyclerBep.Logger.LogWarning("Config Reloaded"); + ColorCyclerBep.Logger.LogWarning($"{nameof(ShouldCreatePollution)}: {ShouldCreatePollution}"); + ColorCyclerBep.Logger.LogWarning($"{nameof(InfinitePaint)}: {InfinitePaint}"); + } + } +} diff --git a/ColorCycler/ColorCyclerMod.cs b/ColorCycler/ColorCyclerMod.cs index 68b201f..250e11d 100644 --- a/ColorCycler/ColorCyclerMod.cs +++ b/ColorCycler/ColorCyclerMod.cs @@ -44,6 +44,7 @@ public static void Prefix(InventoryManager __instance) if (NetworkManager.IsClient) { + ColorCyclerBep.Logger.LogDebug($"Sending {nameof(ThingColorMessage)} to Server. ColorIndex = {current}, ThingId = {sprayCan.ReferenceId}"); NetworkClient.SendToServer(new ThingColorMessage { ThingId = sprayCan.ReferenceId, @@ -59,12 +60,45 @@ public static void Prefix(InventoryManager __instance) public class SprayCanOnUseItemPatch { [UsedImplicitly] - public static bool Prefix(ref bool __result) + public static bool Prefix(SprayCan __instance, ref bool __result, ref float quantity) { - // Modify __result and return false, so that pollution does not occur. __result = true; + + // Make Paint infinite. + if (ColorCyclerBep.Settings.InfinitePaint) + { + ColorCyclerBep.Logger.LogDebug($"Setting Quantity to 0 from {quantity}"); + quantity = 0.0f; + } + ColorCyclerBep.Logger.LogDebug($"Using Quantity {quantity}"); + + // Return true, so that original code is executed, if pollution should occur. + if (ColorCyclerBep.Settings.ShouldCreatePollution) + { + return true; + } + + // No pollution, skip original, but apply Quantity in case of non-infinite paint + __instance.Quantity -= quantity; + return false; + } + } + + // We have to patch Consumable because SprayCan does not implement the method + [HarmonyPatch(typeof(Consumable), nameof(Consumable.GetQuantityText))] + public class ConsumableGetQuantityTextPatch + { + [UsedImplicitly] + public static bool Prefix(Consumable __instance, ref string __result) + { + if (__instance is not SprayCan sprayCan || !ColorCyclerBep.Settings.InfinitePaint) + { + return true; + } + __result = "Infinite"; return false; } + } // We have to patch Consumable because SprayCan does not implement the method @@ -76,7 +110,7 @@ public static void Postfix(Consumable __instance, RocketBinaryWriter writer, ush { if (__instance is SprayCan sprayCan) { - if (Thing.IsNetworkUpdateRequired(4096U, networkUpdateType)) + if (Thing.IsNetworkUpdateRequired(ColorCyclerModHelpers.PaintableMaterialNetworkFlag, networkUpdateType)) { writer.WriteInt32(ColorCyclerModHelpers.GetPaintColorIndex(sprayCan.PaintMaterial)); } @@ -93,7 +127,7 @@ public static void Postfix(Consumable __instance, RocketBinaryReader reader, ush { if (__instance is SprayCan sprayCan) { - if (Thing.IsNetworkUpdateRequired(4096U, networkUpdateType)) + if (Thing.IsNetworkUpdateRequired(ColorCyclerModHelpers.PaintableMaterialNetworkFlag, networkUpdateType)) { int index = reader.ReadInt32(); var paintMaterial = ColorCyclerModHelpers.GetPaintColor(index); @@ -109,6 +143,7 @@ public class ThingColorMessageProcessPatch [UsedImplicitly] public static void Postfix(ThingColorMessage __instance, long hostId) { + ColorCyclerBep.Logger.LogDebug($"Received {nameof(ThingColorMessage)}. ColorIndex = {__instance.ColorIndex}, ThingId = {__instance.ThingId}"); if (Thing.Find(__instance.ThingId) is SprayCan sprayCan) { var paintMaterial = ColorCyclerModHelpers.GetPaintColor(__instance.ColorIndex); diff --git a/ColorCycler/ColorCyclerModHelpers.cs b/ColorCycler/ColorCyclerModHelpers.cs index febd2e9..03afb38 100644 --- a/ColorCycler/ColorCyclerModHelpers.cs +++ b/ColorCycler/ColorCyclerModHelpers.cs @@ -4,55 +4,75 @@ using Assets.Scripts.Objects.Items; using UnityEngine; -internal static class ColorCyclerModHelpers +namespace ColorCycler { - public static int GetPaintColorIndex(UnityEngine.Material paintMaterial) + + internal static class ColorCyclerModHelpers { - for (int i = 0; i < GameManager.Instance.CustomColors.Count; i++) + internal const ushort PaintableMaterialNetworkFlag = 0x1000; //NetworkUpdateType.Thing.GenericFlag2 + + public static int GetPaintColorIndex(UnityEngine.Material paintMaterial) { - if (GameManager.Instance.CustomColors[i].Normal == paintMaterial) + for (int i = 0; i < GameManager.Instance.CustomColors.Count; i++) { - return i; + if (GameManager.Instance.CustomColors[i].Normal == paintMaterial) + { + return i; + } } + return -1; } - return -1; - } - public static UnityEngine.Material GetPaintColor(int colorIndex) - { - return GameManager.Instance.CustomColors[colorIndex].Normal; - } + public static UnityEngine.Material GetPaintColor(int colorIndex) + { + if (colorIndex < 0 || colorIndex > GameManager.Instance.CustomColors.Count) + { + ColorCyclerBep.Logger.LogError($"{nameof(GetPaintColor)}: {nameof(colorIndex)} was {colorIndex:D} which is out of range."); + colorIndex = 0; + } + return GameManager.Instance.CustomColors[colorIndex].Normal; + } - public static void UpdateSprayCan(SprayCan sprayCan, UnityEngine.Material paintMaterial) - { - sprayCan.PaintableMaterial = paintMaterial; - sprayCan.PaintMaterial = sprayCan.PaintableMaterial; - foreach (Thing thing in Prefab.AllPrefabs) + public static void UpdateSprayCan(SprayCan sprayCan, UnityEngine.Material paintMaterial) { - if (thing is SprayCan sprayCan2) + ColorCyclerBep.Logger.LogDebug($"{nameof(ColorCyclerBep.Settings.ShouldCreatePollution)}: {ColorCyclerBep.Settings.ShouldCreatePollution}"); + ColorCyclerBep.Logger.LogDebug($"{nameof(ColorCyclerBep.Settings.InfinitePaint)}: {ColorCyclerBep.Settings.InfinitePaint}"); + ColorCyclerBep.Logger.LogDebug($"Updating {sprayCan.DisplayName} - {sprayCan.ReferenceId} to {paintMaterial.name} on {(NetworkManager.IsServer ? "Server" : "Client")}"); + sprayCan.PaintableMaterial = paintMaterial; + sprayCan.PaintMaterial = sprayCan.PaintableMaterial; + //TODO: Look up prefab hashes and cache for faster lookup + foreach (Thing thing in Prefab.AllPrefabs) { - if (sprayCan2.PaintMaterial == sprayCan.PaintMaterial) + if (thing is SprayCan sprayCan2) { - sprayCan.SetPrefab(sprayCan2); - // Update Hash so that sorting and logic will remain - sprayCan.PrefabHash = sprayCan2.PrefabHash; - // Update "real" name - sprayCan.PrefabName = sprayCan2.PrefabName; - sprayCan.Thumbnail = sprayCan2.Thumbnail; - // Update Mesh such that thrown model appears correctly - if (sprayCan.GetComponent() is MeshRenderer mr) + if (sprayCan2.PaintMaterial == sprayCan.PaintMaterial) { - mr.sharedMaterial = sprayCan.PaintMaterial; + sprayCan.SetPrefab(sprayCan2); + // Update Hash so that sorting and logic will remain + sprayCan.PrefabHash = sprayCan2.PrefabHash; + // Update "real" name + sprayCan.PrefabName = sprayCan2.PrefabName; + sprayCan.Thumbnail = sprayCan2.Thumbnail; + // Update Mesh such that thrown model appears correctly + if (sprayCan.GetComponent() is MeshRenderer mr) + { + mr.sharedMaterial = sprayCan.PaintMaterial; + } + ColorCyclerBep.Logger.LogDebug($"Previous SprayCan Quantity: {sprayCan.Quantity}"); + if (ColorCyclerBep.Settings.InfinitePaint) + { + ColorCyclerBep.Logger.LogDebug($"Setting Quantity to MaxQuantity."); + sprayCan.Quantity = sprayCan.MaxQuantity; + } + break; } - sprayCan.Quantity = sprayCan.MaxQuantity; - break; } } - } - if (NetworkManager.IsServer) - { - sprayCan.NetworkUpdateFlags |= 4096; + if (NetworkManager.IsServer) + { + sprayCan.NetworkUpdateFlags |= PaintableMaterialNetworkFlag; + } } } -} \ No newline at end of file +}