protected void ComposeGuis()
        {
            double pad      = GuiElementItemSlotGridBase.unscaledSlotPadding;
            double slotsize = GuiElementPassiveItemSlot.unscaledSlotSize;

            characterInv = capi.World.Player.InventoryManager.GetOwnInventory(GlobalConstants.characterInvClassName);

            ElementBounds tabBounds = ElementBounds.Fixed(0, -25, 450, 25);

            double ypos = 20 + pad;

            ElementBounds bgBounds = ElementBounds.FixedSize(717, 433).WithFixedPadding(GuiStyle.ElementToDialogPadding);

            ElementBounds dialogBounds = ElementBounds.FixedSize(757, 473).WithAlignment(EnumDialogArea.CenterMiddle)
                                         .WithFixedAlignmentOffset(GuiStyle.DialogToScreenPadding, 0);


            GuiTab[] tabs = new GuiTab[] {
                new GuiTab()
                {
                    Name = "Skin", DataInt = 0
                },
                new GuiTab()
                {
                    Name = "Class", DataInt = 1
                },
                //  new GuiTab() { Name = "Outfit", DataInt = 2 }
            };

            Composers["createcharacter"] =
                capi.Gui
                .CreateCompo("createcharacter", dialogBounds)
                .AddShadedDialogBG(bgBounds, true)
                .AddDialogTitleBar(curTab == 0 ? Lang.Get("Customize Skin") : (curTab == 1 ? Lang.Get("Select character class") : Lang.Get("Select your outfit")), OnTitleBarClose)
                .AddHorizontalTabs(tabs, tabBounds, onTabClicked, CairoFont.WhiteSmallText(), CairoFont.WhiteSmallText().WithWeight(Cairo.FontWeight.Bold), "tabs")
                .BeginChildElements(bgBounds)
            ;

            capi.World.Player.Entity.hideClothing = false;

            if (curTab == 0)
            {
                var skinMod = capi.World.Player.Entity.GetBehavior <EntityBehaviorExtraSkinnable>();

                capi.World.Player.Entity.hideClothing = charNaked;
                var essr = capi.World.Player.Entity.Properties.Client.Renderer as EntitySkinnableShapeRenderer;
                essr.TesselateShape();

                CairoFont smallfont     = CairoFont.WhiteSmallText();
                var       tExt          = smallfont.GetTextExtents(Lang.Get("Show dressed"));
                int       colorIconSize = 22;

                ElementBounds leftSlotBounds = ElementStdBounds.SlotGrid(EnumDialogArea.None, 0, ypos, 4, rows).FixedGrow(2 * pad, 2 * pad);
                insetSlotBounds = ElementBounds.Fixed(0, ypos + 2, 265, leftSlotBounds.fixedHeight - 2 * pad + 10).FixedRightOf(leftSlotBounds, 10);
                ElementBounds rightSlotBounds    = ElementStdBounds.SlotGrid(EnumDialogArea.None, 0, ypos, 1, rows).FixedGrow(2 * pad, 2 * pad).FixedRightOf(insetSlotBounds, 10);
                ElementBounds toggleButtonBounds = ElementBounds.Fixed(
                    (int)insetSlotBounds.fixedX + insetSlotBounds.fixedWidth / 2 - tExt.Width / RuntimeEnv.GUIScale / 2 - 12,
                    0,
                    tExt.Width / RuntimeEnv.GUIScale,
                    tExt.Height / RuntimeEnv.GUIScale
                    )
                                                   .FixedUnder(insetSlotBounds, 4).WithAlignment(EnumDialogArea.LeftFixed).WithFixedPadding(12, 6)
                ;

                ElementBounds bounds     = null;
                ElementBounds prevbounds = null;

                double leftX = 0;

                foreach (var skinpart in skinMod.AvailableSkinParts)
                {
                    bounds = ElementBounds.Fixed(leftX, (prevbounds == null || prevbounds.fixedY == 0) ? -10 : prevbounds.fixedY + 8, colorIconSize, colorIconSize);

                    string code = skinpart.Code;

                    AppliedSkinnablePartVariant appliedVar = skinMod.AppliedSkinParts.FirstOrDefault(sp => sp.PartCode == code);


                    if (skinpart.Type == EnumSkinnableType.Texture && !skinpart.UseDropDown)
                    {
                        int   selectedIndex = 0;
                        int[] colors        = new int[skinpart.Variants.Length];

                        for (int i = 0; i < skinpart.Variants.Length; i++)
                        {
                            colors[i] = skinpart.Variants[i].Color;

                            if (appliedVar?.Code == skinpart.Variants[i].Code)
                            {
                                selectedIndex = i;
                            }
                        }

                        Composers["createcharacter"].AddStaticText(Lang.Get("skinpart-" + code), CairoFont.WhiteSmallText(), bounds   = bounds.BelowCopy(0, 10).WithFixedSize(210, 22));
                        Composers["createcharacter"].AddColorListPicker(colors, (index) => onToggleSkinPartColor(code, index), bounds = bounds.BelowCopy(0, 0).WithFixedSize(colorIconSize, colorIconSize), 180, "picker-" + code);
                        Composers["createcharacter"].ColorListPickerSetValue("picker-" + code, selectedIndex);
                    }
                    else
                    {
                        int selectedIndex = 0;

                        string[] names  = new string[skinpart.Variants.Length];
                        string[] values = new string[skinpart.Variants.Length];

                        for (int i = 0; i < skinpart.Variants.Length; i++)
                        {
                            names[i]  = Lang.Get("skinpart-" + code + "-" + skinpart.Variants[i].Code);
                            values[i] = skinpart.Variants[i].Code;

                            //Console.WriteLine("\"" + names[i] + "\": \"" + skinpart.Variants[i].Code + "\",");

                            if (appliedVar?.Code == values[i])
                            {
                                selectedIndex = i;
                            }
                        }


                        Composers["createcharacter"].AddStaticText(Lang.Get("skinpart-" + code), CairoFont.WhiteSmallText(), bounds = bounds.BelowCopy(0, 10).WithFixedSize(210, 22));
                        Composers["createcharacter"].AddDropDown(values, names, selectedIndex, (variantcode, selected) => onToggleSkinPartColor(code, variantcode), bounds = bounds.BelowCopy(0, 0).WithFixedSize(200, 25), "dropdown-" + code);
                    }

                    prevbounds = bounds.FlatCopy();

                    if (skinpart.Colbreak)
                    {
                        leftX             = insetSlotBounds.fixedX + insetSlotBounds.fixedWidth + 22;
                        prevbounds.fixedY = 0;
                    }
                }



                Composers["createcharacter"]
                .AddInset(insetSlotBounds, 2)
                .AddToggleButton(Lang.Get("Show dressed"), smallfont, OnToggleDressOnOff, toggleButtonBounds, "showdressedtoggle")
                .AddSmallButton(Lang.Get("Randomize"), OnRandomizeSkin, ElementBounds.Fixed(0, 0).FixedUnder(rightSlotBounds, 16).WithAlignment(EnumDialogArea.LeftFixed).WithFixedPadding(12, 6), EnumButtonStyle.Normal, EnumTextOrientation.Center)
                .AddSmallButton(Lang.Get("Confirm Skin"), OnNext, ElementBounds.Fixed(0, 0).FixedUnder(rightSlotBounds, 16).WithAlignment(EnumDialogArea.RightFixed).WithFixedPadding(12, 6), EnumButtonStyle.Normal, EnumTextOrientation.Center)
                ;

                Composers["createcharacter"].GetToggleButton("showdressedtoggle").SetValue(!charNaked);
            }

            if (curTab == 1)
            {
                var essr = capi.World.Player.Entity.Properties.Client.Renderer as EntitySkinnableShapeRenderer;
                essr.TesselateShape();

                ypos -= 10;
                ElementBounds leftSlotBounds = ElementStdBounds.SlotGrid(EnumDialogArea.None, 0, ypos, 0, rows).FixedGrow(2 * pad, 2 * pad);
                insetSlotBounds = ElementBounds.Fixed(0, ypos + 25, 190, leftSlotBounds.fixedHeight - 2 * pad + 8 + 25).FixedRightOf(leftSlotBounds, 10);
                ElementBounds rightSlotBounds = ElementStdBounds.SlotGrid(EnumDialogArea.None, 0, ypos, 1, rows).FixedGrow(2 * pad, 2 * pad).FixedRightOf(insetSlotBounds, 10);

                ElementBounds prevButtonBounds = ElementBounds.Fixed(0, ypos + 25, 35, slotsize - 4).WithFixedPadding(2).FixedRightOf(insetSlotBounds, 20);
                ElementBounds centerTextBounds = ElementBounds.Fixed(0, ypos + 25, 200, slotsize - 4 - 8).FixedRightOf(prevButtonBounds, 20);

                ElementBounds charclasssInset = centerTextBounds.ForkBoundingParent(4, 4, 4, 4);

                ElementBounds nextButtonBounds = ElementBounds.Fixed(0, ypos + 25, 35, slotsize - 4).WithFixedPadding(2).FixedRightOf(charclasssInset, 20);

                CairoFont font = CairoFont.WhiteMediumText();
                centerTextBounds.fixedY += (centerTextBounds.fixedHeight - font.GetFontExtents().Height / RuntimeEnv.GUIScale) / 2;

                ElementBounds charTextBounds = ElementBounds.Fixed(0, 0, 480, 100).FixedUnder(prevButtonBounds, 20).FixedRightOf(insetSlotBounds, 20);

                Composers["createcharacter"]
                .AddInset(insetSlotBounds, 2)

                .AddIconButton("left", (on) => changeClass(-1), prevButtonBounds.FlatCopy())
                .AddInset(charclasssInset, 2)
                .AddDynamicText("Commoner", font, EnumTextOrientation.Center, centerTextBounds, "className")
                .AddIconButton("right", (on) => changeClass(1), nextButtonBounds.FlatCopy())

                .AddRichtext("", CairoFont.WhiteDetailText(), charTextBounds, "characterDesc")
                .AddSmallButton(Lang.Get("Confirm Class"), OnConfirm, ElementBounds.Fixed(0, 0).FixedUnder(rightSlotBounds, 26).WithAlignment(EnumDialogArea.RightFixed).WithFixedPadding(12, 6), EnumButtonStyle.Normal, EnumTextOrientation.Center)
                ;

                changeClass(0);
            }

            /*if (curTab == 2) {
             *
             *  ElementBounds leftPrevButtonBounds = ElementBounds.Fixed(0, ypos + 52, 19, slotsize - 4).WithFixedPadding(2);
             *  ElementBounds leftNextButtonBounds = ElementBounds.Fixed(0, ypos + 52, 19, slotsize - 4).WithFixedPadding(2).FixedRightOf(leftPrevButtonBounds, 6);
             *
             *  ElementBounds leftSlotBounds = ElementStdBounds.SlotGrid(EnumDialogArea.None, 0, ypos, 1, rows).FixedGrow(2 * pad, 2 * pad).FixedRightOf(leftNextButtonBounds, 8);
             *  insetSlotBounds = ElementBounds.Fixed(0, ypos + 25, 220, leftSlotBounds.fixedHeight - 2 * pad - 4 + 25).FixedRightOf(leftSlotBounds, 10);
             *  ElementBounds rightSlotBounds = ElementStdBounds.SlotGrid(EnumDialogArea.None, 0, ypos, 1, rows).FixedGrow(2 * pad, 2 * pad).FixedRightOf(insetSlotBounds, 10);
             *
             *  ElementBounds rightPrevButtonBounds = ElementBounds.Fixed(20, ypos + 1, 19, slotsize - 4).WithFixedPadding(2).FixedRightOf(rightSlotBounds, 6);
             *  ElementBounds rightNextButtonBounds = ElementBounds.Fixed(20, ypos + 1, 19, slotsize - 4).WithFixedPadding(2).FixedRightOf(rightPrevButtonBounds, 6);
             *
             *
             *
             *  Composers["createcharacter"]
             *      .AddItemSlotGrid(characterInv, SendInvPacket, 1, new int[] { 0, 1, 2, 11, 3, 4 }, leftSlotBounds, "leftSlots")
             *
             *          // Shoulder
             *          .AddIconButton("left", (on) => OnPrevious(1), leftPrevButtonBounds.FlatCopy())
             *          .AddIconButton("right", (on) => OnNext(1), leftNextButtonBounds.FlatCopy())
             *
             *          // Upper body
             *          .AddIconButton("left", (on) => OnPrevious(2), leftPrevButtonBounds = leftPrevButtonBounds.BelowCopy(0, 3))
             *          .AddIconButton("right", (on) => OnNext(2), leftNextButtonBounds = leftNextButtonBounds.BelowCopy(0, 3))
             *
             *          // Trousers
             *          .AddIconButton("left", (on) => OnPrevious(3), leftPrevButtonBounds = leftPrevButtonBounds.BelowCopy(0, 3).BelowCopy(0, 3))
             *          .AddIconButton("right", (on) => OnNext(3), leftNextButtonBounds = leftNextButtonBounds.BelowCopy(0, 3).BelowCopy(0, 3))
             *
             *          // Shoes
             *          .AddIconButton("left", (on) => OnPrevious(4), leftPrevButtonBounds = leftPrevButtonBounds.BelowCopy(0, 3))
             *          .AddIconButton("right", (on) => OnNext(4), leftNextButtonBounds = leftNextButtonBounds.BelowCopy(0, 3))
             *
             *          // Gloves (on the right)
             *          //  .AddIconButton("left", (on) => OnPrevious(5), rightPrevButtonBounds = rightPrevButtonBounds.BelowCopy(0, 3).BelowCopy(0, 3).BelowCopy(0, 3).BelowCopy(0, 3))
             *          // .AddIconButton("right", (on) => OnNext(5), rightNextButtonBounds = rightNextButtonBounds.BelowCopy(0, 3).BelowCopy(0, 3).BelowCopy(0, 3).BelowCopy(0, 3))
             *
             *          .AddInset(insetSlotBounds, 2)
             *          //.AddItemSlotGrid(characterInv, SendInvPacket, 1, new int[] { 6, 7, 8, 10, 5, 9 }, rightSlotBounds, "rightSlots")
             *
             *          .AddSmallButton(Lang.Get("Randomize"), OnRandomizeClothes, ElementBounds.Fixed(0, 0).FixedUnder(rightSlotBounds, 20).WithAlignment(EnumDialogArea.LeftFixed).WithFixedPadding(10, 4), EnumButtonStyle.Normal, EnumTextOrientation.Center)
             *          .AddSmallButton(Lang.Get("Confirm Selection"), OnConfirm, ElementBounds.Fixed(0, 0).FixedUnder(rightSlotBounds, 20).WithAlignment(EnumDialogArea.RightFixed).WithFixedPadding(10, 4), EnumButtonStyle.Normal, EnumTextOrientation.Center)
             *
             *      .EndChildElements()
             *  ;
             * }*/


            var tabElem = Composers["createcharacter"].GetHorizontalTabs("tabs");

            tabElem.unscaledTabSpacing = 20;
            tabElem.unscaledTabPadding = 10;
            tabElem.activeElement      = curTab;

            Composers["createcharacter"].Compose();


            /*if (curTab == 2)
             * {
             *  Composers["createcharacter"].GetSlotGrid("leftSlots").CanClickSlot = (slotid) => { return false; };
             *  //Composers["createcharacter"].GetSlotGrid("rightSlots").CanClickSlot = (slotid) => { return false; };
             * }*/
        }
        protected Shape addSkinPart(AppliedSkinnablePartVariant part, Shape entityShape, string[] disableElements, string shapePathForLogging)
        {
            //if (part.PartCode.Contains("hair")) return entityShape; // Disabled until pre.2

            if (disableElements != null)
            {
                foreach (var val in disableElements)
                {
                    entityShape.RemoveElementByName(val);
                }
            }

            ICoreClientAPI api = entity.World.Api as ICoreClientAPI;
            AssetLocation  shapePath;
            CompositeShape tmpl = AvailableSkinPartsByCode[part.PartCode].ShapeTemplate;

            if (part.Shape == null && tmpl != null)
            {
                shapePath      = tmpl.Base.CopyWithPath("shapes/" + tmpl.Base.Path + ".json");
                shapePath.Path = shapePath.Path.Replace("{code}", part.Code);
            }
            else
            {
                shapePath = part.Shape.Base.CopyWithPath("shapes/" + part.Shape.Base.Path + ".json");
            }
            IAsset asset = api.Assets.TryGet(shapePath);

            if (asset == null)
            {
                api.World.Logger.Warning("Entity skin shape {0} defined in entity config {1} not found, was supposed to be at {2}. Skin part will be invisible.", shapePath, entity.Properties.Code, shapePath);
                return(null);
            }

            Shape partShape;

            try
            {
                partShape = asset.ToObject <Shape>();
            }
            catch (Exception e)
            {
                api.World.Logger.Warning("Exception thrown when trying to load entity armor shape {0} defined in {1}. Skin part will be invisible. Exception: {2}", shapePath, entity.Properties.Code, e);
                return(null);
            }


            bool added = false;

            foreach (var val in partShape.Elements)
            {
                ShapeElement elem;

                if (val.StepParentName != null)
                {
                    elem = entityShape.GetElementByName(val.StepParentName, StringComparison.InvariantCultureIgnoreCase);
                    if (elem == null)
                    {
                        api.World.Logger.Warning("Skin part shape {0} defined in entity config {1} requires step parent element with name {2}, but no such element was found in shape {3}. Will not be visible.", shapePath, entity.Properties.Code, val.StepParentName, shapePathForLogging);
                        continue;
                    }
                }
                else
                {
                    api.World.Logger.Warning("Skin part shape element {0} in shape {1} defined in entity config {2} did not define a step parent element. Will not be visible.", val.Name, shapePath, entity.Properties.Code);
                    continue;
                }

                if (elem.Children == null)
                {
                    elem.Children = new ShapeElement[] { val };
                }
                else
                {
                    elem.Children = elem.Children.Append(val);
                }

                val.SetJointIdRecursive(elem.JointId);
                val.WalkRecursive((el) =>
                {
                    foreach (var face in el.Faces)
                    {
                        face.Value.Texture = "#" + "skinpart-" + face.Value.Texture.TrimStart('#');
                    }
                });

                added = true;
            }

            if (added && partShape.Textures != null)
            {
                Dictionary <string, AssetLocation> newdict = new Dictionary <string, AssetLocation>();
                foreach (var val in partShape.Textures)
                {
                    if (val.Key == "seraph")
                    {
                        continue;
                    }

                    newdict["skinpart-" + val.Key] = val.Value;
                }

                partShape.Textures = newdict;

                foreach (var val in partShape.Textures)
                {
                    if (val.Key == "seraph")
                    {
                        continue;
                    }

                    loadTexture(entityShape, val.Key, val.Value, partShape.TextureWidth, partShape.TextureHeight, shapePathForLogging);
                }

                foreach (var val in partShape.TextureSizes)
                {
                    entityShape.TextureSizes[val.Key] = val.Value;
                }
            }

            return(entityShape);
        }