diff --git a/CMakeLists.txt b/CMakeLists.txt index adf9380..d50a446 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -93,7 +93,7 @@ add_executable( src/packages/game/util/IZ_midi.h src/packages/net/core/IZ_websocket.h src/packages/net/core/IZ_websocket.c - src/packages/net/IZ_net_client.c src/packages/net/IZ_net_client.h src/packages/game/IZ_app_net.c src/packages/game/IZ_app_net.h src/packages/game/IZ_app_video.c src/packages/game/IZ_app_video.h src/packages/game/IZ_subsystem.h src/packages/game/IZ_app_input.c src/packages/game/IZ_app_input.h src/packages/game/IZ_app_config.c src/packages/game/IZ_app_config.h src/packages/game/data/IZ_asset.c src/packages/game/data/IZ_asset.h) + src/packages/net/IZ_net_client.c src/packages/net/IZ_net_client.h src/packages/game/IZ_app_net.c src/packages/game/IZ_app_net.h src/packages/game/IZ_app_video.c src/packages/game/IZ_app_video.h src/packages/game/IZ_subsystem.h src/packages/game/IZ_app_input.c src/packages/game/IZ_app_input.h src/packages/game/IZ_app_config.c src/packages/game/IZ_app_config.h src/packages/game/asset/IZ_asset.c src/packages/game/asset/IZ_asset.h) target_link_libraries( game diff --git a/docs/weapons.md b/docs/weapons.md index c6f4205..f054041 100644 --- a/docs/weapons.md +++ b/docs/weapons.md @@ -5,7 +5,7 @@ | Combat knife | Combat knife | Guerrilla | Switzerland | - | | - | - | - | - | - | - | - | | Oriental sword | Katana | Goemon | Japan | - | | - | - | - | - | - | - | - | | Pistol | Beretta 92FS (M9) | Servant | Italy | 9x19mm Parabellum | 15 | 16 | - | 381 | 217 | 38 | 137 | Can be dual-wielded | -| Pistol | Magnum Research Desert Eagle MK XIX | Hitman | United States | .50 Action Express | 7 | 8 | - | 470 | 273.1 | - | - | Uses 20-round extended magazine (from normal 15 rounds) | +| Pistol | Magnum Research Desert Eagle MK XIX | Hitman | United States | .50 Action Express | 7 | 8 | - | 470 | 273.1 | - | - | Uses 20-round extended magazine (from normal 12 rounds) | | Pistol | H&K USP Elite .45 | Ordinator | Germany | .45 ACP | 20 | 10 | - | 350 | 239 | 29 | 151 | - | | Sub-machine gun | H&K MP5A5 | Operator | West Germany | 9x19mm Parabellum | 30 | 10 | 800 | 400 | 680 (stock extended), 504.22 (stock collapsed) | 50 | 260 | - | | Sub-machine gun | H&K MP5KA1 | Tactician | West Germany | 9x19mm Parabellum | 30 | 10 | 900 | 375 | 325 | - | - | - | diff --git a/src/packages/game/IZ_app.c b/src/packages/game/IZ_app.c index 64e3aef..2128403 100644 --- a/src/packages/game/IZ_app.c +++ b/src/packages/game/IZ_app.c @@ -144,7 +144,7 @@ IZ_AppResult IZ_AppRun(struct IZ_App* app, u8 argc, const char* argv[]) { app->ticks = SDL_GetTicks64(); // TODO do audio processing - // TODO do networking + // TODO do inbound networking if (IZ_AppHandleInputEvents(app)) { break; diff --git a/src/packages/game/IZ_app.h b/src/packages/game/IZ_app.h index 49ee258..0500dc9 100644 --- a/src/packages/game/IZ_app.h +++ b/src/packages/game/IZ_app.h @@ -3,7 +3,7 @@ #include #include -#include "data/IZ_asset.h" +#include "asset/IZ_asset.h" #include "memory/IZ_pool.h" #include "IZ_app_config.h" #include "IZ_app_input.h" diff --git a/src/packages/game/data/IZ_asset.c b/src/packages/game/asset/IZ_asset.c similarity index 100% rename from src/packages/game/data/IZ_asset.c rename to src/packages/game/asset/IZ_asset.c diff --git a/src/packages/game/data/IZ_asset.h b/src/packages/game/asset/IZ_asset.h similarity index 100% rename from src/packages/game/data/IZ_asset.h rename to src/packages/game/asset/IZ_asset.h diff --git a/src/packages/game/data/IZ_list.c b/src/packages/game/data/IZ_list.c index 14645b3..e22247a 100644 --- a/src/packages/game/data/IZ_list.c +++ b/src/packages/game/data/IZ_list.c @@ -1,81 +1,119 @@ #include "IZ_list.h" -bool IZ_ListFindFilterAlwaysTrue(IZ_ListNode* _node, u64 _index) { +bool IZ_ListFindFilterAlwaysTrue(IZ_ListNode** _node, u64 _index, IZ_List* _list) { return true; } +/** + * Initializes a list. + * @param list - The list to initialize. + */ void IZ_ListInitialize(IZ_List* list) { list->root = NULL; list->length = 0; + list->iterator = NULL; } +/** + * Performs cleanup on a list. + * @param list - The list to clean up. + */ void IZ_ListTeardown(IZ_List* list) { while (list->root) { - _IZ_ListDeleteFirstNode(list, IZ_ListFindFilterAlwaysTrue); + IZ_ListDeleteFirstNode(list, IZ_ListFindFilterAlwaysTrue); } + list->iterator = NULL; + list->length = 0; } -IZ_ListNode* IZ_ListAppendNode(IZ_List* list, void* node_value) { +/** + * Appends a node to the end of the list. + * @param list - The list to append to. + * @return Pointer to the newly created node. + */ +IZ_ListNode** IZ_ListAppendNode(IZ_List* list, void* node_value) { IZ_ListNode* new_node = SDL_malloc(sizeof(IZ_ListNode)); new_node->value = node_value; + new_node->next = NULL; + list->length += 1; + if (!(list->root)) { list->root = new_node; - } else { - IZ_ListNode *last_node = list->root; - while (last_node->next) { - last_node = last_node->next; - } - last_node->next = new_node; + return &list->root; } - new_node->next = NULL; - list->length += 1; - return new_node; + + IZ_ListNode *last_node = list->root; + while (last_node->next) { + last_node = last_node->next; + } + + last_node->next = new_node; + return &last_node->next; } -void _IZ_ListDeleteFirstNode(IZ_List* list, IZ_ListFindFilter filter) { +/** + * Deletes the first node in the list that matches the filter. + * @param list - The list to delete from. + * @param filter - The filter to use to find the node to delete. + */ +void IZ_ListDeleteFirstNode(IZ_List* list, IZ_ListFindPredicate filter) { if (!(list && list->root)) { + // should we raise warnings here? return; } - IZ_ListNode* iterator = list->root; + list->iterator = &list->root; IZ_ListNode* previous_node = NULL; u64 index = 0; do { - if (!filter(iterator, index)) { - previous_node = iterator; - iterator = iterator->next; + if (!filter(list->iterator, index, list)) { + previous_node = *list->iterator; + list->iterator = &((*list->iterator)->next); index += 1; + // we haven't found the node we're looking for, go to the next one continue; } if (previous_node) { - previous_node->next = iterator->next; + // this is not the first node in the list + previous_node->next = (*list->iterator)->next; } else { - list->root = iterator->next; + // this is the first node, set it as new root + list->root = (*list->iterator)->next; + // if there is only one item in the list, root, gets set to NULL } - SDL_free(iterator); - iterator = NULL; - list->length -= 1; + SDL_free(*list->iterator); + list->iterator = NULL; + if (list->length > 0) { + // avoid underflow + list->length -= 1; + } return; - } while (iterator); + } while (*list->iterator); } -IZ_ListNode* _IZ_ListFindFirstNode(IZ_List* list, IZ_ListFindFilter filter) { +/** + * Finds the first node in the list that matches the filter. + * @param list - The list to search. + * @param filter - The filter to use to find the node. + * @return Pointer to the node that matches the filter. + */ +IZ_ListNode** IZ_ListFindFirstNode(IZ_List* list, IZ_ListFindPredicate filter) { if (!(list && list->root)) { return NULL; } - IZ_ListNode* iterator = list->root; + list->iterator = &list->root; u64 index = 0; do { - if (!filter(iterator, index)) { - iterator = iterator->next; + if (!filter(list->iterator, index, list)) { + list->iterator = &((*list->iterator)->next); index += 1; continue; } - return iterator; - } while (iterator); + return list->iterator; + } while (*list->iterator); return NULL; } diff --git a/src/packages/game/data/IZ_list.h b/src/packages/game/data/IZ_list.h index 7b44b0d..8bdf714 100644 --- a/src/packages/game/data/IZ_list.h +++ b/src/packages/game/data/IZ_list.h @@ -4,32 +4,65 @@ #include "../../common/IZ_common.h" #include "SDL_stdinc.h" +/** + * A node in a linked list. + */ typedef struct IZ_ListNode { + /** + * The value of the node. + */ void* value; + /** + * The next node in the list. + */ struct IZ_ListNode* next; } IZ_ListNode; +/** + * A singly-linked list. + */ typedef struct { + /** + * The first node in the list. + */ IZ_ListNode* root; + /** + * The number of nodes in the list. + */ u64 length; + /** + * The iterator for traversing the list. + */ + IZ_ListNode** iterator; } IZ_List; -typedef bool IZ_ListFindFilter(IZ_ListNode*, u64); +typedef bool IZ_ListFindPredicate(IZ_ListNode**, u64, IZ_List*); +/** + * Initializes a list. + */ void IZ_ListInitialize(IZ_List*); +/** + * Performs cleanup on a list. + */ void IZ_ListTeardown(IZ_List*); -IZ_ListNode* IZ_ListAppendNode(IZ_List*, void*); +/** + * Appends a node to the end of the list. + * @return Pointer to the newly created node. + */ +IZ_ListNode** IZ_ListAppendNode(IZ_List*, void*); -#define IZ_ListFilterFunctionArgs(X) static X = NULL; +/** + * Deletes the first node in the list that matches the filter. + */ +void IZ_ListDeleteFirstNode(IZ_List*, IZ_ListFindPredicate); -void _IZ_ListDeleteFirstNode(IZ_List*, IZ_ListFindFilter); - -#define IZ_ListDeleteFirstNode(X, Y) X = Y; _IZ_ListDeleteFirstNode - -IZ_ListNode* _IZ_ListFindFirstNode(IZ_List*, IZ_ListFindFilter); - -#define IZ_ListFindFirstNode(X, Y) X = Y; _IZ_ListFindFirstNode +/** + * Finds the first node in the list that matches the filter. + * @return Pointer to the node that matches the filter. + */ +IZ_ListNode** IZ_ListFindFirstNode(IZ_List*, IZ_ListFindPredicate); #endif diff --git a/src/packages/game/data/README.md b/src/packages/game/data/README.md new file mode 100644 index 0000000..9dd7ac9 --- /dev/null +++ b/src/packages/game/data/README.md @@ -0,0 +1,57 @@ +# `data` + +Fundamental functions for various data structures used in the project. + +## `list` + +A singly-linked list is used on certain parts of the game, such as the memory pool's entries of currently allocated game +objects. + +Here is how to properly use a list: + +```c +#include +#include "IZ_list.h" + +// find predicates +bool FindNodeWithValueOne(IZ_ListNode**, unsigned long long, IZ_List*); + +bool FindNodeWithValueTwo(IZ_ListNode**, unsigned long long, IZ_List*); + +int main() { + IZ_List list; + + // important to initialize lists first, else there may be garbage data in the list members. + IZ_ListInitialize(&list); + + // lists should accept any type of value (void*), so the implementor is free to use whatever type they want + int node1_value = 1; + IZ_ListAppendNode(&list, &node1_value); + + int node2_value = 2; + IZ_ListAppendNode(&list, &node2_value); + + // pass predicate functions for finding nodes + ListNode* find_node; + find_node = IZ_ListFindFirstNode(&list, &FindNodeWithValueTwo); + if (find_node != NULL) { + printf("Found node with value 2!\n"); + } + + // deletions are done only on one node at a time + IZ_ListDeleteFirstNode(&list, &FindNodeWithValueOne); + + // teardown takes care of de-allocating nodes and making sure data cannot be accessed sensibly anymore. + IZ_ListTeardown(&list); + + return 0; +} + +bool FindNodeWithValueOne(IZ_ListNode** node, unsigned long long index, IZ_List* list) { + return (*node)->value == 1; +} + +bool FindNodeWithValueTwo(IZ_ListNode** node, unsigned long long index, IZ_List* list) { + return (*node)->value == 2; +} +``` diff --git a/src/packages/game/data/data.test.c b/src/packages/game/data/data.test.c index 32cba78..b774a75 100644 --- a/src/packages/game/data/data.test.c +++ b/src/packages/game/data/data.test.c @@ -3,22 +3,27 @@ #include "../../../__mocks__/SDL_stdinc.mock.h" #include "IZ_list.h" -IZ_ListFilterFunctionArgs(IZ_ListNode* __current_item_NodeExists) bool NodeExists(IZ_ListNode* node, u64 _index) { - return *((u64*) node->value) == 42069; +bool NodeExists(IZ_ListNode** node, u64 _index, IZ_List* list) { + return *((u64*) (*node)->value) == 42069; } -IZ_ListFilterFunctionArgs(IZ_ListNode* __current_item_NodeExists2) bool NodeExists2(IZ_ListNode* node, u64 _index) { - return *((u64*) node->value) == 69420; +bool NodeExists2(IZ_ListNode** node, u64 _index, IZ_List* list) { + return *((u64*) (*node)->value) == 69420; } -IZ_ListFilterFunctionArgs(IZ_ListNode* __current_item_NodeDoesNotExist) bool NodeDoesNotExist(IZ_ListNode* node, u64 _index) { - return *((u64*) node->value) == 55555; +bool NodeDoesNotExist(IZ_ListNode** node, u64 _index, IZ_List* list) { + return *((u64*) (*node)->value) == 55555; } spec("data") { describe("list") { describe("Initialize") { static IZ_List list; + + after_each() { + IZ_ListTeardown(&list); + } + it("sets root to NULL") { IZ_ListInitialize(&list); @@ -78,6 +83,14 @@ spec("data") { mock_reset(SDL_malloc); } + after_each() { + IZ_ListTeardown(&list); + } + + after_each() { + IZ_ListTeardown(&list2); + } + it("appends new node to empty list and sets it as root") { static u64 value = 69420u; IZ_ListAppendNode(&list, &value); @@ -115,15 +128,19 @@ spec("data") { IZ_ListAppendNode(&list, &value2); } + after_each() { + IZ_ListTeardown(&list); + } + it("retrieves first node satisfying the filter condition") { - static IZ_ListNode* node; - node = _IZ_ListFindFirstNode(&list, NodeExists); - check(*((u64*) node->value) == 42069u, "Existing node not found."); + static IZ_ListNode** node; + node = IZ_ListFindFirstNode(&list, NodeExists); + check(*((u64*) (*node)->value) == 42069u, "Existing node not found."); } it("returns NULL when all nodes do not satisfy the filter condition") { - static IZ_ListNode* node; - node = _IZ_ListFindFirstNode(&list, NodeDoesNotExist); + static IZ_ListNode** node; + node = IZ_ListFindFirstNode(&list, NodeDoesNotExist); check(node == NULL, "Non-existing node found."); } } @@ -147,7 +164,7 @@ spec("data") { } it("removes first node satisfying the filter condition") { - _IZ_ListDeleteFirstNode(&list, NodeExists); + IZ_ListDeleteFirstNode(&list, NodeExists); check( mock_is_called(SDL_free), @@ -155,12 +172,12 @@ spec("data") { ); check( - _IZ_ListFindFirstNode(&list, NodeExists2), + IZ_ListFindFirstNode(&list, NodeExists2), "Node supposed to be present in list is absent." ); check( - !_IZ_ListFindFirstNode(&list, NodeExists), + !IZ_ListFindFirstNode(&list, NodeExists), "Deleted node still present in list." ); diff --git a/src/packages/game/memory/IZ_pool.c b/src/packages/game/memory/IZ_pool.c index 78f0b25..b842602 100644 --- a/src/packages/game/memory/IZ_pool.c +++ b/src/packages/game/memory/IZ_pool.c @@ -26,7 +26,7 @@ IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, IZ_PoolAllocationArgs args) { } void* pointer = &pool->memory[pool->next_address]; - IZ_ListNode* new_item = IZ_ListAppendNode(&pool->items, &(IZ_PoolItem) { + IZ_ListNode** new_item = IZ_ListAppendNode(&pool->items, &(IZ_PoolItem) { .pointer = pointer, .args = args, .pool = pool, @@ -34,15 +34,15 @@ IZ_PoolItem* IZ_PoolAllocate(IZ_Pool* pool, IZ_PoolAllocationArgs args) { pool->next_address = (pool->next_address + args.size) % POOL_MAX_SIZE; pool->allocated_memory += args.size; - return new_item->value; + return (*new_item)->value; } -IZ_ListFilterFunctionArgs(IZ_PoolItem* __current_item) bool IZ_PoolGetSameItem(IZ_ListNode* node, u64 _index) { - return node->value == __current_item; +bool IZ_PoolGetSameItem(IZ_ListNode** node, u64 _index, IZ_List* list) { + return (*node)->value == (*list->iterator)->value; } void IZ_PoolDeallocate(IZ_PoolItem* item) { - IZ_ListDeleteFirstNode(__current_item, item)(&item->pool->items, IZ_PoolGetSameItem); + IZ_ListDeleteFirstNode(&item->pool->items, IZ_PoolGetSameItem); } void IZ_PoolTeardown(IZ_Pool* pool) { diff --git a/src/packages/game/memory/IZ_pool.h b/src/packages/game/memory/IZ_pool.h index 7014bcc..7ffc06e 100644 --- a/src/packages/game/memory/IZ_pool.h +++ b/src/packages/game/memory/IZ_pool.h @@ -5,7 +5,7 @@ #include "../../common/IZ_common.h" #include "../data/IZ_list.h" -#define POOL_MAX_SIZE (1llu << 23) // 16MB +#define POOL_MAX_SIZE (1llu << 26) // 64MB struct IZ_Pool; @@ -24,7 +24,7 @@ typedef struct { typedef struct IZ_Pool { IZ_List items; u64 next_address; - u64 allocated_memory; + size_t allocated_memory; size_t max_size; void* memory; } IZ_Pool;