public void AddSkin(GameObject gameObject, string SkinFolder, ConfigFile config) { LoadoutAPI.SkinDefInfo skinDefInfo = new LoadoutAPI.SkinDefInfo(); skinDefInfo.BaseSkins = new SkinDef[0]; skinDefInfo.Icon = LoadoutAPI.CreateSkinIcon(config.Bind <Color>("", "IconColorTop", Color.magenta).Value, config.Bind <Color>("", "IconColorRight", Color.black).Value, config.Bind <Color>("", "IconColorBottom", Color.magenta).Value, config.Bind <Color>("", "IconColorLeft", Color.black).Value); skinDefInfo.NameToken = config.Bind <string>("", "SkinName", "DefaultName").Value; skinDefInfo.UnlockableName = config.Bind <string>("", "UnlockableName", "").Value; skinDefInfo.RootObject = gameObject.GetComponentInChildren <ModelLocator>().modelTransform.gameObject; skinDefInfo.RendererInfos = new CharacterModel.RendererInfo[0]; skinDefInfo.MeshReplacements = new SkinDef.MeshReplacement[0]; skinDefInfo.GameObjectActivations = new SkinDef.GameObjectActivation[0]; skinDefInfo.Name = "CUSTOM_" + gameObject.name + "_SKIN"; base.Logger.LogInfo("Adding new skin to " + gameObject.name + " with name " + skinDefInfo.NameToken); int MeshReplacementIndex = config.Bind <int>("", "MeshReplacementIndex", -1).Value; string MeshReplacementKey = config.Bind <string>("", "SkinMeshToUse", "Default").Value; string minionSkinForBody = config.Bind <string>("", "MinionReplacementForBody", "NONE", new ConfigDescription("If this is a minion skin, determines the characterbody for it")).Value; string minionSkinForSkin = config.Bind <string>("", "MinionReplacementForSkin", "NONE", new ConfigDescription("If this is a minion skin, determines the characterbody for it")).Value; bool isMinionSkin = false; if (minionSkinForBody != null) { isMinionSkin = minionSkinForBody != "NONE"; } if (MeshReplacementKey != "Default" && MeshReplacementKey != "Custom" && MeshReplacementKey != null) { SkinDef def1 = gameObject.GetComponentInChildren <ModelLocator>().modelTransform.GetComponentInChildren <ModelSkinController>().skins.First(x => x.nameToken == MeshReplacementKey); MeshReplacementIndex = Array.IndexOf(gameObject.GetComponentInChildren <ModelLocator>().modelTransform.GetComponentInChildren <ModelSkinController>().skins, def1); } SkinDef def = gameObject.GetComponentInChildren <ModelLocator>().modelTransform.GetComponentInChildren <ModelSkinController>().skins[MeshReplacementIndex]; if (def) { skinDefInfo.MeshReplacements = def.meshReplacements; skinDefInfo.RendererInfos = def.rendererInfos; } CharacterModel.RendererInfo[] rendererInfos = skinDefInfo.RendererInfos; CharacterModel.RendererInfo[] array = new CharacterModel.RendererInfo[rendererInfos.Length]; rendererInfos.CopyTo(array, 0); foreach (string MaterialFolder in Directory.EnumerateDirectories(SkinFolder)) { //Get name of render from folder name string[] MaterialIndexVs = MaterialFolder.Split(new string[] { @"\" }, StringSplitOptions.None); string RendererName = MaterialIndexVs[MaterialIndexVs.Length - 1]; //Find the renderer based on the name int index = Array.IndexOf(array, array.FirstOrDefault(x => x.renderer.name == RendererName)); //Get the material of the renderer Material defaultMaterial = array[index].defaultMaterial; if (defaultMaterial) { //Create a clone of the material defaultMaterial = UnityEngine.Object.Instantiate <Material>(defaultMaterial); //Iterate through all files related to this material from the skin folder foreach (string FilePath in Directory.EnumerateFiles(MaterialFolder)) { //Loading and applying textures from .png if (FilePath.EndsWith(".PNG") || FilePath.EndsWith(".png")) { //Use File name to get texture name string[] FilePathVs = FilePath.Split(new string[] { @"\" }, StringSplitOptions.None); string FileName = FilePathVs[FilePathVs.Length - 1].Replace(".PNG", ""); //Create new Texture2d and load image in Texture2D savedTex = new Texture2D(1, 1, TextureFormat.RGBAFloat, false, true); ImageConversion.LoadImage(savedTex, System.IO.File.ReadAllBytes(FilePath)); //Apply the loaded image savedTex.Apply(); //Attempt to place this image onto the material in the correct property if (defaultMaterial.HasProperty(FileName)) { defaultMaterial.enableInstancing = true; defaultMaterial.SetTexture(FileName, GetReadableTextureCopy(savedTex)); } } else if (FilePath.EndsWith(".cfg")) { //Load the config at this path BepInEx.Configuration.ConfigFile perMatConfig = new ConfigFile(FilePath, true); //iterate through material properties and apply via config foreach (string value in floatProperties) { if (defaultMaterial.HasProperty(value)) { defaultMaterial.SetFloat(value, perMatConfig.Bind <float>("", value, defaultMaterial.GetFloat(value), new ConfigDescription("Sets the value for " + value)).Value); } } foreach (string value in colorProperties) { if (defaultMaterial.HasProperty(value)) { defaultMaterial.SetColor(value, perMatConfig.Bind <Color>("", value, defaultMaterial.GetColor(value), new ConfigDescription("Sets the value for " + value)).Value); } } foreach (string value in defaultMaterial.shaderKeywords) { bool isEnabled = perMatConfig.Bind <bool>("", value, defaultMaterial.IsKeywordEnabled(value), new ConfigDescription("Sets the value for " + value)).Value; if (isEnabled) { defaultMaterial.EnableKeyword(value); } else { defaultMaterial.DisableKeyword(value); } } } else { base.Logger.LogError("Unsupported file found in material folder: " + FilePath); } } array[index].defaultMaterial = defaultMaterial; } } skinDefInfo.RendererInfos = array; LoadoutAPI.AddSkinToCharacter(gameObject, skinDefInfo); SkinDef[] skins = gameObject.GetComponentInChildren <ModelLocator>().modelTransform.GetComponentInChildren <ModelSkinController>().skins; skins[skins.Length - 1].minionSkinReplacements = new SkinDef.MinionSkinReplacement[0]; skins[skins.Length - 1].projectileGhostReplacements = new SkinDef.ProjectileGhostReplacement[0]; if (isMinionSkin) { base.Logger.LogInfo("Is a minion skin"); foreach (GameObject body in BodyCatalog.allBodyPrefabs) { if (body.name == minionSkinForBody) { base.Logger.LogInfo("Applying minionskinreplacement"); SkinDef defForMaster = body.GetComponentInChildren <ModelSkinController>().skins.First(x => x.nameToken == minionSkinForSkin); base.Logger.LogInfo("Size was " + defForMaster.minionSkinReplacements.Length); Array.Resize(ref defForMaster.minionSkinReplacements, defForMaster.minionSkinReplacements.Length + 1); defForMaster.minionSkinReplacements[defForMaster.minionSkinReplacements.Length - 1] = new SkinDef.MinionSkinReplacement() { minionBodyPrefab = gameObject, minionSkin = skins[skins.Length - 1] }; base.Logger.LogInfo("Size is now " + defForMaster.minionSkinReplacements.Length); } } } SkinDef[][] newSkins = typeof(BodyCatalog).GetFieldValue <SkinDef[][]>("skins"); newSkins[BodyCatalog.FindBodyIndex(gameObject)] = skins; typeof(BodyCatalog).SetFieldValue <SkinDef[][]>("skins", newSkins); }
public void AddSkin(SurvivorDef def, string SkinFolder, ConfigFile config) { GameObject gameObject = def.bodyPrefab; LoadoutAPI.SkinDefInfo skinDefInfo = new LoadoutAPI.SkinDefInfo(); skinDefInfo.BaseSkins = new SkinDef[0]; skinDefInfo.Icon = LoadoutAPI.CreateSkinIcon(config.Bind <Color>("", "IconColorTop", Color.magenta).Value, config.Bind <Color>("", "IconColorRight", Color.black).Value, config.Bind <Color>("", "IconColorBottom", Color.magenta).Value, config.Bind <Color>("", "IconColorLeft", Color.black).Value); skinDefInfo.NameToken = config.Bind <string>("", "SkinName", "DefaultName").Value; skinDefInfo.UnlockableName = config.Bind <string>("", "UnlockableName", "").Value; skinDefInfo.RootObject = def.bodyPrefab.GetComponent <ModelLocator>().modelTransform.gameObject; skinDefInfo.RendererInfos = new CharacterModel.RendererInfo[0]; skinDefInfo.MeshReplacements = new SkinDef.MeshReplacement[0]; skinDefInfo.GameObjectActivations = new SkinDef.GameObjectActivation[0]; skinDefInfo.Name = "SKIN_" + gameObject.name + "_DEFAULT"; int MeshReplacementIndex = config.Bind <int>("", "MeshReplacementIndex", 0).Value; if (MeshReplacementIndex != -1) { skinDefInfo.MeshReplacements = gameObject.GetComponent <ModelLocator>().modelTransform.GetComponent <ModelSkinController>().skins[MeshReplacementIndex].meshReplacements; skinDefInfo.RendererInfos = gameObject.GetComponent <ModelLocator>().modelTransform.GetComponent <ModelSkinController>().skins[MeshReplacementIndex].rendererInfos; } CharacterModel.RendererInfo[] rendererInfos = skinDefInfo.RendererInfos; CharacterModel.RendererInfo[] array = new CharacterModel.RendererInfo[rendererInfos.Length]; rendererInfos.CopyTo(array, 0); foreach (string MaterialFolder in Directory.EnumerateDirectories(SkinFolder)) { string[] MaterialIndexVs = MaterialFolder.Split(new string[] { @"\" }, StringSplitOptions.None); string RendererName = MaterialIndexVs[MaterialIndexVs.Length - 1]; int index = Array.IndexOf(array, array.FirstOrDefault(x => x.renderer.name == RendererName)); Material defaultMaterial = array[index].defaultMaterial; if (defaultMaterial) { defaultMaterial = UnityEngine.Object.Instantiate <Material>(defaultMaterial); foreach (string FilePath in Directory.EnumerateFiles(MaterialFolder)) { if (FilePath.EndsWith(".PNG") || FilePath.EndsWith(".png")) { string[] FilePathVs = FilePath.Split(new string[] { @"\" }, StringSplitOptions.None); string FileName = FilePathVs[FilePathVs.Length - 1].Replace(".PNG", ""); Texture2D savedTex = new Texture2D(1, 1, TextureFormat.RGBAFloat, false, true); ImageConversion.LoadImage(savedTex, System.IO.File.ReadAllBytes(FilePath)); savedTex.Apply(); if (defaultMaterial.HasProperty(FileName)) { defaultMaterial.enableInstancing = true; defaultMaterial.SetTexture(FileName, GetReadableTextureCopy(savedTex)); } } else if (FilePath.EndsWith(".cfg")) { string[] ConfigPathVs = FilePath.Split(new string[] { @"\" }, StringSplitOptions.None); string ConfigName = @"BepInEx\skins\" + ConfigPathVs[ConfigPathVs.Length - 4] + @"\" + ConfigPathVs[ConfigPathVs.Length - 3] + @"\" + ConfigPathVs[ConfigPathVs.Length - 2] + @"\" + ConfigPathVs[ConfigPathVs.Length - 1]; BepInEx.Configuration.ConfigFile perMatConfig = new ConfigFile(ConfigName, true); { foreach (string value in floatProperties) { if (defaultMaterial.HasProperty(value)) { defaultMaterial.SetFloat(value, perMatConfig.Bind <float>("", value, defaultMaterial.GetFloat(value), new ConfigDescription("Sets the value for " + value)).Value); } } foreach (string value in colorProperties) { if (defaultMaterial.HasProperty(value)) { defaultMaterial.SetColor(value, perMatConfig.Bind <Color>("", value, defaultMaterial.GetColor(value), new ConfigDescription("Sets the value for " + value)).Value); } } foreach (string value in defaultMaterial.shaderKeywords) { bool isEnabled = perMatConfig.Bind <bool>("", value, defaultMaterial.IsKeywordEnabled(value), new ConfigDescription("Sets the value for " + value)).Value; if (isEnabled) { defaultMaterial.EnableKeyword(value); } else { defaultMaterial.DisableKeyword(value); } } } } else if (FilePath.EndsWith(".obj")) { Mesh holderMesh = new Mesh(); ObjImporter newMesh = new ObjImporter(); holderMesh = newMesh.ImportFile(FilePath); if (array[index].renderer.gameObject.GetComponent <MeshFilter>()) { Array.Resize(ref skinDefInfo.MeshReplacements, skinDefInfo.MeshReplacements.Length + 1); skinDefInfo.MeshReplacements[skinDefInfo.MeshReplacements.Length - 1].mesh = holderMesh; skinDefInfo.MeshReplacements[skinDefInfo.MeshReplacements.Length - 1].renderer = array[index].renderer; (skinDefInfo.MeshReplacements[skinDefInfo.MeshReplacements.Length - 1].renderer as SkinnedMeshRenderer).sharedMesh = holderMesh; } } else { base.Logger.LogError("Unsupported file found in material folder: " + FilePath); } } array[index].defaultMaterial = defaultMaterial; } } base.Logger.LogInfo("Added new skin to " + def.bodyPrefab.name + " with name " + skinDefInfo.NameToken); skinDefInfo.RendererInfos = array; LoadoutAPI.AddSkinToCharacter(def.bodyPrefab, skinDefInfo); SkinDef[] skins = def.bodyPrefab.GetComponent <ModelLocator>().modelTransform.GetComponent <ModelSkinController>().skins; SkinDef[][] newSkins = typeof(BodyCatalog).GetFieldValue <SkinDef[][]>("skins"); newSkins[SurvivorCatalog.GetBodyIndexFromSurvivorIndex(def.survivorIndex)] = skins; typeof(BodyCatalog).SetFieldValue <SkinDef[][]>("skins", newSkins); }