From 4734bbe369182f9c11fecc87752c82db4f883a4f Mon Sep 17 00:00:00 2001 From: Wiz Date: Mon, 29 Apr 2024 23:40:17 +0100 Subject: [PATCH] Added Unity plugin. --- CL.Common/Constants.cs | 1 - CL.Common/CustomLicense.cs | 24 ++- CL.Game/LicenseManager.cs | 9 + CL.Unity/CL.Unity.csproj | 23 +++ CL.Unity/CustomLicenseContainer.cs | 36 ++++ CL.Unity/Inspector/ColourDrawer.cs | 35 ++++ .../Inspector/CustomLicenseContainerEditor.cs | 166 ++++++++++++++++++ DVCustomLicenses.sln | 9 + 8 files changed, 298 insertions(+), 5 deletions(-) create mode 100644 CL.Unity/CL.Unity.csproj create mode 100644 CL.Unity/CustomLicenseContainer.cs create mode 100644 CL.Unity/Inspector/ColourDrawer.cs create mode 100644 CL.Unity/Inspector/CustomLicenseContainerEditor.cs diff --git a/CL.Common/Constants.cs b/CL.Common/Constants.cs index 66297ac..6b55113 100644 --- a/CL.Common/Constants.cs +++ b/CL.Common/Constants.cs @@ -11,7 +11,6 @@ public static class Constants public const string LangHelper = "DVLangHelper"; public const string MainModId = "DVCustomLicenses"; public const string ModIdPrefix = "CL_"; - public const string CCL = "DVCustomCarLoader"; // Localization. public const string LocalizeRoot = "customlicenses"; diff --git a/CL.Common/CustomLicense.cs b/CL.Common/CustomLicense.cs index f9ff9c9..553c8a8 100644 --- a/CL.Common/CustomLicense.cs +++ b/CL.Common/CustomLicense.cs @@ -1,5 +1,4 @@ using DVLangHelper.Data; -using Newtonsoft.Json; using System; using UnityEngine; @@ -9,16 +8,18 @@ namespace CL.Common public class CustomLicense { [Header("License properties")] - [Tooltip("Wether this is a general license (locomotives, concurrent jobs, etc) or a job license (hazmat, train length, etc)")] + [Tooltip("Whether this is a general license (locomotives, concurrent jobs, etc) or a job license (hazmat, train length, etc)")] public LicenseType LicenseType = LicenseType.General; [Tooltip("The name (id) of the license")] public string Identifier = "CL_LicenseId"; - public Colour Color = new Colour(0, 0, 1, 1); + public Colour Color = Colour.FromUnity(new Color32(43, 166, 166, byte.MaxValue)); public float Price = 10000; [Tooltip("How much copay should increase after buying this license")] public float InsuranceFeeQuotaIncrease; - [Tooltip("How much bonus time should decrease after buying this license")] + [Tooltip("How much bonus time should decrease after buying this license\n" + + "1% is written as 0.01\n" + + "Negative values will give more bonus time instead")] public float BonusTimeDecreasePercentage; [Header("Requirements (Optional)")] @@ -31,9 +32,13 @@ public class CustomLicense public FreeRoamAvailability Availability = FreeRoamAvailability.OnlyIfUnlockedInCareer; [Header("Localization")] + [Tooltip("The name of the license (DE2, S282, Hazmat 2)")] public TranslationData? TranslationName; + [Tooltip("The description of the license")] public TranslationData? TranslationDescription; + [Tooltip("The name of the inventory item for the license")] public TranslationData? TranslationItem; + [Tooltip("The name of the inventory item for the sample version of the license")] public TranslationData? TranslationInfoItem; public string LocalizationKey => $"{Constants.LocalizeRoot}/{Identifier.Replace(" ", "_").ToLowerInvariant()}"; @@ -42,6 +47,7 @@ public class CustomLicense public string LocalizationKeyInfoItem => $"{LocalizationKey}_sample_item"; // Wrapper class to avoid serialization issues. + [Serializable] public class Colour { public float R, G, B, A; @@ -60,6 +66,16 @@ public Color ToUnity() { return new Color(R, G, B, A); } + + public static Color ToUnity(Colour c) + { + return c.ToUnity(); + } + + public static Colour FromUnity(Color color) + { + return new Colour(color.r, color.g, color.b, color.a); + } } } } diff --git a/CL.Game/LicenseManager.cs b/CL.Game/LicenseManager.cs index 5e5e6d2..4e1b49c 100644 --- a/CL.Game/LicenseManager.cs +++ b/CL.Game/LicenseManager.cs @@ -80,17 +80,26 @@ public static void LoadLicenses(UnityModManager.ModEntry mod) } } + bool flag = false; + // If we did load any licenses... if (newGeneralLicenses.Count > 0) { CLMod.Log($"Loaded {newGeneralLicenses.Count} general licenses from {mod.Path}"); CLMod.Log(string.Join(", ", newGeneralLicenses.Select(x => x.id))); + flag = true; } if (newJobLicenses.Count > 0) { CLMod.Log($"Loaded {newJobLicenses.Count} job licenses from {mod.Path}"); CLMod.Log(string.Join(", ", newJobLicenses.Select(x => x.id))); + flag = true; + } + + if (flag) + { + Globals.G.Types.RecalculateCaches(); } } diff --git a/CL.Unity/CL.Unity.csproj b/CL.Unity/CL.Unity.csproj new file mode 100644 index 0000000..94508b9 --- /dev/null +++ b/CL.Unity/CL.Unity.csproj @@ -0,0 +1,23 @@ + + + $(MSBuildProjectName) + netframework4.8 + enable + 8 + + + + + + + + + + + + + + + + + diff --git a/CL.Unity/CustomLicenseContainer.cs b/CL.Unity/CustomLicenseContainer.cs new file mode 100644 index 0000000..1f85cb0 --- /dev/null +++ b/CL.Unity/CustomLicenseContainer.cs @@ -0,0 +1,36 @@ +using CL.Common; +using Newtonsoft.Json; +using System.IO; +using UnityEditor; +using UnityEngine; + +namespace CL.Unity +{ + [CreateAssetMenu(menuName = "DVCustomLicenses/Custom License")] + internal class CustomLicenseContainer : ScriptableObject + { + public CustomLicense License = new CustomLicense(); + + public string GetFullPath() + { + string path = Application.dataPath; + string assetPath = AssetDatabase.GetAssetPath(this); + path = path + "/" + assetPath.Substring(7); + return Path.GetDirectoryName(path); + } + + public void Export() + { + // Use a JsonSerializer for a cleaner output. + JsonSerializer serializer = new JsonSerializer { Formatting = Formatting.Indented }; + var path = $"{GetFullPath()}\\license.json"; + + using var file = File.CreateText(path); + using var jsonWr = new JsonTextWriter(file); + serializer.Serialize(jsonWr, License); + + EditorUtility.RevealInFinder(path); + AssetDatabase.Refresh(); + } + } +} diff --git a/CL.Unity/Inspector/ColourDrawer.cs b/CL.Unity/Inspector/ColourDrawer.cs new file mode 100644 index 0000000..e874cc0 --- /dev/null +++ b/CL.Unity/Inspector/ColourDrawer.cs @@ -0,0 +1,35 @@ +using UnityEditor; +using UnityEngine; + +using static CL.Common.CustomLicense; + +namespace CL.Unity.Inspector +{ + [CustomPropertyDrawer(typeof(Colour))] + internal class ColourDrawer : PropertyDrawer + { + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + var r = property.FindPropertyRelative(nameof(Colour.R)); + var g = property.FindPropertyRelative(nameof(Colour.G)); + var b = property.FindPropertyRelative(nameof(Colour.B)); + var a = property.FindPropertyRelative(nameof(Colour.A)); + + EditorGUI.BeginProperty(position, label, property); + + var result = EditorGUI.ColorField(position, label, new Color(r.floatValue, g.floatValue, b.floatValue, a.floatValue)); + + r.floatValue = result.r; + g.floatValue = result.g; + b.floatValue = result.b; + a.floatValue = result.a; + + EditorGUI.EndProperty(); + } + + public override float GetPropertyHeight(SerializedProperty property, GUIContent label) + { + return EditorGUIUtility.singleLineHeight; + } + } +} diff --git a/CL.Unity/Inspector/CustomLicenseContainerEditor.cs b/CL.Unity/Inspector/CustomLicenseContainerEditor.cs new file mode 100644 index 0000000..16a0d07 --- /dev/null +++ b/CL.Unity/Inspector/CustomLicenseContainerEditor.cs @@ -0,0 +1,166 @@ +using CL.Common; +using DVLangHelper.Data; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; + +using static CL.Common.CustomLicense; + +namespace CL.Unity.Inspector +{ + [CustomEditor(typeof(CustomLicenseContainer))] + internal class CustomLicenseContainerEditor : Editor + { + private static Dictionary LicenseToColour = new Dictionary() + { + { LicenseColour.Generic, new Color32( 43, 166, 166, byte.MaxValue) }, + { LicenseColour.Locomotive, new Color32( 83, 83, 83, byte.MaxValue) }, + { LicenseColour.Concurrent, new Color32(115, 86, 146, byte.MaxValue) }, + { LicenseColour.Hazmat, new Color32(166, 43, 43, byte.MaxValue) }, + { LicenseColour.Military, new Color32(126, 152, 95, byte.MaxValue) }, + { LicenseColour.Length, new Color32(146, 98, 59, byte.MaxValue) } + }; + + private CustomLicenseContainer _container = null!; + private SerializedProperty _license = null!; + private LicenseColour _selectedColour; + private FillType _selectedFill; + + private void OnEnable() + { + _license = serializedObject.FindProperty(nameof(CustomLicenseContainer.License)); + } + + public override void OnInspectorGUI() + { + var current = _license.FindPropertyRelative(nameof(CustomLicense.LicenseType)); + + do + { + EditorGUILayout.PropertyField(current); + } while (current.Next(false)); + + _container = (CustomLicenseContainer)target; + bool dirty = false; + + EditorGUILayout.Space(); + + using (new EditorGUILayout.HorizontalScope()) + { + _selectedColour = (LicenseColour)EditorGUILayout.EnumPopup(_selectedColour); + + if (GUILayout.Button(new GUIContent("Set colour", + "Sets the colour to one of the base game colours"), + GUILayout.Width(EditorGUIUtility.currentViewWidth * 0.45f))) + { + _container.License.Color = Colour.FromUnity(LicenseToColour[_selectedColour]); + dirty = true; + } + } + + using (new EditorGUILayout.HorizontalScope()) + { + _selectedFill = (FillType)EditorGUILayout.EnumPopup(_selectedFill); + + if (GUILayout.Button(new GUIContent("Autofill", + "Auto fills english translations based on the name and type\n" + + "Will not replace already written text"), + GUILayout.Width(EditorGUIUtility.currentViewWidth * 0.45f))) + { + Autofill(_container.License, _selectedFill); + dirty = true; + } + } + + if (dirty) + { + EditorUtility.SetDirty(target); + AssetDatabase.SaveAssets(); + serializedObject.Update(); + } + + if (GUILayout.Button("Export")) + { + _container.Export(); + } + } + + private static void Autofill(CustomLicense license, FillType fillType) + { + var translation = license.TranslationName!.Items.Where(x => x.Language == DVLanguage.English).FirstOrDefault(); + + if (translation == null || string.IsNullOrEmpty(translation.Value)) + { + Debug.LogWarning("No english name has been assigned to the license, cannot autofill!"); + return; + } + + var name = translation.Value; + + // Item name. + var itemName = license.TranslationItem!.Items.Where(x => x.Language == DVLanguage.English).FirstOrDefault(); + itemName ??= new TranslationItem(DVLanguage.English, string.Empty); + + if (string.IsNullOrEmpty(itemName.Value)) + { + itemName.Value = $"License {name}"; + } + + // Info item name. + var infoItemName = license.TranslationInfoItem!.Items.Where(x => x.Language == DVLanguage.English).FirstOrDefault(); + infoItemName ??= new TranslationItem(DVLanguage.English, string.Empty); + + if (string.IsNullOrEmpty(infoItemName.Value)) + { + infoItemName.Value = $"License {name} Info"; + } + + // Description. + var description = license.TranslationDescription!.Items.Where(x => x.Language == DVLanguage.English).FirstOrDefault(); + description ??= new TranslationItem(DVLanguage.English, string.Empty); + + if (string.IsNullOrEmpty(description.Value)) + { + description.Value = fillType switch + { + FillType.SteamLocomotive => "This license grants you access to all the [WHYTE WHEEL ARRANGEMENT] steam-powered locomotives in Derail Valley. " + + "Use them responsibly! Refer to your vehicle catalog for detailed specifications.", + FillType.DELocomotive => "This license grants you access to all the [# AXLES]-axle diesel-electric locomotives in Derail Valley. " + + "Use them responsibly! Refer to your vehicle catalog for detailed specifications.", + FillType.DHLocomotive => "This license grants you access to all the [# AXLES]-axle diesel-hydraulic locomotives in Derail Valley. " + + "Use them responsibly! Refer to your vehicle catalog for detailed specifications.", + FillType.DMLocomotive => "This license grants you access to all the [# AXLES]-axle diesel-mechanical locomotives in Derail Valley. " + + "Use them responsibly! Refer to your vehicle catalog for detailed specifications.", + FillType.JobType => $"This license grants you access to all orders of the {name} type. This order type involves [DESCRIPTION].", + _ => string.Empty + }; + + if (!string.IsNullOrEmpty(description.Value)) + { + Debug.Log("Please fill out the fields marked [LIKE THIS] in the description of the license!"); + } + } + } + + private enum LicenseColour + { + Generic, + Locomotive, + Concurrent, + Hazmat, + Military, + Length + } + + private enum FillType + { + NoDescription, + SteamLocomotive, + DELocomotive, + DHLocomotive, + DMLocomotive, + JobType + } + } +} diff --git a/DVCustomLicenses.sln b/DVCustomLicenses.sln index d84beff..ca40833 100644 --- a/DVCustomLicenses.sln +++ b/DVCustomLicenses.sln @@ -7,6 +7,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CL.Common", "CL.Common\CL.C EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CL.Game", "CL.Game\CL.Game.csproj", "{2FEE4E2B-F031-483E-AC16-7A8F3527E3B1}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CL.Unity", "CL.Unity\CL.Unity.csproj", "{77595CE5-DE0C-4EE5-BBE4-2F6B716CF9D3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,8 +23,15 @@ Global {2FEE4E2B-F031-483E-AC16-7A8F3527E3B1}.Debug|Any CPU.Build.0 = Debug|Any CPU {2FEE4E2B-F031-483E-AC16-7A8F3527E3B1}.Release|Any CPU.ActiveCfg = Release|Any CPU {2FEE4E2B-F031-483E-AC16-7A8F3527E3B1}.Release|Any CPU.Build.0 = Release|Any CPU + {77595CE5-DE0C-4EE5-BBE4-2F6B716CF9D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {77595CE5-DE0C-4EE5-BBE4-2F6B716CF9D3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {77595CE5-DE0C-4EE5-BBE4-2F6B716CF9D3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {77595CE5-DE0C-4EE5-BBE4-2F6B716CF9D3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {AC27D2F1-A8E1-4B99-84DE-2EC15E5C05CF} + EndGlobalSection EndGlobal