From 73a81d07175ed944af8dd1ec56994da9e3f53f11 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 7 Sep 2022 20:11:14 -0300 Subject: [PATCH 01/23] tweak: keep alive now uses HttpClient --- SimplePartLoader/ModMain.cs | 5 +++-- SimplePartLoader/ModUtils.csproj | 1 + SimplePartLoader/Utils/KeepAlive.cs | 20 +++++++------------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index be04f9b..b9c8738 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -172,8 +172,9 @@ public override void OnMenuLoad() } // Enable heartbeat - KeepAlive.GetInstance().Ready(); - + + if(!File.Exists(autoupdaterPath + "\\disableStatus.txt")) + KeepAlive.GetInstance().Ready(); } public override void OnLoad() diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index 471b903..65cf0a7 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -60,6 +60,7 @@ + diff --git a/SimplePartLoader/Utils/KeepAlive.cs b/SimplePartLoader/Utils/KeepAlive.cs index 29799ca..93ac220 100644 --- a/SimplePartLoader/Utils/KeepAlive.cs +++ b/SimplePartLoader/Utils/KeepAlive.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using UnityEngine; @@ -15,6 +16,7 @@ internal class KeepAlive { private static KeepAlive Instance; string serializedJson; + private HttpClient client = new HttpClient(); private KeepAlive() { @@ -37,26 +39,18 @@ private KeepAlive() var timer = new System.Threading.Timer((e) => { - SendCurrentStatus(); + Task.Run(SendCurrentStatus); }, null, startTimeSpan, periodTimeSpan); } - private void SendCurrentStatus() + private async void SendCurrentStatus() { + // TODO: Test this! Debug.Log("[ModUtils/KeepAlive]: Sending status"); try { - var httpWebRequest = (HttpWebRequest)WebRequest.Create(ModMain.API_URL + "/alive"); - httpWebRequest.ContentType = "application/json"; - httpWebRequest.Accept = "application/json"; - httpWebRequest.Method = "POST"; - - using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream())) - { - streamWriter.Write(serializedJson); - } - - httpWebRequest.GetResponseAsync(); + var content = new StringContent(serializedJson, Encoding.UTF8, "application/json"); + _ = await client.PostAsync(ModMain.API_URL + "/alive", content); } catch (Exception ex) { From 6b67ef468549fec8218278fab545bfb3f9a5011c Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 7 Sep 2022 21:45:40 -0300 Subject: [PATCH 02/23] feat: ModUtils now handles part loading instead of SPL --- SimplePartLoader/ModUtils.csproj | 2 + .../ModUtils/CarParts/ModInstance.cs | 115 ++++++++++++++++++ .../ModUtils/CarParts/ModSettings.cs | 44 +++++++ SimplePartLoader/ModUtils/ModUtils.cs | 19 +++ SimplePartLoader/Objects/Part.cs | 9 +- SimplePartLoader/SPL.cs | 4 +- SimplePartLoader/Utils/Functions.cs | 51 ++++++++ 7 files changed, 241 insertions(+), 3 deletions(-) create mode 100644 SimplePartLoader/ModUtils/CarParts/ModInstance.cs create mode 100644 SimplePartLoader/ModUtils/CarParts/ModSettings.cs diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index 65cf0a7..81fe17c 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -437,6 +437,8 @@ + + diff --git a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs new file mode 100644 index 0000000..60330ec --- /dev/null +++ b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs @@ -0,0 +1,115 @@ +using SimplePartLoader.Utils; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader +{ + public class ModInstance + { + private Mod thisMod; + private List loadedParts; + private ModSettings settings; + + public List Parts + { + get { return loadedParts; } + internal set { loadedParts = value; } + } + + public Mod Mod + { + get { return thisMod; } + } + + public ModSettings Settings + { + get { return settings; } + } + + internal ModInstance(Mod mod) + { + thisMod = mod; + loadedParts = new List(); + settings = new ModSettings(this); + } + + public Part Load(AssetBundle bundle, string prefabName) + { + // Safety checks + if (!bundle) + SPL.SplError("Tried to create a part without valid AssetBundle"); + + if (String.IsNullOrWhiteSpace(prefabName)) + SPL.SplError("Tried to create a part without prefab name"); + + if (Saver.modParts.ContainsKey(prefabName)) + SPL.SplError($"Tried to create an already existing prefab ({prefabName})"); + + GameObject prefab = bundle.LoadAsset(prefabName); + if (!prefab) + SPL.SplError($"Tried to create a prefab but it was not found in the AssetBundle ({prefabName})"); + + GameObject.DontDestroyOnLoad(prefab); // We make sure that our prefab is not deleted in the first scene change + + // Now we determinate the type of part we are loading. + // If it has CarProperties and Partinfo is a full part. + // If it has PrefabGenerator ww know is a dummy with prefab gen. + // If nothing applies is a dummy part. + CarProperties prefabCarProp = prefab.GetComponent(); + Partinfo prefabPartInfo = prefab.GetComponent(); + + if(prefabCarProp && prefabPartInfo) + { + // Automatically add some components and also assign the correct layer. + // Pickup and DISABLER for the part - Required so they work properly! + // Also add CarProperties to all nuts of the part, unexpected behaviour can happen if the component is missing. + prefab.layer = LayerMask.NameToLayer("Ignore Raycast"); + + Pickup prefabPickup = prefab.AddComponent(); + prefabPickup.canHold = true; + prefabPickup.tempParent = GameObject.Find("hand"); + prefabPickup.SphereCOl = GameObject.Find("SphereCollider"); + + prefab.AddComponent(); + + prefabCarProp.PREFAB = prefab; // Saving will not work without this due to a condition located in Saver.Save() + Functions.BoltingSetup(prefab); + + // Now we create the part and add it to the list. + Part part = new Part(prefab, prefabCarProp, prefabPartInfo, prefab.GetComponent(), this); + PartManager.modLoadedParts.Add(part); + + Saver.modParts.Add(part.CarProps.PrefabName, prefab); + + Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (full part) {prefabName} from {thisMod.Name}"); + return part; // We provide the Part instance so the developer can setup the transparents + } + + Part p = new Part(prefab, null, null, null, this); + PrefabGenerator prefabGen = prefab.GetComponent(); + if (prefabGen) + { + p.Name = prefabGen.PrefabName; + Saver.modParts.Add(p.Name, prefab); + + PartManager.prefabGenParts.Add(p); + Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (dummy part with Prefab generator) {prefabName} from {thisMod.Name}"); + } + else + { + p.Name = prefabName; + Saver.modParts.Add(prefabName, prefab); + + PartManager.dummyParts.Add(p); + + Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (dummy part) {prefabName} from {thisMod.Name}"); + } + + return p; + } + } +} diff --git a/SimplePartLoader/ModUtils/CarParts/ModSettings.cs b/SimplePartLoader/ModUtils/CarParts/ModSettings.cs new file mode 100644 index 0000000..37fc2bd --- /dev/null +++ b/SimplePartLoader/ModUtils/CarParts/ModSettings.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePartLoader +{ + public class ModSettings + { + private ModInstance modInstance; + private bool DeveloperLog = false; + private bool Immediate = false; + private bool Cloning = true; + + public ModInstance Mod + { + get { return modInstance; } + } + + public bool EnableDeveloperLog + { + get { return DeveloperLog; } + set { DeveloperLog = value; } + } + + public bool EnableImmediateDestroys + { + get { return Immediate; } + set { Immediate = value; } + } + + public bool PreciseCloning + { + get { return Cloning; } + set { Cloning = value; } + } + + internal ModSettings(ModInstance _modInstance) + { + modInstance = _modInstance; + } + } +} diff --git a/SimplePartLoader/ModUtils/ModUtils.cs b/SimplePartLoader/ModUtils/ModUtils.cs index a8501e5..bb2dfa5 100644 --- a/SimplePartLoader/ModUtils/ModUtils.cs +++ b/SimplePartLoader/ModUtils/ModUtils.cs @@ -23,6 +23,8 @@ public class ModUtils public delegate void OnPlayerCarChangeDelegate(); public static event OnPlayerCarChangeDelegate PlayerCarChanged; + internal static List RegisteredMods = new List(); + internal static void OnLoadCalled() { Player = GameObject.Find("Player"); @@ -179,5 +181,22 @@ public static Vector3 ShiftCoords(Vector3 coordsToShift) { return coordsToShift + PlayerTools.saver.transform.root.position; } + + // Car parts update + public static ModInstance RegisterMod(Mod mod) + { + foreach(ModInstance mi in RegisteredMods) + { + if(mod.ID == mi.Mod.ID) + { + Debug.LogError($"[ModUtils/ModRegister/Error]: Tried to register mod {mod.ID} but it is already registered!"); + return null; + } + } + + ModInstance modInstance = new ModInstance(mod); + RegisteredMods.Add(modInstance); + return modInstance; + } } } diff --git a/SimplePartLoader/Objects/Part.cs b/SimplePartLoader/Objects/Part.cs index 8db2535..b626c7c 100644 --- a/SimplePartLoader/Objects/Part.cs +++ b/SimplePartLoader/Objects/Part.cs @@ -23,13 +23,20 @@ public class Part internal bool SavingEnabled; internal bool UseBetterCopy; + + private ModInstance modInstance; + public ModInstance Mod + { + get { return modInstance; } + } - public Part(GameObject prefab, CarProperties carProp, Partinfo partinfo, Renderer renderer) + public Part(GameObject prefab, CarProperties carProp, Partinfo partinfo, Renderer renderer, ModInstance modInstance) { Prefab = prefab; CarProps = carProp; PartInfo = partinfo; Renderer = renderer; + this.modInstance = modInstance; } [Obsolete("SetupTransparent will be removed on the future, use AddTransparent instead!")] diff --git a/SimplePartLoader/SPL.cs b/SimplePartLoader/SPL.cs index 794dd6c..5478f34 100644 --- a/SimplePartLoader/SPL.cs +++ b/SimplePartLoader/SPL.cs @@ -125,7 +125,7 @@ public static Part LoadPart(AssetBundle bundle, string prefabName) wc.gameObject.AddComponent().convex = true; } - Part p = new Part(prefab, prefabCarProp, prefabPartInfo, prefab.GetComponent()); + Part p = new Part(prefab, prefabCarProp, prefabPartInfo, prefab.GetComponent(), null); PartManager.modLoadedParts.Add(p); Saver.modParts.Add(p.CarProps.PrefabName, prefab); @@ -171,7 +171,7 @@ public static Part LoadDummy(AssetBundle bundle, string prefabName, bool betterC if (!prefab) SplError($"Tried to create a prefab but it was not found in the AssetBundle ({prefabName})"); - Part p = new Part(prefab, null, null, null); + Part p = new Part(prefab, null, null, null, null); p.UseBetterCopy = betterCopy; GameObject.DontDestroyOnLoad(prefab); // We make sure that our prefab is not deleted in the first scene change diff --git a/SimplePartLoader/Utils/Functions.cs b/SimplePartLoader/Utils/Functions.cs index 8fd769b..4e8141d 100644 --- a/SimplePartLoader/Utils/Functions.cs +++ b/SimplePartLoader/Utils/Functions.cs @@ -208,5 +208,56 @@ public static void CopyComponentData(Component comp, Component other, bool preci finfo.SetValue(comp, finfo.GetValue(other)); } } + + public static void BoltingSetup(GameObject prefab) + { + foreach (HexNut hx in prefab.GetComponentsInChildren()) + { + hx.gameObject.AddComponent(); + hx.gameObject.AddComponent(); + + hx.gameObject.layer = LayerMask.NameToLayer("Bolts"); + hx.tight = true; + + if (!hx.GetComponent()) + hx.gameObject.AddComponent(); + } + + foreach (BoltNut bn in prefab.GetComponentsInChildren()) + { + bn.gameObject.AddComponent(); + bn.gameObject.AddComponent(); + + bn.gameObject.layer = LayerMask.NameToLayer("Bolts"); + bn.tight = true; + + if (!bn.GetComponent()) + bn.gameObject.AddComponent(); + } + + foreach (FlatNut fn in prefab.GetComponentsInChildren()) + { + fn.gameObject.AddComponent(); + fn.gameObject.AddComponent(); + + fn.gameObject.layer = LayerMask.NameToLayer("FlatBolts"); + fn.tight = true; + + if (!fn.GetComponent()) + fn.gameObject.AddComponent(); + } + + foreach (WeldCut wc in prefab.GetComponentsInChildren()) + { + wc.gameObject.AddComponent(); + wc.gameObject.AddComponent(); + + wc.gameObject.layer = LayerMask.NameToLayer("Weld"); + wc.welded = true; + + if (!wc.GetComponent()) + wc.gameObject.AddComponent().convex = true; + } + } } } From 65f59898965df4bb9a9f8a4e5f1f42d58af66a1a Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 7 Sep 2022 21:57:31 -0300 Subject: [PATCH 03/23] refactor: reworked how prefab generator works internally, fixes #23 --- SimplePartLoader/PartManager.cs | 400 +++++++++++++++++--------------- SimplePartLoader/SPL.cs | 3 + 2 files changed, 218 insertions(+), 185 deletions(-) diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index b0ee7d2..77e1e64 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -70,191 +70,7 @@ internal static void OnLoadCalled() { SPL.DevLog("First load of the game"); // We create our parts from the prefab generator - foreach (Part part in prefabGenParts) - { - PrefabGenerator data = part.Prefab.GetComponent(); - - foreach(Transform t in part.GetTransforms()) - { - if(t.GetComponent()) - { - HexNut hx = t.GetComponent(); - hx.gameObject.AddComponent(); - hx.gameObject.AddComponent(); - - hx.gameObject.layer = LayerMask.NameToLayer("Bolts"); - hx.tight = true; - - hx.gameObject.AddComponent(); - - if (!hx.GetComponent()) - hx.gameObject.AddComponent(); - } - else if (t.GetComponent()) - { - BoltNut bn = t.GetComponent(); - bn.gameObject.AddComponent(); - bn.gameObject.AddComponent(); - - bn.gameObject.layer = LayerMask.NameToLayer("Bolts"); - bn.tight = true; - - bn.gameObject.AddComponent(); - - if (!bn.GetComponent()) - bn.gameObject.AddComponent(); - } - else if(t.GetComponent()) - { - FlatNut fn = t.GetComponent(); - fn.gameObject.AddComponent(); - fn.gameObject.AddComponent(); - - fn.gameObject.layer = LayerMask.NameToLayer("FlatBolts"); - fn.tight = true; - - fn.gameObject.AddComponent(); - - if (!fn.GetComponent()) - fn.gameObject.AddComponent(); - } - else if(t.GetComponent()) - { - WeldCut wc = t.GetComponent(); - wc.gameObject.AddComponent(); - wc.gameObject.AddComponent(); - - wc.gameObject.layer = LayerMask.NameToLayer("Weld"); - wc.welded = true; - - wc.gameObject.AddComponent(); - - if (!wc.GetComponent()) - wc.gameObject.AddComponent().convex = true; - } - } - - SPL.CopyPartToPrefab(part, data.CopiesFrom, data.EnableMeshChange); - - if(!part.CarProps) - { - Debug.LogWarning($"[ModUtils/SPL/Error]: Prefab generator was unable to create {part.Name}"); - continue; - } - - if(!String.IsNullOrWhiteSpace(data.PartName)) - { - part.CarProps.PartName = data.PartName; - part.CarProps.PartNameExtension = ""; - } - - if(data.NewPrice != 0) - { - if (data.NewPrice < 0) - part.PartInfo.price += Math.Abs(data.NewPrice); - else - part.PartInfo.price = data.NewPrice; - } - - part.PartInfo.DontShowInCatalog = !data.EnablePartOnCatalog; - part.PartInfo.DontSpawnInJunyard = !data.EnablePartOnJunkyard; - - // Mesh stuff - if (data.EnableMeshChange) - { - switch(data.UseMaterialsFrom) - { - case PrefabGenerator.MaterialSettingTypes.DummyOriginal: - part.GetComponent().materials = part.GetDummyOriginal().GetComponent().materials; - break; - case PrefabGenerator.MaterialSettingTypes.PaintingSetup: - PaintingSystem.SetMaterialsForObject(part, 2, 0, 1); - part.EnablePartPainting(PaintingSystem.Types.FullPaintingSupport); - break; - } - } - - if(data.EnableChromed) - { - part.CarProps.ChromeMat = PaintingSystem.GetChromeMaterial(); - } - - if (data.CatalogImage) - { - part.PartInfo.Thumbnail = data.CatalogImage; - } - - if(!String.IsNullOrWhiteSpace(data.RenamedPrefab)) - { - part.PartInfo.RenamedPrefab = data.RenamedPrefab; - } - - if(data.SavingFeatureEnabled) - part.EnableDataSaving(); - - switch (data.AttachmentType) - { - case PrefabGenerator.AttachmentTypes.Prytool: - part.UsePrytoolAttachment(); - break; - - case PrefabGenerator.AttachmentTypes.Hand: - part.UseHandAttachment(); - break; - - case PrefabGenerator.AttachmentTypes.UseMarkedBolts: - { - // We first remove all the FlatNut / HexNut / BoltNut on our part. - foreach (HexNut hx in part.Prefab.GetComponentsInChildren()) - { - if (!hx.GetComponent()) - GameObject.Destroy(hx.gameObject); - } - foreach (FlatNut fn in part.Prefab.GetComponentsInChildren()) - { - if (!fn.GetComponent()) - GameObject.Destroy(fn.gameObject); - } - - foreach (BoltNut bn in part.Prefab.GetComponentsInChildren()) - { - if(!bn.GetComponent()) - GameObject.Destroy(bn.gameObject); - } - - // Now we need to convert our MarkAsFlatnut | MarkAsHexnut / MarkAsBoltnut to actual bolts. - foreach (MarkAsHexnut mhx in part.Prefab.GetComponentsInChildren()) - Functions.ConvertToHexnut(mhx.gameObject); - - foreach (MarkAsFlatnut mfn in part.Prefab.GetComponentsInChildren()) - Functions.ConvertToFlatNut(mfn.gameObject); - - foreach (MarkAsBoltnut mbn in part.Prefab.GetComponentsInChildren()) - Functions.ConvertToBoltNut(mbn.gameObject); - - break; - } - } - - foreach(MarkAsTransparent markedTransparent in part.Prefab.GetComponentsInChildren()) - { - TransparentData tempData = new TransparentData(markedTransparent.name, null, Vector3.zero, Quaternion.identity, false); - tempData.MeshToUse = part.GetComponent().sharedMesh; - - GameObject transparentObject = GetTransparentReadyObject(tempData); - - transparentObject.transform.SetParent(markedTransparent.transform.parent); - transparentObject.transform.localPosition = markedTransparent.transform.localPosition; - transparentObject.transform.localRotation = markedTransparent.transform.localRotation; - transparentObject.transform.localScale = markedTransparent.transform.localScale; - - GameObject.Destroy(markedTransparent.gameObject); - } - - Debug.Log($"[ModUtils/SPL]: Loaded {part.Name} (ingame: {part.CarProps.PartName}) through prefab generator"); - GameObject.Destroy(part.Prefab.GetComponent()); - } - + LoadPrefabGeneratorParts(); SPL.DevLog("Finished prefab generator stuff - Now invoking first load"); try @@ -455,5 +271,219 @@ public static GameObject GetTransparentReadyObject(TransparentData t) return transparentObject; } + + internal static void LoadPrefabGeneratorParts() + { + foreach (Part part in prefabGenParts) + { + // We first get the data from our part + PrefabGenerator data = part.Prefab.GetComponent(); + + // We convert all our HexNut / FlatNut / BoltNut / WeldCut to be supported by the game. + // This is to allow developers to use either the "Mark as [..]" components or work directly with the components + foreach (Transform t in part.GetTransforms()) + { + if (t.GetComponent()) + { + HexNut hx = t.GetComponent(); + hx.gameObject.AddComponent(); + hx.gameObject.AddComponent(); + + hx.gameObject.layer = LayerMask.NameToLayer("Bolts"); + hx.tight = true; + + hx.gameObject.AddComponent(); + + if (!hx.GetComponent()) + hx.gameObject.AddComponent(); + } + else if (t.GetComponent()) + { + BoltNut bn = t.GetComponent(); + bn.gameObject.AddComponent(); + bn.gameObject.AddComponent(); + + bn.gameObject.layer = LayerMask.NameToLayer("Bolts"); + bn.tight = true; + + bn.gameObject.AddComponent(); + + if (!bn.GetComponent()) + bn.gameObject.AddComponent(); + } + else if (t.GetComponent()) + { + FlatNut fn = t.GetComponent(); + fn.gameObject.AddComponent(); + fn.gameObject.AddComponent(); + + fn.gameObject.layer = LayerMask.NameToLayer("FlatBolts"); + fn.tight = true; + + fn.gameObject.AddComponent(); + + if (!fn.GetComponent()) + fn.gameObject.AddComponent(); + } + else if (t.GetComponent()) + { + WeldCut wc = t.GetComponent(); + wc.gameObject.AddComponent(); + wc.gameObject.AddComponent(); + + wc.gameObject.layer = LayerMask.NameToLayer("Weld"); + wc.welded = true; + + wc.gameObject.AddComponent(); + + if (!wc.GetComponent()) + wc.gameObject.AddComponent().convex = true; + } + } + + // We clone to our prefab + SPL.CopyPartToPrefab(part, data.CopiesFrom, data.EnableMeshChange); + + if (!part.CarProps) + { + Debug.LogError($"[ModUtils/SPL/Error]: Prefab generator was unable to create {part.Name}"); + continue; + } + + // Setting part name if set + if (!String.IsNullOrWhiteSpace(data.PartName)) + { + part.CarProps.PartName = data.PartName; + part.CarProps.PartNameExtension = ""; + } + + // Setting part price if is valid. Reuses the same if 0. + if (data.NewPrice != 0) + { + if (data.NewPrice < 0) + part.PartInfo.price += Math.Abs(data.NewPrice); + else + part.PartInfo.price = data.NewPrice; + } + + part.PartInfo.DontShowInCatalog = !data.EnablePartOnCatalog; + part.PartInfo.DontSpawnInJunyard = !data.EnablePartOnJunkyard; + + // Mesh stuff + if (data.EnableMeshChange) + { + switch (data.UseMaterialsFrom) + { + case PrefabGenerator.MaterialSettingTypes.DummyOriginal: + part.GetComponent().materials = part.GetDummyOriginal().GetComponent().materials; + break; + case PrefabGenerator.MaterialSettingTypes.PaintingSetup: + PaintingSystem.SetMaterialsForObject(part, 2, 0, 1); + part.EnablePartPainting(PaintingSystem.Types.FullPaintingSupport); + break; + } + } + + // To enable chroming on our part + if (data.EnableChromed) + { + part.CarProps.ChromeMat = PaintingSystem.GetChromeMaterial(); + } + + if (data.CatalogImage) + { + part.PartInfo.Thumbnail = data.CatalogImage; + } + + if (!String.IsNullOrWhiteSpace(data.RenamedPrefab)) + { + part.PartInfo.RenamedPrefab = data.RenamedPrefab; + } + + if (data.SavingFeatureEnabled) + part.EnableDataSaving(); + + switch (data.AttachmentType) + { + case PrefabGenerator.AttachmentTypes.Prytool: + part.UsePrytoolAttachment(); + break; + + case PrefabGenerator.AttachmentTypes.Hand: + part.UseHandAttachment(); + break; + + case PrefabGenerator.AttachmentTypes.UseMarkedBolts: + { + // We first remove all the FlatNut / HexNut / BoltNut on our part. + foreach (HexNut hx in part.Prefab.GetComponentsInChildren()) + { + if (!hx.GetComponent()) + DestroyConsideringSetting(part, hx.gameObject); + } + foreach (FlatNut fn in part.Prefab.GetComponentsInChildren()) + { + if (!fn.GetComponent()) + DestroyConsideringSetting(part, fn.gameObject); + } + + foreach (BoltNut bn in part.Prefab.GetComponentsInChildren()) + { + if (!bn.GetComponent()) + DestroyConsideringSetting(part, bn.gameObject); + } + + foreach (WeldCut wc in part.Prefab.GetComponentsInChildren()) + { + if (!wc.GetComponent()) + DestroyConsideringSetting(part, wc.gameObject); + } + + // Now we need to convert our MarkAsFlatnut | MarkAsHexnut / MarkAsBoltnut to actual bolts. + foreach (MarkAsHexnut mhx in part.Prefab.GetComponentsInChildren()) + Functions.ConvertToHexnut(mhx.gameObject); + + foreach (MarkAsFlatnut mfn in part.Prefab.GetComponentsInChildren()) + Functions.ConvertToFlatNut(mfn.gameObject); + + foreach (MarkAsBoltnut mbn in part.Prefab.GetComponentsInChildren()) + Functions.ConvertToBoltNut(mbn.gameObject); + + break; + } + } + + foreach (MarkAsTransparent markedTransparent in part.Prefab.GetComponentsInChildren()) + { + TransparentData tempData = new TransparentData(markedTransparent.name, null, Vector3.zero, Quaternion.identity, false); + tempData.MeshToUse = part.GetComponent().sharedMesh; + + GameObject transparentObject = GetTransparentReadyObject(tempData); + + transparentObject.transform.SetParent(markedTransparent.transform.parent); + transparentObject.transform.localPosition = markedTransparent.transform.localPosition; + transparentObject.transform.localRotation = markedTransparent.transform.localRotation; + transparentObject.transform.localScale = markedTransparent.transform.localScale; + + GameObject.Destroy(markedTransparent.gameObject); + } + + Debug.Log($"[ModUtils/SPL]: Loaded {part.Name} (ingame: {part.CarProps.PartName}) through prefab generator"); + GameObject.Destroy(part.Prefab.GetComponent()); + } + } + + public static void DestroyConsideringSetting(Part p, GameObject toDestroy) + { + if (p.Mod != null) + { + if (p.Mod.Settings.EnableImmediateDestroys) + GameObject.DestroyImmediate(toDestroy); + else + GameObject.Destroy(toDestroy); + } + else + GameObject.Destroy(toDestroy); + } } } diff --git a/SimplePartLoader/SPL.cs b/SimplePartLoader/SPL.cs index 5478f34..6924940 100644 --- a/SimplePartLoader/SPL.cs +++ b/SimplePartLoader/SPL.cs @@ -41,6 +41,7 @@ public enum PaintingSupportedTypes /// The name of the prefab to be loaded /// An exception will be thrown if the bundle or prefabName are invalid, if the prefab already exists or if essential components are missing /// + [Obsolete("This method is deprecated, use ModInstance.Load instead")] public static Part LoadPart(AssetBundle bundle, string prefabName) { // Safety checks @@ -142,6 +143,7 @@ public static Part LoadPart(AssetBundle bundle, string prefabName) /// The name of the prefab to be loaded /// An exception will be thrown if the bundle or prefabName are invalid or if the prefab already exists /// The Part instance + [Obsolete("This method is deprecated, use ModInstance.Load instead")] public static Part LoadDummy(AssetBundle bundle, string prefabName) { return LoadDummy(bundle, prefabName, false); @@ -155,6 +157,7 @@ public static Part LoadDummy(AssetBundle bundle, string prefabName) /// Enables a more precise cloning method /// An exception will be thrown if the bundle or prefabName are invalid or if the prefab already exists /// The Part instance + [Obsolete("This method is deprecated, use ModInstance.Load instead")] public static Part LoadDummy(AssetBundle bundle, string prefabName, bool betterCopy = true) { // Safety checks From ee97d2cf79223f82f6378d1a4419c0ffe8c233b4 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 7 Sep 2022 22:09:46 -0300 Subject: [PATCH 04/23] fix: fixed #24 --- SimplePartLoader/ModUtils/PaintingSystem.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index e520659..bd64134 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -511,16 +511,31 @@ public static void SetMaterialsForObject(Part p, int bodymatIndex = -1, int pain if (bodymatIndex != -1) { + if (matsOfPart.Length <= bodymatIndex) + { + Debug.LogError($"[ModUtils/PaintingSystem/Error]: SetMaterialsForObject tried to setup bodymat index {bodymatIndex} on part {p.Prefab.name} but it only has {matsOfPart.Length} materials."); + return; + } matsOfPart[bodymatIndex] = GetBodymatMaterial(); } if (paintRustIndex != -1) { + if (matsOfPart.Length <= paintRustIndex) + { + Debug.LogError($"[ModUtils/PaintingSystem/Error]: SetMaterialsForObject tried to setup paint/rust index {paintRustIndex} on part {p.Prefab.name} but it only has {matsOfPart.Length} materials."); + return; + } matsOfPart[paintRustIndex] = GetPaintRustMaterial(); } if (dirtIndex != -1) { + if (matsOfPart.Length <= dirtIndex) + { + Debug.LogError($"[ModUtils/PaintingSystem/Error]: SetMaterialsForObject tried to setup dirt index {dirtIndex} on part {p.Prefab.name} but it only has {matsOfPart.Length} materials."); + return; + } matsOfPart[dirtIndex] = GetDirtMaterial(); } From b8feae5dc149cad581fb27f35e5a7d0b6359527e Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 7 Sep 2022 22:10:30 -0300 Subject: [PATCH 05/23] fix: fixed #17 --- SimplePartLoader/Objects/Part.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimplePartLoader/Objects/Part.cs b/SimplePartLoader/Objects/Part.cs index b626c7c..367c4bd 100644 --- a/SimplePartLoader/Objects/Part.cs +++ b/SimplePartLoader/Objects/Part.cs @@ -106,7 +106,7 @@ public void UsePrytoolAttachment() Prefab.AddComponent(); Prefab.layer = LayerMask.NameToLayer("Windows"); - Prefab.tag = "Window"; + //Prefab.tag = "Window"; } } @@ -132,7 +132,7 @@ public void UseHandAttachment() Prefab.AddComponent(); Prefab.layer = LayerMask.NameToLayer("Windows"); - //Prefab.tag = "Window"; + Prefab.tag = "Window"; } } From 21df840abf3aec05a0df5ef248d9a946a8328007 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 7 Sep 2022 22:40:27 -0300 Subject: [PATCH 06/23] fix: immediate destroy setting not counting MarkAsTransparent. Added owner to transparent data --- .../ModUtils/CarParts/ModInstance.cs | 19 +++++++++++++-- SimplePartLoader/Objects/Part.cs | 22 +++++++++++++++-- SimplePartLoader/Objects/TransparentData.cs | 7 ++++++ SimplePartLoader/PartManager.cs | 24 +++++++++++++++---- SimplePartLoader/SPL.cs | 13 +++++++++- 5 files changed, 75 insertions(+), 10 deletions(-) diff --git a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs index 60330ec..ab10b98 100644 --- a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs +++ b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs @@ -30,11 +30,18 @@ public ModSettings Settings get { return settings; } } + public string Name + { + get { return Mod.Name; } + } + internal ModInstance(Mod mod) { thisMod = mod; loadedParts = new List(); settings = new ModSettings(this); + + Debug.Log($"[ModUtils/RegisteredMods]: Succesfully registered " + mod.Name); } public Part Load(AssetBundle bundle, string prefabName) @@ -82,7 +89,10 @@ public Part Load(AssetBundle bundle, string prefabName) // Now we create the part and add it to the list. Part part = new Part(prefab, prefabCarProp, prefabPartInfo, prefab.GetComponent(), this); PartManager.modLoadedParts.Add(part); - + loadedParts.Add(part); + + part.PartType = PartTypes.FULL_PART; + Saver.modParts.Add(part.CarProps.PrefabName, prefab); Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (full part) {prefabName} from {thisMod.Name}"); @@ -97,15 +107,20 @@ public Part Load(AssetBundle bundle, string prefabName) Saver.modParts.Add(p.Name, prefab); PartManager.prefabGenParts.Add(p); + loadedParts.Add(p); + + p.PartType = PartTypes.DUMMY_PREFABGEN; Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (dummy part with Prefab generator) {prefabName} from {thisMod.Name}"); } else { p.Name = prefabName; Saver.modParts.Add(prefabName, prefab); - + PartManager.dummyParts.Add(p); + loadedParts.Add(p); + p.PartType = PartTypes.DUMMY; Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (dummy part) {prefabName} from {thisMod.Name}"); } diff --git a/SimplePartLoader/Objects/Part.cs b/SimplePartLoader/Objects/Part.cs index 367c4bd..ade551c 100644 --- a/SimplePartLoader/Objects/Part.cs +++ b/SimplePartLoader/Objects/Part.cs @@ -24,12 +24,20 @@ public class Part internal bool SavingEnabled; internal bool UseBetterCopy; + private PartTypes Type; private ModInstance modInstance; + public ModInstance Mod { get { return modInstance; } } + public PartTypes PartType + { + get { return Type; } + internal set { Type = value; } + } + public Part(GameObject prefab, CarProperties carProp, Partinfo partinfo, Renderer renderer, ModInstance modInstance) { Prefab = prefab; @@ -48,7 +56,8 @@ public void SetupTransparent(string attachesTo, Vector3 transparentLocalPos, Qua { td.MeshToUse = mf.mesh; } - + + td.Owner = this; PartManager.transparentData.Add(td); } @@ -61,7 +70,8 @@ public void SetupTransparent(string attachesTo, Vector3 transparentLocalPos, Qua { td.MeshToUse = mf.mesh; } - + + td.Owner = this; PartManager.transparentData.Add(td); } @@ -84,6 +94,7 @@ public TransparentData AddTransparent(string attachesTo, Vector3 transparentLoca td.MeshToUse = mf.mesh; } + td.Owner = this; PartManager.transparentData.Add(td); return td; } @@ -205,4 +216,11 @@ private void RemoveAttachmentsFromPart() GameObject.Destroy(Prefab.GetComponent()); } } + + public enum PartTypes + { + FULL_PART = 1, + DUMMY_PREFABGEN, + DUMMY + } } diff --git a/SimplePartLoader/Objects/TransparentData.cs b/SimplePartLoader/Objects/TransparentData.cs index 5f8d951..7c7e944 100644 --- a/SimplePartLoader/Objects/TransparentData.cs +++ b/SimplePartLoader/Objects/TransparentData.cs @@ -15,6 +15,13 @@ public class TransparentData public transparents.dependantObjects[] DependantObjects; public int SavePosition; public Mesh MeshToUse; + + private Part createdBy; + public Part Owner + { + get { return createdBy; } + internal set { createdBy = value; } + } public TransparentData(string name, string attachesTo, Vector3 localPos, Quaternion localRot, bool testingModeEnable) { diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index 77e1e64..8864fc5 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -240,8 +240,8 @@ public static GameObject GetTransparentReadyObject(TransparentData t) { GameObject transparentObject = GameObject.CreatePrimitive(PrimitiveType.Cube); - GameObject.Destroy(transparentObject.GetComponent()); - GameObject.Destroy(transparentObject.GetComponent()); + DestroyConsideringSetting(t.Owner, transparentObject.GetComponent()); + DestroyConsideringSetting(t.Owner, transparentObject.GetComponent()); transparentObject.name = t.Name; // Renamed prefab is the one that the game uses for looking for transparent. Prefab name in car props is used for identify which prefab has to be loaded. @@ -457,15 +457,16 @@ internal static void LoadPrefabGeneratorParts() { TransparentData tempData = new TransparentData(markedTransparent.name, null, Vector3.zero, Quaternion.identity, false); tempData.MeshToUse = part.GetComponent().sharedMesh; - + tempData.Owner = part; + GameObject transparentObject = GetTransparentReadyObject(tempData); transparentObject.transform.SetParent(markedTransparent.transform.parent); transparentObject.transform.localPosition = markedTransparent.transform.localPosition; transparentObject.transform.localRotation = markedTransparent.transform.localRotation; transparentObject.transform.localScale = markedTransparent.transform.localScale; - - GameObject.Destroy(markedTransparent.gameObject); + + DestroyConsideringSetting(part, markedTransparent.gameObject); } Debug.Log($"[ModUtils/SPL]: Loaded {part.Name} (ingame: {part.CarProps.PartName}) through prefab generator"); @@ -485,5 +486,18 @@ public static void DestroyConsideringSetting(Part p, GameObject toDestroy) else GameObject.Destroy(toDestroy); } + + public static void DestroyConsideringSetting(Part p, Component toDestroy) + { + if (p.Mod != null) + { + if (p.Mod.Settings.EnableImmediateDestroys) + GameObject.DestroyImmediate(toDestroy); + else + GameObject.Destroy(toDestroy); + } + else + GameObject.Destroy(toDestroy); + } } } diff --git a/SimplePartLoader/SPL.cs b/SimplePartLoader/SPL.cs index 6924940..75fda8b 100644 --- a/SimplePartLoader/SPL.cs +++ b/SimplePartLoader/SPL.cs @@ -249,7 +249,7 @@ public static void CopyPartToPrefab(Part p, string partName, bool ignoreBuiltin p.Prefab.AddComponent(comp.GetType()).GetCopyOf(comp, p.UseBetterCopy); - DevLog($"Now copying component to base object ({comp})"); + DevLog(p, $"Now copying component to base object ({comp})"); } } @@ -451,6 +451,17 @@ internal static void DevLog(string str) Debug.Log("[ModUtils/Dev/SPL]: " + str); } + internal static void DevLog(Part p, string str) + { + if(p.Mod != null) + { + if(p.Mod.Settings.EnableDeveloperLog) + { + Debug.Log($"[ModUtils/Dev/SPL]: {str} (part: part_{p.Prefab.name}, mod: {p.Mod.Name})"); + } + } + } + /// /// Shows an error on log, then generates an exception /// From f4b52600eb83afe8c23156fdd6480ada756733c5 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Sun, 11 Sep 2022 01:59:57 -0300 Subject: [PATCH 07/23] feat: CommonFixes library added for common issues that happen on dummy parts --- SimplePartLoader/ModMain.cs | 2 +- SimplePartLoader/ModUtils.csproj | 2 + SimplePartLoader/ModUtils/ModUtils.cs | 4 + SimplePartLoader/Objects/LightFix.cs | 41 +++++ SimplePartLoader/Utils/CommonFixes.cs | 227 ++++++++++++++++++++++++++ 5 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 SimplePartLoader/Objects/LightFix.cs create mode 100644 SimplePartLoader/Utils/CommonFixes.cs diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index b9c8738..aacf8e8 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -18,7 +18,7 @@ public class ModMain : Mod public override string ID => "ModUtils"; public override string Name => "ModUtils"; public override string Author => "Federico Arredondo"; - public override string Version => "v1.0.0"; bool TESTING_VERSION_REMEMBER = true; + public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index 81fe17c..aea8fd5 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -440,6 +440,8 @@ + + diff --git a/SimplePartLoader/ModUtils/ModUtils.cs b/SimplePartLoader/ModUtils/ModUtils.cs index bb2dfa5..f95f414 100644 --- a/SimplePartLoader/ModUtils/ModUtils.cs +++ b/SimplePartLoader/ModUtils/ModUtils.cs @@ -24,6 +24,10 @@ public class ModUtils public static event OnPlayerCarChangeDelegate PlayerCarChanged; internal static List RegisteredMods = new List(); + public static List ModInstances + { + get { return RegisteredMods; } + } internal static void OnLoadCalled() { diff --git a/SimplePartLoader/Objects/LightFix.cs b/SimplePartLoader/Objects/LightFix.cs new file mode 100644 index 0000000..ef0aa1b --- /dev/null +++ b/SimplePartLoader/Objects/LightFix.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader.Objects +{ + internal class LightFix : MonoBehaviour + { + void Start() + { + CarLight cl = gameObject.GetComponent(); + if (!cl) + return; + + cl.LightRend = cl.transform.parent.GetComponent(); + + if (cl.High) + { + Transform t = cl.transform.parent.Find("High Beam"); + if (t) + { + cl.High = t.GetComponent(); + } + } + + if (cl.Low) + { + Transform t = cl.transform.parent.Find("Low Beam"); + if (t) + { + cl.Low = t.GetComponent(); + } + } + + GameObject.Destroy(this); + } + } +} diff --git a/SimplePartLoader/Utils/CommonFixes.cs b/SimplePartLoader/Utils/CommonFixes.cs new file mode 100644 index 0000000..02c6f42 --- /dev/null +++ b/SimplePartLoader/Utils/CommonFixes.cs @@ -0,0 +1,227 @@ +using SimplePartLoader.Objects; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader +{ + public class CommonFixes + { + public static void FixPart(Part p, FixType type) + { + if(p == null) + { + Debug.LogError("[ModUtils/CommonFixes]: Invalid part was passed on"); + return; + } + + FixPart(p.Prefab, type, p.Mod.Settings.EnableDeveloperLog); + } + + public static void FixPart(GameObject prefab, FixType type, bool printData = true) + { + if (!prefab) + { + Debug.LogError("[ModUtils/CommonFixes]: Invalid part was passed on"); + return; + } + + try + { + switch (type) + { + case FixType.CarLights: + CarLightsFix(prefab, printData); + break; + + case FixType.DriverPassangerSeat: + SeatFix(prefab, printData); + break; + + case FixType.Oilpan: + OilpanFix(prefab, printData); + break; + + case FixType.Radiator: + RadiatorFix(prefab, printData); + break; + + case FixType.CylinderHeadCover: + CylinderHeadCoverFix(prefab, printData); + break; + + case FixType.BrakeCylinder: + BrakeCylinderFix(prefab, printData); + break; + + case FixType.Windows: + Windows(prefab, printData); + break; + + case FixType.Dipstick: + DipstickFix(prefab, printData); + break; + + case FixType.FuelTank: + FuelTankFix(prefab, printData); + break; + } + } + catch(Exception ex) + { + Debug.LogError("[ModUtils/CommonFixes/Error]: A fatal error occured while applying a CommonFix"); + Debug.LogError("[ModUtils/CommonFixes/Error]: Part name: " + prefab.name); + Debug.LogError("[ModUtils/CommonFixes/Error]: Fix: " + type); + Debug.LogError("[ModUtils/CommonFixes/Error]: Exception: " + ex.Message); + Debug.LogError("[ModUtils/CommonFixes/Error]: StackTrace: " + ex.StackTrace); + } + + } + + // 1 function per FixType + internal static void CarLightsFix(GameObject prefab, bool printData) + { + foreach (CarLight cl in prefab.GetComponentsInChildren()) + { + cl.gameObject.AddComponent(); + if (printData) + Debug.Log($"[ModUtils/CommonFix/Light]: Adding light fix to {prefab} ({cl.gameObject.name})"); + } + } + + internal static void RadiatorFix(GameObject prefab, bool printData) + { + if(printData) + Debug.Log($"[ModUtils/CommonFix/Radiator]: Applying radiator fix to {prefab}"); + + Transform CoolantContainer = prefab.transform.Find("CoolantFluidContainer"); + Transform CoolantFluidLevel = prefab.transform.Find("VisualFLuid"); + Transform CoolantCupTransform = prefab.transform.Find("CoolantFluidReservuarCUP/CoolantFluidReservuarCUP"); + FLUID CoolantFluid = CoolantContainer.GetComponent(); + PickupCup CoolantCup = CoolantCupTransform.GetComponent(); + + CoolantFluid.Container = CoolantFluid; + CoolantFluid.VisualFluid = CoolantFluidLevel.gameObject; + CoolantCup.Fluid = CoolantContainer.gameObject; + } + + internal static void FuelTankFix(GameObject prefab, bool printData) + { + if(printData) + Debug.Log($"[ModUtils/CommonFix/FuelTank]: Applying fuel tank fix to {prefab}"); + + Transform FuelTankContainer = prefab.transform.Find("FuelContainer"); + Transform FuelTankCup = prefab.transform.Find("FuelReservuarCUP/FuelReservuarCUP"); + FLUID FuelTankComponent = FuelTankContainer.GetComponent(); + PickupCup FuelTankCupComponent = FuelTankCup.GetComponent(); + + FuelTankComponent.Container = FuelTankComponent; + FuelTankCupComponent.Fluid = FuelTankContainer.gameObject; + } + + internal static void BrakeCylinderFix(GameObject prefab, bool printData) + { + if (printData) + Debug.Log($"[ModUtils/CommonFix/BrakeCylinder]: Applying brake cylinder fix to {prefab}"); + + Transform BrakeFluidContainer = prefab.transform.Find("BrakeFluidContainer"); + Transform BrakeFluidVisual = prefab.transform.Find("VisualFluid"); + Transform BrakeFluidCup = prefab.transform.Find("BrakeFluidReservuarCUP/BrakeFluidReservuarCUP"); + PickupCup BrakeCupComponent = BrakeFluidCup.GetComponent(); + FLUID BrakeFluidComponent = BrakeFluidContainer.GetComponent(); + + BrakeFluidComponent.Container = BrakeFluidComponent; + BrakeFluidComponent.VisualFluid = BrakeFluidVisual.gameObject; + BrakeCupComponent.Fluid = BrakeFluidComponent.gameObject; + } + + internal static void DipstickFix(GameObject prefab, bool printData) + { + if (printData) + Debug.Log($"[ModUtils/CommonFix/Dipstick]: Applying dipstick fix to {prefab}"); + + Transform Dipstick = prefab.transform.Find("Dipstick/Dipstick"); + if(!Dipstick) + { + Debug.LogError("[ModUtils/CommonFix/Dipstick]: Dipstick not found. Make sure to be passing the cylinder block as parameter!"); + return; + } + + Transform DipstickLevel = Dipstick.GetChild(0); + Dipstick.GetComponent().DipstickOil = DipstickLevel.gameObject; + } + + internal static void CylinderHeadCoverFix(GameObject prefab, bool printData) + { + if (printData) + Debug.Log($"[ModUtils/CommonFix/CylinderHeadCover]: Applying cylinder head cover fix to {prefab}"); + + Transform CylinderHeadContainer = prefab.transform.Find("OilFluidContainerHead"); + Transform CylinderHeadCup = prefab.transform.Find("OilReservuarCUP/OilReservuarCUP"); + FLUID OilCylinderHeadComponent = CylinderHeadContainer.GetComponent(); + PickupCup OilCupCylinderHead = CylinderHeadCup.GetComponent(); + + OilCylinderHeadComponent.Container = OilCylinderHeadComponent; + OilCupCylinderHead.Fluid = CylinderHeadContainer.gameObject; + } + + internal static void OilpanFix(GameObject prefab, bool printData) + { + if (printData) + Debug.Log($"[ModUtils/CommonFix/Oilpan]: Applying oilpan fix to {prefab}"); + + Transform OilpanContainer = prefab.transform.Find("OilFluidContainer"); + Transform OilpanCup = prefab.transform.Find("OilReservuarSCREW/OilReservuarSCREW"); + FLUID OilpanComponent = OilpanContainer.GetComponent(); + PickupCup OilpanCupComponent = OilpanCup.GetComponent(); + + OilpanComponent.Container = OilpanComponent; + OilpanCupComponent.Fluid = OilpanContainer.gameObject; + } + + internal static void SeatFix(GameObject prefab, bool printData) + { + if (printData) + Debug.Log($"[ModUtils/CommonFix/Seat]: Applying seat fix to {prefab}"); + + Transform Seat = prefab.transform.Find("SitDrive"); + Seat.GetComponent().seat = prefab; + } + + internal static void Windows(GameObject prefab, bool printData) + { + if (printData) + Debug.Log($"[ModUtils/CommonFix/Windows]: Applying windows fix to {prefab}"); + + foreach (RVP.ShatterPart shatterComp in prefab.GetComponentsInChildren()) + { + Transform t = shatterComp.transform.Find("ShatterParticles"); + if (t) + { + shatterComp.shatterParticles = t.GetComponent(); + Debug.Log("[ModUtils/CommonFix/Windows]: RVP.ShatterPart (windows) fix applied to " + shatterComp.name); + } + else + { + Debug.Log("[ModUtils/CommonFix/Windows]: RVP.ShatterPart (windows) fix could not be applied to " + shatterComp.name); + } + } + } + } + + public enum FixType + { + CarLights = 1, + Radiator, + FuelTank, + BrakeCylinder, + Dipstick, + CylinderHeadCover, + Oilpan, + DriverPassangerSeat, + Windows + } +} From 421ffc5aa31521beb85c4b524d3c85f6e1c6e82a Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Sun, 11 Sep 2022 03:13:36 -0300 Subject: [PATCH 08/23] fix: some stuff not considering immediate destroy setting, also #27 --- SimplePartLoader/ModMain.cs | 8 +++- .../ModUtils/CarParts/ModInstance.cs | 3 +- SimplePartLoader/Objects/LightFix.cs | 5 +- SimplePartLoader/Objects/Part.cs | 46 +++++++++++++++---- SimplePartLoader/PartManager.cs | 20 ++++++-- SimplePartLoader/Utils/Functions.cs | 36 ++++++++++++--- 6 files changed, 95 insertions(+), 23 deletions(-) diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index aacf8e8..194188b 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -18,7 +18,11 @@ public class ModMain : Mod public override string ID => "ModUtils"; public override string Name => "ModUtils"; public override string Author => "Federico Arredondo"; - public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; + public override string Version => "v1.1.0"; + + bool TESTING_VERSION_REMEMBER = true; + string TESTING_VERSION_NUMBER = "1.2-beta2"; + public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; @@ -46,7 +50,7 @@ public ModMain() Debug.Log("ModUtils is loading - Version: " + Version); Debug.Log("Developed by Federico Arredondo - www.github.com/FedeArre"); if(TESTING_VERSION_REMEMBER) - Debug.Log("This is a testing version - remember to report bugs and send feedback"); + Debug.Log($"This is a testing version ({TESTING_VERSION_NUMBER}) - remember to report bugs and send feedback"); // Mod delete string ModsFolderPath = Application.dataPath + "/../Mods/"; diff --git a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs index ab10b98..0610551 100644 --- a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs +++ b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs @@ -61,7 +61,8 @@ public Part Load(AssetBundle bundle, string prefabName) SPL.SplError($"Tried to create a prefab but it was not found in the AssetBundle ({prefabName})"); GameObject.DontDestroyOnLoad(prefab); // We make sure that our prefab is not deleted in the first scene change - + prefab.transform.localScale = Vector3.one; // We set the scale to 1,1,1 to prevent any weird scaling issues + // Now we determinate the type of part we are loading. // If it has CarProperties and Partinfo is a full part. // If it has PrefabGenerator ww know is a dummy with prefab gen. diff --git a/SimplePartLoader/Objects/LightFix.cs b/SimplePartLoader/Objects/LightFix.cs index ef0aa1b..6fd5c0b 100644 --- a/SimplePartLoader/Objects/LightFix.cs +++ b/SimplePartLoader/Objects/LightFix.cs @@ -15,7 +15,10 @@ void Start() if (!cl) return; - cl.LightRend = cl.transform.parent.GetComponent(); + if(!cl.transform.parent || cl.transform.parent.GetComponent()) + cl.LightRend = cl.transform.GetComponent(); + else + cl.LightRend = cl.transform.parent.GetComponent(); if (cl.High) { diff --git a/SimplePartLoader/Objects/Part.cs b/SimplePartLoader/Objects/Part.cs index ade551c..41fa814 100644 --- a/SimplePartLoader/Objects/Part.cs +++ b/SimplePartLoader/Objects/Part.cs @@ -107,7 +107,7 @@ public void Localize(string language, string newTranslation) public void UsePrytoolAttachment() { if(Prefab.GetComponent()) - GameObject.Destroy(Prefab.GetComponent()); + DestroyConsiderSetting(Prefab.GetComponent()); if (!Prefab.GetComponent()) { @@ -133,7 +133,7 @@ public void EnableDataSaving() public void UseHandAttachment() { if (Prefab.GetComponent()) - GameObject.Destroy(Prefab.GetComponent()); + DestroyConsiderSetting(Prefab.GetComponent()); if (!Prefab.GetComponent()) { @@ -193,30 +193,60 @@ private void RemoveAttachmentsFromPart() { foreach (WeldCut wc in Prefab.GetComponentsInChildren()) { - GameObject.Destroy(wc.gameObject); + DestroyConsiderSetting(wc.gameObject); } foreach (BoltNut bn in Prefab.GetComponentsInChildren()) { - GameObject.Destroy(bn.gameObject); + DestroyConsiderSetting(bn.gameObject); } foreach (HexNut hn in Prefab.GetComponentsInChildren()) { - GameObject.Destroy(hn.gameObject); + DestroyConsiderSetting(hn.gameObject); } if (Prefab.GetComponent()) - GameObject.Destroy(Prefab.GetComponent()); + DestroyConsiderSetting(Prefab.GetComponent()); if(Prefab.GetComponent()) - GameObject.Destroy(Prefab.GetComponent()); + DestroyConsiderSetting(Prefab.GetComponent()); if(Prefab.GetComponent()) - GameObject.Destroy(Prefab.GetComponent()); + DestroyConsiderSetting(Prefab.GetComponent()); + } + + private void DestroyConsiderSetting(Component c) + { + if (modInstance != null) + { + if (modInstance.Settings.EnableImmediateDestroys) + GameObject.DestroyImmediate(c); + else + GameObject.Destroy(c); + } + else + { + GameObject.Destroy(c); + } + } + private void DestroyConsiderSetting(GameObject c) + { + if (modInstance != null) + { + if (modInstance.Settings.EnableImmediateDestroys) + GameObject.DestroyImmediate(c); + else + GameObject.Destroy(c); + } + else + { + GameObject.Destroy(c); + } } } + public enum PartTypes { FULL_PART = 1, diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index 8864fc5..c09ccc3 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -286,7 +286,10 @@ internal static void LoadPrefabGeneratorParts() if (t.GetComponent()) { HexNut hx = t.GetComponent(); - hx.gameObject.AddComponent(); + CarProperties cp = hx.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + hx.gameObject.AddComponent(); hx.gameObject.layer = LayerMask.NameToLayer("Bolts"); @@ -300,7 +303,10 @@ internal static void LoadPrefabGeneratorParts() else if (t.GetComponent()) { BoltNut bn = t.GetComponent(); - bn.gameObject.AddComponent(); + CarProperties cp = bn.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + bn.gameObject.AddComponent(); bn.gameObject.layer = LayerMask.NameToLayer("Bolts"); @@ -314,7 +320,10 @@ internal static void LoadPrefabGeneratorParts() else if (t.GetComponent()) { FlatNut fn = t.GetComponent(); - fn.gameObject.AddComponent(); + CarProperties cp = fn.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + fn.gameObject.AddComponent(); fn.gameObject.layer = LayerMask.NameToLayer("FlatBolts"); @@ -328,7 +337,10 @@ internal static void LoadPrefabGeneratorParts() else if (t.GetComponent()) { WeldCut wc = t.GetComponent(); - wc.gameObject.AddComponent(); + CarProperties cp = wc.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + wc.gameObject.AddComponent(); wc.gameObject.layer = LayerMask.NameToLayer("Weld"); diff --git a/SimplePartLoader/Utils/Functions.cs b/SimplePartLoader/Utils/Functions.cs index 4e8141d..036d904 100644 --- a/SimplePartLoader/Utils/Functions.cs +++ b/SimplePartLoader/Utils/Functions.cs @@ -36,8 +36,12 @@ public static GameObject GetCarPart(string partName) /// The GameObject to be converted public static void ConvertToHexnut(GameObject bolt) { - bolt.AddComponent(); + CarProperties cp = bolt.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + bolt.AddComponent(); + HexNut hx = bolt.AddComponent(); MarkAsHexnut mhx = bolt.GetComponent(); bolt.layer = LayerMask.NameToLayer("Bolts"); @@ -57,7 +61,10 @@ public static void ConvertToHexnut(GameObject bolt) /// The GameObject to be converted public static void ConvertToFlatNut(GameObject bolt) { - bolt.AddComponent(); + CarProperties cp = bolt.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + bolt.AddComponent(); bolt.AddComponent().tight = true; @@ -75,7 +82,10 @@ public static void ConvertToFlatNut(GameObject bolt) /// The GameObject to be converted public static void ConvertToBoltNut(GameObject bolt) { - bolt.AddComponent(); + CarProperties cp = bolt.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + bolt.AddComponent(); BoltNut bn = bolt.AddComponent(); MarkAsBoltnut mbn = bolt.GetComponent(); @@ -213,7 +223,10 @@ public static void BoltingSetup(GameObject prefab) { foreach (HexNut hx in prefab.GetComponentsInChildren()) { - hx.gameObject.AddComponent(); + CarProperties cp = hx.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + hx.gameObject.AddComponent(); hx.gameObject.layer = LayerMask.NameToLayer("Bolts"); @@ -225,7 +238,10 @@ public static void BoltingSetup(GameObject prefab) foreach (BoltNut bn in prefab.GetComponentsInChildren()) { - bn.gameObject.AddComponent(); + CarProperties cp = bn.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + bn.gameObject.AddComponent(); bn.gameObject.layer = LayerMask.NameToLayer("Bolts"); @@ -237,7 +253,10 @@ public static void BoltingSetup(GameObject prefab) foreach (FlatNut fn in prefab.GetComponentsInChildren()) { - fn.gameObject.AddComponent(); + CarProperties cp = fn.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + fn.gameObject.AddComponent(); fn.gameObject.layer = LayerMask.NameToLayer("FlatBolts"); @@ -249,7 +268,10 @@ public static void BoltingSetup(GameObject prefab) foreach (WeldCut wc in prefab.GetComponentsInChildren()) { - wc.gameObject.AddComponent(); + CarProperties cp = wc.gameObject.AddComponent(); + cp.Attached = true; + cp.DMGdisplacepart = true; + wc.gameObject.AddComponent(); wc.gameObject.layer = LayerMask.NameToLayer("Weld"); From 9cbe1ebdcd21218852708c02599fcaddb93b231a Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Tue, 13 Sep 2022 20:00:24 -0300 Subject: [PATCH 09/23] feat: some bug fixes, FitsToCar as option --- SimplePartLoader/ModMain.cs | 2 +- .../ModUtils/CarParts/ModInstance.cs | 5 +++++ .../ModUtils/CarParts/ModSettings.cs | 7 +++++++ SimplePartLoader/PartManager.cs | 11 ++++++++++- SimplePartLoader/SPL.cs | 19 ++++++++++++++++--- 5 files changed, 39 insertions(+), 5 deletions(-) diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index 194188b..531a940 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -21,7 +21,7 @@ public class ModMain : Mod public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; - string TESTING_VERSION_NUMBER = "1.2-beta2"; + string TESTING_VERSION_NUMBER = "1.2-beta3"; public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; diff --git a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs index 0610551..5f4ed27 100644 --- a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs +++ b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs @@ -96,6 +96,11 @@ public Part Load(AssetBundle bundle, string prefabName) Saver.modParts.Add(part.CarProps.PrefabName, prefab); + if (part.Mod.Settings.AutomaticFitsToCar != null) + { + part.PartInfo.FitsToCar = part.Mod.Settings.AutomaticFitsToCar; + } + Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (full part) {prefabName} from {thisMod.Name}"); return part; // We provide the Part instance so the developer can setup the transparents } diff --git a/SimplePartLoader/ModUtils/CarParts/ModSettings.cs b/SimplePartLoader/ModUtils/CarParts/ModSettings.cs index 37fc2bd..f548bc7 100644 --- a/SimplePartLoader/ModUtils/CarParts/ModSettings.cs +++ b/SimplePartLoader/ModUtils/CarParts/ModSettings.cs @@ -12,6 +12,7 @@ public class ModSettings private bool DeveloperLog = false; private bool Immediate = false; private bool Cloning = true; + private string[] FitsToCar; public ModInstance Mod { @@ -35,6 +36,12 @@ public bool PreciseCloning get { return Cloning; } set { Cloning = value; } } + + public string[] AutomaticFitsToCar + { + get { return FitsToCar; } + set { FitsToCar = value; } + } internal ModSettings(ModInstance _modInstance) { diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index c09ccc3..a2797b0 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -482,7 +482,16 @@ internal static void LoadPrefabGeneratorParts() } Debug.Log($"[ModUtils/SPL]: Loaded {part.Name} (ingame: {part.CarProps.PartName}) through prefab generator"); - GameObject.Destroy(part.Prefab.GetComponent()); + + // Destroy some stuff + DestroyConsideringSetting(part, part.Prefab.GetComponent()); + + foreach (var bn in part.Prefab.GetComponentsInChildren()) + DestroyConsideringSetting(part, bn); + foreach (var bn in part.Prefab.GetComponentsInChildren()) + DestroyConsideringSetting(part, bn); + foreach (var bn in part.Prefab.GetComponentsInChildren()) + DestroyConsideringSetting(part, bn); } } diff --git a/SimplePartLoader/SPL.cs b/SimplePartLoader/SPL.cs index 75fda8b..410a05c 100644 --- a/SimplePartLoader/SPL.cs +++ b/SimplePartLoader/SPL.cs @@ -215,6 +215,12 @@ public static void CopyPartToPrefab(Part p, string partName, bool ignoreBuiltin Debug.LogError("[ModUtils/SPL/Error]: Tried to do full copy into empty part"); return; } + + if(p.Prefab.GetComponents() == null) + { + Debug.Log("[ModUtils/SPL/Error]: The part that was going to be copied had a null component. Part: " + p.Name); + return; + } // We first delete all the components from our part. foreach (Component comp in p.Prefab.GetComponents()) @@ -252,7 +258,7 @@ public static void CopyPartToPrefab(Part p, string partName, bool ignoreBuiltin DevLog(p, $"Now copying component to base object ({comp})"); } } - + if (!doNotCopyChilds) AttachPrefabChilds(p.Prefab, carPart, p.UseBetterCopy); // Call the recursive function that copies all the child hierarchy. @@ -260,12 +266,19 @@ public static void CopyPartToPrefab(Part p, string partName, bool ignoreBuiltin p.CarProps = p.Prefab.GetComponent(); p.PartInfo = p.Prefab.GetComponent(); p.Renderer = p.Prefab.GetComponent(); - + p.CarProps.PREFAB = p.Prefab; p.CarProps.PrefabName = p.Name; p.PartInfo.RenamedPrefab = String.IsNullOrEmpty(carPart.GetComponent().RenamedPrefab) ? carPart.transform.name : carPart.GetComponent().RenamedPrefab; // Fixes transparents breaking after reloading - + if(p.Mod != null) + { + if(p.Mod.Settings.AutomaticFitsToCar != null) + { + p.PartInfo.FitsToCar = p.Mod.Settings.AutomaticFitsToCar; + } + } + p.OriginalGameobject = carPart; Debug.LogError($"[ModUtils/SPL]: {p.Name} was succesfully loaded"); From 8fd9cfac7a62a2092893d24c050a1b096c95f108 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 14 Sep 2022 15:59:38 -0300 Subject: [PATCH 10/23] feat: WIP furniture support --- SimplePartLoader/FurnitureManager.cs | 29 ++++++++++++ SimplePartLoader/ModUtils.csproj | 5 +++ .../ModUtils/CarParts/ModInstance.cs | 25 +++++++++++ SimplePartLoader/ModUtils/PaintingSystem.cs | 4 +- .../EditorComponents/FurnitureGenerator.cs | 24 ++++++++++ .../Objects/Furniture/Furniture.cs | 39 ++++++++++++++++ .../Furniture/PlayerFurniturePickup.cs | 45 +++++++++++++++++++ .../Objects/Furniture/SaleFurniture.cs | 12 +++++ 8 files changed, 181 insertions(+), 2 deletions(-) create mode 100644 SimplePartLoader/FurnitureManager.cs create mode 100644 SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs create mode 100644 SimplePartLoader/Objects/Furniture/Furniture.cs create mode 100644 SimplePartLoader/Objects/Furniture/PlayerFurniturePickup.cs create mode 100644 SimplePartLoader/Objects/Furniture/SaleFurniture.cs diff --git a/SimplePartLoader/FurnitureManager.cs b/SimplePartLoader/FurnitureManager.cs new file mode 100644 index 0000000..94abf40 --- /dev/null +++ b/SimplePartLoader/FurnitureManager.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePartLoader +{ + internal class FurnitureManager + { + private static Hashtable FurnitureList = new Hashtable(); + + public static Hashtable Furnitures + { + get { return FurnitureList; } + } + + public static void LoadFurniture() + { + + } + + public static void SaveFurniture() + { + + } + } +} diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index aea8fd5..e45381f 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -437,10 +437,15 @@ + + + + + diff --git a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs index 5f4ed27..ff0864e 100644 --- a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs +++ b/SimplePartLoader/ModUtils/CarParts/ModInstance.cs @@ -132,5 +132,30 @@ public Part Load(AssetBundle bundle, string prefabName) return p; } + + public Furniture LoadFurniture(AssetBundle bundle, string prefabName) + { + // Safety checks + if (!bundle) + Debug.Log("[ModUtils/Furniture/Error]: Tried to create a furniture without valid AssetBundle"); + + if (String.IsNullOrWhiteSpace(prefabName)) + Debug.Log("[ModUtils/Furniture/Error]: Tried to create a part without prefab name"); + + if (Saver.modParts.ContainsKey(prefabName)) + Debug.Log($"[ModUtils/Furniture/Error]: Tried to create an already existing prefab ({prefabName})"); + + GameObject prefab = bundle.LoadAsset(prefabName); + if (!prefab) + Debug.Log($"[ModUtils/Furniture/Error]: Tried to create a prefab but it was not found in the AssetBundle ({prefabName})"); + + FurnitureGenerator furnitureGen = prefab.GetComponent(); + if (!furnitureGen) + Debug.Log($"[ModUtils/Furniture/Error]: {prefabName} has no Furniture Generator component"); + + GameObject.DontDestroyOnLoad(prefab); // We make sure that our prefab is not deleted in the first scene change + + + } } } diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index bd64134..625727c 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -507,7 +507,7 @@ public static Material GetChromeMaterial() public static void SetMaterialsForObject(Part p, int bodymatIndex = -1, int paintRustIndex = -1, int dirtIndex = -1) { - Material[] matsOfPart = p.GetComponent().materials; + Material[] matsOfPart = p.Renderer.materials; if (bodymatIndex != -1) { @@ -539,7 +539,7 @@ public static void SetMaterialsForObject(Part p, int bodymatIndex = -1, int pain matsOfPart[dirtIndex] = GetDirtMaterial(); } - p.GetComponent().materials = matsOfPart; + p.Renderer.materials = matsOfPart; } } } diff --git a/SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs b/SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs new file mode 100644 index 0000000..8ac145c --- /dev/null +++ b/SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +internal class FurnitureGenerator : MonoBehaviour +{ + [Header("Basic settings")] + [Tooltip("Internal name that the furniture uses to identify itself internally")] + public string PrefabName = ""; + [Tooltip("Display name that will be show to the player")] + public string DisplayName = ""; + [Tooltip("Price of the furniture")] + public float Price = 0f; + + [Header("Furniture settings")] + [Tooltip("Set it as furniture? Makes only movable with move tool and freezes after a bit")] + public bool EnableFurnitureBehaviour = true; + [Tooltip("Only for parts that have furniture behaviour. Allows to move with hand")] + public bool AllowHandPicking = false; +} + diff --git a/SimplePartLoader/Objects/Furniture/Furniture.cs b/SimplePartLoader/Objects/Furniture/Furniture.cs new file mode 100644 index 0000000..56f08dc --- /dev/null +++ b/SimplePartLoader/Objects/Furniture/Furniture.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader +{ + public class Furniture + { + private string InternalName; + private string DisplayName; + private GameObject ObjectPrefab; + + public string PrefabName + { + get { return InternalName; } + internal set { InternalName = value; } + } + + public string Name + { + get { return DisplayName; } + set { DisplayName = value; } + } + + public GameObject Prefab + { + get { return ObjectPrefab; } + internal set { ObjectPrefab = value; } + } + + public Furniture(GameObject go) + { + ObjectPrefab = go; + } + } +} diff --git a/SimplePartLoader/Objects/Furniture/PlayerFurniturePickup.cs b/SimplePartLoader/Objects/Furniture/PlayerFurniturePickup.cs new file mode 100644 index 0000000..ab183da --- /dev/null +++ b/SimplePartLoader/Objects/Furniture/PlayerFurniturePickup.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader.Objects.Furniture +{ + internal class PlayerFurniturePickup : MonoBehaviour + { + bool DoingHack = false, HackLastFrame = false; + + void LateUpdate() + { + RaycastHit rcHit; + if (tools.tool == 1 || DoingHack) + { + if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out rcHit, 2f, ~LayerMask.NameToLayer("Items"))) + { + if (rcHit.collider.transform.root.name.StartsWith("MODUTILS_FURNITURE_H_")) + { + DoingHack = true; + } + else if (DoingHack) + DoingHack = false; + } + else if (DoingHack) + DoingHack = false; + } + + if (DoingHack) + { + tools.tool = 22; + HackLastFrame = true; + } + + if (HackLastFrame && !DoingHack) + { + tools.tool = 1; + HackLastFrame = false; + } + } + } +} diff --git a/SimplePartLoader/Objects/Furniture/SaleFurniture.cs b/SimplePartLoader/Objects/Furniture/SaleFurniture.cs new file mode 100644 index 0000000..bc04d93 --- /dev/null +++ b/SimplePartLoader/Objects/Furniture/SaleFurniture.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePartLoader +{ + internal class SaleFurniture + { + } +} From 682974524efaec88bf6c1e4d3f9b3fa36f673415 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Fri, 16 Sep 2022 17:14:49 -0300 Subject: [PATCH 11/23] feat: working furniture generator, some bug fixes related to prefab gen --- SimplePartLoader/FurnitureManager.cs | 127 +++++++++++++++++- SimplePartLoader/ModMain.cs | 7 +- SimplePartLoader/ModUtils.csproj | 7 +- .../{CarParts => ModObjects}/ModInstance.cs | 22 +++ .../{CarParts => ModObjects}/ModSettings.cs | 0 .../EditorComponents/FurnitureGenerator.cs | 2 +- .../Objects/Furniture/Furniture.cs | 78 ++++++++++- .../Objects/Furniture/SaleFurniture.cs | 26 +++- .../Objects/Furniture/Saving/FurnitureData.cs | 21 +++ .../Furniture/Saving/FurnitureWrapper.cs | 13 ++ .../Furniture/Saving/ModUtilsFurniture.cs | 24 ++++ SimplePartLoader/Objects/Part.cs | 7 +- SimplePartLoader/PartManager.cs | 9 ++ 13 files changed, 330 insertions(+), 13 deletions(-) rename SimplePartLoader/ModUtils/{CarParts => ModObjects}/ModInstance.cs (88%) rename SimplePartLoader/ModUtils/{CarParts => ModObjects}/ModSettings.cs (100%) create mode 100644 SimplePartLoader/Objects/Furniture/Saving/FurnitureData.cs create mode 100644 SimplePartLoader/Objects/Furniture/Saving/FurnitureWrapper.cs create mode 100644 SimplePartLoader/Objects/Furniture/Saving/ModUtilsFurniture.cs diff --git a/SimplePartLoader/FurnitureManager.cs b/SimplePartLoader/FurnitureManager.cs index 94abf40..a7aab03 100644 --- a/SimplePartLoader/FurnitureManager.cs +++ b/SimplePartLoader/FurnitureManager.cs @@ -1,29 +1,152 @@ -using System; +using Assets.SimpleLocalization; +using Newtonsoft.Json; +using SimplePartLoader.Objects.Furniture; +using SimplePartLoader.Objects.Furniture.Saving; +using System; using System.Collections; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; namespace SimplePartLoader { internal class FurnitureManager { private static Hashtable FurnitureList = new Hashtable(); + internal static List SaleItems = new List(); + + private static FurnitureWrapper SaveData = new FurnitureWrapper(); + + internal static string SavePath = $"{Application.persistentDataPath}/save1/modSaves/"; + internal static string FileName = "ModUtilsFurniture.json"; public static Hashtable Furnitures { get { return FurnitureList; } } - + public static void LoadFurniture() { + ModUtils.GetPlayer().AddComponent(); + + GameObject spawnSpot = new GameObject("SPAWN_POINT_FURNITURE_MODUTILS"); + spawnSpot.transform.position = new Vector3(660.2147f, 56.3729f, -83.6104f); + + foreach(SaleFurniture sf in SaleItems) + { + GameObject furniture = GameObject.Instantiate(sf.Furniture.Prefab); + + furniture.layer = LayerMask.NameToLayer("Items"); + + GameObject.Destroy(furniture.GetComponent()); + GameObject.Destroy(furniture.GetComponent()); + GameObject.DestroyImmediate(furniture.GetComponent()); + + SaleItem si = furniture.AddComponent(); + si.Price = sf.Furniture.Price; + si.Item = sf.Furniture.Prefab; + si.SpawnSpot = spawnSpot; + + furniture.transform.position = sf.Pos; + furniture.transform.eulerAngles = sf.Rot; + + furniture.name = sf.Furniture.Name; + + // Localization of the part + foreach (var dictionary in LocalizationManager.Dictionary) + { + if (dictionary.Value.ContainsKey(sf.Furniture.Prefab.name)) // Ignore case where the name is shared so the translation already exists + continue; + + dictionary.Value.Add(sf.Furniture.Prefab.name, sf.Furniture.Name); + } + } + + // Check if new save. + if (PlayerPrefs.GetFloat("LoadLevel") == 0f) // New game check + { + if (File.Exists(SavePath + FileName)) + File.Delete(SavePath + FileName); + + return; + } + + if (!File.Exists(SavePath + FileName)) + return; + Debug.Log($"[ModUtils/Furniture/Loader]: Starting furniture loader."); + // We load the data now + using (StreamReader r = new StreamReader(SavePath + FileName)) + { + string json = r.ReadToEnd(); + + if (String.IsNullOrEmpty(json)) + return; + + SaveData = JsonConvert.DeserializeObject(json); + } + + Debug.Log($"[ModUtils/Furniture/Loader]: Trying to load {SaveData.Furnitures.Count} furnitures."); + // And then with the data loaded we load the Furnitures + foreach (FurnitureData fd in SaveData.Furnitures) + { + Furniture f = (Furniture) Furnitures[fd.PrefabName]; + if(f != null) + { + GameObject furniture = GameObject.Instantiate(f.Prefab); + furniture.name = f.Prefab.name; + + furniture.transform.position = new Vector3(fd.X, fd.Y, fd.Z); + furniture.transform.eulerAngles = new Vector3(fd.rX, fd.rY, fd.rZ); + + if (furniture.GetComponent() && f.BehaveAsFurniture) + GameObject.DestroyImmediate(furniture.GetComponent()); + } + else + { + Debug.Log("[ModUtils/Furniture/Loader]: A furniture was loaded but not found in-game! Name: " + fd.PrefabName); + } + } + Debug.Log($"[ModUtils/Furniture/Loader]: Furniture load finished."); } public static void SaveFurniture() { + SaveData = new FurnitureWrapper(); + + ModUtilsFurniture[] AllFurnitures = UnityEngine.Object.FindObjectsOfType(); + Debug.Log($"[ModUtils/Furniture/Saver]: Trying to save {AllFurnitures.Length} furnitures."); + + foreach (ModUtilsFurniture f in AllFurnitures) + { + FurnitureData fw = new FurnitureData(); + + fw.PrefabName = f.furnitureRef.PrefabName; + + Vector3 fix = ModUtils.UnshiftCoords(f.transform.position); + fw.X = fix.x; + fw.Y = fix.y; + fw.Z = fix.z; + + fw.rX = f.transform.eulerAngles.x; + fw.rY = f.transform.eulerAngles.y; + fw.rZ = f.transform.eulerAngles.z; + + SaveData.Furnitures.Add(fw); + } + + if (!Directory.Exists(SavePath)) + Directory.CreateDirectory(SavePath); + + using (TextWriter tw = new StreamWriter(SavePath + FileName)) + { + tw.Write(JsonConvert.SerializeObject(SaveData)); + } + Debug.Log($"[ModUtils/Furniture/Saver]: Succesfully saved {AllFurnitures.Length} furnitures."); } } } diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index 531a940..578525a 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -21,12 +21,11 @@ public class ModMain : Mod public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; - string TESTING_VERSION_NUMBER = "1.2-beta3"; + string TESTING_VERSION_NUMBER = "1.2-beta5"; public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; - // Autoupdater public const string API_URL = "https://mygaragemod.xyz/api"; GameObject UI_Prefab, UI_Error_Prefab, UI, UI_BrokenInstallation_Prefab, UI_DeveloperLogEnabled_Prefab; @@ -185,7 +184,8 @@ public override void OnLoad() { ModUtils.OnLoadCalled(); PartManager.OnLoadCalled(); - + FurnitureManager.LoadFurniture(); + PlayerTransform = ModUtils.GetPlayer().transform; if(PlayerPrefs.GetFloat("LoadLevel") == 0f) @@ -247,6 +247,7 @@ public override void OnSaveFinish() return; CustomSaverHandler.Save(); + FurnitureManager.SaveFurniture(); } // For mod utils diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index e45381f..683bbe3 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -438,12 +438,15 @@ - - + + + + + diff --git a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs similarity index 88% rename from SimplePartLoader/ModUtils/CarParts/ModInstance.cs rename to SimplePartLoader/ModUtils/ModObjects/ModInstance.cs index ff0864e..cdbc35b 100644 --- a/SimplePartLoader/ModUtils/CarParts/ModInstance.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs @@ -12,6 +12,7 @@ public class ModInstance { private Mod thisMod; private List loadedParts; + private List loadedFurniture; private ModSettings settings; public List Parts @@ -20,6 +21,12 @@ public List Parts internal set { loadedParts = value; } } + public List Furnitures + { + get { return loadedFurniture; } + internal set { loadedFurniture = value; } + } + public Mod Mod { get { return thisMod; } @@ -39,6 +46,7 @@ internal ModInstance(Mod mod) { thisMod = mod; loadedParts = new List(); + loadedFurniture = new List(); settings = new ModSettings(this); Debug.Log($"[ModUtils/RegisteredMods]: Succesfully registered " + mod.Name); @@ -155,7 +163,21 @@ public Furniture LoadFurniture(AssetBundle bundle, string prefabName) GameObject.DontDestroyOnLoad(prefab); // We make sure that our prefab is not deleted in the first scene change + if(FurnitureManager.Furnitures.ContainsKey(furnitureGen.PrefabName)) + { + Debug.Log($"[ModUtils/Furniture/Error]: {furnitureGen.PrefabName} prefab name is already on use!"); + return null; + } + + Furniture furn = new Furniture(prefab, furnitureGen); + + furn.Mod = this; + + loadedFurniture.Add(furn); + FurnitureManager.Furnitures.Add(furn.PrefabName, furn); + Debug.Log($"[ModUtils/Furniture]: Succesfully loaded {furn.PrefabName} (mod: {Mod.Name})"); + return furn; } } } diff --git a/SimplePartLoader/ModUtils/CarParts/ModSettings.cs b/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs similarity index 100% rename from SimplePartLoader/ModUtils/CarParts/ModSettings.cs rename to SimplePartLoader/ModUtils/ModObjects/ModSettings.cs diff --git a/SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs b/SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs index 8ac145c..fad9410 100644 --- a/SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs +++ b/SimplePartLoader/Objects/EditorComponents/FurnitureGenerator.cs @@ -5,7 +5,7 @@ using System.Threading.Tasks; using UnityEngine; -internal class FurnitureGenerator : MonoBehaviour +public class FurnitureGenerator : MonoBehaviour { [Header("Basic settings")] [Tooltip("Internal name that the furniture uses to identify itself internally")] diff --git a/SimplePartLoader/Objects/Furniture/Furniture.cs b/SimplePartLoader/Objects/Furniture/Furniture.cs index 56f08dc..3e4cef9 100644 --- a/SimplePartLoader/Objects/Furniture/Furniture.cs +++ b/SimplePartLoader/Objects/Furniture/Furniture.cs @@ -1,4 +1,5 @@ -using System; +using SimplePartLoader.Objects.Furniture.Saving; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -9,10 +10,18 @@ namespace SimplePartLoader { public class Furniture { + private GameObject ObjectPrefab; + + // Furniture settings private string InternalName; private string DisplayName; - private GameObject ObjectPrefab; + private float FurniturePrice; + private bool FurnitureBehaviour; + private bool UsingHandPickup; + // Internal stuff + private ModInstance Owner; + public string PrefabName { get { return InternalName; } @@ -31,9 +40,72 @@ public GameObject Prefab internal set { ObjectPrefab = value; } } - public Furniture(GameObject go) + public ModInstance Mod + { + get { return Owner; } + internal set { Owner = value; } + } + + public float Price + { + get { return FurniturePrice; } + set { FurniturePrice = value; } + } + + public bool BehaveAsFurniture + { + get { return FurnitureBehaviour; } + set { FurnitureBehaviour = value; } + } + + public bool HandPickup + { + get { return UsingHandPickup; } + set { UsingHandPickup = value; } + } + + public Furniture(GameObject go, FurnitureGenerator fg) { ObjectPrefab = go; + + FurnitureBehaviour = fg.EnableFurnitureBehaviour; + UsingHandPickup = fg.AllowHandPicking; + FurniturePrice = fg.Price; + Name = fg.DisplayName; + PrefabName = fg.PrefabName; + + ObjectPrefab.AddComponent().PrefabName = PrefabName; + ObjectPrefab.AddComponent(); + ObjectPrefab.layer = LayerMask.NameToLayer("Items"); + + GameObject.Destroy(ObjectPrefab.GetComponent()); + + MooveItem mv = ObjectPrefab.AddComponent(); + mv.IsFurniture = FurnitureBehaviour; + mv.price = (int) FurniturePrice; + if(!mv.IsFurniture && UsingHandPickup) + { + Debug.LogWarning("[ModUtils/Furniture]: Using hand pickup without furniture behaviour is not allowed"); + UsingHandPickup = false; + } + + if(UsingHandPickup) + ObjectPrefab.name = "MODUTILS_FURNITURE_H_" + PrefabName; + else + ObjectPrefab.name = "MODUTILS_FURNITURE_" + PrefabName; + + } + + public SaleFurniture CreateSaleItem(Vector3 position, Vector3 rotation) + { + SaleFurniture sf = new SaleFurniture(); + sf.Furniture = this; + sf.Pos = position; + sf.Rot = rotation; + + FurnitureManager.SaleItems.Add(sf); + + return sf; } } } diff --git a/SimplePartLoader/Objects/Furniture/SaleFurniture.cs b/SimplePartLoader/Objects/Furniture/SaleFurniture.cs index bc04d93..25fae50 100644 --- a/SimplePartLoader/Objects/Furniture/SaleFurniture.cs +++ b/SimplePartLoader/Objects/Furniture/SaleFurniture.cs @@ -3,10 +3,34 @@ using System.Linq; using System.Text; using System.Threading.Tasks; +using UnityEngine; namespace SimplePartLoader { - internal class SaleFurniture + public class SaleFurniture { + private Furniture SellingFurniture; + private Vector3 Position; + private Vector3 Rotation; + + public static readonly Vector3 DEFAULT_MODSHOP_LOCATION = new Vector3(655.4157f, 55.2303f, -43.4625f); + + public Furniture Furniture + { + get { return SellingFurniture; } + internal set { SellingFurniture = value; } + } + + public Vector3 Pos + { + get { return Position; } + set { Position = value; } + } + + public Vector3 Rot + { + get { return Rotation; } + set { Rotation = value; } + } } } diff --git a/SimplePartLoader/Objects/Furniture/Saving/FurnitureData.cs b/SimplePartLoader/Objects/Furniture/Saving/FurnitureData.cs new file mode 100644 index 0000000..430c2f3 --- /dev/null +++ b/SimplePartLoader/Objects/Furniture/Saving/FurnitureData.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePartLoader.Objects.Furniture.Saving +{ + internal class FurnitureData + { + public string PrefabName; + + public float X; + public float Y; + public float Z; + + public float rX; + public float rY; + public float rZ; + } +} diff --git a/SimplePartLoader/Objects/Furniture/Saving/FurnitureWrapper.cs b/SimplePartLoader/Objects/Furniture/Saving/FurnitureWrapper.cs new file mode 100644 index 0000000..7b985e5 --- /dev/null +++ b/SimplePartLoader/Objects/Furniture/Saving/FurnitureWrapper.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePartLoader.Objects.Furniture.Saving +{ + internal class FurnitureWrapper + { + public List Furnitures = new List(); + } +} diff --git a/SimplePartLoader/Objects/Furniture/Saving/ModUtilsFurniture.cs b/SimplePartLoader/Objects/Furniture/Saving/ModUtilsFurniture.cs new file mode 100644 index 0000000..6402dfc --- /dev/null +++ b/SimplePartLoader/Objects/Furniture/Saving/ModUtilsFurniture.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader.Objects.Furniture.Saving +{ + internal class ModUtilsFurniture : MonoBehaviour + { + public string PrefabName; + public SimplePartLoader.Furniture furnitureRef; + + void Start() + { + furnitureRef = (SimplePartLoader.Furniture) FurnitureManager.Furnitures[PrefabName]; + if(furnitureRef == null) + { + Debug.Log("[ModUtils/Furniture/Error]: Could not find reference for furniture with prefab name " + PrefabName); + } + } + } +} diff --git a/SimplePartLoader/Objects/Part.cs b/SimplePartLoader/Objects/Part.cs index 41fa814..f5ab67e 100644 --- a/SimplePartLoader/Objects/Part.cs +++ b/SimplePartLoader/Objects/Part.cs @@ -22,7 +22,7 @@ public class Part internal Hashtable languages = new Hashtable(); internal bool SavingEnabled; - internal bool UseBetterCopy; + public bool UseBetterCopy; private PartTypes Type; private ModInstance modInstance; @@ -45,6 +45,11 @@ public Part(GameObject prefab, CarProperties carProp, Partinfo partinfo, Rendere PartInfo = partinfo; Renderer = renderer; this.modInstance = modInstance; + + if(modInstance != null) + { + UseBetterCopy = modInstance.Settings.PreciseCloning; + } } [Obsolete("SetupTransparent will be removed on the future, use AddTransparent instead!")] diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index a2797b0..548042a 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -353,6 +353,12 @@ internal static void LoadPrefabGeneratorParts() } } + if(!data.EnableMeshChange && part.GetComponent()) + { + Debug.LogError($"[ModUtils/SPL/Error]: Part {part.Name} has a MeshFilter component but EnableMeshChange is set to false. This will cause the part to not be loaded properly. Please set EnableMeshChange to true or remove the MeshFilter component."); + continue; + } + // We clone to our prefab SPL.CopyPartToPrefab(part, data.CopiesFrom, data.EnableMeshChange); @@ -469,10 +475,13 @@ internal static void LoadPrefabGeneratorParts() { TransparentData tempData = new TransparentData(markedTransparent.name, null, Vector3.zero, Quaternion.identity, false); tempData.MeshToUse = part.GetComponent().sharedMesh; + tempData.SavePosition = markedTransparent.SavePosition; tempData.Owner = part; GameObject transparentObject = GetTransparentReadyObject(tempData); + transparentObject.GetComponent().Type = markedTransparent.Type; + transparentObject.transform.SetParent(markedTransparent.transform.parent); transparentObject.transform.localPosition = markedTransparent.transform.localPosition; transparentObject.transform.localRotation = markedTransparent.transform.localRotation; From 9a9aaa1d2e0e04757688b4decf987a349bb1d38a Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Sun, 18 Sep 2022 07:28:11 -0300 Subject: [PATCH 12/23] feat: ChildMove & ChildDestroy components --- SimplePartLoader/ModUtils.csproj | 2 + SimplePartLoader/ModUtils/PaintingSystem.cs | 4 + .../Objects/EditorComponents/ChildDestroy.cs | 14 ++++ .../Objects/EditorComponents/ChildMove.cs | 22 +++++ .../EditorComponents/PrefabGenerator.cs | 2 +- SimplePartLoader/PartManager.cs | 80 +++++++++++++++++++ 6 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 SimplePartLoader/Objects/EditorComponents/ChildDestroy.cs create mode 100644 SimplePartLoader/Objects/EditorComponents/ChildMove.cs diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index 683bbe3..730e182 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -440,6 +440,8 @@ + + diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index 625727c..5edf054 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -172,6 +172,7 @@ internal static void EnablePaintAndRust(Part part) part.Paintable = true; part.CarProps.Paintable = true; part.CarProps.DMGdeformMesh = true; // NOTE! As a side effect this will enable mesh deform on crashes. + part.CarProps.Fairable = true; } @@ -226,6 +227,7 @@ internal static void EnableDirtOnly(Part part) // Final details part.Paintable = true; + part.CarProps.Fairable = true; part.CarProps.Washable = true; } @@ -330,6 +332,7 @@ internal static void EnableFullSupport(Part part) part.Paintable = true; part.CarProps.Paintable = true; part.CarProps.Washable = true; + part.CarProps.Fairable = true; part.CarProps.DMGdeformMesh = true; // NOTE! As a side effect this will enable mesh deform on crashes. } @@ -410,6 +413,7 @@ internal static void EnablePaintAndDirt(Part part) part.Paintable = true; part.CarProps.Paintable = true; part.CarProps.Washable = true; + part.CarProps.Fairable = true; part.CarProps.DMGdeformMesh = true; // NOTE! As a side effect this will enable mesh deform on crashes. } diff --git a/SimplePartLoader/Objects/EditorComponents/ChildDestroy.cs b/SimplePartLoader/Objects/EditorComponents/ChildDestroy.cs new file mode 100644 index 0000000..20fc3ab --- /dev/null +++ b/SimplePartLoader/Objects/EditorComponents/ChildDestroy.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +internal class ChildDestroy : MonoBehaviour +{ + [Header("Basic settings")] + public string ChildName = ""; + public bool StartsWith = false; + public bool EndsWith = false; +} diff --git a/SimplePartLoader/Objects/EditorComponents/ChildMove.cs b/SimplePartLoader/Objects/EditorComponents/ChildMove.cs new file mode 100644 index 0000000..2b446d1 --- /dev/null +++ b/SimplePartLoader/Objects/EditorComponents/ChildMove.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +internal class ChildMove : MonoBehaviour +{ + [Header("Basic settings")] + public string ChildName = ""; + public bool StartsWith = false; + public bool EndsWith = false; + + [Header("Position")] + public bool Move = true; + public Vector3 NewPosition = Vector3.zero; + + [Header("Rotation")] + public bool Rotate = false; + public Vector3 NewRotation = Vector3.zero; +} diff --git a/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs b/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs index 29da76b..4d8703d 100644 --- a/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs +++ b/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs @@ -38,7 +38,7 @@ public class PrefabGenerator : MonoBehaviour public AttachmentTypes AttachmentType = AttachmentTypes.Default; [Tooltip("Enables part to get chromed")] public bool EnableChromed = false; - + public enum AttachmentTypes { Default, diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index 548042a..d91c97e 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -368,6 +368,81 @@ internal static void LoadPrefabGeneratorParts() continue; } + // Now we remove all specific childs / move them. + foreach(ChildDestroy cd in part.Prefab.GetComponentsInChildren()) + { + foreach(Transform t in part.GetTransforms()) + { + if (cd.StartsWith) + { + if (t.name.StartsWith(cd.ChildName)) + DestroyConsideringSetting(part, t.gameObject); + } + else if (cd.EndsWith) + { + if (t.name.EndsWith(cd.ChildName)) + DestroyConsideringSetting(part, t.gameObject); + } + else + { + if (t.name == cd.ChildName) + DestroyConsideringSetting(part, t.gameObject); + } + } + } + + foreach (ChildMove cd in part.Prefab.GetComponentsInChildren()) + { + foreach (Transform t in part.GetTransforms()) + { + if (cd.StartsWith) + { + if (t.name.StartsWith(cd.ChildName)) + { + if(cd.Move) + { + t.localPosition = cd.NewPosition; + } + + if(cd.Rotate) + { + t.localEulerAngles = cd.NewRotation; + } + } + } + else if (cd.EndsWith) + { + if (t.name.EndsWith(cd.ChildName)) + { + if (cd.Move) + { + t.localPosition = cd.NewPosition; + } + + if (cd.Rotate) + { + t.localEulerAngles = cd.NewRotation; + } + } + } + else + { + if (t.name == cd.ChildName) + { + if (cd.Move) + { + t.localPosition = cd.NewPosition; + } + + if (cd.Rotate) + { + t.localEulerAngles = cd.NewRotation; + } + } + } + } + } + // Setting part name if set if (!String.IsNullOrWhiteSpace(data.PartName)) { @@ -501,6 +576,11 @@ internal static void LoadPrefabGeneratorParts() DestroyConsideringSetting(part, bn); foreach (var bn in part.Prefab.GetComponentsInChildren()) DestroyConsideringSetting(part, bn); + + foreach (var bn in part.Prefab.GetComponentsInChildren()) + DestroyConsideringSetting(part, bn); + foreach (var bn in part.Prefab.GetComponentsInChildren()) + DestroyConsideringSetting(part, bn); } } From 1f75d05494ded13da44f927e41dcb00eb926e940 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Thu, 22 Sep 2022 20:14:44 -0300 Subject: [PATCH 13/23] tweak: new settings for ModInstances. --- SimplePartLoader/ModMain.cs | 3 +- .../ModUtils/ModObjects/ModSettings.cs | 14 ++++ SimplePartLoader/ModUtils/PaintingSystem.cs | 66 ++++++++++++++---- .../Resources/autoupdater_ui_canvas | Bin 8860 -> 20828 bytes SimplePartLoader/Utils/CarBuilding.cs | 2 + 5 files changed, 72 insertions(+), 13 deletions(-) diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index 578525a..82f48e7 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -83,8 +83,9 @@ public ModMain() UI_DeveloperLogEnabled_Prefab = AutoupdaterBundle.LoadAsset("CanvasDevLog"); UI_Prefab.GetComponent().sortingOrder = 1; // Fixes canva disappearing after a bit. - UI_Error_Prefab.GetComponent().sortingOrder = 1; + + PaintingSystem.BackfaceShader = AutoupdaterBundle.LoadAsset("BackfaceShader"); AutoupdaterBundle.Unload(false); } diff --git a/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs b/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs index f548bc7..d387cde 100644 --- a/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs @@ -12,6 +12,8 @@ public class ModSettings private bool DeveloperLog = false; private bool Immediate = false; private bool Cloning = true; + private bool CullShader = false; + private bool BetterPaint = false; private string[] FitsToCar; public ModInstance Mod @@ -43,6 +45,18 @@ public string[] AutomaticFitsToCar set { FitsToCar = value; } } + public bool HighPaintResolution + { + get { return BetterPaint; } + set { BetterPaint = value; } + } + + public bool UseBackfaceShader + { + get { return CullShader; } + set { CullShader = value; } + } + internal ModSettings(ModInstance _modInstance) { modInstance = _modInstance; diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index 5edf054..6541f1d 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -14,7 +14,9 @@ public class PaintingSystem static Material PaintRustMaterial = null; static Material DirtMaterial = null; static Material BaseMaterial = null; - + static Material CullBaseMaterial = null; + internal static Shader BackfaceShader = null; + public enum Types { FullPaintingSupport = 1, @@ -77,7 +79,7 @@ internal static void EnablePaintOnly(Part part, int materialIndex) P3dPaintableTexture paintableTexture_colorMap = Prefab.AddComponent(); P3dChangeCounter counter_colorMap = Prefab.AddComponent(); - + P3dSlot p3dSlot_colorMap = new P3dSlot(l2Material_index, "_L2ColorMap"); // Setting up the components @@ -91,7 +93,10 @@ internal static void EnablePaintOnly(Part part, int materialIndex) counter_colorMap.PaintableTexture = paintableTexture_colorMap; counter_colorMap.Threshold = 0.1f; counter_colorMap.enabled = false; + counter_colorMap.DownsampleSteps = 5; + CheckHighResolutionPaint(part, paintableTexture_colorMap); + // Final details part.Paintable = true; part.CarProps.Paintable = true; @@ -163,11 +168,15 @@ internal static void EnablePaintAndRust(Part part) counter_rust.Threshold = 0.5f; counter_rust.enabled = false; counter_rust.Color = new Color(0, 0, 0, 1f); - + counter_rust.DownsampleSteps = 5; + counter_colorMap.PaintableTexture = paintableTexture_colorMap; counter_colorMap.Threshold = 0.1f; counter_colorMap.enabled = false; - + counter_colorMap.DownsampleSteps = 5; + + CheckHighResolutionPaint(part, paintableTexture_colorMap); + // Final details part.Paintable = true; part.CarProps.Paintable = true; @@ -224,10 +233,10 @@ internal static void EnableDirtOnly(Part part) counter_dirt.PaintableTexture = paintableTexture_dirt; counter_dirt.Threshold = 0.7f; counter_dirt.enabled = false; - + counter_dirt.Color = new Color(0.219f, 0.219f, 0.219f, 0f); + counter_dirt.DownsampleSteps = 5; + // Final details - part.Paintable = true; - part.CarProps.Fairable = true; part.CarProps.Washable = true; } @@ -303,7 +312,7 @@ internal static void EnableFullSupport(Part part) // Paintable textures paintableTexture_colorMap.Slot = p3dSlot_colorMap; - + paintableTexture_grungeMap.Slot = p3dSlot_grungeMap; paintableTexture_grungeMap.Group = 100; @@ -318,15 +327,20 @@ internal static void EnableFullSupport(Part part) counter_rust.Threshold = 0.5f; counter_rust.enabled = false; counter_rust.Color = new Color(0, 0, 0, 1f); - + counter_rust.DownsampleSteps = 5; + counter_colorMap.PaintableTexture = paintableTexture_colorMap; counter_colorMap.Threshold = 0.1f; counter_colorMap.enabled = false; - + counter_colorMap.DownsampleSteps = 5; + counter_dirt.PaintableTexture = paintableTexture_dirt; counter_dirt.Threshold = 0.7f; counter_dirt.enabled = false; counter_dirt.Color = new Color(0.219f, 0.219f, 0.219f, 0f); + counter_dirt.DownsampleSteps = 5; + + CheckHighResolutionPaint(part, paintableTexture_colorMap); // Final details part.Paintable = true; @@ -408,6 +422,8 @@ internal static void EnablePaintAndDirt(Part part) paintableTexture_dirt.Slot = p3dSlot_dirt; paintableTexture_dirt.Group = 5; + + CheckHighResolutionPaint(part, paintableTexture_colorMap); // Final details part.Paintable = true; @@ -417,6 +433,18 @@ internal static void EnablePaintAndDirt(Part part) part.CarProps.DMGdeformMesh = true; // NOTE! As a side effect this will enable mesh deform on crashes. } + public static void CheckHighResolutionPaint(Part p, P3dPaintableTexture texture) + { + if(p.Mod != null) + { + if(p.Mod.Settings.HighPaintResolution) + { + texture.Width = 1024; + texture.Height = 1024; + } + } + } + public static Material GetDirtMaterial() { if (!DirtMaterial) @@ -464,6 +492,11 @@ public static Material GetPaintRustMaterial() } public static Material GetBodymatMaterial() + { + return GetBodymatMaterial(false); + } + + public static Material GetBodymatMaterial(bool useBackfaceShader = false) { if (!BaseMaterial) { @@ -474,6 +507,9 @@ public static Material GetBodymatMaterial() if (go.name == "DoorFR06") { BaseMaterial = go.GetComponent().materials[2]; + CullBaseMaterial = Material.Instantiate(BaseMaterial); + CullBaseMaterial.shader = BackfaceShader; + CullBaseMaterial.color = new Color(0f, 0f, 0f, 1f); } } } @@ -483,7 +519,8 @@ public static Material GetBodymatMaterial() { Debug.LogError("[ModUtils/PaintingSystem/Error]: GetBodymatMaterial was not able to retrive the body material. Make sure you are using it on FirstLoad event."); } - return BaseMaterial; + + return useBackfaceShader ? CullBaseMaterial : BaseMaterial; } public static Material GetChromeMaterial() @@ -520,7 +557,12 @@ public static void SetMaterialsForObject(Part p, int bodymatIndex = -1, int pain Debug.LogError($"[ModUtils/PaintingSystem/Error]: SetMaterialsForObject tried to setup bodymat index {bodymatIndex} on part {p.Prefab.name} but it only has {matsOfPart.Length} materials."); return; } - matsOfPart[bodymatIndex] = GetBodymatMaterial(); + bool shader = false; + if(p.Mod != null) + { + shader = p.Mod.Settings.UseBackfaceShader; + } + matsOfPart[bodymatIndex] = GetBodymatMaterial(shader); } if (paintRustIndex != -1) diff --git a/SimplePartLoader/Resources/autoupdater_ui_canvas b/SimplePartLoader/Resources/autoupdater_ui_canvas index 123343451d987bd6886e3417b5090ba853f5017c..899016dfe15ec741b2db3d91ecf1eabb6c5bb9b5 100644 GIT binary patch literal 20828 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

2kp`=XlU+qL)OU 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 diff --git a/SimplePartLoader/Utils/CarBuilding.cs b/SimplePartLoader/Utils/CarBuilding.cs index be5f32e..303ef4a 100644 --- a/SimplePartLoader/Utils/CarBuilding.cs +++ b/SimplePartLoader/Utils/CarBuilding.cs @@ -54,6 +54,8 @@ public static void CopyPartIntoTransform(GameObject partToAdd, Transform locatio addedPart.layer = partToAdd.layer; addedPart.tag = partToAdd.tag; + addedPart.SetActive(partToAdd.activeSelf); + addedPart.transform.localPosition = Vector3.zero; addedPart.transform.localRotation = Quaternion.identity; addedPart.transform.localScale = Vector3.one; From 64eab37e4d6409d29e43793a11abfe73eadd141b Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Sat, 24 Sep 2022 16:08:21 -0300 Subject: [PATCH 14/23] tweak: version bumped to beta6, EA working --- SimplePartLoader/ModMain.cs | 22 +++--- SimplePartLoader/ModUtils.csproj | 14 ++++ .../ModUtils/ModObjects/EACheck.cs | 38 ++++++++++ .../ModUtils/ModObjects/EarlyAccessJson.cs | 14 ++++ .../ModUtils/ModObjects/ModInstance.cs | 70 +++++++++++++++++- SimplePartLoader/ModUtils/ModUtils.cs | 7 +- SimplePartLoader/ModUtils/PaintingSystem.cs | 17 +++-- SimplePartLoader/Objects/Part.cs | 10 ++- SimplePartLoader/PartManager.cs | 16 ++++ .../Resources/autoupdater_ui_canvas | Bin 20828 -> 26225 bytes SimplePartLoader/Utils/KeepAlive.cs | 2 +- 11 files changed, 191 insertions(+), 19 deletions(-) create mode 100644 SimplePartLoader/ModUtils/ModObjects/EACheck.cs create mode 100644 SimplePartLoader/ModUtils/ModObjects/EarlyAccessJson.cs diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index 82f48e7..4071fab 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -21,9 +21,8 @@ public class ModMain : Mod public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; - string TESTING_VERSION_NUMBER = "1.2-beta5"; + string TESTING_VERSION_NUMBER = "1.2-beta6"; - public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; // Autoupdater @@ -86,11 +85,17 @@ public ModMain() UI_Error_Prefab.GetComponent().sortingOrder = 1; PaintingSystem.BackfaceShader = AutoupdaterBundle.LoadAsset("BackfaceShader"); + PaintingSystem.CullBaseMaterial = AutoupdaterBundle.LoadAsset("testMat"); AutoupdaterBundle.Unload(false); + + ModUtils.SetupSteamworks(); } public override void OnMenuLoad() { + string autoupdaterDirectory = Path.Combine(Application.dataPath, "..\\Mods\\NewAutoupdater"); + string autoupdaterPath = autoupdaterDirectory + "\\Autoupdater.exe"; + if (!MenuFirstLoad) { MenuFirstLoad = true; @@ -99,13 +104,17 @@ public override void OnMenuLoad() { Debug.Log($"{m.Name} (ID: {m.ID}) - Version {m.Version}"); } + + // Enable heartbeat + + if (!File.Exists(autoupdaterPath + "\\disableStatus.txt")) + KeepAlive.GetInstance().Ready(); + return; } Debug.Log("[ModUtils/Autoupdater]: Autoupdater check"); // Check for broken ModUtils autoupdater installation - string autoupdaterDirectory = Path.Combine(Application.dataPath, "..\\Mods\\NewAutoupdater"); - string autoupdaterPath = autoupdaterDirectory + "\\Autoupdater.exe"; bool brokenInstallation = false; if(!Directory.Exists(autoupdaterDirectory) || !File.Exists(autoupdaterPath)) @@ -174,11 +183,6 @@ public override void OnMenuLoad() Debug.Log("[ModUtils/Autoupdater/Error]: Error occured while trying to fetch updates, error: " + ex.ToString()); GameObject.Instantiate(UI_Error_Prefab); } - - // Enable heartbeat - - if(!File.Exists(autoupdaterPath + "\\disableStatus.txt")) - KeepAlive.GetInstance().Ready(); } public override void OnLoad() diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index 730e182..e723ee3 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -38,6 +38,18 @@ F:\SteamLibrary\steamapps\common\My Garage\My Garage_Data\Managed\Assembly-CSharp.dll False + + F:\SteamLibrary\steamapps\common\My Garage\My Garage_Data\Managed\Mirror.dll + False + + + F:\SteamLibrary\steamapps\common\My Garage\My Garage_Data\Managed\Mirror.Authenticators.dll + False + + + F:\SteamLibrary\steamapps\common\My Garage\My Garage_Data\Managed\Mirror.Components.dll + False + False F:\SteamLibrary\steamapps\common\My Garage\My Garage_Data\Managed\Newtonsoft.Json.dll @@ -438,6 +450,8 @@ + + diff --git a/SimplePartLoader/ModUtils/ModObjects/EACheck.cs b/SimplePartLoader/ModUtils/ModObjects/EACheck.cs new file mode 100644 index 0000000..b998bcf --- /dev/null +++ b/SimplePartLoader/ModUtils/ModObjects/EACheck.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader +{ + [DisallowMultipleComponent] + internal class EACheck : MonoBehaviour + { + internal int frameCount = 0; + internal bool checkDone = false; + void Update() + { + if (checkDone) + return; + + frameCount++; + if (!SteamManager.Initialized) + return; + + ulong steamID = Steamworks.SteamUser.GetSteamID().m_SteamID; + Debug.Log("[ModUtils/EACheck]: Identified user: " + steamID); + + foreach (ModInstance mi in ModUtils.ModInstances) + { + if (mi.RequiresSteamCheck) + { + mi.Check(steamID); + } + } + + checkDone = true; + } + } +} diff --git a/SimplePartLoader/ModUtils/ModObjects/EarlyAccessJson.cs b/SimplePartLoader/ModUtils/ModObjects/EarlyAccessJson.cs new file mode 100644 index 0000000..79c2d60 --- /dev/null +++ b/SimplePartLoader/ModUtils/ModObjects/EarlyAccessJson.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace SimplePartLoader +{ + internal class EarlyAccessJson + { + public string ModId; + public string SteamId; + } +} diff --git a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs index cdbc35b..d3bc882 100644 --- a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs @@ -1,7 +1,9 @@ -using SimplePartLoader.Utils; +using Newtonsoft.Json; +using SimplePartLoader.Utils; using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Text; using System.Threading.Tasks; using UnityEngine; @@ -15,6 +17,9 @@ public class ModInstance private List loadedFurniture; private ModSettings settings; + internal bool RequiresSteamCheck = false; + internal bool Checked = false; + public List Parts { get { return loadedParts; } @@ -179,5 +184,68 @@ public Furniture LoadFurniture(AssetBundle bundle, string prefabName) return furn; } + + public void EnableEarlyAccessCheck() + { + RequiresSteamCheck = true; + } + + internal async void Check(ulong SteamID) + { + Debug.Log($"Checking for {SteamID} at mod {Mod.Name}"); + if (!RequiresSteamCheck) + return; + + EarlyAccessJson eaJson = new EarlyAccessJson(); + eaJson.ModId = Mod.ID; + eaJson.SteamId = SteamID.ToString(); + + bool allowed = false; + + try + { + string json = JsonConvert.SerializeObject(eaJson); + + var content = new StringContent(json, Encoding.UTF8, "application/json"); + var result = await KeepAlive.GetInstance().client.PostAsync(ModMain.API_URL + "/eacheck", content); + string contents = await result.Content.ReadAsStringAsync(); + + if (contents == "true") + allowed = true; + + Checked = true; + } + catch(Exception ex) + { + Debug.LogError("[ModUtils/EACheck/Error]: An exception occured"); + Debug.LogError(ex); + } + + if(!allowed) + { + Debug.Log("[ModUtils/EACheck]: User is not allowed to use this mod - " + Mod.Name); + foreach (Part p in Parts) + { + if (PartManager.modLoadedParts.Contains(p)) + PartManager.modLoadedParts.Remove(p); + + if (PartManager.dummyParts.Contains(p)) + PartManager.dummyParts.Remove(p); + + if (PartManager.prefabGenParts.Remove(p)) + PartManager.prefabGenParts.Remove(p); + + GameObject.Destroy(p.Prefab); + } + + foreach(Furniture f in Furnitures) + { + FurnitureManager.Furnitures.Remove(f); + } + + Parts.Clear(); + Furnitures.Clear(); + } + } } } diff --git a/SimplePartLoader/ModUtils/ModUtils.cs b/SimplePartLoader/ModUtils/ModUtils.cs index f95f414..75ea4f7 100644 --- a/SimplePartLoader/ModUtils/ModUtils.cs +++ b/SimplePartLoader/ModUtils/ModUtils.cs @@ -15,7 +15,6 @@ public class ModUtils private static AudioManager AudioList; private static AudioSource Source; private static Player RewiredPlayer; - private static MainCarProperties CurrentPlayerCar; internal static List Cars; @@ -29,6 +28,12 @@ public static List ModInstances get { return RegisteredMods; } } + internal static void SetupSteamworks() + { + GameObject ModLoader = GameObject.Find("ModLoader"); + ModLoader.AddComponent(); + } + internal static void OnLoadCalled() { Player = GameObject.Find("Player"); diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index 6541f1d..eb05d0d 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -14,9 +14,8 @@ public class PaintingSystem static Material PaintRustMaterial = null; static Material DirtMaterial = null; static Material BaseMaterial = null; - static Material CullBaseMaterial = null; + internal static Material CullBaseMaterial = null; internal static Shader BackfaceShader = null; - public enum Types { FullPaintingSupport = 1, @@ -507,14 +506,12 @@ public static Material GetBodymatMaterial(bool useBackfaceShader = false) if (go.name == "DoorFR06") { BaseMaterial = go.GetComponent().materials[2]; - CullBaseMaterial = Material.Instantiate(BaseMaterial); - CullBaseMaterial.shader = BackfaceShader; - CullBaseMaterial.color = new Color(0f, 0f, 0f, 1f); } } } } + Debug.Log("GET DOYMAT MATERIAL: " + BaseMaterial + " " + useBackfaceShader + " .. " + CullBaseMaterial); if (!BaseMaterial) { Debug.LogError("[ModUtils/PaintingSystem/Error]: GetBodymatMaterial was not able to retrive the body material. Make sure you are using it on FirstLoad event."); @@ -534,6 +531,7 @@ public static Material GetChromeMaterial() if (go.name == "DoorFR06") { ChromeMaterial = go.GetComponent().ChromeMat; + ChromeMaterial.shader = Shader.Find("Azerilo/Double Sided Standard"); } } } @@ -560,7 +558,14 @@ public static void SetMaterialsForObject(Part p, int bodymatIndex = -1, int pain bool shader = false; if(p.Mod != null) { - shader = p.Mod.Settings.UseBackfaceShader; + if(p.ForceShaderStatus != ShaderSettings.NONE) + { + shader = p.ForceShaderStatus == ShaderSettings.FORCE_BACKSIDE; + } + else + { + shader = p.Mod.Settings.UseBackfaceShader; + } } matsOfPart[bodymatIndex] = GetBodymatMaterial(shader); } diff --git a/SimplePartLoader/Objects/Part.cs b/SimplePartLoader/Objects/Part.cs index f5ab67e..385239f 100644 --- a/SimplePartLoader/Objects/Part.cs +++ b/SimplePartLoader/Objects/Part.cs @@ -23,7 +23,8 @@ public class Part internal bool SavingEnabled; public bool UseBetterCopy; - + public ShaderSettings ForceShaderStatus = ShaderSettings.NONE; + private PartTypes Type; private ModInstance modInstance; @@ -258,4 +259,11 @@ public enum PartTypes DUMMY_PREFABGEN, DUMMY } + + public enum ShaderSettings + { + NONE = 0, + FORCE_BACKSIDE, + FORCE_DOUBLESIDED + } } diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index d91c97e..9d637bf 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -64,6 +64,12 @@ internal static void OnLoadCalled() } } + if(!GameObject.Find("ModLoader").GetComponent()) + { + Debug.Log("[ModUtils/Safety]: EACheck could not be found. This is a safety check. Please report this to the developer of the mod that is causing this."); + return; + } + SPL.DevLog("Starting first load check"); // We need to check if this is the first load. if (!hasFirstLoadOccured) @@ -101,6 +107,16 @@ internal static void OnLoadCalled() modLoadedParts.Remove(part); } + if(part.Mod != null) + { + if(part.Mod.RequiresSteamCheck && !part.Mod.Checked) + { + Debug.Log($"[ModUtils/SPL/Safety]: Removing {part.Prefab.name}"); + GameObject.Destroy(part.Prefab); + modLoadedParts.Remove(part); + } + } + if (!part.Prefab.GetComponent()) { part.Prefab.AddComponent(); diff --git a/SimplePartLoader/Resources/autoupdater_ui_canvas b/SimplePartLoader/Resources/autoupdater_ui_canvas index 899016dfe15ec741b2db3d91ecf1eabb6c5bb9b5..e5879ef671d75c2fe85eab0ab79961579a9453ff 100644 GIT binary patch literal 26225 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 literal 20828 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

2kp`=XlU+qL)OU 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 Date: Sat, 1 Oct 2022 19:36:45 -0300 Subject: [PATCH 15/23] feat: thumbnail generator for developers --- SimplePartLoader/ModMain.cs | 2 +- SimplePartLoader/ModUtils.csproj | 6 ++ .../ModUtils/ModObjects/ModInstance.cs | 8 ++ SimplePartLoader/Objects/Part.cs | 2 + SimplePartLoader/PartManager.cs | 8 ++ SimplePartLoader/Utils/CarBuilding.cs | 53 +++++++++++++- SimplePartLoader/Utils/ModUtils_Snapshoter.cs | 73 +++++++++++++++++++ 7 files changed, 150 insertions(+), 2 deletions(-) create mode 100644 SimplePartLoader/Utils/ModUtils_Snapshoter.cs diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index 4071fab..70b767f 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -21,7 +21,7 @@ public class ModMain : Mod public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; - string TESTING_VERSION_NUMBER = "1.2-beta6"; + string TESTING_VERSION_NUMBER = "1.2-beta7"; public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index e723ee3..9e6d75e 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -69,6 +69,11 @@ F:\SteamLibrary\steamapps\common\My Garage\My Garage_Data\Managed\Rewired_Windows.dll False + + False + F:\SteamLibrary\steamapps\common\My Garage\My Garage_Data\Managed\RuntimePreviewGenerator.Runtime.dll + False + @@ -499,6 +504,7 @@ + diff --git a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs index d3bc882..bf49de6 100644 --- a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs @@ -20,6 +20,8 @@ public class ModInstance internal bool RequiresSteamCheck = false; internal bool Checked = false; + internal bool Thumbnails = false; + public List Parts { get { return loadedParts; } @@ -190,6 +192,12 @@ public void EnableEarlyAccessCheck() RequiresSteamCheck = true; } + public void GenerateThumbnails() + { + Thumbnails = true; + PartManager.ThumbnailGeneratorEnabled = true; + } + internal async void Check(ulong SteamID) { Debug.Log($"Checking for {SteamID} at mod {Mod.Name}"); diff --git a/SimplePartLoader/Objects/Part.cs b/SimplePartLoader/Objects/Part.cs index 385239f..5dfff24 100644 --- a/SimplePartLoader/Objects/Part.cs +++ b/SimplePartLoader/Objects/Part.cs @@ -27,6 +27,8 @@ public class Part private PartTypes Type; private ModInstance modInstance; + + public bool RotateThumbnail; public ModInstance Mod { diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index 9d637bf..f0a6ebd 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -38,6 +38,8 @@ public class PartManager /// public static List gameParts; + internal static bool ThumbnailGeneratorEnabled = false; + ///

/// Handles the OnLoad function when called. /// @@ -244,6 +246,12 @@ internal static void OnLoadCalled() if (!hasFirstLoadOccured) hasFirstLoadOccured = true; + if(ThumbnailGeneratorEnabled) + { + GameObject PictureTake = new GameObject("ModUtils_Snapshoter"); + PictureTake.AddComponent(); + } + SPL.InvokeLoadFinishedEvent(); } diff --git a/SimplePartLoader/Utils/CarBuilding.cs b/SimplePartLoader/Utils/CarBuilding.cs index 303ef4a..183b2de 100644 --- a/SimplePartLoader/Utils/CarBuilding.cs +++ b/SimplePartLoader/Utils/CarBuilding.cs @@ -138,6 +138,12 @@ public static void UpdateTransparentsReferences(GameObject p) newDependants[i] = new transparents.dependantObjects(); referenceUpdated = false; + if(dp == null || dp.dependant == null) + { + continue; + } + + int savePosition = dp.dependant.GetComponent().SavePosition; foreach (transparents t2 in p.GetComponentsInChildren()) { if(t2 == null) @@ -149,7 +155,7 @@ public static void UpdateTransparentsReferences(GameObject p) { continue; } - if (t2.name == dp.dependant.name) + if (t2.name == dp.dependant.name && t2.SavePosition == savePosition) { newDependants[i].dependant = t2.gameObject; referenceUpdated = true; @@ -166,6 +172,51 @@ public static void UpdateTransparentsReferences(GameObject p) } t.DEPENDANTS = newDependants; } + + // Attachables + if (t.ATTACHABLES != null && t.ATTACHABLES.Length > 0) + { + transparents.AttachingObjects[] newAttachables = new transparents.AttachingObjects[t.ATTACHABLES.Length]; + for (int i = 0; i < t.ATTACHABLES.Length; i++) + { + transparents.AttachingObjects dp = t.ATTACHABLES[i]; + newAttachables[i] = new transparents.AttachingObjects(); + referenceUpdated = false; + + if(dp == null || dp.Attachable == null) + { + continue; + } + + int savePosition = dp.Attachable.GetComponent().SavePosition; + foreach (transparents t2 in p.GetComponentsInChildren()) + { + if (t2 == null) + { + continue; + } + + if (dp.Attachable == null) + { + continue; + } + if (t2.name == dp.Attachable.name && t2.SavePosition == savePosition) + { + newAttachables[i].Attachable = t2.gameObject; + referenceUpdated = true; + break; + } + } + if (!referenceUpdated) + { + if (dp.Attachable == null) + Debug.LogError("[ModUtils/CarBuilding/Error]: Attachable object (null) not found in " + p.name + ", on part " + t.name); + else + Debug.LogError("[ModUtils/CarBuilding/Error]: Attachable object " + dp.Attachable.name + " not found in " + p.name + ", on part " + t.name); + } + } + t.ATTACHABLES = newAttachables; + } } } diff --git a/SimplePartLoader/Utils/ModUtils_Snapshoter.cs b/SimplePartLoader/Utils/ModUtils_Snapshoter.cs new file mode 100644 index 0000000..9f47124 --- /dev/null +++ b/SimplePartLoader/Utils/ModUtils_Snapshoter.cs @@ -0,0 +1,73 @@ +using PaintIn3D; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace SimplePartLoader.Utils +{ + internal class ModUtils_Snapshoter : MonoBehaviour + { + Vector3 defaultPosition = new Vector3(-0.6f, -0.6f, -0.6f); + Vector3 rotatedPosition = new Vector3(0.6f, -0.6f, 0.6f); + void Start() + { + RuntimePreviewGenerator.BackgroundColor = new Color(0f, 0f, 0f, 0f); + Sprite s = null; + + if(!Directory.Exists("./Mods/ModUtilsThumbnails")) + { + Directory.CreateDirectory("./Mods/ModUtilsThumbnails"); + } + + GameObject matParent = GameObject.Find("MaterialParent"); + + foreach (Part p in PartManager.modLoadedParts) + { + if (p.Mod == null) + { + continue; + } + + if(p.Mod.Thumbnails) + { + GameObject instanciated = GameObject.Instantiate(p.Prefab); + if (instanciated.GetComponent() && instanciated.GetComponent().Paintable) + { + instanciated.GetComponent().Color = Color.gray; + instanciated.GetComponent().Activate(); + } + + if(instanciated.GetComponent().Interior) + { + instanciated.GetComponent().material = matParent.GetComponent().Interior1; + } + + foreach (var a in instanciated.GetComponentsInChildren()) + { + GameObject.DestroyImmediate(a.gameObject); + } + foreach (var a in instanciated.GetComponentsInChildren()) + { + GameObject.DestroyImmediate(a.gameObject); + } + foreach (var a in instanciated.GetComponentsInChildren()) + { + GameObject.DestroyImmediate(a.gameObject); + } + foreach (var a in instanciated.GetComponentsInChildren()) + { + GameObject.DestroyImmediate(a.gameObject); + } + + RuntimePreviewGenerator.PreviewDirection = p.RotateThumbnail ? rotatedPosition : defaultPosition; + s = Sprite.Create(RuntimePreviewGenerator.GenerateModelPreview(instanciated.transform, 500, 500, false), new Rect(0f, 0f, 500f, 500f), new Vector2(0.5f, 0.5f), 100f); + SnapshotCamera.SavePNG(s.texture, p.CarProps.PrefabName + ".png", "./Mods/ModUtilsThumbnails/"); + } + } + } + } +} From c338a8083fbfd94e4e95b3c3052eedf796c0ac84 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Sun, 2 Oct 2022 01:45:50 -0300 Subject: [PATCH 16/23] fix: HQ paint was not accounted on single material paint support --- SimplePartLoader/ModUtils/PaintingSystem.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index eb05d0d..da29099 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -45,6 +45,8 @@ internal static void EnablePaintOnly(Part part, int materialIndex) Prefab.AddComponent().Index = materialIndex; + CheckHighResolutionPaint(part, paintableTexture); + part.CarProps.Paintable = true; part.Paintable = true; } From 469c2a2804df1627f9461b288b5a94bbbbf441e1 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Sun, 2 Oct 2022 02:02:38 -0300 Subject: [PATCH 17/23] tweak: more precise behaviour when copying materials from dummy on prefab generator --- SimplePartLoader/ModMain.cs | 2 +- SimplePartLoader/PartManager.cs | 18 +++++++++++++++++- SimplePartLoader/Utils/KeepAlive.cs | 1 - 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index 70b767f..dc924a4 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -21,7 +21,7 @@ public class ModMain : Mod public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; - string TESTING_VERSION_NUMBER = "1.2-beta7"; + string TESTING_VERSION_NUMBER = "1.2-rc1"; public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index f0a6ebd..5024eb8 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -492,8 +492,24 @@ internal static void LoadPrefabGeneratorParts() switch (data.UseMaterialsFrom) { case PrefabGenerator.MaterialSettingTypes.DummyOriginal: - part.GetComponent().materials = part.GetDummyOriginal().GetComponent().materials; + Material[] dummyMats = part.GetDummyOriginal().GetComponent().materials; + if (dummyMats.Length == part.Renderer.materials.Length) + part.Renderer.materials = dummyMats; + else if (dummyMats.Length < part.Renderer.materials.Length) + { + Material[] newMats = part.Renderer.materials; + for (int i = 0; i < dummyMats.Length; i++) + newMats[i] = dummyMats[i]; + + part.Renderer.materials = newMats; + } + else + { + Debug.Log($"[ModUtils/PaintingSystem/Error]: {part.Prefab} prefab has {part.Renderer.materials.Length} materials but the dummy original has {dummyMats.Length}. This is only a warning, but you should fix it."); + part.Renderer.materials = dummyMats; + } break; + case PrefabGenerator.MaterialSettingTypes.PaintingSetup: PaintingSystem.SetMaterialsForObject(part, 2, 0, 1); part.EnablePartPainting(PaintingSystem.Types.FullPaintingSupport); diff --git a/SimplePartLoader/Utils/KeepAlive.cs b/SimplePartLoader/Utils/KeepAlive.cs index f53718b..89ea774 100644 --- a/SimplePartLoader/Utils/KeepAlive.cs +++ b/SimplePartLoader/Utils/KeepAlive.cs @@ -45,7 +45,6 @@ private KeepAlive() private async void SendCurrentStatus() { - // TODO: Test this! Debug.Log("[ModUtils/KeepAlive]: Sending status"); try { From b1c07bf66db3485e20c94b9ca3f01dd17c45b974 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Tue, 4 Oct 2022 01:08:48 -0300 Subject: [PATCH 18/23] tweak!: changed paint resolution setting --- .../ModUtils/ModObjects/ModInstance.cs | 10 +++++- .../ModUtils/ModObjects/ModSettings.cs | 8 ++--- SimplePartLoader/ModUtils/PaintingSystem.cs | 34 ++++++++++++------- SimplePartLoader/Utils/Functions.cs | 29 ++++++++++++++++ SimplePartLoader/Utils/ModUtils_Snapshoter.cs | 5 --- 5 files changed, 64 insertions(+), 22 deletions(-) diff --git a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs index bf49de6..02c037a 100644 --- a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs @@ -19,6 +19,8 @@ public class ModInstance internal bool RequiresSteamCheck = false; internal bool Checked = false; + + internal bool CheckedAndAllowed = false; internal bool Thumbnails = false; @@ -48,6 +50,11 @@ public string Name { get { return Mod.Name; } } + + public bool CheckAllow + { + get { return CheckedAndAllowed; } + } internal ModInstance(Mod mod) { @@ -220,7 +227,8 @@ internal async void Check(ulong SteamID) if (contents == "true") allowed = true; - + + CheckedAndAllowed = allowed; Checked = true; } catch(Exception ex) diff --git a/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs b/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs index d387cde..e78e633 100644 --- a/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs @@ -13,7 +13,7 @@ public class ModSettings private bool Immediate = false; private bool Cloning = true; private bool CullShader = false; - private bool BetterPaint = false; + private PaintingSystem.PartPaintResolution PaintRes = PaintingSystem.PartPaintResolution.Low; private string[] FitsToCar; public ModInstance Mod @@ -45,10 +45,10 @@ public string[] AutomaticFitsToCar set { FitsToCar = value; } } - public bool HighPaintResolution + public PaintingSystem.PartPaintResolution PaintResolution { - get { return BetterPaint; } - set { BetterPaint = value; } + get { return PaintRes; } + set { PaintRes = value; } } public bool UseBackfaceShader diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index da29099..f79182d 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -25,6 +25,13 @@ public enum Types OnlyPaintAndDirt } + public enum PartPaintResolution + { + Low = 1, + Medium = 2, + High = 3 + } + internal static void EnablePaintOnly(Part part, int materialIndex) { GameObject Prefab = part.Prefab; @@ -93,8 +100,7 @@ internal static void EnablePaintOnly(Part part, int materialIndex) counter_colorMap.PaintableTexture = paintableTexture_colorMap; counter_colorMap.Threshold = 0.1f; - counter_colorMap.enabled = false; - counter_colorMap.DownsampleSteps = 5; + counter_colorMap.enabled = false; CheckHighResolutionPaint(part, paintableTexture_colorMap); @@ -169,12 +175,10 @@ internal static void EnablePaintAndRust(Part part) counter_rust.Threshold = 0.5f; counter_rust.enabled = false; counter_rust.Color = new Color(0, 0, 0, 1f); - counter_rust.DownsampleSteps = 5; counter_colorMap.PaintableTexture = paintableTexture_colorMap; counter_colorMap.Threshold = 0.1f; counter_colorMap.enabled = false; - counter_colorMap.DownsampleSteps = 5; CheckHighResolutionPaint(part, paintableTexture_colorMap); @@ -235,7 +239,6 @@ internal static void EnableDirtOnly(Part part) counter_dirt.Threshold = 0.7f; counter_dirt.enabled = false; counter_dirt.Color = new Color(0.219f, 0.219f, 0.219f, 0f); - counter_dirt.DownsampleSteps = 5; // Final details part.CarProps.Washable = true; @@ -319,7 +322,7 @@ internal static void EnableFullSupport(Part part) paintableTexture_rust.Slot = p3dSlot_rustDirt; paintableTexture_rust.Group = 100; - + paintableTexture_dirt.Slot = p3dSlot_dirt; paintableTexture_dirt.Group = 5; @@ -328,18 +331,15 @@ internal static void EnableFullSupport(Part part) counter_rust.Threshold = 0.5f; counter_rust.enabled = false; counter_rust.Color = new Color(0, 0, 0, 1f); - counter_rust.DownsampleSteps = 5; counter_colorMap.PaintableTexture = paintableTexture_colorMap; counter_colorMap.Threshold = 0.1f; counter_colorMap.enabled = false; - counter_colorMap.DownsampleSteps = 5; counter_dirt.PaintableTexture = paintableTexture_dirt; counter_dirt.Threshold = 0.7f; counter_dirt.enabled = false; counter_dirt.Color = new Color(0.219f, 0.219f, 0.219f, 0f); - counter_dirt.DownsampleSteps = 5; CheckHighResolutionPaint(part, paintableTexture_colorMap); @@ -438,10 +438,20 @@ public static void CheckHighResolutionPaint(Part p, P3dPaintableTexture texture) { if(p.Mod != null) { - if(p.Mod.Settings.HighPaintResolution) + switch(p.Mod.Settings.PaintResolution) { - texture.Width = 1024; - texture.Height = 1024; + case PartPaintResolution.High: + texture.Width = 2048; + texture.Height = 2048; + break; + case PartPaintResolution.Medium: + texture.Width = 1024; + texture.Height = 1024; + break; + case PartPaintResolution.Low: + texture.Width = 512; + texture.Height = 512; + break; } } } diff --git a/SimplePartLoader/Utils/Functions.cs b/SimplePartLoader/Utils/Functions.cs index 036d904..7bdf67f 100644 --- a/SimplePartLoader/Utils/Functions.cs +++ b/SimplePartLoader/Utils/Functions.cs @@ -281,5 +281,34 @@ public static void BoltingSetup(GameObject prefab) wc.gameObject.AddComponent().convex = true; } } + + public static void RemoveDisplacementFromBolts(Part p) + { + CarProperties cp = null; + foreach(var a in p.Prefab.GetComponentsInChildren()) + { + cp = a.GetComponent(); + if (cp) + cp.DMGdisplacepart = false; + } + foreach (var a in p.Prefab.GetComponentsInChildren()) + { + cp = a.GetComponent(); + if (cp) + cp.DMGdisplacepart = false; + } + foreach (var a in p.Prefab.GetComponentsInChildren()) + { + cp = a.GetComponent(); + if (cp) + cp.DMGdisplacepart = false; + } + foreach (var a in p.Prefab.GetComponentsInChildren()) + { + cp = a.GetComponent(); + if (cp) + cp.DMGdisplacepart = false; + } + } } } diff --git a/SimplePartLoader/Utils/ModUtils_Snapshoter.cs b/SimplePartLoader/Utils/ModUtils_Snapshoter.cs index 9f47124..4879fa3 100644 --- a/SimplePartLoader/Utils/ModUtils_Snapshoter.cs +++ b/SimplePartLoader/Utils/ModUtils_Snapshoter.cs @@ -41,11 +41,6 @@ void Start() instanciated.GetComponent().Activate(); } - if(instanciated.GetComponent().Interior) - { - instanciated.GetComponent().material = matParent.GetComponent().Interior1; - } - foreach (var a in instanciated.GetComponentsInChildren()) { GameObject.DestroyImmediate(a.gameObject); From 3f0e02bfab64285aca7e89085475e5960bfbe9f4 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Tue, 4 Oct 2022 01:12:33 -0300 Subject: [PATCH 19/23] tweak: now marked bolts force game to use bolts if dummy uses prytool / hand attachment --- SimplePartLoader/PartManager.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index 5024eb8..ce42907 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -582,6 +582,23 @@ internal static void LoadPrefabGeneratorParts() foreach (MarkAsBoltnut mbn in part.Prefab.GetComponentsInChildren()) Functions.ConvertToBoltNut(mbn.gameObject); + // Also, we make the part actually use bolts + part.Prefab.layer = LayerMask.NameToLayer("Ignore Raycast"); + part.Prefab.tag = "Untagged"; + + Pickup prefabPickup = part.Prefab.AddComponent(); + prefabPickup.canHold = true; + prefabPickup.tempParent = GameObject.Find("hand"); + prefabPickup.SphereCOl = GameObject.Find("SphereCollider"); + + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); + + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); + + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); break; } } From 7c757bdad438b2cb05d147c8f5e8dbb8ec7c637d Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Wed, 5 Oct 2022 18:39:10 -0300 Subject: [PATCH 20/23] tweak: new settings for mods --- SimplePartLoader/ModMain.cs | 2 +- SimplePartLoader/ModUtils.csproj | 1 + .../ModUtils/ModObjects/ModInstance.cs | 5 ++ .../ModUtils/ModObjects/ModSettings.cs | 8 ++- SimplePartLoader/ModUtils/ModUtils.cs | 12 ++++ SimplePartLoader/ModUtils/PaintingSystem.cs | 13 +++- .../Objects/EditorComponents/OriginalMesh.cs | 12 ++++ .../EditorComponents/PrefabGenerator.cs | 3 +- SimplePartLoader/PartManager.cs | 63 +++++++++++++++---- SimplePartLoader/SPL.cs | 5 ++ 10 files changed, 107 insertions(+), 17 deletions(-) create mode 100644 SimplePartLoader/Objects/EditorComponents/OriginalMesh.cs diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index dc924a4..055ed51 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -21,7 +21,7 @@ public class ModMain : Mod public override string Version => "v1.1.0"; bool TESTING_VERSION_REMEMBER = true; - string TESTING_VERSION_NUMBER = "1.2-rc1"; + string TESTING_VERSION_NUMBER = "1.2-rc3"; public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; diff --git a/SimplePartLoader/ModUtils.csproj b/SimplePartLoader/ModUtils.csproj index 9e6d75e..73dee1b 100644 --- a/SimplePartLoader/ModUtils.csproj +++ b/SimplePartLoader/ModUtils.csproj @@ -463,6 +463,7 @@ + diff --git a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs index 02c037a..0bc43b7 100644 --- a/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModInstance.cs @@ -123,6 +123,11 @@ public Part Load(AssetBundle bundle, string prefabName) part.PartInfo.FitsToCar = part.Mod.Settings.AutomaticFitsToCar; } + if (part.Mod.Settings.AutomaticFitsToEngine != null) + { + part.PartInfo.FitsToEngine = part.Mod.Settings.AutomaticFitsToEngine; + } + Debug.Log($"[ModUtils/SPL]: Succesfully loaded part (full part) {prefabName} from {thisMod.Name}"); return part; // We provide the Part instance so the developer can setup the transparents } diff --git a/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs b/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs index e78e633..d28c7e2 100644 --- a/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs +++ b/SimplePartLoader/ModUtils/ModObjects/ModSettings.cs @@ -15,6 +15,7 @@ public class ModSettings private bool CullShader = false; private PaintingSystem.PartPaintResolution PaintRes = PaintingSystem.PartPaintResolution.Low; private string[] FitsToCar; + private string[] FitsToEngine; public ModInstance Mod { @@ -44,7 +45,12 @@ public string[] AutomaticFitsToCar get { return FitsToCar; } set { FitsToCar = value; } } - + public string[] AutomaticFitsToEngine + { + get { return FitsToEngine; } + set { FitsToEngine = value; } + } + public PaintingSystem.PartPaintResolution PaintResolution { get { return PaintRes; } diff --git a/SimplePartLoader/ModUtils/ModUtils.cs b/SimplePartLoader/ModUtils/ModUtils.cs index 75ea4f7..1dabd90 100644 --- a/SimplePartLoader/ModUtils/ModUtils.cs +++ b/SimplePartLoader/ModUtils/ModUtils.cs @@ -207,5 +207,17 @@ public static ModInstance RegisterMod(Mod mod) RegisteredMods.Add(modInstance); return modInstance; } + + public static void RegisterEngineCategory(string name) + { + if (!PartManager.EngineCategoriesToAdd.Contains(name)) + PartManager.EngineCategoriesToAdd.Add(name); + } + + public static void RegisterCarCategory(string name) + { + if (!PartManager.CarCategoriesToAdd.Contains(name)) + PartManager.CarCategoriesToAdd.Add(name); + } } } diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index f79182d..f78809d 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -290,6 +290,14 @@ internal static void EnableFullSupport(Part part) return; } + // Check for original mesh + OriginalMesh orMesh = Prefab.GetComponent(); + Mesh meshToUse = null; + if(orMesh) + { + meshToUse = orMesh.Mesh; + } + // Now we create our painting components. P3dMaterialCloner materialCloner_l2 = Prefab.AddComponent(); P3dMaterialCloner materialCloner_paint = Prefab.AddComponent(); @@ -331,15 +339,18 @@ internal static void EnableFullSupport(Part part) counter_rust.Threshold = 0.5f; counter_rust.enabled = false; counter_rust.Color = new Color(0, 0, 0, 1f); + counter_rust.MaskMesh = meshToUse; counter_colorMap.PaintableTexture = paintableTexture_colorMap; counter_colorMap.Threshold = 0.1f; counter_colorMap.enabled = false; - + counter_colorMap.MaskMesh = meshToUse; + counter_dirt.PaintableTexture = paintableTexture_dirt; counter_dirt.Threshold = 0.7f; counter_dirt.enabled = false; counter_dirt.Color = new Color(0.219f, 0.219f, 0.219f, 0f); + counter_dirt.MaskMesh = meshToUse; CheckHighResolutionPaint(part, paintableTexture_colorMap); diff --git a/SimplePartLoader/Objects/EditorComponents/OriginalMesh.cs b/SimplePartLoader/Objects/EditorComponents/OriginalMesh.cs new file mode 100644 index 0000000..3f29694 --- /dev/null +++ b/SimplePartLoader/Objects/EditorComponents/OriginalMesh.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +public class OriginalMesh : MonoBehaviour +{ + [Tooltip("Non-fixed seams version of the mesh")] + public Mesh Mesh = null; +} diff --git a/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs b/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs index 4d8703d..0a08573 100644 --- a/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs +++ b/SimplePartLoader/Objects/EditorComponents/PrefabGenerator.cs @@ -44,7 +44,8 @@ public enum AttachmentTypes Default, Prytool, Hand, - UseMarkedBolts + UseMarkedBolts, + ForceUseMarkedBolts } public enum MaterialSettingTypes diff --git a/SimplePartLoader/PartManager.cs b/SimplePartLoader/PartManager.cs index ce42907..465d4aa 100644 --- a/SimplePartLoader/PartManager.cs +++ b/SimplePartLoader/PartManager.cs @@ -40,6 +40,9 @@ public class PartManager internal static bool ThumbnailGeneratorEnabled = false; + internal static List CarCategoriesToAdd = new List(); + + internal static List EngineCategoriesToAdd = new List(); /// /// Handles the OnLoad function when called. /// @@ -252,6 +255,26 @@ internal static void OnLoadCalled() PictureTake.AddComponent(); } + // Load custom categories + if(CarCategoriesToAdd.Count != 0 || EngineCategoriesToAdd.Count != 0) + { + CatalogueManager catalog = Resources.FindObjectsOfTypeAll().First(); + + foreach (string s in CarCategoriesToAdd) + { + TMPro.TMP_Dropdown.OptionData newItem = new TMPro.TMP_Dropdown.OptionData(); + newItem.text = s; + catalog.CarDropdown.options.Add(newItem); + } + + foreach (string s in EngineCategoriesToAdd) + { + TMPro.TMP_Dropdown.OptionData newItem = new TMPro.TMP_Dropdown.OptionData(); + newItem.text = s; + catalog.EngineDropdown.options.Add(newItem); + } + } + SPL.InvokeLoadFinishedEvent(); } @@ -546,6 +569,7 @@ internal static void LoadPrefabGeneratorParts() part.UseHandAttachment(); break; + case PrefabGenerator.AttachmentTypes.ForceUseMarkedBolts: case PrefabGenerator.AttachmentTypes.UseMarkedBolts: { // We first remove all the FlatNut / HexNut / BoltNut on our part. @@ -583,22 +607,35 @@ internal static void LoadPrefabGeneratorParts() Functions.ConvertToBoltNut(mbn.gameObject); // Also, we make the part actually use bolts - part.Prefab.layer = LayerMask.NameToLayer("Ignore Raycast"); - part.Prefab.tag = "Untagged"; - - Pickup prefabPickup = part.Prefab.AddComponent(); - prefabPickup.canHold = true; - prefabPickup.tempParent = GameObject.Find("hand"); - prefabPickup.SphereCOl = GameObject.Find("SphereCollider"); + if(data.AttachmentType == PrefabGenerator.AttachmentTypes.ForceUseMarkedBolts) + { + part.Prefab.layer = LayerMask.NameToLayer("Ignore Raycast"); + part.Prefab.tag = "Untagged"; + + Pickup prefabPickup = part.Prefab.AddComponent(); + prefabPickup.canHold = true; + prefabPickup.tempParent = GameObject.Find("hand"); + prefabPickup.SphereCOl = GameObject.Find("SphereCollider"); + + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); - if (part.Prefab.GetComponent()) - DestroyConsideringSetting(part, part.Prefab.GetComponent()); + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); - if (part.Prefab.GetComponent()) - DestroyConsideringSetting(part, part.Prefab.GetComponent()); + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); + + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); + + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); + + if (part.Prefab.GetComponent()) + DestroyConsideringSetting(part, part.Prefab.GetComponent()); + } - if (part.Prefab.GetComponent()) - DestroyConsideringSetting(part, part.Prefab.GetComponent()); break; } } diff --git a/SimplePartLoader/SPL.cs b/SimplePartLoader/SPL.cs index 410a05c..11c5856 100644 --- a/SimplePartLoader/SPL.cs +++ b/SimplePartLoader/SPL.cs @@ -277,6 +277,11 @@ public static void CopyPartToPrefab(Part p, string partName, bool ignoreBuiltin { p.PartInfo.FitsToCar = p.Mod.Settings.AutomaticFitsToCar; } + + if (p.Mod.Settings.AutomaticFitsToEngine != null) + { + p.PartInfo.FitsToEngine = p.Mod.Settings.AutomaticFitsToEngine; + } } p.OriginalGameobject = carPart; From 9d5012d6a2f1f7f95b28b22e0459d4aa1eb4b9da Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Thu, 6 Oct 2022 01:32:58 -0300 Subject: [PATCH 21/23] fix: removed old debug message --- SimplePartLoader/ModUtils/PaintingSystem.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index f78809d..266f464 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -31,7 +31,7 @@ public enum PartPaintResolution Medium = 2, High = 3 } - + internal static void EnablePaintOnly(Part part, int materialIndex) { GameObject Prefab = part.Prefab; @@ -534,7 +534,6 @@ public static Material GetBodymatMaterial(bool useBackfaceShader = false) } } - Debug.Log("GET DOYMAT MATERIAL: " + BaseMaterial + " " + useBackfaceShader + " .. " + CullBaseMaterial); if (!BaseMaterial) { Debug.LogError("[ModUtils/PaintingSystem/Error]: GetBodymatMaterial was not able to retrive the body material. Make sure you are using it on FirstLoad event."); From bbe450ffccb936bd0afddd56d5bf1795d27aea83 Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Thu, 6 Oct 2022 15:13:13 -0300 Subject: [PATCH 22/23] tweak: bump version to 1.2 --- SimplePartLoader/ModMain.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SimplePartLoader/ModMain.cs b/SimplePartLoader/ModMain.cs index 055ed51..50b1358 100644 --- a/SimplePartLoader/ModMain.cs +++ b/SimplePartLoader/ModMain.cs @@ -18,9 +18,9 @@ public class ModMain : Mod public override string ID => "ModUtils"; public override string Name => "ModUtils"; public override string Author => "Federico Arredondo"; - public override string Version => "v1.1.0"; + public override string Version => "v1.2.0"; - bool TESTING_VERSION_REMEMBER = true; + bool TESTING_VERSION_REMEMBER = false; string TESTING_VERSION_NUMBER = "1.2-rc3"; public override byte[] Icon => Properties.Resources.SimplePartLoaderIcon; From 6e3b8b7361677f9bc580e8ac196d09bc1e332ced Mon Sep 17 00:00:00 2001 From: Federico Arredondo Date: Thu, 6 Oct 2022 15:28:34 -0300 Subject: [PATCH 23/23] fix: hacky-way to add painting had wrong default color --- SimplePartLoader/ModUtils/PaintingSystem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/SimplePartLoader/ModUtils/PaintingSystem.cs b/SimplePartLoader/ModUtils/PaintingSystem.cs index 266f464..1925922 100644 --- a/SimplePartLoader/ModUtils/PaintingSystem.cs +++ b/SimplePartLoader/ModUtils/PaintingSystem.cs @@ -47,6 +47,7 @@ internal static void EnablePaintOnly(Part part, int materialIndex) Prefab.AddComponent(); P3dPaintableTexture paintableTexture = Prefab.AddComponent(); + paintableTexture.Color = Color.gray; paintableTexture.Slot = new P3dSlot(materialIndex, "_MainTex"); paintableTexture.UpdateMaterial();