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. */