diff --git a/.gitattributes b/.gitattributes index b4225bda..7119a795 100644 --- a/.gitattributes +++ b/.gitattributes @@ -16,4 +16,4 @@ *.rtf diff=astextplain *.RTF diff=astextplain -Source/ export-ignore \ No newline at end of file +Source/ export-ignore diff --git a/1.2/Assemblies/AlienRace.dll b/1.2/Assemblies/AlienRace.dll index 039ed15a..f1d83498 100644 Binary files a/1.2/Assemblies/AlienRace.dll and b/1.2/Assemblies/AlienRace.dll differ diff --git a/1.2/Shader/shader b/1.2/Shader/shader new file mode 100644 index 00000000..d611b674 Binary files /dev/null and b/1.2/Shader/shader differ diff --git a/Source/AlienRace/AlienRace/AlienPartGenerator.BodyAddon.cs b/Source/AlienRace/AlienRace/AlienPartGenerator.BodyAddon.cs index d176fcb4..c476c572 100644 --- a/Source/AlienRace/AlienRace/AlienPartGenerator.BodyAddon.cs +++ b/Source/AlienRace/AlienRace/AlienPartGenerator.BodyAddon.cs @@ -130,19 +130,19 @@ public virtual bool CanDrawAddon(Pawn pawn) => if (variantCounting <= 0) variantCounting = 1; - ExposableValueTuple channel = pawn.GetComp().GetChannel(this.ColorChannel); + ExposableValueTuple channel = pawn.GetComp().GetChannel(this.ColorChannel); int tv; //Log.Message($"{pawn.Name.ToStringFull}\n{channel.first.ToString()} | {pawn.story.hairColor}"); return !returnPath.NullOrEmpty() ? - GraphicDatabase.Get(returnPath += (tv = (savedIndex.HasValue ? (sharedIndex = savedIndex.Value % variantCounting) : + TriColorGraphicDatabase.Get(returnPath += (tv = (savedIndex.HasValue ? (sharedIndex = savedIndex.Value % variantCounting) : (this.linkVariantIndexWithPrevious ? sharedIndex % variantCounting : (sharedIndex = Rand.Range(min: 0, variantCounting))))) == 0 ? "" : tv.ToString(), - ContentFinder.Get(returnPath + "_northm", reportFailure: false) == null ? this.ShaderType.Shader : ShaderDatabase.CutoutComplex, //ShaderDatabase.Transparent, + ContentFinder.Get(returnPath + "_northm", reportFailure: false) == null ? this.ShaderType.Shader : TriColorShaderDatabase.Tricolor, //ShaderDatabase.Transparent, this.drawSize * 1.5f, - channel.first, channel.second, new GraphicData + channel.first, channel.second, channel.third, new GraphicData { drawRotated = !this.drawRotated }) : diff --git a/Source/AlienRace/AlienRace/AlienPartGenerator.cs b/Source/AlienRace/AlienRace/AlienPartGenerator.cs index 41c03063..5d7be1c0 100644 --- a/Source/AlienRace/AlienRace/AlienPartGenerator.cs +++ b/Source/AlienRace/AlienRace/AlienPartGenerator.cs @@ -6,7 +6,8 @@ using Verse; namespace AlienRace -{ +{ + using System.Runtime.ExceptionServices; using System.Text; public partial class AlienPartGenerator @@ -39,20 +40,35 @@ public partial class AlienPartGenerator public string RandomAlienHead(string userpath, Pawn pawn) => GetAlienHead(userpath, (this.useGenderedHeads ? pawn.gender.ToString() : ""), pawn.GetComp().crownType = this.aliencrowntypes[Rand.Range(min: 0, this.aliencrowntypes.Count)]); public static string GetAlienHead(string userpath, string gender, string crowntype) => userpath.NullOrEmpty() ? "" : userpath + (userpath == GraphicPaths.VANILLA_HEAD_PATH ? gender + "/" : "") + (!gender.NullOrEmpty() ? gender + "_" : "") + crowntype; - + public Graphic GetNakedGraphic(BodyTypeDef bodyType, Shader shader, Color skinColor, Color skinColorSecond, string userpath, string gender) => - GraphicDatabase.Get(typeof(Graphic_Multi), GetNakedPath(bodyType, userpath, this.useGenderedBodies ? gender : ""), shader, Vector2.one, + GraphicDatabase.Get(typeof(Graphic_Multi), GetNakedPath(bodyType, userpath, this.useGenderedBodies ? gender : ""), shader, Vector2.one, skinColor, skinColorSecond, data: null, shaderParameters: null); + + // New GetNakedGraphic, gets our new Graphic type + public Graphic GetNakedGraphic(BodyTypeDef bodyType, Shader shader, Color skinColor, Color skinColorSecond, Color skinColorThird, string userpath, string gender) => + TriColorGraphicDatabase.Get(typeof(Graphic_Multi), GetNakedPath(bodyType, userpath, this.useGenderedBodies ? gender : ""), shader, Vector2.one, + skinColor, skinColorSecond, skinColorThird, data: null, shaderParameters: null); //GraphicDatabase.Get(path: GetNakedPath(bodyType: bodyType, userpath: userpath, gender: this.useGenderedBodies ? gender : ""), shader: shader, drawSize: Vector2.one, color: skinColor, colorTwo: skinColorSecond); - + public static string GetNakedPath(BodyTypeDef bodyType, string userpath, string gender) => userpath + (!gender.NullOrEmpty() ? gender + "_" : "") + "Naked_" + bodyType; - public Color SkinColor(Pawn alien, bool first = true) + + // New SkinColor, not really that different. + public Color SkinColor(Pawn alien, int channel = 1) { AlienComp alienComp = alien.TryGetComp(); - ExposableValueTuple skinColors = alienComp.GetChannel(channel: "skin"); - return first ? skinColors.first : skinColors.second; + ExposableValueTuple skinColors = alienComp.GetChannel(channel: "skin"); + switch (channel) + { + default: + return skinColors.first; + case 2: + return skinColors.second; + case 3: + return skinColors.third; + } } public void GenerateMeshsAndMeshPools() @@ -141,11 +157,14 @@ void AddToStringBuilder(string s) Log.Message($"Loaded body addon variants for {this.alienProps.defName}\n{logBuilder}"); } + + // Added third generator public class ColorChannelGenerator { public string name = ""; public ColorGenerator first; public ColorGenerator second; + public ColorGenerator third; } @@ -164,41 +183,44 @@ public class AlienComp : ThingComp public List addonGraphics; public List addonVariants; - private Dictionary> colorChannels; + private Dictionary> colorChannels; - public Dictionary> ColorChannels + public Dictionary> ColorChannels { get { if (this.colorChannels == null || !this.colorChannels.Any()) { - this.colorChannels = new Dictionary>(); + this.colorChannels = new Dictionary>(); Pawn pawn = (Pawn) this.parent; ThingDef_AlienRace alienProps = ((ThingDef_AlienRace) this.parent.def); AlienPartGenerator apg = alienProps.alienRace.generalSettings.alienPartGenerator; - this.colorChannels.Add(key: "base", new ExposableValueTuple(Color.white, Color.white)); - this.colorChannels.Add(key: "hair", new ExposableValueTuple(Color.clear, Color.clear)); + this.colorChannels.Add(key: "base", new ExposableValueTuple(Color.white, Color.white, Color.white)); + this.colorChannels.Add(key: "hair", new ExposableValueTuple(Color.clear, Color.clear, Color.clear)); Color skinColor = PawnSkinColors.GetSkinColor(pawn.story.melanin); - this.colorChannels.Add(key: "skin", new ExposableValueTuple(skinColor, skinColor)); + this.colorChannels.Add(key: "skin", new ExposableValueTuple(skinColor, skinColor, skinColor)); foreach (ColorChannelGenerator channel in apg.colorChannels) { if (!this.colorChannels.ContainsKey(channel.name)) - this.colorChannels.Add(channel.name, new ExposableValueTuple(Color.white, Color.white)); - ExposableValueTuple colors = this.colorChannels[channel.name]; + this.colorChannels.Add(channel.name, new ExposableValueTuple(Color.white, Color.white, Color.white)); + ExposableValueTuple colors = this.colorChannels[channel.name]; if (channel.first != null) colors.first = this.GenerateColor(channel.first); if (channel.second != null) colors.second = this.GenerateColor(channel.second); + if (channel.third != null) + colors.third = this.GenerateColor(channel.third); } - ExposableValueTuple hairColors = this.colorChannels[key: "hair"]; + ExposableValueTuple hairColors = this.colorChannels[key: "hair"]; if (hairColors.first == Color.clear) { Color color = PawnHairColors.RandomHairColor(pawn.story.SkinColor, pawn.ageTracker.AgeBiologicalYears); hairColors.first = color; hairColors.second = color; + hairColors.third = color; } pawn.story.hairColor = hairColors.first; @@ -228,7 +250,10 @@ public Color GenerateColor(ColorGenerator gen) { case ColorGenerator_CustomAlienChannel ac: string[] split = ac.colorChannel.Split('_'); - return split[1] == "1" ? this.ColorChannels[split[0]].first : this.ColorChannels[split[0]].second; + if (split[1] == "1") { return this.ColorChannels[split[0]].first; } + if (split[1] == "3") { return this.colorChannels[split[0]].third; } + return this.ColorChannels[split[0]].second; + //return split[1] == "1" ? this.ColorChannels[split[0]].first : this.ColorChannels[split[0]].second; default: return gen.NewRandomizedColor(); } @@ -253,7 +278,7 @@ public override void PostExposeData() Scribe_Collections.Look(ref this.colorChannels, label: "colorChannels"); } - public ExposableValueTuple GetChannel(string channel) + public ExposableValueTuple GetChannel(string channel) { if (this.ColorChannels.ContainsKey(channel)) return this.ColorChannels[channel]; @@ -264,16 +289,17 @@ public ExposableValueTuple GetChannel(string channel) foreach (ColorChannelGenerator apgChannel in apg.colorChannels) if (apgChannel.name == channel) { - this.ColorChannels.Add(channel, new ExposableValueTuple()); + this.ColorChannels.Add(channel, new ExposableValueTuple()); if (apgChannel.first != null) this.ColorChannels[channel].first = this.GenerateColor(apgChannel.first); if (apgChannel.second != null) this.ColorChannels[channel].second = this.GenerateColor(apgChannel.second); - + if (apgChannel.third != null) + this.ColorChannels[channel].third = this.GenerateColor(apgChannel.third); return this.ColorChannels[channel]; } - return new ExposableValueTuple(Color.white, Color.white); + return new ExposableValueTuple(Color.white, Color.white, Color.white); } internal void AssignProperMeshs() @@ -296,25 +322,28 @@ private static void RegenerateColorchannels() } } - public class ExposableValueTuple : IExposable + public class ExposableValueTuple : IExposable { public K first; public V second; + public P third; public ExposableValueTuple() { } - public ExposableValueTuple(K first, V second) + public ExposableValueTuple(K first, V second, P third) { this.first = first; this.second = second; + this.third = third; } public void ExposeData() { Scribe_Values.Look(ref this.first, label: "first"); Scribe_Values.Look(ref this.second, label: "second"); + Scribe_Values.Look(ref this.third, label: "third"); } } diff --git a/Source/AlienRace/AlienRace/HarmonyPatches.cs b/Source/AlienRace/AlienRace/HarmonyPatches.cs index a1eaae99..fc30847c 100644 --- a/Source/AlienRace/AlienRace/HarmonyPatches.cs +++ b/Source/AlienRace/AlienRace/HarmonyPatches.cs @@ -2059,38 +2059,45 @@ public static bool ResolveAllGraphicsPrefix(PawnGraphicSet __instance) alienComp.AssignProperMeshs(); + // There were crimes against formatting here. + Traverse.Create(alien.story).Field(name: "headGraphicPath").SetValue(alienComp.crownType.NullOrEmpty() ? - apg.RandomAlienHead( - graphicPaths.head, alien) : - AlienPartGenerator.GetAlienHead(graphicPaths.head, - apg.useGenderedHeads ? - alien.gender.ToString() : - "", alienComp.crownType)); + apg.RandomAlienHead( + graphicPaths.head, alien) : + AlienPartGenerator.GetAlienHead(graphicPaths.head, + apg.useGenderedHeads ? + alien.gender.ToString() : + "", alienComp.crownType)); + + // Has 3rd color now & using new shader __instance.nakedGraphic = !graphicPaths.body.NullOrEmpty() ? - apg.GetNakedGraphic(alien.story.bodyType, - ContentFinder.Get( - AlienPartGenerator.GetNakedPath(alien.story.bodyType, graphicPaths.body, - apg.useGenderedBodies ? alien.gender.ToString() : "") + - "_northm", reportFailure: false) == null ? - graphicPaths.skinShader?.Shader ?? ShaderDatabase.Cutout : - ShaderDatabase.CutoutComplex, __instance.pawn.story.SkinColor, - apg.SkinColor(alien, first: false), graphicPaths.body, - alien.gender.ToString()) : - null; + apg.GetNakedGraphic(alien.story.bodyType, + ContentFinder.Get( + AlienPartGenerator.GetNakedPath(alien.story.bodyType, graphicPaths.body, + apg.useGenderedBodies ? alien.gender.ToString() : "") + + "_northm", reportFailure: false) == null ? + graphicPaths.skinShader?.Shader ?? ShaderDatabase.Cutout : + TriColorShaderDatabase.Tricolor, __instance.pawn.story.SkinColor, + apg.SkinColor(alien, 2), apg.SkinColor(alien, 3), graphicPaths.body, + alien.gender.ToString()) : null; + + // Has 3rd color now & using new shader __instance.rottingGraphic = !graphicPaths.body.NullOrEmpty() ? - apg.GetNakedGraphic(alien.story.bodyType, graphicPaths.skinShader?.Shader ?? ShaderDatabase.Cutout, - PawnGraphicSet.RottingColor, PawnGraphicSet.RottingColor, graphicPaths.body, - alien.gender.ToString()) : - null; - __instance.dessicatedGraphic = !graphicPaths.skeleton.NullOrEmpty() ? GraphicDatabase.Get((graphicPaths.skeleton == GraphicPaths.VANILLA_SKELETON_PATH ? alien.story.bodyType.bodyDessicatedGraphicPath : graphicPaths.skeleton), ShaderDatabase.Cutout) : null; + apg.GetNakedGraphic(alien.story.bodyType, graphicPaths.skinShader?.Shader ?? TriColorShaderDatabase.Tricolor, + PawnGraphicSet.RottingColor, PawnGraphicSet.RottingColor, PawnGraphicSet.RottingColor, graphicPaths.body, + alien.gender.ToString()) : null; + + __instance.dessicatedGraphic = !graphicPaths.skeleton.NullOrEmpty() ? GraphicDatabase.Get((graphicPaths.skeleton == GraphicPaths.VANILLA_SKELETON_PATH ? alien.story.bodyType.bodyDessicatedGraphicPath : graphicPaths.skeleton), ShaderDatabase.Cutout) : null; + + // Has 3rd color now & using new shader __instance.headGraphic = alien.health.hediffSet.HasHead && !alien.story.HeadGraphicPath.NullOrEmpty() ? - GraphicDatabase.Get(alien.story.HeadGraphicPath, - ContentFinder.Get(alien.story.HeadGraphicPath + "_northm", reportFailure: false) == null ? - graphicPaths.skinShader?.Shader ?? ShaderDatabase.Cutout : - ShaderDatabase.CutoutComplex, Vector2.one, alien.story.SkinColor, - apg.SkinColor(alien, first: false)) : - null; + TriColorGraphicDatabase.Get(alien.story.HeadGraphicPath, + ContentFinder.Get(alien.story.HeadGraphicPath + "_northm", reportFailure: false) == null ? + graphicPaths.skinShader?.Shader ?? ShaderDatabase.Cutout : + TriColorShaderDatabase.Tricolor, Vector2.one, alien.story.SkinColor, + apg.SkinColor(alien, 2), apg.SkinColor(alien, 3)) : null; + __instance.desiccatedHeadGraphic = alien.health.hediffSet.HasHead && !alien.story.HeadGraphicPath.NullOrEmpty() ? GraphicDatabase.Get(alien.story.HeadGraphicPath, ShaderDatabase.Cutout, Vector2.one, PawnGraphicSet.RottingColor) : @@ -2098,15 +2105,19 @@ public static bool ResolveAllGraphicsPrefix(PawnGraphicSet __instance) __instance.skullGraphic = alien.health.hediffSet.HasHead && !graphicPaths.skull.NullOrEmpty() ? GraphicDatabase.Get(graphicPaths.skull, ShaderDatabase.Cutout, Vector2.one, Color.white) : null; - __instance.hairGraphic = GraphicDatabase.Get(__instance.pawn.story.hairDef.texPath, + + // Has 3rd color now & using new shader + __instance.hairGraphic = TriColorGraphicDatabase.Get(__instance.pawn.story.hairDef.texPath, ContentFinder.Get(__instance.pawn.story.hairDef.texPath + "_northm", reportFailure: false) == null ? (alienProps.alienRace.hairSettings.shader?.Shader ?? ShaderDatabase.Cutout) : - ShaderDatabase.CutoutComplex, Vector2.one, alien.story.hairColor, alienComp.GetChannel(channel: "hair").second); + TriColorShaderDatabase.Tricolor, Vector2.one, alien.story.hairColor, alienComp.GetChannel(channel: "hair").second, alienComp.GetChannel(channel: "hair").third); + + // Has 3rd color now & using new shader __instance.headStumpGraphic = !graphicPaths.stump.NullOrEmpty() ? - GraphicDatabase.Get(graphicPaths.stump, - alien.story.SkinColor == apg.SkinColor(alien, first: false) ? ShaderDatabase.Cutout : ShaderDatabase.CutoutComplex, Vector2.one, - alien.story.SkinColor, apg.SkinColor(alien, first: false)) : - null; + TriColorGraphicDatabase.Get(graphicPaths.stump, + alien.story.SkinColor == apg.SkinColor(alien, 2) ? ShaderDatabase.Cutout : TriColorShaderDatabase.Tricolor, Vector2.one, + alien.story.SkinColor, apg.SkinColor(alien, 2), apg.SkinColor(alien, 3)) : null; + __instance.desiccatedHeadStumpGraphic = !graphicPaths.stump.NullOrEmpty() ? GraphicDatabase.Get(graphicPaths.stump, ShaderDatabase.Cutout, Vector2.one, diff --git a/Source/AlienRace/AlienRace/TriColorShader.cs b/Source/AlienRace/AlienRace/TriColorShader.cs new file mode 100644 index 00000000..e416e7b3 --- /dev/null +++ b/Source/AlienRace/AlienRace/TriColorShader.cs @@ -0,0 +1,540 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; +using UnityEngine; +using HarmonyLib; + +namespace AlienRace +{ + // 4 classes and 2 structs is probably the leanest I can make it, without turning everything unreadable. + public class TriColorGraphic_Multi : Graphic + { + /* + // Replaces the vanilla Rimworld Pawn graphic class for alien races, is basically identical with the addition of a third color + // and allowing our shader to be used with masks. The shader itself does not require a third color to be specified, + // so it works just as well with vanilla pawns and HAR pawns without a third channel, and hasn't caused trouble with any race mod I've tried. + */ + public Color colorThree = Color.white; + private Material[] mats = new Material[4]; + private bool westFlipped; + private bool eastFlipped; + private float drawRotatedExtraAngleOffset; + + public string GraphicPath + { + get + { + return this.path; + } + } + + public override Material MatSingle + { + get + { + + return this.MatSouth; + } + } + + public override Material MatWest + { + get + { + return this.mats[3]; + } + } + + public override Material MatSouth + { + get + { + return this.mats[2]; + } + } + + public override Material MatEast + { + get + { + return this.mats[1]; + } + } + + public override Material MatNorth + { + get + { + return this.mats[0]; + } + } + + public override bool WestFlipped + { + get + { + return this.westFlipped; + } + } + + public override bool EastFlipped + { + get + { + return this.eastFlipped; + } + } + + public override bool ShouldDrawRotated + { + get + { + if (this.data != null && !this.data.drawRotated) + return false; + return this.MatEast == this.MatNorth || this.MatWest == this.MatNorth; + } + } + + public override float DrawRotatedExtraAngleOffset + { + get + { + return this.drawRotatedExtraAngleOffset; + } + } + public void Init(TriColorGraphicRequest req) + + { + this.data = req.graphicData; + this.path = req.path; + this.color = req.color; + this.colorTwo = req.colorTwo; + this.colorThree = req.colorThree; + this.drawSize = req.drawSize; + Texture2D[] texture2DArray1 = new Texture2D[this.mats.Length]; + texture2DArray1[0] = ContentFinder.Get(req.path + "_north", false); + texture2DArray1[1] = ContentFinder.Get(req.path + "_east", false); + texture2DArray1[2] = ContentFinder.Get(req.path + "_south", false); + texture2DArray1[3] = ContentFinder.Get(req.path + "_west", false); + if (texture2DArray1[0] == null) + { + if (texture2DArray1[2] != null) + { + texture2DArray1[0] = texture2DArray1[2]; + this.drawRotatedExtraAngleOffset = 180f; + } + else if (texture2DArray1[1] != null) + { + texture2DArray1[0] = texture2DArray1[1]; + this.drawRotatedExtraAngleOffset = -90f; + } + else if (texture2DArray1[3] != null) + { + texture2DArray1[0] = texture2DArray1[3]; + this.drawRotatedExtraAngleOffset = 90f; + } + else + texture2DArray1[0] = ContentFinder.Get(req.path, false); + } + if (texture2DArray1[0] == null) + { + Log.Error("Failed to find any textures at " + req.path + " while constructing " + this.ToStringSafe(), false); + } + + else + { + if (texture2DArray1[2] == null) + texture2DArray1[2] = texture2DArray1[0]; + if (texture2DArray1[1] == null) + { + if (texture2DArray1[3] != null) + { + texture2DArray1[1] = texture2DArray1[3]; + this.eastFlipped = this.DataAllowsFlip; + } + else + texture2DArray1[1] = texture2DArray1[0]; + } + if (texture2DArray1[3] == null) + { + if (texture2DArray1[1] != null) + { + texture2DArray1[3] = texture2DArray1[1]; + this.westFlipped = this.DataAllowsFlip; + } + else + texture2DArray1[3] = texture2DArray1[0]; + } + Texture2D[] texture2DArray2 = new Texture2D[this.mats.Length]; + if (req.shader == TriColorShaderDatabase.Tricolor) + { + texture2DArray2[0] = ContentFinder.Get(req.path + "_northm", false); + texture2DArray2[1] = ContentFinder.Get(req.path + "_eastm", false); + texture2DArray2[2] = ContentFinder.Get(req.path + "_southm", false); + texture2DArray2[3] = ContentFinder.Get(req.path + "_westm", false); + if (texture2DArray2[0] == null) + { + if (texture2DArray2[2] != null) + texture2DArray2[0] = texture2DArray2[2]; + else if (texture2DArray2[1] != null) + texture2DArray2[0] = texture2DArray2[1]; + else if (texture2DArray2[3] != null) + texture2DArray2[0] = texture2DArray2[3]; + } + if (texture2DArray2[2] == null) + texture2DArray2[2] = texture2DArray2[0]; + if (texture2DArray2[1] == null) + texture2DArray2[1] = !(texture2DArray2[3] != null) ? texture2DArray2[0] : texture2DArray2[3]; + if (texture2DArray2[3] == null) + texture2DArray2[3] = !(texture2DArray2[1] != null) ? texture2DArray2[0] : texture2DArray2[1]; + } + for (int index = 0; index < this.mats.Length; ++index) + { + this.mats[index] = TriColorMaterialPool.MatFrom(new TriColorMaterialRequest() + { + mainTex = texture2DArray1[index], + shader = req.shader, + color = this.color, + colorTwo = this.colorTwo, + colorThree = this.colorThree, + maskTex = texture2DArray2[index], + shaderParameters = req.shaderParameters + }); + + }; + } + } + public TriColorGraphic_Multi GetColoredVersion( + + Shader newShader, + Color newColor, + Color newColorTwo, + Color newColorThree) + { + return TriColorGraphicDatabase.Get(this.path, newShader, this.drawSize, newColor, newColorTwo, newColorThree, this.data); + } + + public override string ToString() + { + return "Multi(initPath=" + this.path + ", color=" + (object)this.color + ", colorTwo=" + (object)this.colorTwo + ")"; + } + + public override int GetHashCode() + { + return Gen.HashCombineStruct(Gen.HashCombineStruct(Gen.HashCombineStruct(Gen.HashCombine(0, this.path), this.color), this.colorTwo), this.ColorThree); + } + } + public static class TriColorGraphicDatabase + { + /* + // RimWorld sure does have a lot of ways to ask for basically the same thing! + // Not a lot has changed compared to vanilla, we're just using our graphic class for the relevant methods. + // This is here so RimWorld doesn't have to re-generate the same request for every pawn. + */ + private static Dictionary allGraphics = new Dictionary(); + public static TriColorGraphic_Multi Get( + string path, + Shader shader, + Vector2 drawSize, + Color color, + Color colorTwo, + Color colorThree, + GraphicData data) + where T : TriColorGraphic_Multi, new() + { + return (TriColorGraphic_Multi)TriColorGraphicDatabase.GetInner(new TriColorGraphicRequest(typeof(T), path, shader, drawSize, color, colorTwo, colorThree, data, 0, (List)null)); + } + public static TriColorGraphic_Multi Get( + string path, + Shader shader, + Vector2 drawSize, + Color color, + Color colorTwo, + Color colorThree) + where T : TriColorGraphic_Multi, new() + { + return (TriColorGraphic_Multi)TriColorGraphicDatabase.GetInner(new TriColorGraphicRequest(typeof(T), path, shader, drawSize, color, colorTwo, colorThree, (GraphicData)null, 0, (List)null)); + } + public static TriColorGraphic_Multi Get( + System.Type graphicClass, + string path, + Shader shader, + Vector2 drawSize, + Color color, + Color colorTwo, + Color colorThree) + { + return TriColorGraphicDatabase.Get(graphicClass, path, shader, drawSize, color, colorTwo, colorThree, (GraphicData)null, (List)null); + } + + public static TriColorGraphic_Multi Get( + System.Type graphicClass, + string path, + Shader shader, + Vector2 drawSize, + Color color, + Color colorTwo, + Color colorThree, + GraphicData data, + List shaderParameters) + { + TriColorGraphicRequest req = new TriColorGraphicRequest(graphicClass, path, shader, drawSize, color, colorTwo, colorThree, data, 0, shaderParameters); + if (req.graphicClass == typeof(Graphic_Multi)) + { + return (TriColorGraphic_Multi)TriColorGraphicDatabase.GetInner(req); + } + try + { + return (TriColorGraphic_Multi)GenGeneric.InvokeStaticGenericMethod(typeof(TriColorGraphicDatabase), req.graphicClass, "GetInner", (object)req); + } + catch (Exception ex) + { + Log.Error("Exception getting " + (object)graphicClass + " at " + path + ": " + ex.ToString(), false); + } + return (TriColorGraphic_Multi)BaseContent.BadGraphic; + } + + private static T GetInner(TriColorGraphicRequest req) where T : TriColorGraphic_Multi, new() + { + + req.color = (Color)(Color32)req.color; + req.colorTwo = (Color)(Color32)req.colorTwo; + req.colorThree = (Color)(Color32)req.colorThree; + TriColorGraphic_Multi graphic; + if (!TriColorGraphicDatabase.allGraphics.TryGetValue(req, out graphic)) + { + graphic = (TriColorGraphic_Multi)new T(); + graphic.Init(req); + TriColorGraphicDatabase.allGraphics.Add(req, graphic); + } + return (T)graphic; + } + } + public static class TriColorMaterialPool + { + /* + // Another class that exists so that RimWorld doesn't have to re-generate requests. + // And again, almost identical to the original code, just have to allow our shader to be used and supply the third color property to the shader. + // If there's a fast way to tie the request to a specific pawn, none of this would really be needed, but I can't find a good angle to attack that from. + */ + public static Material MatFrom(TriColorMaterialRequest req) + { + if (!UnityData.IsInMainThread) + { + Log.Error("Tried to get a material from a different thread.", false); + return null; + } + if (req.mainTex == null) + { + Log.Error("MatFrom with null sourceTex.", false); + return BaseContent.BadMat; + } + if (req.shader == null) + { + Log.Warning("Matfrom with null shader.", false); + return BaseContent.BadMat; + } + Material material; + if (!TriColorMaterialPool.matDictionary.TryGetValue(req, out material)) + { + material = new Material(req.shader); + material.name = req.shader.name + "_" + req.mainTex.name; + material.mainTexture = req.mainTex; + material.color = req.color; + material.SetTexture(ShaderPropertyIDs.MaskTex, req.maskTex); + material.SetColor(ShaderPropertyIDs.ColorTwo, req.colorTwo); + material.SetColor(TriColorShaderDatabase.ColorThree, req.colorThree); + material.SetTexture(ShaderPropertyIDs.MaskTex, req.maskTex); + if (req.renderQueue != 0) + { + material.renderQueue = req.renderQueue; + } + if (!req.shaderParameters.NullOrEmpty()) + { + for (int i = 0; i < req.shaderParameters.Count; i++) + { + req.shaderParameters[i].Apply(material); + } + } + TriColorMaterialPool.matDictionary.Add(req, material); + if (req.shader == ShaderDatabase.CutoutPlant || req.shader == ShaderDatabase.TransparentPlant) + { + WindManager.Notify_PlantMaterialCreated(material); + } + } + return material; + } + + private static Dictionary matDictionary = new Dictionary(); + } + public struct TriColorMaterialRequest : IEquatable + { + /* + // Struct for the material with a third color. + */ + + public override int GetHashCode() + { + return Gen.HashCombine>(Gen.HashCombineInt(Gen.HashCombine(Gen.HashCombine(Gen.HashCombineStruct(Gen.HashCombineStruct(Gen.HashCombine(0, this.shader), this.color), this.colorTwo), this.mainTex), this.maskTex), this.renderQueue), this.shaderParameters); + } + + public override bool Equals(object obj) + { + return obj is TriColorMaterialRequest && this.Equals((TriColorMaterialRequest)obj); + } + + public bool Equals(TriColorMaterialRequest other) + { + return other.shader == this.shader && other.mainTex == this.mainTex && other.color == this.color && other.colorTwo == this.colorTwo && other.maskTex == this.maskTex && other.renderQueue == this.renderQueue && other.shaderParameters == this.shaderParameters; + } + + public static bool operator ==(TriColorMaterialRequest lhs, TriColorMaterialRequest rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(TriColorMaterialRequest lhs, TriColorMaterialRequest rhs) + { + return !(lhs == rhs); + } + + public override string ToString() + { + return string.Concat(new string[] + { + "AvaliMaterialRequest(", + this.shader.name, + ", ", + this.mainTex.name, + ", ", + this.color.ToString(), + ", ", + this.colorTwo.ToString(), + ", ", + this.colorThree.ToString(), + ",", + this.maskTex.ToString(), + ", ", + this.renderQueue.ToString(), + ")" + }); + } + + public Shader shader; + public Texture2D mainTex; + public Color color; + public Color colorTwo; + public Texture2D maskTex; + public int renderQueue; + public List shaderParameters; + public Color colorThree; + } + public struct TriColorGraphicRequest : IEquatable + { + /* + // Struct for the Graphic with a third color. + */ + + public System.Type graphicClass; + public string path; + public Shader shader; + public Vector2 drawSize; + public Color color; + public Color colorTwo; + public Color colorThree; + public GraphicData graphicData; + public int renderQueue; + public List shaderParameters; + + public TriColorGraphicRequest( + System.Type graphicClass, + string path, + Shader shader, + Vector2 drawSize, + Color color, + Color colorTwo, + Color colorThree, + GraphicData graphicData, + int renderQueue, + List shaderParameters) + { + this.graphicClass = graphicClass; + this.path = path; + this.shader = shader; + this.drawSize = drawSize; + this.color = color; + this.colorTwo = colorTwo; + this.colorThree = colorThree; + this.graphicData = graphicData; + this.renderQueue = renderQueue; + this.shaderParameters = shaderParameters.NullOrEmpty() ? (List)null : shaderParameters; + } + + public override int GetHashCode() + { + if (this.path == null) + this.path = BaseContent.BadTexPath; + return Gen.HashCombine>(Gen.HashCombine(Gen.HashCombine(Gen.HashCombineStruct(Gen.HashCombineStruct(Gen.HashCombineStruct(Gen.HashCombine(Gen.HashCombine(Gen.HashCombine(0, this.graphicClass), this.path), this.shader), this.drawSize), this.color), this.colorTwo), this.graphicData), this.renderQueue), this.shaderParameters); + } + + public override bool Equals(object obj) + { + return obj is TriColorGraphicRequest other && this.Equals(other); + } + + public bool Equals(TriColorGraphicRequest other) + { + return this.graphicClass == other.graphicClass && this.path == other.path && ((UnityEngine.Object)this.shader == (UnityEngine.Object)other.shader && this.drawSize == other.drawSize) && (this.color == other.color && this.colorTwo == other.colorTwo && (this.graphicData == other.graphicData && this.renderQueue == other.renderQueue)) && this.shaderParameters == other.shaderParameters; + } + + public static bool operator ==(TriColorGraphicRequest lhs, TriColorGraphicRequest rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(TriColorGraphicRequest lhs, TriColorGraphicRequest rhs) + { + return !(lhs == rhs); + } + } + + [StaticConstructorOnStartup] + public class TriColorShaderDatabase + { + /* + // Loads and makes the shaderID available to the rest of the mod. + */ + + public static string dir = AlienRaceMod.settings.Mod.Content.RootDir.ToString(); + public static AssetBundle shaderLoader(string info) + { + AssetBundle assetBundle = AssetBundle.LoadFromFile(info); + return assetBundle; + } + static TriColorShaderDatabase() + { + // This is where you'd change the path it loads the shader from. + string path = dir + "/1.2/Shader/TriColorShader"; + AssetBundle bundle = shaderLoader(path); + + // internal assetbundle name, do not change. + Tricolor = (Shader)bundle.LoadAsset("assets/resources/materials/avalishader.shader"); + } + + public static Shader Tricolor; + public static int ColorThree = Shader.PropertyToID("_ColorThree"); + + public static Shader DefaultShader + { + get + { + return TriColorShaderDatabase.Tricolor; + } + } + } +} + diff --git a/Source/AlienRace/AlienRace/Utilities.cs b/Source/AlienRace/AlienRace/Utilities.cs index eda0991e..d2f76b5c 100644 --- a/Source/AlienRace/AlienRace/Utilities.cs +++ b/Source/AlienRace/AlienRace/Utilities.cs @@ -96,9 +96,10 @@ public LoadDefFromField(string defName) public Def GetDef(Type defType) => GenDefDatabase.GetDef(defType, this.defName); - } - - public class Graphic_Multi_RotationFromData : Graphic_Multi + } + + public class Graphic_Multi_RotationFromData : TriColorGraphic_Multi + //public class Graphic_Multi_RotationFromData : Graphic_Multi { public override bool ShouldDrawRotated => this.data?.drawRotated ?? false;