code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RimWorld;
using Verse;
using HarmonyLib;
using UnityEngine;
using rjw;
using Rimworld_Animations;
using System.Reflection;

//since I test system alot, source cord is very dirty and not optimized.

namespace SizedApparel
{
    public struct supportedIndex
    {

    }

    [StaticConstructorOnStartup]
    [HarmonyPatch(typeof(Pawn_HealthTracker), "Notify_HediffChanged")]
    public class PawnHealthTrackerPatch
    {
        public static void Postfix(Hediff hediff, Pawn_HealthTracker __instance, ref Pawn ___pawn)
        {
            if (___pawn == null)
                return;
            var comp = ___pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
            if (hediff == null)
                return;

            if (SizedApparelUtility.isRJWParts(hediff))///
            {
                //comp.ClearAll();
                //comp.Update();
                comp.SetDirty(false,true,false);
                //already doing set dirty in hediffchange method.
                //___pawn.Drawer.renderer.graphics.SetApparelGraphicsDirty();
                //PortraitsCache.SetDirty(___pawn);
                //GlobalTextureAtlasManager.TryMarkPawnFrameSetDirty(___pawn);
                return;
            }
            if (SizedApparelUtility.isBellyBulgeHediff(hediff))
            {
                comp.SetDirty(false, true, false);
                return;
            }

        }
    }

    [StaticConstructorOnStartup]
    [HarmonyPatch(typeof(Pawn_AgeTracker), "PostResolveLifeStageChange")]
    public class PawnAgeTrackerPatch
    {
        public static void Postfix(Pawn ___pawn)
        {
            var comp = ___pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
            comp.SetDirty(false,false,false,true,true);//Apparel and Hediff will be changed with other reason. just set skeleton dirty.
        }
    }

    [StaticConstructorOnStartup]
    public class HeddifPatchForRimNudeWorld
    {
        //hediff.get_Severity()
        public static void GetSeverityPostFix(Hediff __instance)
        {
            if (__instance.Part != null)
            {

                if (__instance.Part.def.defName.Equals(SizedApparelUtility.chestString))
                {
                    if (__instance.def.defName.EndsWith(SizedApparelUtility.breastsString))
                    {
                        //Log.Message("Found Breast Hediff");
                        //_breastSeverity = __instance.Severity;
                        //_breastHediff = __instance;
                        //result = true;
                        //Log.Message(_breastSeverity.ToString());
                    }
                }
            }
        }

        //...get_severity()
        /*
        public static void BodyAddonHediffSeverityGraphicPatch(AlienRace.AlienPartGenerator.BodyAddonHediffSeverityGraphic __instance, ref float __result)
        {
            if (!SizedApparelPatch.rimNudeWorldActive) { return; }
            if (!SizedApparelSettings.matchBreastToSupportedApparelSize) { return; }
            if (__instance.path.Contains(SizedApparelUtility.breastsString))
            {

            }
        }*/
    }

    [Obsolete]
    [StaticConstructorOnStartup]
    public class BodyPatch
    {
        public static void SetBodyGraphic(Pawn pawn, bool drawClothFlag = true, bool fromGraphicRecord = true, bool revert = false)
        {
            //Pawn_ApparelTracker __instance;

            //GetBreastSeverity(__instance.pawn, out breastSeverity, out breastHediff);
            //bool flag = hasUnSupportedApparel(__instance.pawn, breastSeverity, breastHediff);
            ApparelRecorderComp comp = pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;

            if (revert)
            {
                var pawnRenderer = pawn.Drawer?.renderer?.graphics;
                //Log.Message("useBodyTexture");

                /*
                if (!pawnRenderer.AllResolved)
                {
                    pawnRenderer.ResolveAllGraphics();
                }*/

                if (pawnRenderer == null)
                    return;
                if (comp.graphicSourceNaked != null)
                    pawnRenderer.nakedGraphic = comp.graphicSourceNaked.GetColoredVersion(pawnRenderer.nakedGraphic.Shader, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo);
                if (comp.graphicSourceRotten != null)
                    pawnRenderer.rottingGraphic = comp.graphicSourceRotten.GetColoredVersion(pawnRenderer.rottingGraphic.Shader, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo);
                if (comp.graphicSourceFurCovered != null)
                    pawnRenderer.furCoveredGraphic = comp.graphicSourceRotten.GetColoredVersion(pawnRenderer.furCoveredGraphic.Shader, pawnRenderer.furCoveredGraphic.color, pawnRenderer.furCoveredGraphic.colorTwo);

            }

            if (!comp.hasUpdateBefore)
            {
                //comp.Update(true, fromGraphicRecord);
            }

            float breastSeverity = comp.breastSeverity;
            Hediff breastHediff = comp.breastHediff;

            if (SizedApparelSettings.drawBodyParts == true && SizedApparelSettings.useBodyTexture)//old:SizedApparelSettings.useBodyTexture
            {
                //if (SizedApparelSettings.Debug)
                //    Log.Message("[Sized Apparel] Trying to change" + pawn.Name + "'s body texture.");

                var pawnRenderer = pawn.Drawer?.renderer?.graphics;
                //Log.Message("useBodyTexture");

                /*
                if (!pawnRenderer.AllResolved)
                {
                    pawnRenderer.ResolveAllGraphics();
                }*/
                if (pawnRenderer == null)
                    return;

                if (!comp.hasUnsupportedApparel || SizedApparelUtility.isPawnNaked(pawn) || !drawClothFlag)
                {

                    if (comp.graphicbaseBodyNaked != null)
                    {
                        pawnRenderer.nakedGraphic = comp.graphicbaseBodyNaked.GetColoredVersion(pawnRenderer.nakedGraphic.Shader, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo);

                    }
                    if (comp.graphicbaseBodyRotten != null)
                    {
                        pawnRenderer.rottingGraphic = comp.graphicbaseBodyRotten.GetColoredVersion(pawnRenderer.rottingGraphic.Shader, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo);

                    }
                    if (comp.graphicbaseBodyFurCovered != null)
                    {
                        pawnRenderer.furCoveredGraphic = comp.graphicbaseBodyFurCovered.GetColoredVersion(pawnRenderer.furCoveredGraphic.Shader, pawnRenderer.furCoveredGraphic.color, pawnRenderer.furCoveredGraphic.colorTwo);

                    }
                }
                else
                {
                    if (comp.graphicSourceNaked != null)
                        pawnRenderer.nakedGraphic = comp.graphicSourceNaked.GetColoredVersion(pawnRenderer.nakedGraphic.Shader, pawnRenderer.nakedGraphic.color, pawnRenderer.nakedGraphic.colorTwo);
                    if (comp.graphicSourceRotten != null)
                        pawnRenderer.rottingGraphic = comp.graphicSourceRotten.GetColoredVersion(pawnRenderer.rottingGraphic.Shader, pawnRenderer.rottingGraphic.color, pawnRenderer.rottingGraphic.colorTwo);
                    if (comp.graphicSourceFurCovered != null)
                        pawnRenderer.furCoveredGraphic = comp.graphicSourceFurCovered.GetColoredVersion(pawnRenderer.furCoveredGraphic.Shader, pawnRenderer.furCoveredGraphic.color, pawnRenderer.furCoveredGraphic.colorTwo);

                }

                return;//no need to replace full body texture anymore.

                /*
                if (SizedApparelSettings.useBodyTexture == false)
                    return;

                //Log.Message("Hello");
                if (pawnGraphicSet == null)
                    return;

                if (pawnGraphicSet.pawn.RaceProps.Humanlike == false)
                    return;

                return;

                //Log.Message("SetBodyGraphic");
                //pawnGraphicSet.ClearCache();
                string path = pawnGraphicSet.pawn.story.bodyType.bodyNakedGraphicPath;
                string path_bodyDessicated = pawnGraphicSet.pawn.story.bodyType.bodyDessicatedGraphicPath;
                string filename;
                string pathname;
                string filename_bodyDessicated;
                string pathname_bodyDessicated;
                pathname = System.IO.Path.GetDirectoryName(path);
                filename = System.IO.Path.GetFileName(path);
                filename_bodyDessicated = System.IO.Path.GetFileName(path_bodyDessicated);
                pathname_bodyDessicated = System.IO.Path.GetDirectoryName(path_bodyDessicated);

                //Log.Message("SetPath");
                bool validBody = false;
                bool validDessicatedBody = false;

                //pawnGraphicSet.pawn.Drawer.renderer.graphics.nakedGraphic
                //pawnGraphicSet.pawn.Drawer.renderer.graphics.dessicatedGraphic

                if (hasUnsupportApparel)
                {
                    //Log.Message("IfhasUnsupportApparel");
                    //Graphic newBodyGraphic = null;
                    //Graphic newRottingGraphic = null;
                    //string path;

                    //Log.Message("tryUnsupportedApparelBodyTexture");
                    //OLD::pawnGraphicSet.pawn.Drawer.renderer.graphics
                    if (pawnGraphicSet.nakedGraphic != null)
                        if (ContentFinder<Texture2D>.Get((pawnGraphicSet.pawn.Drawer.renderer.graphics.nakedGraphic.path + "_UnsupportedApparel" + "_south"), false) != null)
                        {
                            pawnGraphicSet.pawn.Drawer.renderer.graphics.nakedGraphic = GraphicDatabase.Get<Graphic_Multi>(pawnGraphicSet.nakedGraphic.path + "_UnsupportedApparel", pawnGraphicSet.nakedGraphic.Shader, pawnGraphicSet.nakedGraphic.drawSize, pawnGraphicSet.nakedGraphic.color, pawnGraphicSet.nakedGraphic.colorTwo);
                            validBody = true;
                        }
                    if (pawnGraphicSet.dessicatedGraphic != null)
                        if (ContentFinder<Texture2D>.Get((pawnGraphicSet.dessicatedGraphic.path + "_UnsupportedApparel" + "_south"), false) != null)
                        {
                            pawnGraphicSet.dessicatedGraphic = GraphicDatabase.Get<Graphic_Multi>(pawnGraphicSet.dessicatedGraphic.path + "_UnsupportedApparel", pawnGraphicSet.rottingGraphic.Shader, pawnGraphicSet.rottingGraphic.drawSize, pawnGraphicSet.rottingGraphic.color, pawnGraphicSet.rottingGraphic.colorTwo);
                            validDessicatedBody = true;
                        }
                }
                else
                {
                    //Log.Message("undo");
                    string currentPath = pawnGraphicSet.nakedGraphic.path;
                    string currentDessicatedPath = pawnGraphicSet.dessicatedGraphic.path;
                    //Log.Message(currentPath.Substring(0,currentPath.Length - "_UnsupportedApparel".Length));
                    if (pawnGraphicSet.nakedGraphic != null)
                        if (ContentFinder<Texture2D>.Get(currentPath.Substring(0, currentPath.Length - "_UnsupportedApparel".Length) + "_south", false) != null)
                        {
                            pawnGraphicSet.nakedGraphic = GraphicDatabase.Get<Graphic_Multi>((currentPath.Substring(0, currentPath.Length - "_UnsupportedApparel".Length)), pawnGraphicSet.nakedGraphic.Shader, pawnGraphicSet.nakedGraphic.drawSize, pawnGraphicSet.nakedGraphic.color, pawnGraphicSet.nakedGraphic.colorTwo);

                        }
                    if (pawnGraphicSet.dessicatedGraphic != null)
                        if (ContentFinder<Texture2D>.Get(currentDessicatedPath.Substring(0, currentDessicatedPath.Length - "_UnsupportedApparel".Length) + "_south", false) != null)
                        {
                            pawnGraphicSet.dessicatedGraphic = GraphicDatabase.Get<Graphic_Multi>((currentDessicatedPath.Substring(0, currentDessicatedPath.Length - "_UnsupportedApparel".Length)), pawnGraphicSet.nakedGraphic.Shader, pawnGraphicSet.nakedGraphic.drawSize, pawnGraphicSet.nakedGraphic.color, pawnGraphicSet.nakedGraphic.colorTwo);

                        }

                }*/
                //pawnGraphicSet.ClearCache();
            }
        }

        private static void GetBreastSeverity(Pawn pawn, out float breastSeverity, out Hediff breastHediff)
        {
            throw new NotImplementedException();
        }
    }

    [Obsolete]
    [StaticConstructorOnStartup]
    //[HarmonyPatch(typeof(Pawn_ApparelTracker), "ExposeData")]
    class ApparelTrackerExposePatch
    {
        static void Postfix(Pawn_ApparelTracker __instance)
        {
            if (!UnityData.IsInMainThread)
            {
                return;
            }
            if (__instance.pawn == null)
                return;
            if (Scribe.mode == LoadSaveMode.PostLoadInit)
            {
                ApparelRecorderComp comp = __instance.pawn.GetComp<ApparelRecorderComp>();
                if (comp == null)
                    return;
                if (!comp.hasUpdateBefore)
                    comp.Update(true, false);
            }

        }
    }

    //[StaticConstructorOnStartup]
    //[HarmonyPatch(typeof(Pawn_ApparelTracker), "Notify_ApparelChanged")]
    //rimworld 1.2 => apparelChanged, rimworld 1.3 => apparelAdded, apparelRemoved
    public class ApparelTrackerPatch
    {
        //Prefix
        public static void Changed(Pawn_ApparelTracker __instance)
        {
            /*
            if (Current.Game.World == null)
                return;
            */
            if (!UnityData.IsInMainThread)
            {
                return;
            }
            if (__instance.pawn == null)
                return;

            if (SizedApparelSettings.Debug)
                Log.Message("[Sized Apparel] " + __instance.pawn.Name + "'s apparels are changed. updating sizedApparels for it.");

            //GetBreastSeverity(__instance.pawn, out breastSeverity, out breastHediff);
            //bool flag = hasUnSupportedApparel(__instance.pawn, breastSeverity, breastHediff);
            ApparelRecorderComp comp = __instance.pawn.GetComp<ApparelRecorderComp>();
            if (comp != null)
            {
                //comp.ClearBreastCacheValue();
                //comp.ClearAll();
                //bool flag = false;
                //SizedApparelUtility.GetBreastSeverity(__instance.pawn, out breastSeverity, out breastHediff);
                //flag = SizedApparelUtility.hasUnSupportedApparel(__instance.pawn, breastSeverity, breastHediff);
                //flag = SizedApparelUtility.hasUnSupportedApparelFromWornData(__instance.pawn, breastSeverity, breastHediff);
                //comp.hasUpdateBefore = true;
                //comp.hasUnsupportedApparel = flag;
                //comp.breastHediff = breastHediff; ;
                //comp.breastSeverity = breastSeverity;
                //comp.Update(true, false);//TODO: Coverd But No Graphic may cause Big Issue!!!
                //comp.Update(true, true);

                comp.SetDirty(false,false,true);

                /*
                if (SizedApparelSettings.drawBodyParts)//old:SizedApparelSettings.useBodyTexture
                    BodyPatch.SetBodyGraphic(__instance.pawn);
                */
                /*
                //Log.Message(comp.testbool.ToString());
                //Log.Message("ApparelChanged");
                //comp.hasUnsupportedApparel = flag;
                //comp.hasUpdateBefore = true;
                //comp.SetHasUnsupportedApparel(flag);
                //comp.SetHasUpdateBefore(true);
                //if (__instance.pawn.Drawer.renderer.graphics != null)

                LongEventHandler.ExecuteWhenFinished(delegate
                {
                    SetBodyGraphic(__instance.pawn.Drawer.renderer.graphics, flag);
                }
                );
                */

            }

        }
    }
    [StaticConstructorOnStartup]
    //[HarmonyPatch(typeof(PawnGraphicSet), "SetApparelGraphicsDirty")]
    class SetApparelGraphicsDirtyPatch
    {
        public static bool Prefix(PawnGraphicSet __instance)
        {
            if (SizedApparelSettings.useBodyTexture)
            {
                //__instance.SetAllGraphicsDirty();
                //return false;
            }
            return true;
        }
    }

    //TODO
    [StaticConstructorOnStartup]
    //[HarmonyPatch(typeof(PawnGraphicSet), "get_apparelGraphics")]
    class PrivatePartsPatch
    {
        public static void Postfix(PawnGraphicSet __instance, ref List<ApparelGraphicRecord> __result)
        {
            var resualtCach = __result;

            if (SizedApparelSettings.drawBodyParts)
            {
                var privateParts = new List<ApparelGraphicRecord>();
                if (SizedApparelSettings.drawPenis)
                {

                }
                if (SizedApparelSettings.drawVagina)
                {

                }
                if (SizedApparelSettings.drawHips)
                {

                }
                if (SizedApparelSettings.drawHips)
                {

                }
                if (SizedApparelSettings.drawAnus)
                {

                }
            }
        }
    }

    //[HarmonyPatch(typeof(PawnGraphicSet), "MatsBodyBaseAt")]
    public class MatBodyBaseAtPatch
    {
        public static void Postfix(PawnGraphicSet __instance, Rot4 facing, RotDrawMode bodyCondition, bool drawClothes, List<Material> __result)
        {
            if (__result == null)
                return;
            int num = facing.AsInt + 1000 * (int)bodyCondition;
            List<Material> copy;
            copy = __result.ListFullCopy();
            for (int i = 0;  i<__result.Count; i++)
            {
                //SizedApparelsDatabase.GetSupportedApparelOriginalPath(__result[i].g)
            }
        }

    }

    //Apparel Graphic Texture injection
    [StaticConstructorOnStartup]
    [HarmonyPatch(typeof(ApparelGraphicRecordGetter), "TryGetGraphicApparel")]
    [HarmonyBefore(new string[]{"QualityOfBuilding"})]
    public class GetApparelGraphicFix
    {
        public static void Postfix(Apparel apparel, BodyTypeDef bodyType, ref ApparelGraphicRecord rec, ref bool __result)
        {
            if (__result == false)
                return;

            if (apparel == null)
                return;

            if (bodyType == null)
                return;

            if (apparel.Wearer != null)
            {
                //rec = new ApparelGraphicRecord(null, null);
                var comp = apparel.Wearer.GetComp<ApparelRecorderComp>();

                //if (SizedApparelSettings.matchBodyTextureToMinimumApparelSize)
                //    BreastSeverity = comp.BreastSeverityCache;
                //int currentBreastSizeIndex = 0;
                //float currentBreastSeverity = -1;
                //int minSupportedBreastSizeIndex = 1000;
                //float minSupportedBreastSeverity = 1000;

                //SizedApparelUtility.GetBreastSeverity(apparel.Wearer, out BreastSeverity, out breastHediff);
                if (comp != null)
                {

                    if (comp.hasUpdateBefore == false)
                    {
                        //SizedApparelUtility.GetBreastSeverity(apparel.Wearer, out BreastSeverity, out breastHediff);
                        //comp.hasUnsupportedApparel = SizedApparelUtility.hasUnSupportedApparelFromWornData(apparel.Wearer, BreastSeverity, breastHediff);
                        //comp.breastSeverity = BreastSeverity;
                        //comp.breastHediff = breastHediff;
                        //comp.hasUpdateBefore = true;
                        //comp.Update(true,false);
                    }
                    if (comp.isDirty == true)
                    {
                        //return;
                        //comp.ClearAll();
                        //comp.Update(true, false);
                    }
                    /*
                    if (comp.needToCheckApparelGraphicRecords)
                    {
                        TODO;
                        if (comp.isApparelGraphicRecordChanged())
                            comp.Update(true, false);

                    }*/
                    if (comp.needToCheckApparelGraphicRecords)
                    {
                        /*
                        if (comp.isApparelGraphicRecordChanged())
                        {
                            //return;
                            //comp.Update(true, true); //1.3
                            //SizedApparelUtility.UpdateAllApparel(___pawn, true);
                        }*/
                    }

                    //Log.Message("1");
                    var breastHediff = comp.breastHediff;
                    float BreastSeverity = comp.breastSeverity;
                    //Log.Message("2");

                    if (SizedApparelSettings.useBreastSizeCapForApparels) //SizedApparelSettings.useBreastSizeCapForApparels //wip
                            BreastSeverity = Math.Min(comp.BreastSeverityCache, BreastSeverity);
                    //Log.Message("3");
                    if (comp.hasUnsupportedApparel == false)//&& (comp.bodyPartBreasts.bodyPartGraphic !=null || comp.bodyPartBreasts.bodyPartGraphicHorny != null)
                    {
                        Graphic sizedGraphic = null;
                        //Log.Message("4");
                        string resultPath = SizedApparelsDatabase.GetSupportedApparelSizedPath(new SizedApparelsDatabase.SizedApparelDatabaseKey(rec.graphic.path, apparel?.Wearer?.def.defName, breastHediff?.def?.defName, apparel.Wearer.gender, apparel?.Wearer?.story?.bodyType?.defName, SizedApparelUtility.BreastSeverityInt(BreastSeverity))).pathWithSizeIndex;
                        if(resultPath != null)
                        {
                            //sizedGraphic = SizedApparelUtility.GetSizedApparelGraphic(rec.graphic, BreastSeverity, apparel?.Wearer?.def.defName, breastHediff.def.defName);
                            sizedGraphic = GraphicDatabase.Get<Graphic_Multi>(resultPath, rec.graphic.Shader, rec.graphic.drawSize, rec.graphic.color, rec.graphic.colorTwo);
                        }

                        if(sizedGraphic != null)
                        rec = new ApparelGraphicRecord(sizedGraphic, rec.sourceApparel);

                        //minSupportedBreastSizeIndex = Math.Min(currentBreastSizeIndex, minSupportedBreastSizeIndex);
                        //comp.breastSeverityCapToDraw = Math.Min(comp.breastSeverityCapToDraw, minSupportedBreastSeverity);
                    }
                }

                else
                {
                    if (SizedApparelSettings.Debug)
                        Log.Warning("[Sized Apparel] " + apparel.Wearer.Name + " doesn't have SizedApparel Compoenet!!");

                }
            }
        }
    }

    [StaticConstructorOnStartup]
    [HarmonyPatch(typeof(PawnGraphicSet), "ClearCache")]
    class GraphicSetClearFix
    {
        public static void Postfix(PawnGraphicSet __instance)
        {
            if (__instance.pawn == null)
            {
                return;
            }
            var comp = __instance.pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
            //comp.ClearAll(false);
            //comp.needToCheckApparelGraphicRecords = true;
            comp.SetDirty(false,true,false,false,false); // Check Hediff. If you don't the crotch will not have graphic on first load
        }
    }

    //[HarmonyPatch(typeof(PawnGraphicSet), "MatsBodyBaseAt")]
    public class PawnGraphicSetPatch
    {
        public static void Postfix(ref List<Material> __result, ref PawnGraphicSet __instance, Rot4 facing, RotDrawMode bodyCondition)
        {

        }
    }

    //TODO: Patch After RJW (Sexualize_GenerateNewPawnInternal) or just postfix to Sexualize
    [HarmonyPatch(typeof(PawnGenerator), "GenerateNewPawnInternal")]
    public class PawnGeneratorPatch
    {

    }

    [HarmonyPatch(typeof(Corpse), "RotStageChanged")]
    public class RotStagePatch
    {
        public static void Prefix(CompRottable __instance)
        {
            var comp = __instance.parent.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
            comp.SetDirty(false,false,false); // should clear graphicSet....?
        }
    }

    //Should I Patch this?
    //[HarmonyPatch(typeof(Pawn_AgeTracker), "RecalculateLifeStageIndex")]
    public class AgePatch
    {
        public static void Postfix(Pawn_AgeTracker __instance, Pawn ___pawn)
        {
            var comp = ___pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
            comp.CheckAgeChanged();
        }
    }

    //Styling Station patch..? wip
    //[HarmonyPatch(typeof(PawnGraphicSet), "MatsBodyBaseAt")]
    public class BodyMatPatch
    {
        public static void Postfix(PawnGraphicSet __instance, RotDrawMode bodyCondition, Rot4 facing, ref List<Material> __result, bool drawClothes)
        {
            List<Material> loc = new List<Material>();

            if (bodyCondition == RotDrawMode.Dessicated)
            {
                return;
            }

            for (int i = 0; i< __result.Count; i++)
            {
                if (bodyCondition == RotDrawMode.Fresh)
                {
                    if (__result[i] == __instance.nakedGraphic.MatAt(facing, null))
                    {

                        continue;
                    }

                }
                else if (bodyCondition == RotDrawMode.Rotting || __instance.dessicatedGraphic == null)
                {
                    if (__result[i] == __instance.rottingGraphic.MatAt(facing, null))
                    {

                        continue;
                    }
                }

                if (drawClothes)
                {

                }

                loc.Add(__result[i]);
            }

        }
    }
    //RimWorld 1.3
    //WIPWIPWIP TODO
    [HarmonyPatch(typeof(PawnRenderer), "BaseHeadOffsetAt")]
    public class BaseHeadOffsetAtPatch
    {
        public static void Postfix(ref PawnRenderer __instance, Pawn ___pawn, Rot4 rotation, ref Vector3 __result)
        {
            ApparelRecorderComp apparelRecorder = ___pawn.GetComp<ApparelRecorderComp>();
            if (apparelRecorder == null)
                return;
            if (apparelRecorder.customPose != null)
            {
                //var item = apparelRecorder.currentCustomPose.headOffset.FirstOrDefault(b => b.bodyType == ___pawn.story.bodyType.label);
                //__result += item.offsets.GetOffset(rotation);
            }
        }
    }

    [HarmonyPatch(typeof(Pawn_GeneTracker), "Notify_GenesChanged")]
    public class GeneChangePatch
    {
        public static void Postfix(Pawn_GeneTracker __instance, GeneDef addedOrRemovedGene)
        {
            ApparelRecorderComp apparelRecorder = __instance.pawn.GetComp<ApparelRecorderComp>();
            if (apparelRecorder == null)
                return;
            if (addedOrRemovedGene.bodyType!= null)
            {
                /*
                apparelRecorder.Update();
                if (SizedApparelSettings.drawBodyParts)
                    BodyPatch.SetBodyGraphic(__instance.pawn);
                    */
                apparelRecorder.SetDirty(false,false,false,true);
                return;
            }
            if(addedOrRemovedGene.graphicData != null)
            {
                if(addedOrRemovedGene.graphicData.fur != null)
                {
                    apparelRecorder.SetDirty(false,false,false,true);
                    return;
                }
            }
        }
    }

    //RimWorld 1.3 , 1.4
    [HarmonyPatch(typeof(PawnRenderer), "DrawPawnBody")]
    public class DrawPawnBodyPatch
    {
        static MethodInfo overrideMatMethod = AccessTools.Method(typeof(PawnRenderer), "OverrideMaterialIfNeeded");

        public static void Prefix(ref PawnRenderer __instance, Pawn ___pawn, PawnRenderFlags flags)
        {
            if (!SizedApparelSettings.drawBodyParts)
                return;
            if (___pawn == null)
                return;
            ApparelRecorderComp apparelRecorder = ___pawn.GetComp<ApparelRecorderComp>();
            if (apparelRecorder == null)
                return;
            //!flags.FlagSet(PawnRenderFlags.StylingStation)&&
            bool flag = false;
            //if (apparelRecorder.needToCheckApparelGraphicRecords && apparelRecorder.isApparelGraphicRecordChanged())
            /*
            if (apparelRecorder.isApparelGraphicRecordChanged())
            {
                flag = true;
            }
            */

            if (false && flags.FlagSet(PawnRenderFlags.StylingStation))//TODO...?
            {
                //apparelRecorder.isDirty is allways true

                if (true)//StylingStation Doesn't work with cache! patch in postfix
                {
                    if(apparelRecorder.recentClothFlag != flags.FlagSet(PawnRenderFlags.Clothes))
                        apparelRecorder.Update(true, true, true, flags.FlagSet(PawnRenderFlags.Clothes));
                    if(flags.FlagSet(PawnRenderFlags.Clothes))
                        SizedApparelUtility.UpdateAllApparel(___pawn, true);
                }

            }
            else
            {
                if ((!apparelRecorder.hasUpdateBefore || apparelRecorder.isDirty))
                {
                    if (SizedApparelSettings.Debug)
                        Log.Message("[SizedApparel] trying to draw " + ___pawn.Name + " with unupdated component or SetDirty! Updating it.");
                    //apparelRecorder.ClearAll();
                    //Todo. Async Update?
                    apparelRecorder.Update(true, true, true, flags.FlagSet(PawnRenderFlags.Clothes));
                    SizedApparelUtility.UpdateAllApparel(___pawn,true);
                }
                if (flag)
                {
                    //apparelRecorder.Update(true, true, true, flags.FlagSet(PawnRenderFlags.Clothes));
                    //apparelRecorder.Update(true, true); 1.3
                    //SizedApparelUtility.UpdateAllApparel(___pawn, true);
                }
            }
            return;
            //don't change body graphic file. it will inject material in PawnGraphicSet.MatsBodyBaseAt
            if (SizedApparelSettings.drawBodyParts)
                BodyPatch.SetBodyGraphic(___pawn, flags.FlagSet(PawnRenderFlags.Clothes), false);
            else
                BodyPatch.SetBodyGraphic(___pawn, flags.FlagSet(PawnRenderFlags.Clothes), false, false);
        }

        public static void Postfix(ref PawnRenderer __instance, Vector3 rootLoc, float angle, Rot4 facing, RotDrawMode bodyDrawType, PawnRenderFlags flags, Pawn ___pawn, Mesh bodyMesh)
        {
            if (___pawn == null)
                return;
            ApparelRecorderComp apparelRecorder = ___pawn.GetComp<ApparelRecorderComp>();
            if (apparelRecorder == null)
                return;
            Quaternion quaternion = Quaternion.AngleAxis(angle, Vector3.up);

            if (bodyMesh == null)
                return;

            Quaternion quat = Quaternion.AngleAxis(angle, Vector3.up);

            string defName = __instance.graphics.pawn.def.defName;

            /*
            Shader shader = ___pawn.Drawer.renderer.graphics.nakedGraphic.Shader;
            Color skinColor = Color.white;
            Color skinColor2 = Color.white;
            if (bodyDrawType == RotDrawMode.Fresh)
            {
                shader = ___pawn.Drawer.renderer.graphics.nakedGraphic.Shader;
                if (!ShaderUtility.SupportsMaskTex(shader))
                    shader = ShaderDatabase.CutoutSkinOverlay;
                skinColor = ___pawn.Drawer.renderer.graphics.nakedGraphic.Color;
                skinColor2 = ___pawn.Drawer.renderer.graphics.nakedGraphic.ColorTwo;
            }
            else if(bodyDrawType == RotDrawMode.Rotting)
            {
                shader = ___pawn.Drawer.renderer.graphics.rottingGraphic.Shader;
                if (!ShaderUtility.SupportsMaskTex(shader))
                    shader = ShaderDatabase.CutoutSkinOverlay;
                skinColor = ___pawn.Drawer.renderer.graphics.rottingGraphic.Color;
                skinColor2 = ___pawn.Drawer.renderer.graphics.rottingGraphic.ColorTwo;
            }*/

            /*
            //FurCoveredColor
            if(bodyDrawType == RotDrawMode.Fresh && __instance.graphics.furCoveredGraphic != null)
            {
                shader = ___pawn.Drawer.renderer.graphics.furCoveredGraphic.Shader;
                if (!ShaderUtility.SupportsMaskTex(shader))
                    shader = ShaderDatabase.CutoutSkinOverlay;
                skinColor = ___pawn.Drawer.renderer.graphics.furCoveredGraphic.Color;
                skinColor2 = ___pawn.Drawer.renderer.graphics.furCoveredGraphic.ColorTwo;
            }*/

            if (flags.FlagSet(PawnRenderFlags.StylingStation))//Styling station doesn't affect to real pawn data. so cannot cache to component.
            {

            }

            //breasts are only rendered when all of worn apparels are supported or nude.
            if (__instance.graphics.furCoveredGraphic == null)
            {
                apparelRecorder.UpdateTickAnim(rootLoc,angle);
                apparelRecorder.DrawAllBodyParts(rootLoc,angle,facing,bodyDrawType,flags,___pawn, bodyMesh);
            }

            //else. the DrawPawnFur will draw bodyparts becaust it should be upper

        }
    }

    //Base Body Graphic Injection
    [HarmonyPatch(typeof(PawnGraphicSet), "MatsBodyBaseAt")]
    public class MatsBodyBastAtPatch
    {
        public static void Postfix(ref List<Material> __result, PawnGraphicSet __instance, Rot4 facing, bool dead, RotDrawMode bodyCondition, bool drawClothes)
        {
            if (!SizedApparelSettings.useBodyTexture)
                return;

            if (__result.NullOrEmpty())
                return;

            if (!SizedApparelUtility.CanApplySizedApparel(__instance.pawn))
                return;

            var comp = __instance.pawn.GetComp<ApparelRecorderComp>();
            if (comp == null) // maybe it can be null? but why...? mechanoids?
                return;

            if (drawClothes)
            {
                if (comp.hasUnsupportedApparel)
                    return;
            }

            Material bodyMat = null;
            Material sizedApparelBaseBodyMat = null;
            switch (bodyCondition)
            {
                case RotDrawMode.Fresh:
                    if (dead && __instance.corpseGraphic != null)
                    {
                        return; //don't inject for corpse graphic since the mod doesn't support yet.
                        bodyMat = __instance.corpseGraphic.MatAt(facing, null);
                        if(comp.graphicbaseBodyCorpse != null)
                            sizedApparelBaseBodyMat = comp.graphicbaseBodyCorpse.MatAt(facing, null);
                    }
                    else if(__instance.nakedGraphic != null && comp.graphicbaseBodyNaked != null)
                    {
                        bodyMat = __instance.nakedGraphic.MatAt(facing, null);
                        sizedApparelBaseBodyMat = comp.graphicbaseBodyNaked.MatAt(facing, null);
                    }
                    break;
                case RotDrawMode.Rotting:
                    if (__instance.rottingGraphic != null && comp.graphicbaseBodyRotten != null)
                    {
                        bodyMat = __instance.rottingGraphic.MatAt(facing, null);
                        sizedApparelBaseBodyMat = comp.graphicbaseBodyRotten.MatAt(facing, null);
                    }
                    break;
                case RotDrawMode.Dessicated:
                    return;// //don't inject for Dessicated graphic. it doesn't need to patch for this
                    break;
                default:
                    bodyMat = null;
                    sizedApparelBaseBodyMat = null;
                    break;
            }

            if (sizedApparelBaseBodyMat == null)
                return;

            //the body mat would be in first index but not sure. so search from start
            for (int i = 0; i < __result.Count; i++)
            {
                if(__result[i] == bodyMat)
                {
                    __result[i] = sizedApparelBaseBodyMat;
                    //should inject body part graphics here?
                    break;
                }
            }
            //should do something more? such as add body parts or somthing?
        }
    }

    [HarmonyPatch(typeof(PawnRenderer), "DrawPawnFur")]
    public class DrawPawnFurPatch
    {
        public static void Prefix()
        {

        }
        //when this function called, the drawpawnbody did not draw sizedapparel body parts. draw pawn fur will draw those.
        //this is for sort graphics in some renderer case, some render are sorted by call order
        public static void Postfix(PawnRenderer __instance, Pawn ___pawn, Vector3 shellLoc, Rot4 facing, Quaternion quat, PawnRenderFlags flags)
        {
            var comp = ___pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
            float angle;
            Vector3 v;
            //angle = Quaternion.Angle(quat, Quaternion.AngleAxis(0, Vector3.up));
            quat.ToAngleAxis(out angle, out v);
            angle = angle * v.y; // Quaternion only gives 180 degree. but angle needs 360 degree

            /*
            //for more safe angle calculation, Not need till someone touched pawn's quaternion system. (for now, axis is fixed as Vector.up)
            angle = angle * new Vector3(0, v.y, 0).normalized.y;
            //

            */

            //Quaternion.Inverse(quat).ToAngleAxis(out angle, out v);
            //angle = angle / 57.29578f;
            //angle = Quaternion.Angle(Quaternion.AngleAxis(0, Vector3.up), quat);
            Mesh mesh = HumanlikeMeshPoolUtility.GetHumanlikeBodySetForPawn(___pawn).MeshAt(facing);
            Vector3 loc = shellLoc;
            loc.y -= 0.009187258f; //rimworld 1.4 add 0.009187258f;

            comp.UpdateTickAnim(loc, angle);
            comp.DrawAllBodyParts(loc, angle, facing, RotDrawMode.Fresh, flags, ___pawn, mesh);
        }
    }
    //Base Body Graphic Injection for FurCovered
    [HarmonyPatch(typeof(PawnGraphicSet), "FurMatAt")]
    public class MatsFurMatAtPatch
    {
        //TODO should do in Postfix...? or Prefix?
        public static void Postfix(ref Material __result, PawnGraphicSet __instance, Rot4 facing, bool portrait = false, bool cached = false)
        {
            if (!SizedApparelSettings.useBodyTexture)
                return;

            if (__result == null)
                return;
            var comp = __instance.pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
            Material sizedApparelBaseBodyMat = null;

            if (comp.graphicbaseBodyFurCovered != null)
                sizedApparelBaseBodyMat = comp.graphicbaseBodyFurCovered.MatAt(facing, null);

            if (sizedApparelBaseBodyMat == null)
                return;

            if (!portrait && __instance.pawn.IsInvisible())
            {
                sizedApparelBaseBodyMat = InvisibilityMatPool.GetInvisibleMat(sizedApparelBaseBodyMat);
            }
            if (!cached)
            {
                sizedApparelBaseBodyMat = __instance.flasher.GetDamagedMat(sizedApparelBaseBodyMat);
            }

            __result = sizedApparelBaseBodyMat;
        }
    }

    //TODO
    [HarmonyPatch(typeof(PawnRenderer), "BaseHeadOffsetAt")]
    public class HeadOffsetPatch
    {

        public static void Postfix(PawnRenderer __instance, Pawn ___pawn, Rot4 rotation, ref Vector3 __result)
        {
            var comp = ___pawn.GetComp<ApparelRecorderComp>();
            if (comp == null)
                return;
        }

    }

}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Verse;
using RimWorld;
using HarmonyLib;
using UnityEngine;

namespace SizedApparel
{
    /*
    [HarmonyPatch(typeof(PawnRenderer), "BaseHeadOffsetAt")]
    [HarmonyAfter(new string[]
    {
        "rimworld.erdelf.alien_race.main"
    })]
    */
    //TODO
    public static class PawnRenderer_BaseHeadOffsetAt_Patch_For_Pose
    {
        [HarmonyPostfix]
        public static void BaseHeadOffsetAtPostfix_Post(PawnRenderer __instance, Rot4 rotation, ref Vector3 __result, ref Pawn ___pawn)
        {
            return;

            /*
            var comp = ___pawn.GetComp<ApparelRecorderComp>();

            if (comp == null)
                return;
            if (comp.customPose == null)
                return;

            SizedApparelPoseDef poseDef = DefDatabase<SizedApparelPoseDef>.GetNamed(comp.customPose);
            if (poseDef == null)
                return;

            Rot4Offsets? headOffset = new Rot4Offsets();

            string bodyType = ___pawn.story?.bodyType?.defName;
            if (bodyType == null)
            {
                bodyType = "default";
                headOffset = poseDef.headOffset.FirstOrDefault(b => b.bodyType.ToLower() == "default" | b.bodyType.ToLower() == "null").offsets;
            }
            else
            {
                headOffset = poseDef.headOffset.FirstOrDefault(b => b.bodyType.ToLower() == bodyType.ToLower()).offsets;
            }

            if (headOffset == null)
                return;
            */

            //headOffset.

            //TODO: Mesh Based Scaled Offset
            //__result = __result + headOffset;

            return;
        }
    }
    public class SizedApparelPoseSetDef : Def
    {

        public List<SizedApparelPose> poses;

    }

    public class PoseDef : Def
    {

    }

    public class SizedApparelPose
    {
        //public string poseName; use defName as PoseName
        public SizedApparelBodyPartOf targetBodyPart = SizedApparelBodyPartOf.Torso;
        //public List<BodyTypeAndOffset> headOffset;

    }

}

license: unknown


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using RimWorld;
using Verse;
using HarmonyLib;
using UnityEngine;
using rjw;

namespace SizedApparel
{
    [HarmonyPatch(typeof(PawnGraphicSet), "CalculateHairMats")]
    public static class CalculateHairMatsPatch
    {
        public static void Postfix()
        {

        }
    }

    public class PubicHairDef : StyleItemDef
    {

    }

    class SizedApparelPubicHair
    {
    }

    public static class IdeoStyleTackerPatch
    {

    }
}


code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity;
using UnityEngine;
using Verse;

namespace SizedApparel
{
    //include Human, set humanlike's custom setting
    //Only few settings are allow in ModSetting. other needs to be set in Def (xml) file

    public class AlienRaceSetting : IExposable
    {
        public string raceName = null;
        public bool overrideDef = false;
        public bool asHuman = false;
        public bool allowRaceNamedApparel = true;
        public float drawMinAge = -1; //pawn's Biological age. -1 to ignore.

        public AlienRaceSetting(string raceName)
        {
            this.raceName = raceName;
        }
        public AlienRaceSetting()
        {

        }

        public void ExposeData()
        {
            Scribe_Values.Look(ref raceName, "raceName", null);
            Scribe_Values.Look(ref overrideDef, "overrideDef", false);
            Scribe_Values.Look(ref asHuman, "asHuman", false);
            Scribe_Values.Look(ref allowRaceNamedApparel, "allowRaceNamedApparel", true);
            Scribe_Values.Look(ref drawMinAge, "drawMinAge", -1);
        }

        //public int ageYoung = -1; //use receDefName_young folder. -1 to ignore
        //public int ageOld = -1; //use raceDefName_old folder. -1 to ignore.
    }

    public class SizedApparelSettings : ModSettings
    {

        public static bool Debug = false;
        public static bool DetailLog = false;
        public static bool autoClearCacheOnWriteSetting = true;

        public static bool PreCacheOnLoad = true;
        public static float PreCacheRandomFactor = 0.5f;

        public static bool useBodyTexture = true;//for user who not use rimnudeworld

        public static bool useGenderSpecificTexture = true;

        public static bool matchBodyTextureToMinimumApparelSize = true;//for avoiding breasts cliping

        public static bool useBreastSizeCapForApparels = true;

        public static bool DontReplaceBodyTextureOnNude = true;
        //public static bool DontReplaceBodyTextureOnUnsupported = true;

        //Apply Target Pawn Category
        public static bool ApplyHumanlikes = true; //Always true.
        public static bool ApplyAnimals = true;
        public static bool ApplyAnimalsPlayerFactionOnly = true; //TODO
        public static bool ApplyMechanoid = true;

        public static bool ApplyApparelPatchForMale = false; //only ApparelServerityWork.

        public static bool ApplyColonists = true;
        public static bool ApplySlaves = true;
        public static bool ApplyPrisoner = true;
        public static bool ApplyNeutralAndAlly = true;
        public static bool ApplyHostile = false;

        public static bool AnimationPatch = true;

            //TODO: Standalone render bodyparts.
        public static bool drawBodyParts = true;//for user who not use rimnudeworld
        public static bool drawBreasts = true;
        public static bool drawPenis = true;
        public static bool drawVagina = true;
        public static bool drawMuscleOverlay = true;
        public static bool drawHips = true;//TODO
        public static bool drawAnus = true;
        public static bool drawBelly = false;//TODO
        public static bool drawUdder = false;//TODO
        public static bool drawPubicHair = true;
        public static bool hideBallOfFuta = false;
        public static bool hidePenisOfMale = false;
        public static bool matchBreastToSupportedApparelSize = true;//for avoiding breasts cliping

        public static bool useBodyPartsVariation = true;
        public static bool showBodyPartsVariation = true;

        public static bool breastsPhysics = false;

        //RimNudeWorld
        public static bool drawSizedApparelBreastsOnlyWorn = false;
        public static bool hideRimNudeWorldBreasts = false;//disable rimnudeworld breasts.

        [Obsolete]
        public static bool useUnsupportedBodyTexture = true;//bodytexture when wearing unsupported apparel.
        public static bool useSafeJobBreasts = true;

        public static bool changeBodyType;
        public static bool fatToFemale;
        public static bool hulkToThin;

        public static bool onlyForFemale = true;
        public static bool useRandomSize = true;//for user who play without rimjobworld
        public static float randomSizeMin = 0.01f;
        public static float randomSizeMax = 1.01f;

        //Lagacy Variable
        public static bool useTitanic = true;
        public static bool useColossal = true;
        public static bool useGargantuan = true;
        public static bool useMassive = true;
        public static bool useEnormous = true;
        public static bool useHuge = true;
        public static bool useLarge = true;
        public static bool useAverage = true;
        public static bool useSmall = true;
        public static bool useTiny = true;
        public static bool useNipples = true;

        //Alien Race Settings
        [Obsolete]
        public static bool UnsupportedRaceToUseHumanlike = false;
        public static List<string> alienRaces = new List<string>();
        public static List<string> alienRacesAllowHumanlikTextures = new List<string>(); //This Value Will be Saved and loaded
        public static string alienRaceSearch = "";
        public static Vector2 alienRacesListScrollPos;
        public static List<AlienRaceSetting> alienRaceSettings = new List<AlienRaceSetting>();

        //Force All Apparel as supported
        public static bool ForcedSupportApparel = false;

        public static bool getUseSettingFromIndex(int target)
        {
            if (target < 0)
                return false;
            else if (target == 0)
                return useNipples;
            else if (target == 1)
                return useTiny;
            else if (target == 2)
                return useSmall;
            else if (target == 3)
                return useAverage;
            else if (target == 4)
                return useLarge;
            else if (target == 5)
                return useHuge;
            else if (target == 6)
                return useEnormous;
            else if (target == 7)
                return useMassive;
            else if (target == 8)
                return useGargantuan;
            else if (target == 9)
                return useColossal;
            else if (target == 10)
                return useTitanic;
            else
                return false;
        }

        public static bool useUnderBreasts = true;
        public static float UnderBreastsOffset = -0.0013f;

        public override void ExposeData()
        {

            Scribe_Values.Look(ref Debug, "Debug", false);
            Scribe_Values.Look(ref DetailLog, "DetailLog", false);
            Scribe_Values.Look(ref autoClearCacheOnWriteSetting, "autoClearCacheOnWriteSetting", true);

            //force to use it. this is important thing.
            //Scribe_Values.Look(ref useBreastSizeCapForApparels, "useBreastSizeCapForApparels", true);

            //Apply Categories.
            Scribe_Values.Look(ref ApplyAnimals, "ApplyAnimals", true);
            Scribe_Values.Look(ref ApplyHumanlikes, "ApplyHumanlikes", true);
            Scribe_Values.Look(ref ApplyMechanoid, "ApplyMechanoid", true);

            Scribe_Values.Look(ref AnimationPatch, "AnimationPatch", true);

            Scribe_Values.Look(ref useBodyTexture, "useBodyTexture", true);
            Scribe_Values.Look(ref useGenderSpecificTexture, "useGenderSpecificTexture", true);

            Scribe_Values.Look(ref matchBodyTextureToMinimumApparelSize, "matchBodyTextureToMinimumApparelSize", true);
            Scribe_Values.Look(ref matchBreastToSupportedApparelSize, "matchBreastToSupportedApparelSize", true);

            //Unsurpported to forced Surpported
            //Scribe_Values.Look(ref UnsupportedRaceToUseHumanlike, "UnsupportedRaceToUseHumanlike", false);
            Scribe_Values.Look(ref ForcedSupportApparel, "ForcedSupportApparel", false);

            Scribe_Collections.Look<AlienRaceSetting>(ref alienRaceSettings, "alienSettings", LookMode.Deep);
            if (Scribe.mode == LoadSaveMode.LoadingVars)
            {
                if (alienRaceSettings == null)
                {
                    alienRaceSettings = new List<AlienRaceSetting>();
                }

                SizedApparelMod.CheckAndLoadAlienRaces();

                //Initialize Setting for missing Race
                foreach (var raceName in SizedApparelMod.alienDefList)
                {
                    AlienRaceSetting raceSetting = null;
                    foreach (var r in SizedApparelSettings.alienRaceSettings)
                    {
                        if (r.raceName == null)
                            continue;
                        if (raceName == r.raceName)
                        {
                            raceSetting = r;
                            break;
                        }
                    }
                    if (raceSetting == null)
                    {
                        raceSetting = new AlienRaceSetting(raceName);
                        SizedApparelSettings.alienRaceSettings.Add(raceSetting);
                    }
                }

            }
            if (Scribe.mode == LoadSaveMode.ResolvingCrossRefs)
            {
                if(!alienRaceSettings.NullOrEmpty())
                    alienRaceSettings.RemoveAll((AlienRaceSetting x) => string.IsNullOrEmpty(x.raceName));
            }

            Scribe_Values.Look(ref useUnsupportedBodyTexture, "useUnsupportedBodyTexture", true);
            Scribe_Values.Look(ref DontReplaceBodyTextureOnNude, "DontReplaceBodyTextureOnNude", false);

            Scribe_Values.Look(ref hideRimNudeWorldBreasts, "hideRimNudeWorldBreasts", false);
            Scribe_Values.Look(ref useSafeJobBreasts, "useSafeJobBreasts", true);

            Scribe_Values.Look(ref useRandomSize, "useRandomSize", true);
            Scribe_Values.Look(ref randomSizeMin, "randomSizeMin", 0.01f);
            Scribe_Values.Look(ref randomSizeMax, "randomSizeMax", 1.01f);

            Scribe_Values.Look(ref drawBodyParts, "drawBodyParts", true);
            Scribe_Values.Look(ref useBodyPartsVariation, "useBodyPartsVariation", true); // forse true for now. TODO
            Scribe_Values.Look(ref showBodyPartsVariation, "showBodyPartsVariation", true);

            Scribe_Values.Look(ref drawMuscleOverlay, "drawMuscleOverlay", true);
            Scribe_Values.Look(ref drawBreasts, "drawBreasts", true);
            Scribe_Values.Look(ref drawSizedApparelBreastsOnlyWorn, "drawSizedApparelBreastsOnlyWorn", false);
            Scribe_Values.Look(ref drawPenis, "drawPenis", true);
            Scribe_Values.Look(ref drawVagina, "drawVagina", true);
            Scribe_Values.Look(ref drawAnus, "drawAnus", true);
            Scribe_Values.Look(ref drawUdder, "drawUdder", true);
            Scribe_Values.Look(ref drawBelly, "drawBelly", true);
            Scribe_Values.Look(ref drawPubicHair, "drawPubicHair", true);

            //force to draw all size type
            /*
            Scribe_Values.Look(ref useTitanic, "useTitanic", true);
            Scribe_Values.Look(ref useColossal, "useColossal", true);
            Scribe_Values.Look(ref useGargantuan, "useGargantuan", true);
            Scribe_Values.Look(ref useMassive, "useMassive", true);
            Scribe_Values.Look(ref useEnormous, "useEnormous", true);
            Scribe_Values.Look(ref useHuge, "useHuge", true);
            Scribe_Values.Look(ref useLarge, "useLarge", true);
            Scribe_Values.Look(ref useAverage, "useAverage", true);
            Scribe_Values.Look(ref useSmall, "useSmall", true);
            Scribe_Values.Look(ref useTiny, "useTiny", true);
            Scribe_Values.Look(ref useNipples, "useNipples", true);
            */

            Scribe_Values.Look(ref useUnderBreasts, "useUnderBreasts",true);
            Scribe_Values.Look(ref UnderBreastsOffset, "UnderBreastsOffset", -0.0013f);

            //TODO: Humanlike Setting Per Race
            //Scribe_Values.Look(ref alienRacesAllowHumanlikTextures, "alienRacesAllowHumanlikTextures");

            //BreastsPhysics
            Scribe_Values.Look(ref breastsPhysics, "breastsPhysics", false);

            base.ExposeData();
        }

    }

    public class SizedApparelMod : Mod
    {

        SizedApparelSettings settings;
        private static Vector2 ScrollPosL = Vector2.zero;
        private static Vector2 ScrollPosR = Vector2.zero;
        public static List<string> alienDefList = new List<string>(); // to load aliens and compare with modsetting

        public override void WriteSettings()
        {
            base.WriteSettings();
            if(SizedApparelSettings.autoClearCacheOnWriteSetting)
                ClearCache();
        }

        public static void CheckAndLoadAlienRaces()
        {
            if(alienDefList == null)
                alienDefList = new List<string>();
            if (true)//alienDefList.Count == 0
            {
                IEnumerable<ThingDef> HumanlikeRaces;
                HumanlikeRaces = DefDatabase<ThingDef>.AllDefs.Where(b => b.race?.Humanlike == true);

                foreach (ThingDef raceDef in HumanlikeRaces)
                {
                    //Default Value Is True
                    alienDefList.Add(raceDef.defName);
                }
            }
        }

        public static void ClearCache(bool clearPawnGraphicSet = true)
        {
            SizedApparelsDatabase.ClearAll();

            if (Find.CurrentMap != null)
            {
                foreach (Pawn pawn in Find.CurrentMap.mapPawns.AllPawns)
                {
                    if (pawn == null)
                        continue;
                    var comp = pawn.GetComp<ApparelRecorderComp>();
                    if (comp != null)
                    {
                        comp.UpdateRaceSettingData();
                        comp.SetDirty(clearPawnGraphicSet,true,true,true);
                    }

                }
            }
        }

        public SizedApparelMod(ModContentPack content) : base(content)
        {
            this.settings = GetSettings<SizedApparelSettings>();
        }

        public override void DoSettingsWindowContents(Rect inRect)
        {

            const float alienRaceSettingHeight = 120;

            //CheckAndLoadAlienRaces();
            Listing_Standard listingStandard = new Listing_Standard();
            //Rect rect = new Rect(0f, 0f, inRect.width, 950);
            //Rect rect = inRect.ExpandedBy(0.9f);
            Rect leftRect = new Rect(inRect.position, new Vector2(inRect.width / 2, inRect.height));
            Rect rightRect = new Rect(inRect.position + new Vector2(inRect.width / 2,0), new Vector2(inRect.width / 2, inRect.height));
            //rect.xMax *= 0.9f;
            //leftRect = leftRect.ContractedBy(10f);
            rightRect = rightRect.ContractedBy(10f);
            Rect scrollRect = new Rect(0, 0, leftRect.width - 30f, Math.Max(leftRect.height + (float)alienDefList.Count* alienRaceSettingHeight, 1f));
            Widgets.BeginScrollView(leftRect, ref ScrollPosL, scrollRect, true);
            leftRect = new Rect(leftRect.x, leftRect.y, leftRect.width - 30f, leftRect.height + Math.Max((float)alienDefList.Count * alienRaceSettingHeight, 1f) + 250f);
            listingStandard.Begin(leftRect);
            listingStandard.maxOneColumn = true;

            listingStandard.CheckboxLabeled("Debug Log", ref SizedApparelSettings.Debug, "Debug logs.\nDefault: false");
            if (SizedApparelSettings.Debug)
            {
                listingStandard.CheckboxLabeled("Debug Log (Detail)", ref SizedApparelSettings.DetailLog, "Debug logs for checking missing textures.\nDefault: false");

            }
            listingStandard.GapLine(1f);
            listingStandard.CheckboxLabeled("Auto Clear Cache On Close Setting", ref SizedApparelSettings.autoClearCacheOnWriteSetting, "Auto clear cache data to apply Setting.\nDefault: true");
            if(SizedApparelSettings.autoClearCacheOnWriteSetting == false)
            {
                listingStandard.Label("If you changed options, try Clear Cache to apply. Some options may need to restart");
                if (listingStandard.ButtonTextLabeled("Clear Cache", "Press If you changed Option."))//\n do not push unless you really need. \n if this button still not work. reload savefile. if still not work, reload rimworld"
                {
                    ClearCache();
                }
                if (listingStandard.ButtonTextLabeled("RandomPreCache", "15 sec ~ 2 min"))
                {
                    SizedApparelsDatabase.RandomPreCacheForApparels();
                    SizedApparelsDatabase.RandomPreCacheForBodyParts();
                }
            }

            listingStandard.Gap();
            listingStandard.GapLine();

            /*
            listingStandard.Label("Optimization",-1,"");
            //listingStandard.CheckboxLabeled("Debug Log", ref SizedApparelSettings.Debug, "Debug logs.\nDefault: false");
            listingStandard.Gap(8);
            listingStandard.Label("no more optimization setting yet.\n It's hardly optimized already :)", -1, "");
            listingStandard.GapLine(5f);
            */
            //listingStandard.CheckboxLabeled("Use Breast Size Cap from Apparels(recommended: true)", ref SizedApparelSettings.useBreastSizeCapForApparels, "unite breast size from apparels. Smallest value will be used.\nIf you change this option, you need to redress Pawn\nDefault: true");

            //listingStandard.BeginScrollView(rect, ref ScrollPos, ref rect);
            //listingStandard.Label("Body(Torso)Texture Option", -1, "");
            //listingStandard.CheckboxLabeled("use Body (Torso) Texture", ref SizedApparelSettings.useBodyTexture, "change body texture if the pawn is wearing supported apparels only.\nIt may override bodytexture you use.\nIf you use rimnudeworld, don't use this option.\nDefault: false");
            //if (SizedApparelSettings.useBodyTexture == true)
            //{
            //    listingStandard.CheckboxLabeled("  use unsupportedApparel Body Texture", ref SizedApparelSettings.useUnsupportedBodyTexture, "Use \"_UnsupportedApparel\" Body Texture when pawn is wearing unsupported apparel.\nIf this option is false, the body will be default texture.\nDefault: true");
            //    listingStandard.CheckboxLabeled("  Match BodyTexture To Minimum ApparelSize", ref SizedApparelSettings.matchBodyTextureToMinimumApparelSize, "Avoid Clipping When breasts bigger than supported sized apparel.\nDefault: true");
            //
            //}
            listingStandard.Gap(8);
            listingStandard.Label("Other Mod Compatibility");
            listingStandard.Gap(8);
            listingStandard.CheckboxLabeled(" Force ignore unsupported apparel", ref SizedApparelSettings.ForcedSupportApparel, "It may have clipping issue from unsupported parts.\nDefault: false");

            /*
            if(SizedApparelPatch.DubsApparelTweaksActive == true)
            {
                listingStandard.Label("   Dubs Apparel Tweaks Patched! (may not work in 1.3)");
                listingStandard.Gap(8);
            }*/

            //sizeList.EndScrollView(ref rect);
            //listingStandard.EndSection(sizeList);
            //listingStandard.EndScrollView(ref sizeScrollRect);
            listingStandard.Label("Non RimJobWorld Compatibility (wip)", -1, "User Who play without RimJobWorld");
            if (!SizedApparelPatch.RJWActive)
            {
                if (SizedApparelPatch.SJWActive)
                {
                    listingStandard.Label("  SafeJobWorld is Actived ", -1, "");
                    listingStandard.CheckboxLabeled("     use SafeJobWorld's Breasts(Hidden to player but it exist)", ref SizedApparelSettings.useSafeJobBreasts, "use BreastsSize from SJW.\nDefault: true");

                }
                if(SizedApparelPatch.SJWActive? SizedApparelSettings.useSafeJobBreasts==false : true)
                {
                    listingStandard.CheckboxLabeled("       use Random Breasts Size(not yet work)", ref SizedApparelSettings.useRandomSize, "use breasts random size for pawn.\nDefault: true");
                    listingStandard.Label("     random Size Min: " + SizedApparelSettings.UnderBreastsOffset.ToString(), -1, "Defualt: 0.01");
                    SizedApparelSettings.randomSizeMin = listingStandard.Slider(SizedApparelSettings.randomSizeMin, 0f, 2f);
                    listingStandard.Label("     random Size Max: " + SizedApparelSettings.UnderBreastsOffset.ToString(), -1, "Defualt: 1.00");
                    SizedApparelSettings.randomSizeMax = listingStandard.Slider(SizedApparelSettings.randomSizeMax, SizedApparelSettings.randomSizeMin, 2f);

                }
                if (SizedApparelPatch.SJWActive == false)
                {

                }
            }
            else
            {
                //RimJobWorld is Actived
                listingStandard.Label("  RimJobWorld is Actived ", -1, "");

                if (SizedApparelPatch.MenstruationActive)
                {
                    listingStandard.Label("     RJW Menstuation is Active ", -1, "");
                }
                else
                {
                    listingStandard.Label("     RJW Menstuation is Not Active", -1, "");
                }

            }
            listingStandard.GapLine(1);
            listingStandard.Gap(12);
            listingStandard.Label("AlienRace Compatibility (wip)", -1, "");

            //listingStandard.CheckboxLabeled("  Unsupported race render as \"Humanlike\" ", ref SizedApparelSettings.UnsupportedRaceToUseHumanlike, "If unchecked, unsupported humanlike race will not be patched!\nIf you change this option, you need to restart rimworld or clear cache\nDefault: false");

            if (SizedApparelPatch.alienRaceActive)
            {
                listingStandard.Label("  AlienRace is Actived ", -1, "");
                //listingStandard.CheckboxLabeled("Force to use Human's BodyParts for unsuported Alien races", null, "");

                //TODO: Allow Humanlike Settings Per Races
                /*
                SizedApparelSettings.alienRaces = SizedApparelsDatabase.GetAlienRacesDefNames();

                listingStandard.Label("Alien Race Settings", -1f, null);

                SizedApparelSettings.alienRaceSearch = listingStandard.TextEntry(SizedApparelSettings.alienRaceSearch, 1);
                RaceSettings(new Rect(0f, 60f, 16f, 300f), SizedApparelSettings.alienRaces, ref SizedApparelSettings.alienRacesAllowHumanlikTextures, null);

                listingStandard.Gap(listingStandard.verticalSpacing);
                */
                /*
                Widgets.BeginScrollView(aliensRect, ref ScrollPos, leftRect);
                List<bool> alienSettingListLoc = new List<bool>();
                foreach(var item in SizedApparelsDatabase.AlienRaceUseHumanlike)
                {
                    //Widgets.CheckboxLabeled(aliensRect, item.Key, ref);
                }
                Widgets.EndScrollView();
                */
            }
            else
            {
                listingStandard.Label("  AlienRace is not Actived ", -1, "");
            }

            if (alienDefList.NullOrEmpty())
                CheckAndLoadAlienRaces();

            float h = alienDefList.Count * alienRaceSettingHeight;
            Listing_Standard Race_ListingStandard = listingStandard.BeginSection(h);
            foreach (var raceName in alienDefList)
            {
                Race_ListingStandard.Label(raceName);
                Race_ListingStandard.GapLine(1f);
                AlienRaceSetting raceSetting = null;
                foreach (var r in SizedApparelSettings.alienRaceSettings)
                {
                    if (r.raceName == null)
                        continue;
                    if (raceName == r.raceName)
                    {
                        raceSetting = r;
                        break;
                    }
                }
                if (raceSetting == null)
                {
                    raceSetting = new AlienRaceSetting(raceName);

                    SizedApparelSettings.alienRaceSettings.Add(raceSetting);
                }
                if(raceName != "Human")
                    Race_ListingStandard.CheckboxLabeled("If Unsupported, As Human race", ref raceSetting.asHuman, "This Race will use Human race if it doesn't have own textures. useful for race that Unsupported but simillar to human");
                Race_ListingStandard.CheckboxLabeled("Allow Race Named Apparel", ref raceSetting.allowRaceNamedApparel, "This Race Can use separated texture from common race. even same BodyType name. \n Default: True");
                Race_ListingStandard.Label((raceSetting.drawMinAge <= 100 ? "" : "[overdrive]") + "SA BodyPart Draw Min Age: " + raceSetting.drawMinAge.ToString(), -1, "Lower than this age will not use Sized Apparel. Useful for BnC. -1 for disable");
                raceSetting.drawMinAge = Mathf.Round(Race_ListingStandard.Slider(raceSetting.drawMinAge, raceSetting.drawMinAge <= 100 ? -1: 100, raceSetting.drawMinAge >= 100 ? 1000 : 100));
                Race_ListingStandard.Gap();
            }

            listingStandard.EndSection(Race_ListingStandard);
            Widgets.EndScrollView();
            //listingStandard.Gap(alienSettingHeight);
            listingStandard.Gap(8);
            listingStandard.GapLine(4f);

            listingStandard.Gap(8);
            listingStandard.Gap(8);
            listingStandard.Label("RimNudeWorld Compatibility (WIP)", -1, "");

            //listingStandard.CheckboxLabeled("  Don't Replace Body Texture On Nude", ref SizedApparelSettings.DontReplaceBodyTextureOnNude, "Only Replace BodyTexture On Not Nude. Trigers are Torso And Chests.\nDefault: False");
            if (SizedApparelPatch.rimNudeWorldActive)
            {
                listingStandard.Label("  RimNudeWorld is On!. Please check SizedApparel's Body parts render option", -1, "disable all body parts render except the breasts. and set it to only worn option true");
                listingStandard.CheckboxLabeled(" use Sized Apparel Breasts graphic when worn.", ref SizedApparelSettings.drawSizedApparelBreastsOnlyWorn, "use Sized Apparel's breasts render for breasts of apparel. it will be hidden when the pawn is naked and rimnudeworld will handle nude. \ndefault = true;");
                //listingStandard.CheckboxLabeled("  Hide RimNudeWorld Breasts Addon", ref SizedApparelSettings.hideRimNudeWorldBreasts, "For User Who Use Body(Torso) Texture option, remove double drawn breasts.\nYou can use this option as only using Rimnudeworld genital and else without breasts.\nDefault: False");

                if (listingStandard.ButtonTextLabeled("Easy Setting Button", "Apply Rimnude Setting"))
                {
                    SizedApparelSettings.drawSizedApparelBreastsOnlyWorn = true;
                    SizedApparelSettings.useBodyTexture = false;
                    SizedApparelSettings.drawBreasts = true;
                    SizedApparelSettings.drawPenis = false;
                    SizedApparelSettings.drawVagina = false;
                    SizedApparelSettings.drawAnus = false;
                    SizedApparelSettings.drawBelly = false;
                    SizedApparelSettings.drawPubicHair = false;
                }

                if (false)//SizedApparelSettings.hideRimNudeWorldBreasts == false
                {
                    //listingStandard.CheckboxLabeled("  match Breast Texture To Minimum ApparelSize (not work)", ref SizedApparelSettings.matchBreastTextureToMinimumApparelSize, "Avoid Clipping When breasts bigger than supported sized apparel.\nDefault: true");

                    //listingStandard.CheckboxLabeled("  use Under Breasts addon (RimNudeWorld)(not recomanded)", ref SizedApparelSettings.useUnderBreasts, "draw breasts under apparel.");
                    listingStandard.Label("  Under Breasts Offset: " + SizedApparelSettings.UnderBreastsOffset.ToString(), -1, "offset from defeault layer offset. Defualt: -0.0013");
                    SizedApparelSettings.UnderBreastsOffset = listingStandard.Slider(SizedApparelSettings.UnderBreastsOffset, -0.025f, 0.025f);
                }
                if (SizedApparelSettings.useBodyTexture)
                {

                }
            }
            else
            {
                listingStandard.Label("  RimNudeWorld is not Actived ", -1, "");
                if (listingStandard.ButtonTextLabeled("Easy Setting Button", "Apply Non Rimnude Setting"))
                {
                    SizedApparelSettings.drawSizedApparelBreastsOnlyWorn = false;
                    SizedApparelSettings.useBodyTexture = true;
                    SizedApparelSettings.drawBreasts = true;
                    SizedApparelSettings.drawPenis = true;
                    SizedApparelSettings.drawVagina = true;
                    SizedApparelSettings.drawAnus = true;
                    SizedApparelSettings.drawBelly = true;
                    SizedApparelSettings.drawPubicHair = true;
                }
            }
            listingStandard.Gap(8);
            listingStandard.GapLine(5f);
            if (SizedApparelPatch.RimworldAnimationActive)
            {
                listingStandard.Label("RimworldAnimation (rjwAnimation) is Actived ", -1, "");
                listingStandard.CheckboxLabeled(" Animated SizedApparel BodyParts (wip)", ref SizedApparelSettings.AnimationPatch, "this option may animated breasts jiggle during animation.\n but not copatable with rimnudeworld.\ndefault: true");
            }
            else
            {
                listingStandard.Label("RimworldAnimation (rjwAnimation) is not Actived ", -1, "");
            }

            listingStandard.End();

            ////RightRect
            scrollRect = new Rect(0, 0, rightRect.width - 30f, Math.Max(rightRect.height + 100f, 1f));

            Widgets.BeginScrollView(rightRect, ref ScrollPosR, scrollRect, true);
            rightRect = new Rect(0, 0, rightRect.width - 30f, rightRect.height + 100f + 250f);
            listingStandard.maxOneColumn = true;

            listingStandard.Begin(rightRect);

            listingStandard.Label("SizedApparel System Apply (apparel and body parts)");
            listingStandard.CheckboxLabeled(" Apply Humanlikes", ref SizedApparelSettings.ApplyHumanlikes, "Try to Apply SizedApparel to Humanlikes if The textures are valid.\nDefault: true");
            listingStandard.CheckboxLabeled(" Apply Animals", ref SizedApparelSettings.ApplyAnimals, "Try to Apply SizedApparel to Animals if The textures are valid.\nThis may heavy performance \nDefault: false");
            //TODO
            /*
            if (SizedApparelSettings.ApplyAnimals)
                listingStandard.CheckboxLabeled("   Apply Player Faction Animals Only", ref SizedApparelSettings.ApplyAnimalsPlayerFactionOnly, "Default: true");
            */
            listingStandard.CheckboxLabeled(" Apply Mechanoid", ref SizedApparelSettings.ApplyMechanoid, "Try to Apply SizedApparel to Mech if The textures are valid.\nDefault: true");
            listingStandard.GapLine(5f);

            listingStandard.Label("Apparel Patch (Breasts Sized Apparel)");
            listingStandard.CheckboxLabeled(" Apply Apparel Patch for Male", ref SizedApparelSettings.ApplyApparelPatchForMale, "It Skips breasts size test for male. Do you need man with breasts...? may be not.\nDefault: false");
            listingStandard.GapLine(5f);

            listingStandard.Label("If you changed the option, try change apparels or reload save", -1);
            listingStandard.Label("Body Part Render Option (wip)",-1,"standalone BodyPart Render System from this mod. It's for user who don't use RimNudeWorld\nIf you use RimNudeWorld, you should turn off this.");

            listingStandard.CheckboxLabeled("Use Gender Specific Textures.", ref SizedApparelSettings.useGenderSpecificTexture,"Use Gender Specific texture for body and apparel if it's valid. \nDefault: true");
            listingStandard.GapLine(5);
            listingStandard.CheckboxLabeled("Draw Body Parts", ref SizedApparelSettings.drawBodyParts, "Draw Breasts..etc. when the pawn is wearing supported apparels. \nDefault: true");
            if (SizedApparelSettings.drawBodyParts)
            {
                listingStandard.CheckboxLabeled("  Use (Sized Apparel) Base Body Texture", ref SizedApparelSettings.useBodyTexture, "change pawn's body texture when the pawn is wearing supported apparels. Recommanded\nDefault: true");

                //listingStandard.CheckboxLabeled("  Draw Muscle Overlay (wip)", ref SizedApparelSettings.drawMuscleOverlay, "\nDisable this option when you use RimNudeWorld");

                listingStandard.CheckboxLabeled("  Draw Breasts", ref SizedApparelSettings.drawBreasts, "this option is why this mod exist.\nDefault: true");
                if (SizedApparelSettings.drawBreasts)
                {
                    listingStandard.CheckboxLabeled("     Match Breasts size to supported apparels",ref SizedApparelSettings.matchBreastToSupportedApparelSize, "to avoid breasts clipping(when breasts are bigger), you need this option.\nDefault: true");
                    listingStandard.CheckboxLabeled("     draw Breasts on worn pawn only (RimNudeWorld)", ref SizedApparelSettings.drawSizedApparelBreastsOnlyWorn, "when the pawn is nude, the breasts graphic for sized apparel will be hidden. \nDefault: false" );
                    listingStandard.CheckboxLabeled("     (Wip) Breasts Physics", ref SizedApparelSettings.breastsPhysics, "Breasts can be jiggled (for now. it works when nude only). It may be heavy for performance. \n Won't work with RimNudeWorld Breasts Rendering. \ndefault = false");
                }
                listingStandard.CheckboxLabeled("  Draw Penis", ref SizedApparelSettings.drawPenis,"Disable this option when you use RimNudeWorld");
                listingStandard.CheckboxLabeled("  Draw Vagina", ref SizedApparelSettings.drawVagina, "Disable this option when you use RimNudeWorld");
                listingStandard.CheckboxLabeled("  Draw Anus", ref SizedApparelSettings.drawAnus, "Disable this option when you use RimNudeWorld");
                listingStandard.CheckboxLabeled("  Draw Belly Buldge", ref SizedApparelSettings.drawBelly, "Disable this option when you use RimNudeWorld");

                listingStandard.CheckboxLabeled("  Draw Pubic Hair", ref SizedApparelSettings.drawPubicHair, "Disable this option when you use RimNudeWorld");

                listingStandard.CheckboxLabeled("  Hide Balls of Futa", ref SizedApparelSettings.hideBallOfFuta, "Hide Balls from penis of Futa.\nDefault: false");
                listingStandard.CheckboxLabeled("  Hide Penis of Man(Not Work yet)", ref SizedApparelSettings.hidePenisOfMale, "this option is for someone who really hate to see male's dick around.\nDefault: false");

                //listingStandard.Gap();
                //listingStandard.CheckboxLabeled(" Use Body Part Variation", ref SizedApparelSettings.useBodyPartsVariation, "Use graphic variation such as inverted nipple.\nDefault: true");
                //listingStandard.CheckboxLabeled(" Show Body Part Variaion Button(WIP)", ref SizedApparelSettings.showBodyPartsVariationIcon, "WIP. Not work for now.\nDefault: true");

                listingStandard.Gap();
                //listingStandard.CheckboxLabeled(" Use BodyPart Variation", ref SizedApparelSettings.useBodyPartsVariation, ""); //TODO
                listingStandard.CheckboxLabeled(" Show BodyPart Variation Description", ref SizedApparelSettings.showBodyPartsVariation, "Show more info in bodyparts that sized apparel added. such as inverted nipple");
            }
            /*
            listingStandard.Gap(4);
            listingStandard.Label("Breast Size Toggle Option", -1, "default option is setted for RimnudeWorld. you should not change this unless you have the textures for that size.");
            listingStandard.Gap(4);
            //Rect sizeScrollRect = new Rect(inRect.position+ new Vector2(0, listingStandard.CurHeight), inRect.size/3);
            //Vector2 sizeScrollPosition = new Vector2(0.9f, 0.5f);
            //listingStandard.BeginScrollView(sizeScrollRect, ref sizeScrollPosition, ref sizeScrollRect);
            //Listing_Standard sizeList = listingStandard.BeginSection_NewTemp(150);

            //sizeList.BeginScrollView(rect, ref ScrollPos, ref rect);

            listingStandard.CheckboxLabeled("  use Nipples", ref SizedApparelSettings.useNipples, "use Nipples(Flat breasts) Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Tiny", ref SizedApparelSettings.useTiny, "use Tiny breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Small", ref SizedApparelSettings.useSmall, "use Small breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Average", ref SizedApparelSettings.useAverage, "use Average breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Large", ref SizedApparelSettings.useLarge, "use Large breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Huge", ref SizedApparelSettings.useHuge, "use Huge breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Enormous", ref SizedApparelSettings.useEnormous, "use Enormous breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Massive", ref SizedApparelSettings.useMassive, "use Massive breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Gargantuan", ref SizedApparelSettings.useGargantuan, "use Gargantuan breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Colossal", ref SizedApparelSettings.useColossal, "use Colossal breasts Sized Apparel.\nDefault: true");
            listingStandard.CheckboxLabeled("  use Titanic", ref SizedApparelSettings.useTitanic, "use Titanic breasts Sized Apparel.\nDefault: true");
            */
            Widgets.EndScrollView();
            listingStandard.End();

            //listingStandard.EndScrollView(ref rect);
            base.DoSettingsWindowContents(inRect);
        }

        public override string SettingsCategory()
        {
            return "Sized Apparel for RJW";
        }

        //copy from BnC
        public static bool Contai(string source, string toCheck, StringComparison comp)
        {
            return source != null && source.IndexOf(toCheck, comp) >= 0;
        }
        //copy from BnC
        public static void RaceSettings(Rect rect, List<string> label, ref List<string> alienRacesToAllowHumanlikes, string tooltip = null)
        {
            bool flag = !GenText.NullOrEmpty(tooltip);
            if (flag)
            {
                bool flag2 = Mouse.IsOver(rect);
                if (flag2)
                {
                    Widgets.DrawHighlight(rect);
                }
                TooltipHandler.TipRegion(rect, tooltip);
            }
            bool flag3 = GenList.NullOrEmpty<string>(alienRacesToAllowHumanlikes);
            if (flag3)
            {
                alienRacesToAllowHumanlikes = new List<string>();
            }
            Listing_Standard listing_Standard = new Listing_Standard();
            Rect rect2 = rect;
            Rect rect3 = rect;
            rect3.height = (float)label.Count * 30f;
            rect3.width -= 16f;
            Widgets.BeginScrollView(rect2, ref SizedApparelSettings.alienRacesListScrollPos, rect3, true);
            listing_Standard.Begin(rect3);
            for (int i = 0; i < SizedApparelSettings.alienRaces.Count; i++)
            {
                bool flag4 = GenList.NullOrEmpty<string>(alienRacesToAllowHumanlikes) || !alienRacesToAllowHumanlikes.Contains(label[i]);
                bool flag5 = SizedApparelSettings.alienRaceSearch == null || Contai(SizedApparelSettings.alienRaces[i], SizedApparelSettings.alienRaceSearch.ToLower(), StringComparison.OrdinalIgnoreCase);
                if (flag5)
                {
                    WidgetRow widgetRow = new WidgetRow(rect.x,listing_Standard.CurHeight, UIDirection.RightThenUp, 99999f, 1f);
                    widgetRow.Label(label[i], rect.width * 0.8f, null, -1f);

                    bool flag6 = label[i] != "Human";
                    if (flag6)
                    {
                        widgetRow.ToggleableIcon(ref flag4, TexButton.IconBook, "Use Shared Body Parts texture (\"Humanlike\" body plarts).\nIf Unchecked, the race will use race's owned texture. \n If the race not have supported textures, try this option.", null, null);
                    }
                    else
                    {
                        //TODO: should I let human can use humanlike textures?
                        widgetRow.Icon(TexButton.IconBook, "Human Race is forced to use \"Human\" Textures. not \"Humanlike\"");
                    }

                    /*
                    bool flag7 = widgetRow.ButtonIcon(TexButton.ToggleTweak, "Allow Humanlike Body parts rendering from Sized Apparel(NOT RIMNUDE!)", null, null, null, true, -1f);
                    if (flag7)
                    {
                        bool flag8 = Current.Game != null;
                        if (flag8)
                        {
                            bool flag9 = !Find.WindowStack.TryRemove(typeof(RaceEditorWindow), true);
                            if (flag9)
                            {
                                RaceSettings sizeSettings = RaceUtility.GetSizeSettings(DefDatabase<ThingDef>.GetNamed(label[i], false));
                                RaceEditorWindow raceEditorWindow = new RaceEditorWindow();
                                raceEditorWindow.alienRace = DefDatabase<ThingDef>.GetNamed(label[i], true);
                                bool flag10 = sizeSettings != null;
                                if (flag10)
                                {
                                    raceEditorWindow.raceSettings = sizeSettings;
                                    raceEditorWindow.headOffset = sizeSettings.headOffset;
                                    raceEditorWindow.sizeModifier = sizeSettings.sizeModifier;
                                    raceEditorWindow.hairSizeModifier = sizeSettings.hairSizeModifier;
                                    raceEditorWindow.headSizeModifier = sizeSettings.headSizeModifier;
                                    raceEditorWindow.scaleChild = sizeSettings.scaleChild;
                                    raceEditorWindow.scaleTeen = sizeSettings.scaleTeen;
                                }
                                Find.WindowStack.Add(raceEditorWindow);
                            }
                        }
                        else
                        {
                            Messages.Message("You need to be in-game to open size editor", MessageTypeDefOf.RejectInput, true);
                        }
                    }
                    */
                    bool flag11 = !flag4;
                    if (flag11)
                    {
                        bool flag12 = !alienRacesToAllowHumanlikes.Contains(label[i]);
                        if (flag12)
                        {
                            alienRacesToAllowHumanlikes.Add(label[i]);
                        }
                    }
                    else
                    {
                        bool flag13 = alienRacesToAllowHumanlikes.Contains(label[i]);
                        if (flag13)
                        {
                            alienRacesToAllowHumanlikes.Remove(label[i]);
                        }
                    }
                    listing_Standard.Gap(30f);
                }
            }
            listing_Standard.End();
            Widgets.EndScrollView();
        }
    }

}