diff --git a/ClassicalSharp/Rendering/HeldBlockRenderer.cs b/ClassicalSharp/Rendering/HeldBlockRenderer.cs index 1be945108..0e45eccc4 100644 --- a/ClassicalSharp/Rendering/HeldBlockRenderer.cs +++ b/ClassicalSharp/Rendering/HeldBlockRenderer.cs @@ -222,9 +222,8 @@ namespace ClassicalSharp.Renderers { } } - /// Skeleton implementation of a player entity so we can reuse - /// block model rendering code. - internal class FakePlayer : Player { + /// Skeleton implementation of player entity so we can reuse block model rendering code. + class FakePlayer : Player { public FakePlayer(Game game) : base(game) { NoShade = true; diff --git a/src/Client/Client.vcxproj b/src/Client/Client.vcxproj index 6d93bd9a8..1e4389051 100644 --- a/src/Client/Client.vcxproj +++ b/src/Client/Client.vcxproj @@ -295,7 +295,6 @@ - diff --git a/src/Client/Client.vcxproj.filters b/src/Client/Client.vcxproj.filters index aecb638ff..4553f2188 100644 --- a/src/Client/Client.vcxproj.filters +++ b/src/Client/Client.vcxproj.filters @@ -419,9 +419,6 @@ Source Files\Math - - Source Files\Utils - Source Files\2D\Utils diff --git a/src/Client/Entity.h b/src/Client/Entity.h index 4b6e69c3d..aed0bbcef 100644 --- a/src/Client/Entity.h +++ b/src/Client/Entity.h @@ -29,24 +29,18 @@ typedef struct LocationUpdate_ { Real32 RotX, RotY, RotZ, HeadX; /* Whether this update includes an absolute or relative position. */ bool IncludesPosition; - /* Whether the positon is absolute, or relative to the last positionreceived from the server. */ + /* Whether the positon is absolute, or relative to the last position received from the server. */ bool RelativePosition; } LocationUpdate; /* Clamps the given angle so it lies between [0, 360). */ Real32 LocationUpdate_Clamp(Real32 degrees); -/* Constructs a location update with values for every field. -You should generally prefer using the alternative constructors. */ void LocationUpdate_Construct(LocationUpdate* update, Real32 x, Real32 y, Real32 z, Real32 rotX, Real32 rotY, Real32 rotZ, Real32 headX, bool incPos, bool relPos); -/* Constructs a location update that does not have any position or orientation information. */ void LocationUpdate_Empty(LocationUpdate* update); -/* Constructs a location update that only consists of orientation information. */ void LocationUpdate_MakeOri(LocationUpdate* update, Real32 rotY, Real32 headX); -/* Constructs a location update that only consists of position information. */ void LocationUpdate_MakePos(LocationUpdate* update, Vector3 pos, bool rel); -/* Constructs a location update that consists of position and orientation information. */ void LocationUpdate_MakePosAndOri(LocationUpdate* update, Vector3 pos, Real32 rotY, Real32 headX, bool rel); diff --git a/src/Client/Funcs.c b/src/Client/Funcs.c deleted file mode 100644 index ae586023f..000000000 --- a/src/Client/Funcs.c +++ /dev/null @@ -1,10 +0,0 @@ -#include "Funcs.h" - -bool Char_IsUpper(UInt8 c) { - return c >= 'A' && c <= 'Z'; -} - -UInt8 Char_ToLower(UInt8 c) { - if (!Char_IsUpper(c)) return c; - return (UInt8)(c + ' '); -} \ No newline at end of file diff --git a/src/Client/Funcs.h b/src/Client/Funcs.h index 64f3518e4..e7b7cfd8e 100644 --- a/src/Client/Funcs.h +++ b/src/Client/Funcs.h @@ -15,11 +15,6 @@ /* returns number of elements in given array. */ #define Array_NumElements(arr) (sizeof(arr) / sizeof(arr[0])) -/* returns whether character is uppercase letter */ -bool Char_IsUpper(UInt8 c); -/* Converts uppercase letter to lowercase */ -UInt8 Char_ToLower(UInt8 c); - #define QuickSort_Swap_Maybe()\ if (i <= j) {\ key = keys[i]; keys[i] = keys[j]; keys[j] = key;\ diff --git a/src/Client/Gui.c b/src/Client/Gui.c index 3fdc64afb..4900088a5 100644 --- a/src/Client/Gui.c +++ b/src/Client/Gui.c @@ -36,12 +36,12 @@ void GuiElement_Reset(GuiElement* elem) { void Screen_Reset(Screen* screen) { GuiElement_Reset(&screen->Base); - screen->HandlesAllInput = false; - screen->BlocksWorld = false; - screen->HidesHUD = false; - screen->RenderHUDOver = false; - screen->OnResize = NULL; - screen->OnContextLost = NULL; + screen->HandlesAllInput = false; + screen->BlocksWorld = false; + screen->HidesHUD = false; + screen->RenderHUDOver = false; + screen->OnResize = NULL; + screen->OnContextLost = NULL; screen->OnContextRecreated = NULL; } diff --git a/src/Client/Hotkeys.c b/src/Client/Hotkeys.c index 09564dd3b..5d1b9079d 100644 --- a/src/Client/Hotkeys.c +++ b/src/Client/Hotkeys.c @@ -24,6 +24,41 @@ UInt8 Hotkeys_LWJGL[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +void Hotkeys_QuickSort(Int32 left, Int32 right) { + HotkeyData* keys = HotkeysList; HotkeyData key; + + while (left < right) { + Int32 i = left, j = right; + UInt8 pivot = keys[(i + j) / 2].Flags; + + /* partition the list */ + while (i <= j) { + while (pivot > keys[i].Flags) i++; + while (pivot < keys[j].Flags) j--; + QuickSort_Swap_Maybe(); + } + /* recurse into the smaller subset */ + QuickSort_Recurse(Hotkeys_QuickSort) + } +} + +void Hotkeys_AddNewHotkey(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more) { + HotkeyData hKey; + hKey.BaseKey = baseKey; + hKey.Flags = flags; + hKey.TextIndex = HotkeysText.Count; + hKey.StaysOpen = more; + + if (HotkeysText.Count == HOTKEYS_MAX_COUNT) { + ErrorHandler_Fail("Cannot define more than 256 hotkeys"); + } + + HotkeysList[HotkeysText.Count] = hKey; + StringsBuffer_Add(&HotkeysText, text); + /* sort so that hotkeys with largest modifiers are first */ + Hotkeys_QuickSort(0, HotkeysText.Count - 1); +} + void Hotkeys_Add(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more) { UInt32 i; for (i = 0; i < HotkeysText.Count; i++) { @@ -53,41 +88,6 @@ bool Hotkeys_Remove(Key baseKey, UInt8 flags) { return false; } -void Hotkeys_AddNewHotkey(Key baseKey, UInt8 flags, STRING_PURE String* text, bool more) { - HotkeyData hKey; - hKey.BaseKey = baseKey; - hKey.Flags = flags; - hKey.TextIndex = HotkeysText.Count; - hKey.StaysOpen = more; - - if (HotkeysText.Count == HOTKEYS_MAX_COUNT) { - ErrorHandler_Fail("Cannot define more than 256 hotkeys"); - } - - HotkeysList[HotkeysText.Count] = hKey; - StringsBuffer_Add(&HotkeysText, text); - /* sort so that hotkeys with largest modifiers are first */ - Hotkeys_QuickSort(0, HotkeysText.Count - 1); -} - -void Hotkeys_QuickSort(Int32 left, Int32 right) { - HotkeyData* keys = HotkeysList; HotkeyData key; - - while (left < right) { - Int32 i = left, j = right; - UInt8 pivot = keys[(i + j) / 2].Flags; - - /* partition the list */ - while (i <= j) { - while (pivot > keys[i].Flags) i++; - while (pivot < keys[j].Flags) j--; - QuickSort_Swap_Maybe(); - } - /* recurse into the smaller subset */ - QuickSort_Recurse(Hotkeys_QuickSort) - } -} - bool Hotkeys_IsHotkey(Key key, STRING_TRANSIENT String* text, bool* moreInput) { UInt8 flags = 0; if (Key_IsControlPressed()) flags |= 1; diff --git a/src/Client/Hotkeys.h b/src/Client/Hotkeys.h index 5519bf27c..31de583d1 100644 --- a/src/Client/Hotkeys.h +++ b/src/Client/Hotkeys.h @@ -3,6 +3,10 @@ #include "Typedefs.h" #include "Input.h" #include "String.h" +/* Maintains list of hotkeys defined by the client and SetTextHotkey packets. + Copyright 2017 ClassicalSharp | Licensed under BSD-3 +*/ + extern UInt8 Hotkeys_LWJGL[256]; typedef struct HotkeyData_ { diff --git a/src/Client/Input.c b/src/Client/Input.c index cb0be1b69..7f2cb98f2 100644 --- a/src/Client/Input.c +++ b/src/Client/Input.c @@ -154,7 +154,7 @@ void KeyBind_Save(void) { for (i = 0; i < KeyBind_Count; i++) { KeyBind_MakeName(name); String value = String_FromReadonly(Key_Names[i]); - Options_Set(name.buffer, value); + Options_Set(name.buffer, &value); } } diff --git a/src/Client/ModelCache.c b/src/Client/ModelCache.c index d53404529..f3146fa8d 100644 --- a/src/Client/ModelCache.c +++ b/src/Client/ModelCache.c @@ -23,7 +23,7 @@ IModel* ModelCache_Get(STRING_PURE String* name) { Int32 i; for (i = 0; i < ModelCache_modelCount; i++) { CachedModel* m = &ModelCache_Models[i]; - if (!String_Equals(&m->Name, name)) continue; + if (!String_CaselessEquals(&m->Name, name)) continue; if (!m->Instance->initalised) { m->Instance->CreateParts(); @@ -38,7 +38,7 @@ Int32 ModelCache_GetTextureIndex(STRING_PURE String* texName) { Int32 i; for (i = 0; i < ModelCache_texCount; i++) { CachedTexture* tex = &ModelCache_Textures[i]; - if (String_Equals(&tex->Name, texName)) return 1; + if (String_CaselessEquals(&tex->Name, texName)) return 1; } return -1; } diff --git a/src/Client/Screens.c b/src/Client/Screens.c index 6ba2daae3..ab2c826cf 100644 --- a/src/Client/Screens.c +++ b/src/Client/Screens.c @@ -3,6 +3,8 @@ #include "Game.h" #include "Event.h" #include "GraphicsCommon.h" +#include "Platform.h" +#include "Inventory.h" void Screen_FreeWidgets(Widget** widgets, UInt32 widgetsCount) { if (widgets == NULL) return; @@ -96,5 +98,151 @@ void ClickableScreen_Create(ClickableScreen* screen) { screen->OnWidgetSelected = ClickableScreen_DefaultWidgetSelected; } -Screen AA; -extern Screen* InventoryScreen_Unsafe_RawPointer = &AA; +typedef struct InventoryScreen_ { + Screen Base; + FontDesc Font; + TableWidget Table; + bool ReleasedInv; +} InventoryScreen; +InventoryScreen InventoryScreen_Instance; + +void InventoryScreen_OnBlockChanged(void) { + TableWidget_OnInventoryChanged(&InventoryScreen_Instance.Table); +} + +void InventoryScreen_ContextLost(void) { + GuiElement* elem = &InventoryScreen_Instance.Table.Base.Base; + elem->Free(elem); +} + +void InventoryScreen_ContextRecreated(void) { + GuiElement* elem = &InventoryScreen_Instance.Table.Base.Base; + elem->Recreate(elem); +} + +void InventoryScreen_Init(GuiElement* elem) { + InventoryScreen* screen = (InventoryScreen*)elem; + screen->Font.Size = 16; + Platform_MakeFont(&screen->Font, &Game_FontName); + elem = &screen->Table.Base.Base; + TableWidget_Create(&screen->Table); + screen->Table.Font = screen->Font; + screen->Table.ElementsPerRow = Game_PureClassic ? 9 : 10; + elem->Init(&elem); + + Key_KeyRepeat = true; + Event_RegisterVoid(&BlockEvents_PermissionsChanged, InventoryScreen_OnBlockChanged); + Event_RegisterVoid(&BlockEvents_BlockDefChanged, InventoryScreen_OnBlockChanged); + Event_RegisterVoid(&GfxEvents_ContextLost, InventoryScreen_ContextLost); + Event_RegisterVoid(&GfxEvents_ContextRecreated, InventoryScreen_ContextRecreated); +} + +void InventoryScreen_Render(GuiElement* elem, Real64 delta) { + InventoryScreen* screen = (InventoryScreen*)elem; + elem = &screen->Table.Base.Base; + elem->Render(elem, delta); +} + +void InventoryScreen_OnResize(Screen* elem) { + InventoryScreen* screen = (InventoryScreen*)elem; + Widget* widget = &screen->Table.Base; + widget->Reposition(widget); +} + +void InventoryScreen_Free(GuiElement* elem) { + InventoryScreen* screen = (InventoryScreen*)elem; + Platform_FreeFont(&screen->Font); + elem = &screen->Table.Base.Base; + elem->Free(&elem); + + Key_KeyRepeat = false; + Event_UnregisterVoid(&BlockEvents_PermissionsChanged, InventoryScreen_OnBlockChanged); + Event_UnregisterVoid(&BlockEvents_BlockDefChanged, InventoryScreen_OnBlockChanged); + Event_UnregisterVoid(&GfxEvents_ContextLost, InventoryScreen_ContextLost); + Event_UnregisterVoid(&GfxEvents_ContextRecreated, InventoryScreen_ContextRecreated); +} + +bool InventoryScreen_HandlesKeyDown(GuiElement* elem, Key key) { + InventoryScreen* screen = (InventoryScreen*)elem; + TableWidget* table = &screen->Table; + GuiElement* elem = &screen->Table.Base.Base; + if (key == KeyBind_Get(KeyBind_PauseOrExit)) { + gGui_SetNewScreen(NULL); + } else if (key == KeyBind_Get(KeyBind_Inventory) && screen->ReleasedInv) { + Gui_SetNewScreen(NULL); + } else if (key == Key_Enter && table->SelectedIndex != -1) { + Inventory_SetSelectedBlock(table->Elements[table->SelectedIndex]); + Gui_SetNewScreen(NULL); + } else if (elem->HandlesKeyDown(elem, key)) { + } else { + game.Gui.hudScreen.hotbar.HandlesKeyDown(key); + } + return true; +} + +bool InventoryScreen_HandlesKeyUp(GuiElement* elem, Key key) { + InventoryScreen* screen = (InventoryScreen*)elem; + if (key == KeyBind_Get(KeyBind_Inventory)) { + screen->ReleasedInv = true; return true; + } + return game.Gui.hudScreen.hotbar.HandlesKeyUp(key); +} + +bool InventoryScreen_HandlesMouseDown(GuiElement* elem, Int32 x, Int32 y, MouseButton btn) { + InventoryScreen* screen = (InventoryScreen*)elem; + TableWidget* table = &screen->Table; + GuiElement* elem = &screen->Table.Base.Base; + if (table->Scroll.DraggingMouse || game.Gui.hudScreen.hotbar.HandlesMouseDown(x, y, btn)) + return true; + + bool handled = elem->HandlesMouseDown(elem, x, y, btn); + if ((!handled || table->PendingClose) && btn == MouseButton_Left) { + bool hotbar = Key_IsControlPressed(); + if (!hotbar) Gui_SetNewScreen(NULL); + } + return true; +} + +bool InventoryScreen_HandlesMouseUp(GuiElement* elem, Int32 x, Int32 y, MouseButton btn) { + InventoryScreen* screen = (InventoryScreen*)elem; + GuiElement* elem = &screen->Table.Base.Base; + return elem->HandlesMouseUp(elem, x, y, btn); +} + +bool InventoryScreen_HandlesMouseMove(GuiElement* elem, Int32 x, Int32 y) { + InventoryScreen* screen = (InventoryScreen*)elem; + GuiElement* elem = &screen->Table.Base.Base; + return elem->HandlesMouseMove(elem, x, y); +} + +bool InventoryScreen_HandlesMouseScroll(GuiElement* elem, Real32 delta) { + InventoryScreen* screen = (InventoryScreen*)elem; + GuiElement* elem = &screen->Table.Base.Base; + + bool hotbar = Key_IsAltPressed() || Key_IsControlPressed() || Key_IsShiftPressed(); + if (hotbar) return false; + return elem->HandlesMouseScroll(elem, delta); +} + +Screen* InventoryScreen_GetInstance(void) { + InventoryScreen* screen = &InventoryScreen_Instance; + Platform_MemSet(&screen, 0, sizeof(InventoryScreen)); + Screen_Reset(&screen->Base); + + screen->Base.Base.HandlesKeyDown = InventoryScreen_HandlesKeyDown; + screen->Base.Base.HandlesKeyUp = InventoryScreen_HandlesKeyUp; + screen->Base.Base.HandlesMouseDown = InventoryScreen_HandlesMouseDown; + screen->Base.Base.HandlesMouseUp = InventoryScreen_HandlesMouseUp; + screen->Base.Base.HandlesMouseMove = InventoryScreen_HandlesMouseMove; + screen->Base.Base.HandlesMouseScroll = InventoryScreen_HandlesMouseScroll; + + screen->Base.OnContextLost = InventoryScreen_ContextLost; + screen->Base.OnContextRecreated = InventoryScreen_ContextRecreated; + screen->Base.OnResize = InventoryScreen_OnResize; + screen->Base.Base.Init = InventoryScreen_Init; + screen->Base.Base.Render = InventoryScreen_Render; + screen->Base.Base.Free = InventoryScreen_Free; + + return &screen->Base; +} +extern Screen* InventoryScreen_Unsafe_RawPointer = &InventoryScreen_Instance.Base; diff --git a/src/Client/String.c b/src/Client/String.c index 12c6a8ddb..ff932744d 100644 --- a/src/Client/String.c +++ b/src/Client/String.c @@ -3,6 +3,12 @@ #include "ErrorHandler.h" #include "Platform.h" +bool Char_IsUpper(UInt8 c) { return c >= 'A' && c <= 'Z'; } +UInt8 Char_ToLower(UInt8 c) { + if (!Char_IsUpper(c)) return c; + return (UInt8)(c + ' '); +} + String String_Init(STRING_REF UInt8* buffer, UInt16 length, UInt16 capacity) { String str; str.buffer = buffer; @@ -81,8 +87,8 @@ bool String_CaselessEquals(STRING_PURE String* a, STRING_PURE String* b) { Int32 i; for (i = 0; i < a->length; i++) { - UInt8 aCur = Char_ToLower(a->buffer[i]); - UInt8 bCur = Char_ToLower(b->buffer[i]); + UInt8 aCur = a->buffer[i]; if (aCur >= 'A' && aCur <= 'Z') { aCur += ' '; } + UInt8 bCur = b->buffer[i]; if (bCur >= 'A' && bCur <= 'Z') { bCur += ' '; } if (aCur != bCur) return false; } return true; @@ -131,9 +137,7 @@ bool String_AppendInt32(STRING_TRANSIENT String* str, Int32 num) { bool String_AppendPaddedInt32(STRING_TRANSIENT String* str, Int32 num, Int32 minDigits) { UInt8 numBuffer[STRING_INT32CHARS]; Int32 i; - for (i = 0; i < minDigits; i++) { - numBuffer[i] = '0'; - } + for (i = 0; i < minDigits; i++) { numBuffer[i] = '0'; } Int32 numLen = String_MakeInt32(num, numBuffer); if (numLen < minDigits) numLen = minDigits; diff --git a/src/Client/String.h b/src/Client/String.h index c1d6e0747..4aa6fd5f7 100644 --- a/src/Client/String.h +++ b/src/Client/String.h @@ -19,6 +19,9 @@ Thus it is **NOT SAFE** to allocate a string on the stack. */ #define STRING_REF +bool Char_IsUpper(UInt8 c); +UInt8 Char_ToLower(UInt8 c); + typedef struct String_ { UInt8* buffer; /* Pointer to raw characters. Size is capacity + 1, as buffer is null terminated. */ UInt16 length; /* Number of characters used. */