Ejemplo n.º 1
0
        public override void OnActivate()
        {
            scrollPanel.Append(uiLoader);
            modPacks.Clear();
            Task.Factory
            .StartNew(delegate {
                mods = ModOrganizer.FindMods().Select(m => m.Name).ToArray();

                Directory.CreateDirectory(ModPacksDirectory);
                return(Directory.GetFiles(ModPacksDirectory, "*.json", SearchOption.TopDirectoryOnly));
            })
            .ContinueWith(task => {
                foreach (string modPackPath in task.Result)
                {
                    try {
                        if (!IsValidModpackName(Path.GetFileNameWithoutExtension(modPackPath)))
                        {
                            throw new Exception();
                        }
                        string[] modPackMods = JsonConvert.DeserializeObject <string[]>(File.ReadAllText(modPackPath));
                        modPacks.Add(new UIModPackItem(Path.GetFileNameWithoutExtension(modPackPath), modPackMods));
                    }
                    catch {
                        var badModPackMessage = new UIAutoScaleTextTextPanel <string>(Language.GetTextValue("tModLoader.ModPackMalformed", Path.GetFileName(modPackPath)))
                        {
                            Width  = { Percent = 1 },
                            Height = { Pixels = 50, Percent = 0 }
                        };
                        modPacks.Add(badModPackMessage);
                    }
                }
                scrollPanel.RemoveChild(uiLoader);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
Ejemplo n.º 2
0
 internal void Populate()
 {
     if (SynchronizationContext.Current == null)
     {
         SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
     }
     Task.Factory.StartNew(
         delegate
     {
         var modSources = ModLoader.FindModSources();
         var modFiles   = ModOrganizer.FindMods();
         return(Tuple.Create(modSources, modFiles));
     })
     .ContinueWith(task =>
     {
         var modSources = task.Result.Item1;
         var modFiles   = task.Result.Item2;
         foreach (string sourcePath in modSources)
         {
             var builtMod = modFiles.SingleOrDefault(m => m.Name == Path.GetFileName(sourcePath));
             items.Add(new UIModSourceItem(sourcePath, builtMod));
         }
         updateNeeded = true;
     }, TaskScheduler.FromCurrentSynchronizationContext());
 }
Ejemplo n.º 3
0
        internal static void ServerModMenu()
        {
            bool exit = false;

            while (!exit)
            {
                Console.WriteLine("Terraria Server " + Main.versionNumber2 + " - " + ModLoader.versionedName);
                Console.WriteLine();
                var mods = ModOrganizer.FindMods();
                for (int k = 0; k < mods.Length; k++)
                {
                    Console.Write((k + 1) + "\t\t" + mods[k].DisplayName);
                    Console.WriteLine(" (" + (ModLoader.IsEnabled(mods[k].Name) ? "enabled" : "disabled") + ")");
                }
                if (mods.Length == 0)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine($"No mods were found in: \"{ModLoader.ModPath}\"\nIf you are running a dedicated server, you may wish to use the 'modpath' command line switch or server config setting to specify a custom mods directory.\n");
                    Console.ResetColor();
                }
                Console.WriteLine("e\t\tEnable All");
                Console.WriteLine("d\t\tDisable All");
                Console.WriteLine("r\t\tReload and return to world menu");
                Console.WriteLine("Type a number to switch between enabled/disabled");
                Console.WriteLine();
                Console.WriteLine("Type a command: ");
                string command = Console.ReadLine();
                if (command == null)
                {
                    command = "";
                }
                command = command.ToLower();
                Console.Clear();
                if (command == "e")
                {
                    foreach (var mod in mods)
                    {
                        mod.Enabled = true;
                    }
                }
                else if (command == "d")
                {
                    foreach (var mod in mods)
                    {
                        mod.Enabled = false;
                    }
                }
                else if (command == "r")
                {
                    ModLoader.Reload();
                    exit = true;
                }
                else if (int.TryParse(command, out int value) && value > 0 && value <= mods.Length)
                {
                    mods[value - 1].Enabled ^= true;
                }
            }
        }
Ejemplo n.º 4
0
        internal static void ServerModMenu()
        {
            bool exit = false;

            while (!exit)
            {
                Console.WriteLine("Terraria Server " + Main.versionNumber2 + " - " + ModLoader.versionedName);
                Console.WriteLine();
                var mods = ModOrganizer.FindMods();
                for (int k = 0; k < mods.Length; k++)
                {
                    Console.Write((k + 1) + "\t\t" + mods[k].DisplayName);
                    Console.WriteLine(" (" + (ModLoader.IsEnabled(mods[k].Name) ? "enabled" : "disabled") + ")");
                }
                if (mods.Length == 0)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine(Language.GetTextValue("tModLoader.ModsNotFoundServer", ModLoader.ModPath));
                    Console.ResetColor();
                }
                Console.WriteLine("e\t\t" + Language.GetTextValue("tModLoader.ModsEnableAll"));
                Console.WriteLine("d\t\t" + Language.GetTextValue("tModLoader.ModsDisableAll"));
                Console.WriteLine("r\t\t" + Language.GetTextValue("tModLoader.ModsReloadAndReturn"));
                Console.WriteLine(Language.GetTextValue("tModLoader.AskForModIndex"));
                Console.WriteLine();
                Console.WriteLine(Language.GetTextValue("tModLoader.AskForCommand"));
                string command = Console.ReadLine();
                if (command == null)
                {
                    command = "";
                }
                command = command.ToLower();
                Console.Clear();
                if (command == "e")
                {
                    foreach (var mod in mods)
                    {
                        mod.Enabled = true;
                    }
                }
                else if (command == "d")
                {
                    foreach (var mod in mods)
                    {
                        mod.Enabled = false;
                    }
                }
                else if (command == "r")
                {
                    ModLoader.Reload();
                    exit = true;
                }
                else if (int.TryParse(command, out int value) && value > 0 && value <= mods.Length)
                {
                    mods[value - 1].Enabled ^= true;
                }
            }
        }
Ejemplo n.º 5
0
        internal void EnableDependencies(UIMouseEvent evt, UIElement listeningElement)
        {
            var modList     = ModOrganizer.FindMods();
            var missingRefs = new List <string>();

            EnableDepsRecursive(modList, _modReferences, missingRefs);

            if (missingRefs.Any())
            {
                Interface.infoMessage.Show(Language.GetTextValue("tModLoader.ModDependencyModsNotFound", string.Join(",", missingRefs)), Interface.modsMenuID);
            }
        }
Ejemplo n.º 6
0
        public static void SaveModList(string filename)
        {
            // TODO
            //Main.menuMode = Interface.modsMenuID;

            //Main.PlaySound(10, -1, -1, 1);
            Directory.CreateDirectory(ModListSaveDirectory);

            string path      = ModListSaveDirectory + Path.DirectorySeparatorChar + filename + ".json";
            var    foundMods = ModOrganizer.FindMods().Select(x => x.Name).Intersect(ModLoader.EnabledMods).ToList();
            string json      = JsonConvert.SerializeObject(foundMods, Formatting.Indented);

            File.WriteAllText(path, json);

            Main.menuMode = Interface.modPacksMenuID;             // should reload
        }
Ejemplo n.º 7
0
        public override void OnActivate()
        {
            scrollPanel.Append(uiLoader);
            modListList.Clear();
            if (SynchronizationContext.Current == null)
            {
                SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
            }
            Task.Factory
            .StartNew(delegate
            {
                mods = ModOrganizer.FindMods().Select(m => m.Name).ToArray();
                return(FindModLists());
            })
            .ContinueWith(task =>
            {
                string[] modListsFullPath = task.Result;
                foreach (string modListFilePath in modListsFullPath)
                {
                    try
                    {
                        string[] mods = { };
                        //string path = ModListSaveDirectory + Path.DirectorySeparatorChar + modListFilePath + ".json";

                        if (File.Exists(modListFilePath))
                        {
                            using (StreamReader r = new StreamReader(modListFilePath))
                            {
                                string json = r.ReadToEnd();

                                mods = JsonConvert.DeserializeObject <string[]>(json);
                            }
                        }
                        UIModPackItem modItem = new UIModPackItem(Path.GetFileNameWithoutExtension(modListFilePath), mods);
                        modListList.Add(modItem);
                    }
                    catch
                    {
                        UIAutoScaleTextTextPanel <string> badModPackMessage = new UIAutoScaleTextTextPanel <string>(Language.GetTextValue("tModLoader.ModPackMalformed", Path.GetFileName(modListFilePath)));
                        badModPackMessage.Width.Set(0, 1);
                        badModPackMessage.Height.Set(50, 0);
                        modListList.Add(badModPackMessage);
                    }
                }
                scrollPanel.RemoveChild(uiLoader);
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }
Ejemplo n.º 8
0
 internal void Populate()
 {
     Task.Factory.StartNew(
         delegate {
         var modSources = ModCompile.FindModSources();
         var modFiles   = ModOrganizer.FindMods();
         return(Tuple.Create(modSources, modFiles));
     }, _cts.Token)
     .ContinueWith(task => {
         var modSources = task.Result.Item1;
         var modFiles   = task.Result.Item2;
         foreach (string sourcePath in modSources)
         {
             var builtMod = modFiles.SingleOrDefault(m => m.Name == Path.GetFileName(sourcePath));
             _items.Add(new UIModSourceItem(sourcePath, builtMod));
         }
         _updateNeeded = true;
     }, _cts.Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
 }
Ejemplo n.º 9
0
        internal void EnableDependencies(UIMouseEvent evt, UIElement listeningElement)
        {
            var modList = ModOrganizer.FindMods();
            var missing = new List <string>();

            foreach (var modRef in _modReferences)
            {
                ModLoader.EnableMod(modRef);
                if (modList.All(m => m.Name != modRef))
                {
                    missing.Add(modRef);
                }
            }

            Main.menuMode = Interface.modsMenuID;
            if (missing.Any())
            {
                Interface.infoMessage.Show(Language.GetTextValue("tModLoader.ModDependencyModsNotFound", string.Join(",", missing)), Interface.modsMenuID);
            }
        }
Ejemplo n.º 10
0
        public static void SaveModList(string filename)
        {
            // Sanitize input if not valid
            if (!IsValidModpackName(filename))
            {
                VirtualKeyboard.Text = SanitizeModpackName(filename);
                return;
            }
            // TODO
            //Main.menuMode = Interface.modsMenuID;

            //Main.PlaySound(10, -1, -1, 1);
            Directory.CreateDirectory(ModPacksDirectory);

            string path      = Path.Combine(ModPacksDirectory, filename + ".json");
            var    foundMods = ModOrganizer.FindMods().Select(x => x.Name).Intersect(ModLoader.EnabledMods).ToList();
            string json      = JsonConvert.SerializeObject(foundMods, Formatting.Indented);

            File.WriteAllText(path, json);

            Main.menuMode = Interface.modPacksMenuID;             // should reload
        }
Ejemplo n.º 11
0
        public UIModItem(LocalMod mod)
        {
            this.mod          = mod;
            BorderColor       = new Color(89, 116, 213) * 0.7f;
            dividerTexture    = TextureManager.Load("Images/UI/Divider");
            innerPanelTexture = TextureManager.Load("Images/UI/InnerPanelBackground");
            Height.Pixels     = 90;
            Width.Percent     = 1f;
            SetPadding(6f);
            //base.OnClick += this.ToggleEnabled;
            string text = mod.DisplayName + " v" + mod.modFile.version;

            if (mod.tModLoaderVersion < new Version(0, 10))
            {
                text += $" [c/FF0000:({Language.GetTextValue("tModLoader.ModOldWarning")})]";
            }

            if (mod.modFile.HasFile("icon.png"))
            {
                try {
                    Texture2D modIconTexture;
                    using (mod.modFile.Open())
                        using (var s = mod.modFile.GetStream("icon.png"))
                            modIconTexture = Texture2D.FromStream(Main.instance.GraphicsDevice, s);

                    if (modIconTexture.Width == 80 && modIconTexture.Height == 80)
                    {
                        modIcon = new UIImage(modIconTexture)
                        {
                            Left = { Percent = 0f },
                            Top  = { Percent = 0f }
                        };
                        Append(modIcon);
                        modIconAdjust += 85;
                    }
                }
                catch { }
            }
            modName = new UIText(text)
            {
                Left = new StyleDimension(modIconAdjust + 10f, 0f),
                Top  = { Pixels = 5 }
            };
            Append(modName);

            var moreInfoButton = new UIAutoScaleTextTextPanel <string>(Language.GetTextValue("tModLoader.ModsMoreInfo"))
            {
                Width  = { Pixels = 100 },
                Height = { Pixels = 36 },
                Left   = { Pixels = 430 },
                Top    = { Pixels = 40 }
            }.WithFadedMouseOver();

            moreInfoButton.PaddingTop    -= 2f;
            moreInfoButton.PaddingBottom -= 2f;
            moreInfoButton.OnClick       += Moreinfo;
            Append(moreInfoButton);

            toggleModEnabledButton = new UIAutoScaleTextTextPanel <string>(mod.Enabled ? Language.GetTextValue("tModLoader.ModsDisable") : Language.GetTextValue("tModLoader.ModsEnable"))
            {
                Width  = { Pixels = 100 },
                Height = { Pixels = 36 },
                Top    = { Pixels = 40 }
            }.WithFadedMouseOver();
            toggleModEnabledButton.Left.Pixels    = moreInfoButton.Left.Pixels - toggleModEnabledButton.Width.Pixels - 5f;
            toggleModEnabledButton.PaddingTop    -= 2f;
            toggleModEnabledButton.PaddingBottom -= 2f;
            toggleModEnabledButton.OnClick       += ToggleEnabled;
            Append(toggleModEnabledButton);

            Mod loadedMod = ModLoader.GetMod(mod.Name);

            if (loadedMod != null && ConfigManager.Configs.ContainsKey(loadedMod))             // and has config
            {
                configButton = new UITextPanel <string>("Config", 1f, false);
                configButton.Width.Set(100f, 0f);
                configButton.Height.Set(30f, 0f);
                configButton.Left.Set(toggleModEnabledButton.Left.Pixels - configButton.Width.Pixels - 5f, 0f);
                configButton.Top.Set(40f, 0f);
                configButton.PaddingTop    -= 2f;
                configButton.PaddingBottom -= 2f;
                configButton.WithFadedMouseOver();
                configButton.OnClick += this.OpenConfig;
                Append(configButton);
                if (ConfigManager.ModNeedsReload(loadedMod))
                {
                    configChangesRequireReload = true;
                }
            }

            var modRefs = mod.properties.modReferences.Select(x => x.mod).ToArray();

            if (modRefs.Length > 0 && !mod.Enabled)
            {
                string refs = string.Join(", ", mod.properties.modReferences);
                var    icon = Texture2D.FromStream(Main.instance.GraphicsDevice,
                                                   Assembly.GetExecutingAssembly().GetManifestResourceStream("Terraria.ModLoader.UI.ButtonExclamation.png"));
                var modReferenceIcon = new UIHoverImage(icon, Language.GetTextValue("tModLoader.ModDependencyClickTooltip", refs))
                {
                    Left = new StyleDimension(toggleModEnabledButton.Left.Pixels - 24f, 0f),
                    Top  = { Pixels = 47 }
                };
                modReferenceIcon.OnClick += (a, b) => {
                    var modList = ModOrganizer.FindMods();
                    var missing = new List <string>();
                    foreach (var modRef in modRefs)
                    {
                        ModLoader.EnableMod(modRef);
                        if (!modList.Any(m => m.Name == modRef))
                        {
                            missing.Add(modRef);
                        }
                    }

                    Main.menuMode = Interface.modsMenuID;
                    if (missing.Any())
                    {
                        Interface.infoMessage.Show(Language.GetTextValue("tModLoader.ModDependencyModsNotFound", String.Join(",", missing)), Interface.modsMenuID);
                    }
                };
                Append(modReferenceIcon);
            }
            if (mod.modFile.ValidModBrowserSignature)
            {
                keyImage = new UIHoverImage(Main.itemTexture[ID.ItemID.GoldenKey], Language.GetTextValue("tModLoader.ModsOriginatedFromModBrowser"))
                {
                    Left = { Pixels = -20, Percent = 1f }
                };
                Append(keyImage);
            }
            if (ModLoader.badUnloaders.Contains(mod.Name))
            {
                keyImage = new UIHoverImage(Texture2D.FromStream(Main.instance.GraphicsDevice,
                                                                 Assembly.GetExecutingAssembly().GetManifestResourceStream("Terraria.ModLoader.UI.ButtonError.png")), "This mod did not fully unload during last unload.")
                {
                    Left = { Pixels = modIconAdjust + 4 },
                    Top  = { Pixels = 3 }
                };
                Append(keyImage);
                modName.Left.Pixels += 20;
            }
            if (mod.properties.beta)
            {
                keyImage = new UIHoverImage(Main.itemTexture[ID.ItemID.ShadowKey], Language.GetTextValue("tModLoader.BetaModCantPublish"))
                {
                    Left = { Pixels = -10, Percent = 1f }
                };
                Append(keyImage);
            }
            if (loadedMod != null)
            {
                loaded = true;
                int[]    values           = { loadedMod.items.Count, loadedMod.npcs.Count, loadedMod.tiles.Count, loadedMod.walls.Count, loadedMod.buffs.Count, loadedMod.mountDatas.Count };
                string[] localizationKeys = { "ModsXItems", "ModsXNPCs", "ModsXTiles", "ModsXWalls", "ModsXBuffs", "ModsXMounts" };
                int      xOffset          = -40;
                for (int i = 0; i < values.Length; i++)
                {
                    if (values[i] > 0)
                    {
                        Texture2D iconTexture = Main.instance.infoIconTexture[i];
                        keyImage = new UIHoverImage(iconTexture, Language.GetTextValue($"tModLoader.{localizationKeys[i]}", values[i]))
                        {
                            Left = { Pixels = xOffset, Percent = 1f }
                        };
                        Append(keyImage);
                        xOffset -= 18;
                    }
                }
            }
        }
Ejemplo n.º 12
0
        public UIModItem(LocalMod mod)
        {
            this.mod               = mod;
            this.BorderColor       = new Color(89, 116, 213) * 0.7f;
            this.dividerTexture    = TextureManager.Load("Images/UI/Divider");
            this.innerPanelTexture = TextureManager.Load("Images/UI/InnerPanelBackground");
            this.Height.Set(90f, 0f);
            this.Width.Set(0f, 1f);
            base.SetPadding(6f);
            //base.OnClick += this.ToggleEnabled;
            string text = mod.DisplayName + " v" + mod.modFile.version;

            if (mod.tModLoaderVersion < new Version(0, 10))
            {
                text += $" [c/FF0000:({Language.GetTextValue("tModLoader.ModOldWarning")})]";
            }

            if (mod.modFile.HasFile("icon.png"))
            {
                try
                {
                    Texture2D modIconTexture;
                    using (mod.modFile.EnsureOpen())
                        using (var s = mod.modFile.GetStream("icon.png"))
                            modIconTexture = Texture2D.FromStream(Main.instance.GraphicsDevice, s);

                    if (modIconTexture.Width == 80 && modIconTexture.Height == 80)
                    {
                        modIcon = new UIImage(modIconTexture);
                        modIcon.Left.Set(0f, 0f);
                        modIcon.Top.Set(0f, 0f);
                        Append(modIcon);
                        modIconAdjust += 85;
                    }
                }
                catch { }
            }
            this.modName = new UIText(text, 1f, false);
            this.modName.Left.Set(modIconAdjust + 10f, 0f);
            this.modName.Top.Set(5f, 0f);
            base.Append(this.modName);
            UIAutoScaleTextTextPanel <string> moreInfoButton = new UIAutoScaleTextTextPanel <string>(Language.GetTextValue("tModLoader.ModsMoreInfo"), 1f, false);

            moreInfoButton.Width.Set(100f, 0f);
            moreInfoButton.Height.Set(36f, 0f);
            moreInfoButton.Left.Set(430f, 0f);
            moreInfoButton.Top.Set(40f, 0f);
            moreInfoButton.PaddingTop    -= 2f;
            moreInfoButton.PaddingBottom -= 2f;
            moreInfoButton.OnMouseOver   += UICommon.FadedMouseOver;
            moreInfoButton.OnMouseOut    += UICommon.FadedMouseOut;
            moreInfoButton.OnClick       += this.Moreinfo;
            base.Append(moreInfoButton);
            toggleModEnabledButton = new UIAutoScaleTextTextPanel <string>(mod.Enabled ? Language.GetTextValue("tModLoader.ModsDisable") : Language.GetTextValue("tModLoader.ModsEnable"), 1f, false);
            toggleModEnabledButton.Width.Set(100f, 0f);
            toggleModEnabledButton.Height.Set(36f, 0f);
            toggleModEnabledButton.Left.Set(moreInfoButton.Left.Pixels - toggleModEnabledButton.Width.Pixels - 5f, 0f);
            toggleModEnabledButton.Top.Set(40f, 0f);
            toggleModEnabledButton.PaddingTop    -= 2f;
            toggleModEnabledButton.PaddingBottom -= 2f;
            toggleModEnabledButton.OnMouseOver   += UICommon.FadedMouseOver;
            toggleModEnabledButton.OnMouseOut    += UICommon.FadedMouseOut;
            toggleModEnabledButton.OnClick       += this.ToggleEnabled;
            base.Append(toggleModEnabledButton);

            var modRefs = mod.properties.modReferences.Select(x => x.mod).ToArray();

            if (modRefs.Length > 0 && !mod.Enabled)
            {
                string    refs = String.Join(", ", mod.properties.modReferences);
                Texture2D icon = Texture2D.FromStream(Main.instance.GraphicsDevice,
                                                      Assembly.GetExecutingAssembly().GetManifestResourceStream("Terraria.ModLoader.UI.ButtonExclamation.png"));
                UIHoverImage modReferenceIcon = new UIHoverImage(icon, Language.GetTextValue("tModLoader.ModDependencyClickTooltip", refs));
                modReferenceIcon.Left.Set(toggleModEnabledButton.Left.Pixels - 24f, 0f);
                modReferenceIcon.Top.Set(47f, 0f);
                modReferenceIcon.OnClick += (a, b) =>
                {
                    var modList = ModOrganizer.FindMods();
                    var missing = new List <string>();
                    foreach (var modRef in modRefs)
                    {
                        ModLoader.EnableMod(modRef);
                        if (!modList.Any(m => m.Name == modRef))
                        {
                            missing.Add(modRef);
                        }
                    }

                    Main.menuMode = Interface.modsMenuID;
                    if (missing.Any())
                    {
                        Interface.infoMessage.SetMessage(Language.GetTextValue("tModLoader.ModDependencyModsNotFound", String.Join(",", missing)));
                        Interface.infoMessage.SetGotoMenu(Interface.modsMenuID);
                        Main.menuMode = Interface.infoMessageID;
                    }
                };
                base.Append(modReferenceIcon);
            }
            if (mod.modFile.ValidModBrowserSignature)
            {
                keyImage = new UIHoverImage(Main.itemTexture[ID.ItemID.GoldenKey], Language.GetTextValue("tModLoader.ModsOriginatedFromModBrowser"));
                keyImage.Left.Set(-20, 1f);
                base.Append(keyImage);
            }
            if (mod.properties.beta)
            {
                keyImage = new UIHoverImage(Main.itemTexture[ID.ItemID.ShadowKey], Language.GetTextValue("tModLoader.BetaModCantPublish"));
                keyImage.Left.Set(-10, 1f);
                Append(keyImage);
            }
            Mod loadedMod = ModLoader.GetMod(mod.Name);

            if (loadedMod != null)
            {
                loaded = true;
                int[]    values           = { loadedMod.items.Count, loadedMod.npcs.Count, loadedMod.tiles.Count, loadedMod.walls.Count, loadedMod.buffs.Count, loadedMod.mountDatas.Count };
                string[] localizationKeys = { "ModsXItems", "ModsXNPCs", "ModsXTiles", "ModsXWalls", "ModsXBuffs", "ModsXMounts" };
                int      xOffset          = -40;
                for (int i = 0; i < values.Length; i++)
                {
                    if (values[i] > 0)
                    {
                        Texture2D iconTexture = Main.instance.infoIconTexture[i];
                        keyImage = new UIHoverImage(iconTexture, Language.GetTextValue($"tModLoader.{localizationKeys[i]}", values[i]));
                        keyImage.Left.Set(xOffset, 1f);
                        base.Append(keyImage);
                        xOffset -= 18;
                    }
                }
            }
        }