diff --git a/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs b/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs index 247291f37..e499f3430 100644 --- a/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/EditHotkeyScreen.cs @@ -9,13 +9,11 @@ namespace ClassicalSharp.Gui.Screens { public sealed class EditHotkeyScreen : MenuScreen { const int keyI = 0, modifyI = 1, actionI = 2; - HotkeyList hotkeys; Hotkey curHotkey, origHotkey; int selectedI = -1; static FastColour grey = new FastColour(150, 150, 150); public EditHotkeyScreen(Game game, Hotkey original) : base(game) { - hotkeys = game.Input.Hotkeys; origHotkey = original; curHotkey = original; } @@ -97,15 +95,15 @@ namespace ClassicalSharp.Gui.Screens { void SaveChangesClick(Game game, Widget widget) { if (origHotkey.BaseKey != Key.Unknown) { - hotkeys.RemoveHotkey(origHotkey.BaseKey, origHotkey.Flags); - hotkeys.UserRemovedHotkey(origHotkey.BaseKey, origHotkey.Flags); + HotkeyList.Remove(origHotkey.BaseKey, origHotkey.Flags); + HotkeyList.UserRemovedHotkey(origHotkey.BaseKey, origHotkey.Flags); } MenuInputWidget input = (MenuInputWidget)widgets[actionI]; if (curHotkey.BaseKey != Key.Unknown) { - hotkeys.AddHotkey(curHotkey.BaseKey, curHotkey.Flags, + HotkeyList.Add(curHotkey.BaseKey, curHotkey.Flags, input.Text.ToString(), curHotkey.StaysOpen); - hotkeys.UserAddedHotkey(curHotkey.BaseKey, curHotkey.Flags, + HotkeyList.UserAddedHotkey(curHotkey.BaseKey, curHotkey.Flags, curHotkey.StaysOpen, input.Text.ToString()); } game.Gui.SetNewScreen(new HotkeyListScreen(game)); @@ -113,8 +111,8 @@ namespace ClassicalSharp.Gui.Screens { void RemoveHotkeyClick(Game game, Widget widget) { if (origHotkey.BaseKey != Key.Unknown) { - hotkeys.RemoveHotkey(origHotkey.BaseKey, origHotkey.Flags); - hotkeys.UserRemovedHotkey(origHotkey.BaseKey, origHotkey.Flags); + HotkeyList.Remove(origHotkey.BaseKey, origHotkey.Flags); + HotkeyList.UserRemovedHotkey(origHotkey.BaseKey, origHotkey.Flags); } game.Gui.SetNewScreen(new HotkeyListScreen(game)); } diff --git a/ClassicalSharp/2D/Screens/Menu/HotkeyListScreen.cs b/ClassicalSharp/2D/Screens/Menu/HotkeyListScreen.cs index 2fe7c48e9..6a2876e86 100644 --- a/ClassicalSharp/2D/Screens/Menu/HotkeyListScreen.cs +++ b/ClassicalSharp/2D/Screens/Menu/HotkeyListScreen.cs @@ -12,12 +12,11 @@ namespace ClassicalSharp.Gui.Screens { public HotkeyListScreen(Game game) : base(game) { titleText = "Modify hotkeys"; - HotkeyList hotkeys = game.Input.Hotkeys; - int count = hotkeys.Hotkeys.Count; - entries = new string[hotkeys.Hotkeys.Count + items]; + int count = HotkeyList.Hotkeys.Count; + entries = new string[count + items]; for (int i = 0; i < count; i++) { - Hotkey hKey = hotkeys.Hotkeys[i]; + Hotkey hKey = HotkeyList.Hotkeys[i]; entries[i] = hKey.BaseKey + " |" + MakeFlagsString(hKey.Flags); } for (int i = 0; i < items; i++) @@ -49,12 +48,10 @@ namespace ClassicalSharp.Gui.Screens { if (value.Contains("Shift")) flags |= 2; if (value.Contains("Alt")) flags |= 4; - Key hKey = (Key)Enum.Parse(typeof(Key), key); - HotkeyList hotkeys = game.Input.Hotkeys; - - for (int i = 0; i < hotkeys.Hotkeys.Count; i++) { - Hotkey h = hotkeys.Hotkeys[i]; - if (h.BaseKey == hKey && h.Flags == flags) return h; + Key baseKey = (Key)Enum.Parse(typeof(Key), key); + for (int i = 0; i < HotkeyList.Hotkeys.Count; i++) { + Hotkey h = HotkeyList.Hotkeys[i]; + if (h.BaseKey == baseKey && h.Flags == flags) return h; } return default(Hotkey); } diff --git a/ClassicalSharp/Game/InputHandler.cs b/ClassicalSharp/Game/InputHandler.cs index ac3e02d8e..284b42479 100644 --- a/ClassicalSharp/Game/InputHandler.cs +++ b/ClassicalSharp/Game/InputHandler.cs @@ -11,10 +11,6 @@ namespace ClassicalSharp { public sealed class InputHandler { - #if !ANDROID - public HotkeyList Hotkeys; - #endif - Game game; bool[] buttonsDown = new bool[3]; PickingHandler picking; @@ -23,11 +19,7 @@ namespace ClassicalSharp { RegisterInputHandlers(); Keys = new KeyMap(); picking = new PickingHandler(game, this); - - #if !ANDROID - Hotkeys = new HotkeyList(); - Hotkeys.LoadSavedHotkeys(); - #endif + HotkeyList.LoadSavedHotkeys(); } void RegisterInputHandlers() { @@ -185,7 +177,7 @@ namespace ClassicalSharp { void HandleHotkey(Key key) { string text; bool more; - if (!Hotkeys.IsHotkey(key, game.Input, out text, out more)) return; + if (!HotkeyList.IsHotkey(key, game.Input, out text, out more)) return; if (!more) { game.Server.SendChat(text); diff --git a/ClassicalSharp/Hotkeys/HotkeyList.cs b/ClassicalSharp/Hotkeys/HotkeyList.cs index 18580f629..69c1c7fc5 100644 --- a/ClassicalSharp/Hotkeys/HotkeyList.cs +++ b/ClassicalSharp/Hotkeys/HotkeyList.cs @@ -7,12 +7,12 @@ using OpenTK.Input; namespace ClassicalSharp.Hotkeys { /// Maintains the list of hotkeys defined by the client and by SetTextHotkey packets. - public sealed class HotkeyList { + public static class HotkeyList { - public List Hotkeys = new List(); + public static List Hotkeys = new List(); /// Creates or updates an existing hotkey with the given baseKey and modifier flags. - public void AddHotkey(Key baseKey, byte flags, string text, bool more) { + public static void Add(Key baseKey, byte flags, string text, bool more) { if (!UpdateExistingHotkey(baseKey, flags, text, more)) AddNewHotkey(baseKey, flags, text, more); } @@ -20,7 +20,7 @@ namespace ClassicalSharp.Hotkeys { /// Removes an existing hotkey with the given baseKey and modifier flags. /// Whether a hotkey with the given baseKey and modifier flags was found /// and subsequently removed. - public bool RemoveHotkey(Key baseKey, byte flags) { + public static bool Remove(Key baseKey, byte flags) { for (int i = 0; i < Hotkeys.Count; i++) { Hotkey hKey = Hotkeys[i]; if (hKey.BaseKey == baseKey && hKey.Flags == flags) { @@ -31,7 +31,7 @@ namespace ClassicalSharp.Hotkeys { return false; } - bool UpdateExistingHotkey(Key baseKey, byte flags, string text, bool more) { + static bool UpdateExistingHotkey(Key baseKey, byte flags, string text, bool more) { for (int i = 0; i < Hotkeys.Count; i++) { Hotkey hKey = Hotkeys[i]; if (hKey.BaseKey == baseKey && hKey.Flags == flags) { @@ -44,7 +44,7 @@ namespace ClassicalSharp.Hotkeys { return false; } - void AddNewHotkey(Key baseKey, byte flags, string text, bool more) { + static void AddNewHotkey(Key baseKey, byte flags, string text, bool more) { Hotkey hotkey; hotkey.BaseKey = baseKey; hotkey.Flags = flags; @@ -60,8 +60,7 @@ namespace ClassicalSharp.Hotkeys { /// Determines whether a hotkey is active based on the given key, /// and the currently active control, alt, and shift modifiers - public bool IsHotkey(Key key, InputHandler input, - out string text, out bool moreInput) { + public static bool IsHotkey(Key key, InputHandler input, out string text, out bool moreInput) { byte flags = 0; if (input.ControlDown) flags |= 1; if (input.ShiftDown) flags |= 2; @@ -82,7 +81,7 @@ namespace ClassicalSharp.Hotkeys { } const string prefix = "hotkey-"; - public void LoadSavedHotkeys() { + public static void LoadSavedHotkeys() { for (int i = 0; i < Options.OptionsKeys.Count; i++) { string key = Options.OptionsKeys[i]; if (!Utils.CaselessStarts(key, prefix)) continue; @@ -108,16 +107,16 @@ namespace ClassicalSharp.Hotkeys { Utils.LogDebug("Hotkey {0} has invalid arguments", key); continue; } - AddHotkey(hotkey, flags, strText, moreInput); + Add(hotkey, flags, strText, moreInput); } } - public void UserRemovedHotkey(Key baseKey, byte flags) { + public static void UserRemovedHotkey(Key baseKey, byte flags) { string key = "hotkey-" + baseKey + "&" + flags; Options.Set(key, null); } - public void UserAddedHotkey(Key baseKey, byte flags, bool moreInput, string text) { + public static void UserAddedHotkey(Key baseKey, byte flags, bool moreInput, string text) { string key = "hotkey-" + baseKey + "&" + flags; string value = moreInput + "&" + text; Options.Set(key, value); diff --git a/ClassicalSharp/Map/Formats/NbtFile.cs b/ClassicalSharp/Map/Formats/NbtFile.cs index 5c331e17a..1e1b92cf4 100644 --- a/ClassicalSharp/Map/Formats/NbtFile.cs +++ b/ClassicalSharp/Map/Formats/NbtFile.cs @@ -22,7 +22,6 @@ namespace ClassicalSharp.Map { End, Int8, Int16, Int32, Int64, Real32, Real64, Int8Array, String, List, Compound, Int32Array, - Invalid = 255, } public sealed class NbtFile { @@ -82,9 +81,7 @@ namespace ClassicalSharp.Map { public unsafe NbtTag ReadTag(byte typeId, bool readTagName) { NbtTag tag = default(NbtTag); - if (typeId == 0) { - tag.TagId = NbtTagType.Invalid; return tag; - } + if (typeId == 0) return tag; tag.Name = readTagName ? ReadString() : null; tag.TagId = (NbtTagType)typeId; @@ -118,10 +115,10 @@ namespace ClassicalSharp.Map { tag.Value = list; break; case NbtTagType.Compound: + byte childTagId; Dictionary children = new Dictionary(); - NbtTag child; - while ((child = ReadTag(reader.ReadByte(), true)).TagId != NbtTagType.Invalid) { - children[child.Name] = child; + while ((childTagId = reader.ReadByte()) != (byte)NbtTagType.End) { + NbtTag child = ReadTag(childTagId, true); children[child.Name] = child; } tag.Value = children; break; diff --git a/ClassicalSharp/Network/Protocols/CPE.cs b/ClassicalSharp/Network/Protocols/CPE.cs index 7e1a021d5..615fe11d7 100644 --- a/ClassicalSharp/Network/Protocols/CPE.cs +++ b/ClassicalSharp/Network/Protocols/CPE.cs @@ -105,12 +105,12 @@ namespace ClassicalSharp.Network.Protocols { Utils.LogDebug("CPE Hotkey added: " + key + "," + keyMods + " : " + action); if (action == "") { - game.Input.Hotkeys.RemoveHotkey(key, keyMods); + HotkeyList.Remove(key, keyMods); } else if (action[action.Length - 1] == '◙') { // graphical form of \n action = action.Substring(0, action.Length - 1); - game.Input.Hotkeys.AddHotkey(key, keyMods, action, false); + HotkeyList.Add(key, keyMods, action, false); } else { // more input needed by user - game.Input.Hotkeys.AddHotkey(key, keyMods, action, true); + HotkeyList.Add(key, keyMods, action, true); } #endif } diff --git a/src/Client/Chat.c b/src/Client/Chat.c index 63a548b64..62ef83b09 100644 --- a/src/Client/Chat.c +++ b/src/Client/Chat.c @@ -44,7 +44,7 @@ void Chat_SetLogName(STRING_PURE String* name) { String noColsName = String_InitAndClearArray(noColsBuffer); String_AppendColorless(&noColsName, name); - UInt32 i; + Int32 i; for (i = 0; i < noColsName.length; i++) { if (Chat_AllowedLogChar(noColsName.buffer[i])) { String_Append(&Chat_LogName, noColsName.buffer[i]); @@ -59,7 +59,7 @@ void Chat_OpenLog(DateTime* now) { } /* Ensure multiple instances do not end up overwriting each other's log entries. */ - UInt32 i; + Int32 i; for (i = 0; i < 20; i++) { UInt8 pathBuffer[String_BufferSize(FILENAME_SIZE)]; String path = String_InitAndClearArray(pathBuffer); @@ -137,8 +137,8 @@ void Chat_AddOf(STRING_PURE String* text, Int32 msgType) { typedef struct ChatCommand_ { - String Name; - String Help[6]; + const UInt8* Name; + const UInt8* Help[5]; void (*Execute)(STRING_PURE String* args, UInt32 argsCount); bool SingleplayerOnly; } ChatCommand; @@ -146,10 +146,8 @@ typedef void (*ChatCommandConstructor)(ChatCommand* cmd); #define COMMANDS_PREFIX "/client" #define COMMANDS_PREFIX_SPACE "/client " -#define Command_SetName(raw) String name = String_FromConst(raw); cmd->Name = name; -#define Command_SetHelp(Num, raw) String help ## Num = String_FromConst(raw); cmd->Help[Num] = help ## Num; ChatCommand commands_list[8]; -UInt32 commands_count; +Int32 commands_count; bool Commands_IsCommandPrefix(STRING_PURE String* input) { if (input->length == 0) return false; @@ -167,8 +165,7 @@ void Commands_Register(ChatCommandConstructor constructor) { ErrorHandler_Fail("Commands_Register - hit max client commands"); } - ChatCommand command; - Platform_MemSet(&command, 0, sizeof(ChatCommand)); + ChatCommand command = { 0 }; constructor(&command); commands_list[commands_count++] = command; } @@ -182,10 +179,11 @@ void Commands_Log(const UInt8* format, void* a1) { ChatCommand* Commands_GetMatch(STRING_PURE String* cmdName) { ChatCommand* match = NULL; - UInt32 i; + Int32 i; for (i = 0; i < commands_count; i++) { ChatCommand* cmd = &commands_list[i]; - if (!String_CaselessStarts(&cmd->Name, cmdName)) continue; + String name = String_FromReadonly(cmd->Name); + if (!String_CaselessStarts(&name, cmdName)) continue; if (match != NULL) { Commands_Log("&e/client: Multiple commands found that start with: \"&f%s&e\".", cmdName); @@ -209,11 +207,11 @@ ChatCommand* Commands_GetMatch(STRING_PURE String* cmdName) { void Commands_PrintDefined(void) { UInt8 strBuffer[String_BufferSize(STRING_SIZE)]; String str = String_InitAndClearArray(strBuffer); - UInt32 i; + Int32 i; for (i = 0; i < commands_count; i++) { ChatCommand* cmd = &commands_list[i]; - String name = cmd->Name; + String name = String_FromReadonly(cmd->Name); if ((str.length + name.length + 2) > str.capacity) { Chat_Add(&str); @@ -265,24 +263,24 @@ void HelpCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { ChatCommand* cmd = Commands_GetMatch(&args[1]); if (cmd == NULL) return; - UInt32 i; + Int32 i; for (i = 0; i < Array_Elems(cmd->Help); i++) { - String* help = &cmd->Help[i]; - if (help->length == 0) continue; - Chat_Add(help); + if (cmd->Help[i] == NULL) continue; + String help = String_FromReadonly(cmd->Help[i]); + Chat_Add(&help); } } } void HelpCommand_Make(ChatCommand* cmd) { - Command_SetName("Help"); - Command_SetHelp(0, "&a/client help [command name]"); - Command_SetHelp(1, "&eDisplays the help for the given command."); + cmd->Name = "Help"; + cmd->Help[0] = "&a/client help [command name]"; + cmd->Help[1] = "&eDisplays the help for the given command."; cmd->Execute = HelpCommand_Execute; } void GpuInfoCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { - UInt32 i; + Int32 i; for (i = 0; i < Array_Elems(Gfx_ApiInfo); i++) { if (Gfx_ApiInfo[i].length == 0) continue; UInt8 msgBuffer[String_BufferSize(STRING_SIZE)]; @@ -295,9 +293,9 @@ void GpuInfoCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { } void GpuInfoCommand_Make(ChatCommand* cmd) { - Command_SetName("GpuInfo"); - Command_SetHelp(0, "&a/client gpuinfo"); - Command_SetHelp(1, "&eDisplays information about your GPU."); + cmd->Name = "GpuInfo"; + cmd->Help[0] = "&a/client gpuinfo"; + cmd->Help[1] = "&eDisplays information about your GPU."; cmd->Execute = GpuInfoCommand_Execute; } @@ -312,12 +310,12 @@ void RenderTypeCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { } void RenderTypeCommand_Make(ChatCommand* cmd) { - Command_SetName("RenderType"); - Command_SetHelp(0, "&a/client rendertype [normal/legacy/legacyfast]"); - Command_SetHelp(1, "&bnormal: &eDefault renderer, with all environmental effects enabled."); - Command_SetHelp(2, "&blegacy: &eMay be slightly slower than normal, but produces the same environmental effects."); - Command_SetHelp(3, "&blegacyfast: &eSacrifices clouds, fog and overhead sky for faster performance."); - Command_SetHelp(4, "&bnormalfast: &eSacrifices clouds, fog and overhead sky for faster performance."); + cmd->Name = "RenderType"; + cmd->Help[0] = "&a/client rendertype [normal/legacy/legacyfast]"; + cmd->Help[1] = "&bnormal: &eDefault renderer, with all environmental effects enabled."; + cmd->Help[2] = "&blegacy: &eMay be slightly slower than normal, but produces the same environmental effects."; + cmd->Help[3] = "&blegacyfast: &eSacrifices clouds, fog and overhead sky for faster performance."; + cmd->Help[4] = "&bnormalfast: &eSacrifices clouds, fog and overhead sky for faster performance."; cmd->Execute = RenderTypeCommand_Execute; } @@ -338,9 +336,9 @@ void ResolutionCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { } void ResolutionCommand_Make(ChatCommand* cmd) { - Command_SetName("Resolution"); - Command_SetHelp(0, "&a/client resolution [width] [height]"); - Command_SetHelp(1, "&ePrecisely sets the size of the rendered window."); + cmd->Name = "Resolution"; + cmd->Help[0] = "&a/client resolution [width] [height]"; + cmd->Help[1] = "&ePrecisely sets the size of the rendered window."; cmd->Execute = ResolutionCommand_Execute; } @@ -357,10 +355,10 @@ void ModelCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { } void ModelCommand_Make(ChatCommand* cmd) { - Command_SetName("Model"); - Command_SetHelp(0, "&a/client model [name]"); - Command_SetHelp(1, "&bnames: &echibi, chicken, creeper, human, pig, sheep"); - Command_SetHelp(2, "&e skeleton, spider, zombie, sitting, ") + cmd->Name = "Model"; + cmd->Help[0] = "&a/client model [name]"; + cmd->Help[1] = "&bnames: &echibi, chicken, creeper, human, pig, sheep"; + cmd->Help[2] = "&e skeleton, spider, zombie, sitting, "; cmd->SingleplayerOnly = true; cmd->Execute = ModelCommand_Execute; } @@ -456,12 +454,12 @@ void CuboidCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { } void CuboidCommand_Make(ChatCommand* cmd) { - Command_SetName("Cuboid"); - Command_SetHelp(0, "&a/client cuboid [block] [persist]"); - Command_SetHelp(1, "&eFills the 3D rectangle between two points with [block]."); - Command_SetHelp(2, "&eIf no block is given, uses your currently held block."); - Command_SetHelp(3, "&e If persist is given and is \"yes\", then the command"); - Command_SetHelp(4, "&e will repeatedly cuboid, without needing to be typed in again."); + cmd->Name = "Cuboid"; + cmd->Help[0] = "&a/client cuboid [block] [persist]"; + cmd->Help[1] = "&eFills the 3D rectangle between two points with [block]."; + cmd->Help[2] = "&eIf no block is given, uses your currently held block."; + cmd->Help[3] = "&e If persist is given and is \"yes\", then the command"; + cmd->Help[4] = "&e will repeatedly cuboid, without needing to be typed in again."; cmd->SingleplayerOnly = true; cmd->Execute = CuboidCommand_Execute; } @@ -484,9 +482,9 @@ void TeleportCommand_Execute(STRING_PURE String* args, UInt32 argsCount) { } void TeleportCommand_Make(ChatCommand* cmd) { - Command_SetName("TP"); - Command_SetHelp(0, "&a/client tp [x y z]"); - Command_SetHelp(1, "&eMoves you to the given coordinates."); + cmd->Name = "TP"; + cmd->Help[0] = "&a/client tp [x y z]"; + cmd->Help[1] = "&eMoves you to the given coordinates."; cmd->SingleplayerOnly = true; cmd->Execute = TeleportCommand_Execute; } @@ -503,7 +501,7 @@ void Chat_Send(STRING_PURE String* text) { } } -void Commands_Init(void) { +void Chat_Init(void) { Commands_Register(GpuInfoCommand_Make); Commands_Register(HelpCommand_Make); Commands_Register(RenderTypeCommand_Make); @@ -511,6 +509,9 @@ void Commands_Init(void) { Commands_Register(ModelCommand_Make); Commands_Register(CuboidCommand_Make); Commands_Register(TeleportCommand_Make); + + StringsBuffer_Init(&Chat_Log); + StringsBuffer_Init(&Chat_InputLog); } void Chat_Reset(void) { @@ -518,14 +519,17 @@ void Chat_Reset(void) { String_Clear(&Chat_LogName); } -void Commands_Free(void) { +void Chat_Free(void) { commands_count = 0; + + StringsBuffer_Free(&Chat_Log); + StringsBuffer_Free(&Chat_InputLog); } IGameComponent Chat_MakeGameComponent(void) { IGameComponent comp = IGameComponent_MakeEmpty(); - comp.Init = Commands_Init; + comp.Init = Chat_Init; comp.Reset = Chat_Reset; - comp.Free = Commands_Free; + comp.Free = Chat_Free; return comp; } \ No newline at end of file diff --git a/src/Client/Formats.c b/src/Client/Formats.c index 216478247..944424af5 100644 --- a/src/Client/Formats.c +++ b/src/Client/Formats.c @@ -183,7 +183,6 @@ void Fcm_Load(Stream* stream) { #define NBT_TAG_LIST 9 #define NBT_TAG_COMPOUND 10 #define NBT_TAG_INT32_ARRAY 11 -#define NBT_TAG_INVALID 255 struct NbtTag_; typedef struct NbtTag_ { @@ -243,11 +242,10 @@ UInt8 NbtTag_U8_At(NbtTag* tag, Int32 i) { } void Nbt_ReadTag(UInt8 typeId, bool readTagName, Stream* stream, NbtTag* parent) { - NbtTag tag; - tag.TagID = NBT_TAG_INVALID; - tag.NameBuffer[0] = NULL; - if (typeId == 0) return tag; + if (typeId == NBT_TAG_END) return; + NbtTag tag; + tag.NameBuffer[0] = NULL; tag.Name = readTagName ? ReadString() : null; tag.TagID = typeId; tag.Parent = parent; @@ -284,7 +282,7 @@ void Nbt_ReadTag(UInt8 typeId, bool readTagName, Stream* stream, NbtTag* parent) break; case NBT_TAG_COMPOUND: - while ((childTagId = Stream_ReadUInt8(stream)) != NBT_TAG_INVALID) { + while ((childTagId = Stream_ReadUInt8(stream)) != NBT_TAG_END) { Nbt_ReadTag(childTagId, true, stream, &tag); } break; diff --git a/src/Client/Gui.c b/src/Client/Gui.c index dbc909c62..ec1f2b5c6 100644 --- a/src/Client/Gui.c +++ b/src/Client/Gui.c @@ -272,7 +272,7 @@ void TextAtlas_AddInt(TextAtlas* atlas, Int32 value, VertexP3fT2fC4b** vertices) } UInt8 digits[STRING_SIZE]; - Int32 i, count = String_MakeInt32(value, digits); + Int32 i, count = String_MakeUInt32((UInt32)value, digits); for (i = count - 1; i >= 0; i--) { TextAtlas_Add(atlas, digits[i] - '0' , vertices); } diff --git a/src/Client/Menus.c b/src/Client/Menus.c index 76ba35bc7..c965f1d92 100644 --- a/src/Client/Menus.c +++ b/src/Client/Menus.c @@ -1463,15 +1463,15 @@ void HotkeyListScreen_EntryClick(GuiElement* screenElem, GuiElement* w) { String alt = String_FromConst("Alt"); UInt8 flags = 0; - if (String_ContainsString(&text, &ctrl)) flags |= HOTKEYS_FLAG_CTRL; - if (String_ContainsString(&text, &shift)) flags |= HOTKEYS_FLAG_SHIFT; - if (String_ContainsString(&text, &alt)) flags |= HOTKEYS_FLAG_ALT; + if (String_ContainsString(&value, &ctrl)) flags |= HOTKEYS_FLAG_CTRL; + if (String_ContainsString(&value, &shift)) flags |= HOTKEYS_FLAG_SHIFT; + if (String_ContainsString(&value, &alt)) flags |= HOTKEYS_FLAG_ALT; - Key hKey = Utils_ParseEnum(&key, Key_Unknown, Key_Names, Array_Elems(Key_Names)); + Key baseKey = Utils_ParseEnum(&key, Key_Unknown, Key_Names, Array_Elems(Key_Names)); Int32 i; for (i = 0; i < HotkeysText.Count; i++) { HotkeyData h = HotkeysList[i]; - if (h.BaseKey == hKey && h.Flags == flags) { original = h; break; } + if (h.BaseKey == baseKey && h.Flags == flags) { original = h; break; } } Gui_SetNewScreen(EditHotkeyScreen_MakeInstance(original)); } @@ -1857,6 +1857,97 @@ Screen* MouseKeyBindingsScreen_MakeInstance(void) { /*########################################################################################################################* *--------------------------------------------------MenuOptionsScreen------------------------------------------------------* *#########################################################################################################################*/ +MenuOptionsScreen MenuOptionsScreen_Instance; +GuiElementVTABLE MenuOptionsScreen_VTABLE; +void Menu_GetBool(bool v, STRING_TRANSIENT String* raw) { + String_AppendConst(raw, v ? "ON" : "OFF"); +} + +bool Menu_SetBool(STRING_PURE String* raw, const UInt8* key) { + bool isOn = String_CaselessEqualsConst(raw, "ON"); + Options_SetBool(key, isOn); return isOn; +} + +void MenuOptionsScreen_GetFPS(STRING_TRANSIENT String* raw) { + String_AppendConst(raw, FpsLimit_Names[Game_FpsLimit]); +} +void MenuOptionsScreen_SetFPS(STRING_PURE String* raw) { + UInt32 method = Utils_ParseEnum(raw, FpsLimit_VSync, FpsLimit_Names, Array_Elems(FpsLimit_Names)); + Game_SetFpsLimitMethod(method); + + String value = String_FromReadonly(FpsLimit_Names[method]); + Options_Set(OPTION_FPS_LIMIT, &value); +} + +void MenuOptionsScreen_Set(MenuOptionsScreen* screen, Int32 i, STRING_PURE String* text) { + screen->Buttons[i].SetValue(text); + /* need to get btn again here (e.g. changing FPS invalidates all widgets) */ + + UInt8 titleBuffer[String_BufferSize(STRING_SIZE)]; + String title = String_InitAndClearArray(titleBuffer); + String_AppendConst(&title, screen->Buttons[i].OptName); + String_AppendConst(&title, ": "); + screen->Buttons[i].GetValue(&title); + ButtonWidget_SetText(&screen->Buttons[i], &title); +} + +void MenuOptionsScreen_FreeExtHelp(MenuOptionsScreen* screen) { + if (screen->ExtHelp.LinesCount == 0) return; + Elem_Free(&screen->ExtHelp); + screen->ExtHelp.LinesCount = 0; +} + +void MenuOptionsScreen_RepositionExtHelp(MenuOptionsScreen* screen) { + screen->ExtHelp.XOffset = Game_Width / 2 - screen->ExtHelp.Width / 2; + screen->ExtHelp.YOffset = Game_Height / 2 + 100; + Widget_Reposition(&screen->ExtHelp); +} + +void MenuOptionsScreen_SelectExtHelp(MenuOptionsScreen* screen, Int32 idx) { + MenuOptionsScreen_FreeExtHelp(screen); + if (screen->Descriptions == NULL || screen->ActiveI >= 0) return; + const UInt8* desc = screen->Descriptions[idx]; + if (desc == NULL) return; + + String descRaw = String_FromReadonly(desc); + String descLines[5]; + UInt32 descLinesCount = Array_Elems(descLines); + String_UNSAFE_Split(&descRaw, '%', descLines, &descLinesCount); + + TextGroupWidget_Create(&screen->ExtHelp, descLinesCount, &screen->TextFont, NULL, screen->ExtHelp_Textures, screen->ExtHelp_Buffer); + Widget_SetLocation((Widget*)(&screen->ExtHelp), ANCHOR_MIN, ANCHOR_MIN, 0, 0); + Elem_Init(&screen->ExtHelp); + + Int32 i; + for (i = 0; i < descLinesCount; i++) { + TextGroupWidget_SetText(&screen->ExtHelp, i, &descLines[i]); + } + MenuOptionsScreen_RepositionExtHelp(screen); +} + +void MenuOptionsScreen_FreeInput(MenuOptionsScreen* screen) { + if (screen->ActiveI == -1) return; + + Int32 i; + for (i = screen->WidgetsCount - 3; i < screen->WidgetsCount; i++) { + Elem_Free(screen->WidgetsPtr[i]); + screen->WidgetsPtr[i] = NULL; + } +} + +void MenuOptionsScreen_EnterInput(MenuOptionsScreen* screen) { + String text = screen->Input.Base.Text; + MenuInputValidator* validator = &screen->Input.Validator; + + if (validator->IsValidValue(validator, &text)) { + MenuOptionsScreen_Set(screen, screen->ActiveI, &text); + } + + MenuOptionsScreen_SelectExtHelp(screen, screen->ActiveI); + screen->ActiveI = -1; + MenuOptionsScreen_FreeInput(screen); +} + void MenuOptionsScreen_Init(GuiElement* elem) { MenuScreen_Init(elem); Key_KeyRepeat = true; @@ -1887,7 +1978,7 @@ void MenuOptionsScreen_OnResize(GuiElement* elem) { MenuOptionsScreen* screen = (MenuOptionsScreen*)elem; MenuScreen_OnResize(elem); if (screen->ExtHelp.LinesCount == 0) return; - RepositionExtendedHelp(); + MenuOptionsScreen_RepositionExtHelp(screen); } void MenuOptionsScreen_ContextLost(void* obj) { @@ -1908,7 +1999,7 @@ bool MenuOptionsScreen_HandlesKeyDown(GuiElement* elem, Key key) { if (screen->ActiveI >= 0) { if (Elem_HandlesKeyDown(&screen->Input.Base, key)) return true; if (key == Key_Enter || key == Key_KeypadEnter) { - EnterInput(); return true; + MenuOptionsScreen_EnterInput(screen); return true; } } return MenuScreen_HandlesKeyDown(elem, key); @@ -1927,7 +2018,7 @@ bool MenuOptionsScreen_HandlesMouseMove(GuiElement* elem, Int32 x, Int32 y) { if (screen->Descriptions == NULL || i >= screen->DescriptionsCount) return true; screen->SelectedI = i; - if (screen->ActiveI == -1) SelectExtendedHelp(i); + if (screen->ActiveI == -1) MenuOptionsScreen_SelectExtHelp(screen, i); return true; } @@ -1940,83 +2031,31 @@ void MenuOptionsScreen_Make(MenuOptionsScreen* screen, Int32 i, Int32 dir, Int32 ButtonWidget* btn = &screen->Buttons[i]; screen->WidgetsPtr[i] = (Widget*)btn; - ButtonWidget_Create(btn, 300, &title, &screen->TitleFont, onClick); + ButtonWidget_Create(btn, &title, 300, &screen->TitleFont, onClick); Widget_SetLocation((Widget*)btn, ANCHOR_CENTRE, ANCHOR_CENTRE, 160 * dir, y); btn->OptName = optName; btn->GetValue = getter; btn->SetValue = setter; - return btn; } -void Menu_GetBool(bool v, STRING_TRANSIENT String* raw) { - String_AppendConst(raw, v ? "ON" : "OFF"); -} -bool Menu_SetBool(STRING_PURE String* raw, const UInt8* key) { - bool isOn = String_CaselessEqualsConst(raw, "ON"); - Options_SetBool(key, isOn); return isOn; +void MenuOptionsScreen_OK(GuiElement* screenElem, GuiElement* widget) { + MenuOptionsScreen* screen = (MenuOptionsScreen*)screenElem; + MenuOptionsScreen_EnterInput(screen); } -void MenuOptionsScreen_GetFPS(STRING_TRANSIENT String* raw) { - String_AppendConst(raw, FpsLimit_Names[Game_FpsLimit]); -} -void MenuOptionsScreen_SetFPS(STRING_PURE String* raw) { - UInt32 method = Utils_ParseEnum(raw, FpsLimit_VSync, FpsLimit_Names, Array_Elems(FpsLimit_Names)); - Game_SetFpsLimitMethod(method); - Options_Set(OPTION_FPS_LIMIT, FpsLimit_Names[method]); -} - -void MenuOptionsScreen_SelectExtHelp(MenuOptionsScreen* screen, Int32 idx) { - MenuOptionsScreen_FreeExtHelp(screen); - if (screen->Descriptions == NULL || screen->ActiveI >= 0) return; - const UInt8* desc = screen->Descriptions[idx]; - if (desc == NULL) return; - - String descRaw = String_FromReadonly(desc); - String descLines[5]; - UInt32 descLinesCount = Array_Elems(descLines); - String_UNSAFE_Split(&descRaw, '%', &descLines, &descLinesCount); - - TextGroupWidget_Create(&screen->ExtHelp, descLinesCount, &screen->TextFont, NULL, &screen->ExtHelp_Textures, &screen->ExtHelp_Buffer); - Widget_SetLocation((Widget*)(&screen->ExtHelp), ANCHOR_MIN, ANCHOR_MIN, 0, 0); - Elem_Init(&screen->ExtHelp); - - Int32 i; - for (i = 0; i < descLinesCount; i++) { - TextGroupWidget_SetText(&screen->ExtHelp, i, &descLines[i]); - } - MenuOptionsScreen_RepositionExtHelp(screen); -} - -void MenuOptionsScreen_RepositionExtHelp(MenuOptionsScreen* screen) { - screen->ExtHelp.XOffset = Game_Width / 2 - screen->ExtHelp.Width / 2; - screen->ExtHelp.YOffset = Game_Height / 2 + 100; - Widget_Reposition(&screen->ExtHelp); -} - -void MenuOptionsScreen_FreeExtHelp(MenuOptionsScreen* screen) { - if (screen->ExtHelp.LinesCount == 0) return; - Elem_Free(&screen->ExtHelp); - screen->ExtHelp.LinesCount = 0; -} - -void MenuOptionsScreen_Set(MenuOptionsScreen* screen, Int32 i, STRING_PURE String* text) { - screen->Buttons[i].SetValue(text); - /* need to get btn again here (e.g. changing FPS invalidates all widgets) */ - - UInt8 titleBuffer[String_BufferSize(STRING_SIZE)]; - String title = String_InitAndClearArray(titleBuffer); - String_AppendConst(&title, screen->Buttons[i].OptName); - String_AppendConst(&title, ": "); - screen->Buttons[i].GetValue(&title); - ButtonWidget_SetText(&screen->Buttons[i], &title); +void MenuOptionsScreen_Default(GuiElement* screenElem, GuiElement* widget) { + MenuOptionsScreen* screen = (MenuOptionsScreen*)screenElem; + String text = String_FromReadonly(screen->DefaultValues[screen->ActiveI]); + InputWidget_Clear(&screen->Input.Base); + InputWidget_AppendString(&screen->Input.Base, &text); } void MenuOptionsScreen_Bool(GuiElement* screenElem, GuiElement* widget) { MenuOptionsScreen* screen = (MenuOptionsScreen*)screenElem; ButtonWidget* button = (ButtonWidget*)widget; Int32 index = MenuScreen_Index((MenuScreen*)screen, (Widget*)widget); - SelectExtendedHelp(index); + MenuOptionsScreen_SelectExtHelp(screen, index); UInt8 valueBuffer[String_BufferSize(STRING_SIZE)]; String value = String_InitAndClearArray(valueBuffer); @@ -2031,7 +2070,7 @@ void MenuOptionsScreen_Enum(GuiElement* screenElem, GuiElement* widget) { MenuOptionsScreen* screen = (MenuOptionsScreen*)screenElem; ButtonWidget* button = (ButtonWidget*)widget; Int32 index = MenuScreen_Index((MenuScreen*)screen, (Widget*)widget); - SelectExtendedHelp(index); + MenuOptionsScreen_SelectExtHelp(screen, index); MenuInputValidator* validator = &screen->Validators[index]; const UInt8** names = (const UInt8**)validator->Meta_Ptr[0]; @@ -2059,15 +2098,15 @@ void MenuOptionsScreen_Input(GuiElement* screenElem, GuiElement* widget) { MenuInputValidator* validator = &screen->Validators[screen->ActiveI]; MenuInputWidget_Create(&screen->Input, 400, 30, &value, &screen->TextFont, validator); - Widget_SettLocation((Widget*)(&screen->Input), ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 110); + Widget_SetLocation((Widget*)(&screen->Input), ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 110); screen->Input.Base.ShowCaret = true; String okMsg = String_FromConst("OK"); - ButtonWidget_Create(&screen->OK, 40, &okMsg, &screen->TitleFont, MenuOptionsScreen_OK); + ButtonWidget_Create(&screen->OK, &okMsg, 40, &screen->TitleFont, MenuOptionsScreen_OK); Widget_SetLocation((Widget*)(&screen->OK), ANCHOR_CENTRE, ANCHOR_CENTRE, 240, 110); String defMsg = String_FromConst("Default value") - ButtonWidget_Create(&screen->Default, 200, &defMsg, &screen->TitleFont, MenuOptionsScreen_Default); + ButtonWidget_Create(&screen->Default, &defMsg, 200, &screen->TitleFont, MenuOptionsScreen_Default); Widget_SetLocation((Widget*)(&screen->Default), ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 150); Widget** widgets = screen->WidgetsPtr; @@ -2076,37 +2115,27 @@ void MenuOptionsScreen_Input(GuiElement* screenElem, GuiElement* widget) { widgets[screen->WidgetsCount - 3] = (Widget*)(&screen->Default); } -void MenuOptionsScreen_OK(GuiElement* screenElem, GuiElement* widget) { - MenuOptionsScreen* screen = (MenuOptionsScreen*)screenElem; - MenuOptionsScreen_EnterInput(screen); -} +MenuOptionsScreen* MenuOptionsScreen_MakeInstance(Widget** widgets, Int32 count, Menu_ContextRecreated contextRecreated, MenuInputValidator* validators, + const UInt8** descriptions, const UInt8** defaultValues, ButtonWidget* buttons, Int32 descsCount) { + MenuOptionsScreen* screen = &MenuOptionsScreen_Instance; + Platform_MemSet(screen, 0, sizeof(MenuOptionsScreen)); + MenuScreen_MakeInstance((MenuScreen*)screen, widgets, count, contextRecreated); + screen->VTABLE = &MenuOptionsScreen_VTABLE; -void MenuOptionsScreen_Default(GuiElement* screenElem, GuiElement* widget) { - MenuOptionsScreen* screen = (MenuOptionsScreen*)screenElem; - String text = String_FromReadonly(screen->DefaultValues[screen->ActiveI]); - InputWidget_Clear(&screen->Input.Base); - InputWidget_AppendString(&screen->Input.Base, &text); -} + screen->VTABLE->HandlesKeyDown = MenuOptionsScreen_HandlesKeyDown; + screen->VTABLE->HandlesKeyUp = MenuOptionsScreen_HandlesKeyUp; + screen->VTABLE->HandlesKeyPress = MenuOptionsScreen_HandlesKeyPress; + screen->VTABLE->HandlesMouseMove = MenuOptionsScreen_HandlesMouseMove; -void MenuOptionsScreen_EnterInput(MenuOptionsScreen* screen) { - String text = screen->Input.Base.Text; - MenuInputValidator* validator = &screen->Input.Validator; + screen->OnResize = MenuOptionsScreen_OnResize; + screen->VTABLE->Init = MenuOptionsScreen_Init; + screen->VTABLE->Render = MenuOptionsScreen_Render; + screen->VTABLE->Free = MenuOptionsScreen_Free; - if (validator->IsValidValue(validator, &text)) { - MenuOptionsScreen_Set(screen, screen->ActiveI, &text); - } - - MenuOptionsScreen_SelectExtHelp(screen, screen->ActiveI); - screen->ActiveI = -1; - MenuOptionsScreen_FreeInput(screen); -} - -void MenuOptionsScreen_FreeInput(MenuOptionsScreen* screen) { - if (screen->ActiveI == -1) return; - - Int32 i; - for (i = screen->WidgetsCount - 3; i < screen->WidgetsCount; i++) { - Elem_Free(screen->WidgetsPtr[i]); - screen->WidgetsPtr[i] = NULL; - } + screen->Validators = validators; + screen->Descriptions = descriptions; + screen->DefaultValues = defaultValues; + screen->Buttons = buttons; + screen->DescriptionsCount = descsCount; + return screen; } \ No newline at end of file diff --git a/src/Client/String.c b/src/Client/String.c index c5fab5771..0b8809e09 100644 --- a/src/Client/String.c +++ b/src/Client/String.c @@ -136,8 +136,8 @@ bool String_AppendBool(STRING_TRANSIENT String* str, bool value) { return String_AppendConst(str, text); } -Int32 String_MakeInt32(Int32 num, UInt8* numBuffer) { - Int32 len = 0; +Int32 String_MakeUInt32(UInt32 num, UInt8* numBuffer) { + UInt32 len = 0; do { numBuffer[len] = (UInt8)('0' + (num % 10)); @@ -149,13 +149,16 @@ Int32 String_MakeInt32(Int32 num, UInt8* numBuffer) { bool String_AppendInt32(STRING_TRANSIENT String* str, Int32 num) { if (num < 0) { num = -num; - if (!String_Append(str, (UInt8)'-')) return false; + if (!String_Append(str, '-')) return false; } + return String_AppendUInt32(str, (UInt32)num); +} +bool String_AppendUInt32(STRING_TRANSIENT String* str, UInt32 num) { UInt8 numBuffer[STRING_INT32CHARS]; - Int32 numLen = String_MakeInt32(num, numBuffer); + Int32 numLen = String_MakeUInt32(num, numBuffer); Int32 i; - + for (i = numLen - 1; i >= 0; i--) { if (!String_Append(str, numBuffer[i])) return false; } @@ -167,7 +170,7 @@ bool String_AppendPaddedInt32(STRING_TRANSIENT String* str, Int32 num, Int32 min Int32 i; for (i = 0; i < minDigits; i++) { numBuffer[i] = '0'; } - Int32 numLen = String_MakeInt32(num, numBuffer); + Int32 numLen = String_MakeUInt32(num, numBuffer); if (numLen < minDigits) numLen = minDigits; for (i = numLen - 1; i >= 0; i--) { @@ -335,34 +338,40 @@ Int32 String_Compare(STRING_PURE String* a, STRING_PURE String* b) { return a->length < b->length ? 1 : -1; } -void String_Format1(STRING_TRANSIENT String* str, const UInt8* format, void* a1) { +void String_Format1(STRING_TRANSIENT String* str, const UInt8* format, const void* a1) { String_Format4(str, format, a1, NULL, NULL, NULL); } -void String_Format2(STRING_TRANSIENT String* str, const UInt8* format, void* a1, void* a2) { +void String_Format2(STRING_TRANSIENT String* str, const UInt8* format, const void* a1, const void* a2) { String_Format4(str, format, a1, a2, NULL, NULL); } -void String_Format3(STRING_TRANSIENT String* str, const UInt8* format, void* a1, void* a2, void* a3) { +void String_Format3(STRING_TRANSIENT String* str, const UInt8* format, const void* a1, const void* a2, const void* a3) { String_Format4(str, format, a1, a2, a3, NULL); } -void String_Format4(STRING_TRANSIENT String* str, const UInt8* format, void* a1, void* a2, void* a3, void* a4) { +void String_Format4(STRING_TRANSIENT String* str, const UInt8* format, const void* a1, const void* a2, const void* a3, const void* a4) { String formatStr = String_FromReadonly(format); - void* args[4] = { a1, a2, a3, a4 }; + const void* args[4] = { a1, a2, a3, a4 }; Int32 i, j = 0; for (i = 0; i < formatStr.length; i++) { if (formatStr.buffer[i] != '%') { String_Append(str, formatStr.buffer[i]); continue; } - switch (formatStr.buffer[i + 1]) { - case 'b': String_AppendInt32(str, *((UInt8*)args[j])); break; - case 'i': String_AppendInt32(str, *((Int32*)args[j])); break; - case 'f': String_AppendReal32(str, *((Real32*)args[j])); break; - case 'p': String_AppendBool(str, *((bool*)args[j])); break; - case 'c': String_AppendConst(str, (UInt8*)args[j]); break; - case 's': String_AppendString(str, (String*)args[j]); break; - default: ErrorHandler_Fail("Invalid type for string format"); + const void* arg = args[j++]; + switch (formatStr.buffer[i++]) { + case 'b': + String_AppendInt32(str, *((UInt8*)arg)); break; + case 'i': + String_AppendInt32(str, *((Int32*)arg)); break; + case 'f': + String_AppendReal32(str, *((Real32*)arg)); break; + case 'p': + String_AppendBool(str, *((bool*)arg)); break; + case 'c': + String_AppendConst(str, (UInt8*)arg); break; + case 's': + String_AppendString(str, (String*)arg); break; + default: + ErrorHandler_Fail("Invalid type for string format"); } - - i++; j++; /* skip over type following % */ } } diff --git a/src/Client/String.h b/src/Client/String.h index 12153e822..307b5b81d 100644 --- a/src/Client/String.h +++ b/src/Client/String.h @@ -54,11 +54,12 @@ void String_UNSAFE_Split(STRING_REF String* str, UInt8 c, STRING_TRANSIENT Strin bool String_Equals(STRING_PURE String* a, STRING_PURE String* b); bool String_CaselessEquals(STRING_PURE String* a, STRING_PURE String* b); bool String_CaselessEqualsConst(STRING_PURE String* a, STRING_PURE const UInt8* b); -Int32 String_MakeInt32(Int32 num, UInt8* numBuffer); +Int32 String_MakeUInt32(UInt32 num, UInt8* numBuffer); bool String_Append(STRING_TRANSIENT String* str, UInt8 c); bool String_AppendBool(STRING_TRANSIENT String* str, bool value); bool String_AppendInt32(STRING_TRANSIENT String* str, Int32 num); +bool String_AppendUInt32(STRING_TRANSIENT String* str, UInt32 num); /* Attempts to append an integer value to the end of a string, padding left with 0. */ bool String_AppendPaddedInt32(STRING_TRANSIENT String* str, Int32 num, Int32 minDigits); bool String_AppendConst(STRING_TRANSIENT String* str, const UInt8* toAppend); @@ -80,10 +81,10 @@ bool String_CaselessStarts(STRING_PURE String* str, STRING_PURE String* sub); bool String_CaselessEnds(STRING_PURE String* str, STRING_PURE String* sub); Int32 String_Compare(STRING_PURE String* a, STRING_PURE String* b); -void String_Format1(STRING_TRANSIENT String* str, const UInt8* format, void* a1); -void String_Format2(STRING_TRANSIENT String* str, const UInt8* format, void* a1, void* a2); -void String_Format3(STRING_TRANSIENT String* str, const UInt8* format, void* a1, void* a2, void* a3); -void String_Format4(STRING_TRANSIENT String* str, const UInt8* format, void* a1, void* a2, void* a3, void* a4); +void String_Format1(STRING_TRANSIENT String* str, const UInt8* format, const void* a1); +void String_Format2(STRING_TRANSIENT String* str, const UInt8* format, const void* a1, const void* a2); +void String_Format3(STRING_TRANSIENT String* str, const UInt8* format, const void* a1, const void* a2, const void* a3); +void String_Format4(STRING_TRANSIENT String* str, const UInt8* format, const void* a1, const void* a2, const void* a3, const void* a4); UInt16 Convert_CP437ToUnicode(UInt8 c); UInt8 Convert_UnicodeToCP437(UInt16 c); diff --git a/src/Client/TexturePack.c b/src/Client/TexturePack.c index c42e9e7dc..2e7a5544a 100644 --- a/src/Client/TexturePack.c +++ b/src/Client/TexturePack.c @@ -12,20 +12,6 @@ typedef struct EntryList_ { StringsBuffer Entries; } EntryList; -void EntryList_Add(EntryList* list, STRING_PURE String* entry) { - StringsBuffer_Add(&list->Entries, entry); - EntryList_Save(list); -} - -bool EntryList_Has(EntryList* list, STRING_PURE String* entry) { - Int32 i; - for (i = 0; i < list->Entries.Count; i++) { - String curEntry = StringsBuffer_UNSAFE_Get(&list->Entries, i); - if (String_Equals(&curEntry, entry)) return true; - } - return false; -} - void EntryList_Load(EntryList* list) { String folder = String_FromRawArray(list->FolderBuffer); String filename = String_FromRawArray(list->FileBuffer); @@ -80,6 +66,20 @@ void EntryList_Save(EntryList* list) { ErrorHandler_CheckOrFail(result, "EntryList_Save - close file"); } +void EntryList_Add(EntryList* list, STRING_PURE String* entry) { + StringsBuffer_Add(&list->Entries, entry); + EntryList_Save(list); +} + +bool EntryList_Has(EntryList* list, STRING_PURE String* entry) { + Int32 i; + for (i = 0; i < list->Entries.Count; i++) { + String curEntry = StringsBuffer_UNSAFE_Get(&list->Entries, i); + if (String_Equals(&curEntry, entry)) return true; + } + return false; +} + void EntryList_Make(EntryList* list, STRING_PURE const UInt8* folder, STRING_PURE const UInt8* file) { String dstFolder = String_InitAndClearArray(list->FolderBuffer); String_AppendConst(&dstFolder, folder); @@ -91,10 +91,19 @@ void EntryList_Make(EntryList* list, STRING_PURE const UInt8* folder, STRING_PUR } #define TEXCACHE_FOLDER "texturecache" +/* Because I didn't store milliseconds in original C# client */ +#define TEXCACHE_TICKS_PER_MS 10000LL EntryList cache_accepted, cache_denied, cache_eTags, cache_lastModified; -#define TexCache_InitAndMakePath(url) UInt8 pathBuffer[String_BufferSize(FILENAME_SIZE)]; \ -path = String_InitAndClearArray(pathBuffer); TextureCache_MakePath(&path, url); +#define TexCache_InitAndMakePath(url) \ +UInt8 pathBuffer[String_BufferSize(FILENAME_SIZE)]; \ +path = String_InitAndClearArray(pathBuffer); \ +TextureCache_MakePath(&path, url); + +#define TexCache_Crc32(url) \ +UInt8 crc32Buffer[STRING_INT32CHARS];\ +crc32 = String_InitAndClearArray(crc32Buffer);\ +String_AppendUInt32(&crc32, Utils_CRC32(url->buffer, url->length)); void TextureCache_Init(void) { EntryList_Make(&cache_accepted, TEXCACHE_FOLDER, "acceptedurls.txt"); @@ -108,6 +117,11 @@ bool TextureCache_HasDenied(STRING_PURE String* url) { return EntryList_Has(&c void TextureCache_Accept(STRING_PURE String* url) { EntryList_Add(&cache_accepted, url); } void TextureCache_Deny(STRING_PURE String* url) { EntryList_Add(&cache_denied, url); } +void TextureCache_MakePath(STRING_TRANSIENT String* path, STRING_PURE String* url) { + String crc32; TexCache_Crc32(url); + String_Format3(path, "%c%b%s", TEXCACHE_FOLDER, &Platform_DirectorySeparator, &crc32); +} + bool TextureCache_HasUrl(STRING_PURE String* url) { String path; TexCache_InitAndMakePath(url); return Platform_FileExists(url); @@ -128,11 +142,29 @@ bool TextureCache_GetStream(STRING_PURE String* url, Stream* stream) { return true; } +void TexturePack_GetFromTags(STRING_PURE String* url, STRING_TRANSIENT String* result, EntryList* list) { + String crc32; TexCache_Crc32(url); + Int32 i; + for (i = 0; i < list->Entries.Count; i++) { + String entry = StringsBuffer_UNSAFE_Get(&list->Entries, i); + if (!String_CaselessStarts(&entry, &crc32)) continue; + + Int32 sepIndex = String_IndexOf(&entry, ' ', 0); + if (sepIndex == -1) continue; + + String value = String_UNSAFE_SubstringAt(&entry, sepIndex + 1); + String_AppendString(result, &value); + } +} + void TextureCache_GetLastModified(STRING_PURE String* url, DateTime* time) { - string entry = GetFromTags(url, LastModified); - long ticks = 0; - if (entry != null && long.TryParse(entry, out ticks)) { - return new DateTime(ticks, DateTimeKind.Utc); + UInt8 entryBuffer[String_BufferSize(STRING_SIZE)]; + String entry = String_InitAndClearArray(entryBuffer); + TexturePack_GetFromTags(url, &entry, &cache_lastModified); + + Int64 ticks; + if (entry.length > 0 && Convert_TryParseInt64(&entry, &ticks)) { + *time = DateTime_FromTotalMs(ticks / TEXCACHE_TICKS_PER_MS); } else { String path; TexCache_InitAndMakePath(url); return Platform_FileGetWriteTime(path); @@ -140,23 +172,7 @@ void TextureCache_GetLastModified(STRING_PURE String* url, DateTime* time) { } void TextureCache_GetETag(STRING_PURE String* url, STRING_PURE String* etag) { - TexturePack_GetFromTags(url, etag, ETags); -} - -void TexturePack_GetFromTags(STRING_PURE String* url, STRING_TRANSIENT String* result, EntryList* list) { - string crc32 = CRC32(url); - - Int32 i; - for (i = 0; i < list->Entries.Count; i++) { - String entry = StringsBuffer_UNSAFE_Get(&list->Entries, i); - if (!String_CaselessStarts(&entry, &crc32)) continue; - - Int32 sepIndex = String_IndexOf(&entry, ' '); - if (sepIndex == -1) continue; - - String value = String_UNSAFE_SubstringAt(&entry, sepIndex + 1); - String_AppendString(result, &value); - } + TexturePack_GetFromTags(url, etag, &cache_eTags); } void* TextureCache_CreateFile(STRING_PURE String* path) { @@ -167,7 +183,7 @@ void* TextureCache_CreateFile(STRING_PURE String* path) { } void* file; - ReturnCode result = Platform_FileCreate(&file, &path); + ReturnCode result = Platform_FileCreate(&file, path); /* TODO: Should we just log failure to save? */ ErrorHandler_CheckOrFail(result, "TextureCache_CreateFile - open file"); return file; @@ -193,19 +209,8 @@ void TextureCache_AddData(STRING_PURE String* url, UInt8* data, UInt32 length) { ErrorHandler_CheckOrFail(result, "TextureCache_AddData - close file"); } -void TextureCache_AddETag(STRING_PURE String* url, STRING_PURE String* etag) { - if (etag->length == 0) return; - TextureCache_AddToTags(url, etag, ETags); -} - -void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModified) { - if (lastModified->Year == 0 && lastModified->Month == 0) return; - String data = lastModified.ToUniversalTime().Ticks.ToString(); - TextureCache_AddToTags(url, data, LastModified); -} - void TextureCache_AddToTags(STRING_PURE String* url, STRING_PURE String* data, EntryList* list) { - String crc32 = CRC32(url); + String crc32; TexCache_Crc32(url); UInt8 entryBuffer[String_BufferSize(2048)]; String entry = String_InitAndClearArray(entryBuffer); String_Format2(&entry, "%s %s", &crc32, data); @@ -221,11 +226,17 @@ void TextureCache_AddToTags(STRING_PURE String* url, STRING_PURE String* data, E EntryList_Add(list, &entry); } -void TextureCache_MakePath(STRING_TRANSIENT String* path, STRING_PURE String* url) { - return PathIO.Combine(folder, CRC32(url)); +void TextureCache_AddETag(STRING_PURE String* url, STRING_PURE String* etag) { + if (etag->length == 0) return; + TextureCache_AddToTags(url, etag, &cache_eTags); } -void TextureCache_CRC32(STRING_PURE String* url) { - UInt32 crc32 = Utils_CRC32(url->buffer, url->length); - return crc32.ToString(); +void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModified) { + if (lastModified->Year == 0 && lastModified->Month == 0) return; + Int64 ticks = DateTime_TotalMs(lastModified) * TEXCACHE_TICKS_PER_MS; + + UInt8 dataBuffer[String_BufferSize(STRING_SIZE)]; + String data = String_InitAndClearArray(dataBuffer); + String_AppendInt64(&data, ticks); + TextureCache_AddToTags(url, &data, &cache_lastModified); } \ No newline at end of file diff --git a/src/Client/Utils.h b/src/Client/Utils.h index de9574708..06f689698 100644 --- a/src/Client/Utils.h +++ b/src/Client/Utils.h @@ -22,6 +22,7 @@ typedef struct Bitmap_ Bitmap; #define DATETIME_SECONDS_PER_HOUR (60 * 60) #define DATETIME_SECONDS_PER_DAY (60 * 60 * 24) +DateTime DateTime_FromTotalMs(Int64 ms); Int64 DateTime_TotalMs(DateTime* time); Int64 DateTime_MsBetween(DateTime* start, DateTime* end);