--- /dev/null
+*.o
+DragonblocksServer
+Dragonblocks
--- /dev/null
+COMMON = array.o binsearch.o linkedlist.o map.o
+SERVER = $(COMMON) server.o
+
+all: DragonblocksServer
+
+DragonblocksServer: $(SERVER)
+ gcc -o DragonblocksServer $(SERVER)
+
+%.o: %.c
+ gcc -c -o $@ -Wall -Wextra -Wpedantic $<
--- /dev/null
+#include <string.h>
+#include <stdlib.h>
+#include "array.h"
+
+static void array_realloc(Array *array)
+{
+ if (array->siz > array->cap) {
+ array->cap = array->siz + ARRAY_REALLOC_EXTRA;
+ array->ptr = realloc(array->ptr, array->cap * sizeof(void *));
+ }
+}
+
+static void array_alloc(Array *array, size_t siz)
+{
+ array->siz += siz;
+ array_realloc(array);
+}
+
+void array_insert(Array *array, void *elem, size_t idx)
+{
+ size_t oldsiz = array->siz;
+ array_alloc(array, 1);
+
+ void **iptr = array->ptr + idx;
+ memmove(iptr + 1, iptr, oldsiz - idx);
+ *iptr = elem;
+}
+
+void array_append(Array *array, void *elem)
+{
+ size_t oldsiz = array->siz;
+ array_alloc(array, 1);
+
+ array->ptr[oldsiz] = elem;
+}
+
+Array array_create()
+{
+ return (Array) {0, 0, NULL};
+}
--- /dev/null
+#ifndef _ARRAY_H_
+#define _ARRAY_H_
+
+#define ARRAY_REALLOC_EXTRA 25
+
+#include <stddef.h>
+
+typedef struct
+{
+ size_t siz, cap;
+ void **ptr;
+} Array;
+
+void array_insert(Array *array, void *elem, size_t idx);
+void array_append(Array *array, void *elem);
+Array array_create();
+
+#endif
--- /dev/null
+#include "binsearch.h"
+
+BinsearchResult binsearch(void *search, void **array, size_t size, BinsearchComparator cmp)
+{
+ size_t min, max, index;
+
+ min = index = 0;
+ max = size;
+
+ while (min < max) {
+ index = min;
+
+ size_t mid = (max + min) / 2;
+ s8 state = cmp(search, array[mid]);
+
+ if (state == 0)
+ return (BinsearchResult) {true, mid};
+ else if (state < 0)
+ max = mid;
+ else
+ min = mid;
+ }
+
+ return (BinsearchResult) {false, index};
+}
--- /dev/null
+#ifndef _BINSEARCH_H_
+#define _BINSEARCH_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include "types.h"
+
+typedef s8 (*BinsearchComparator)(void *search, void *element);
+
+typedef struct {
+ bool success;
+ size_t index;
+} BinsearchResult;
+
+BinsearchResult binsearch(void *search, void **array, size_t size, BinsearchComparator cmp);
+
+#endif
--- /dev/null
+#include <stdlib.h>
+#include "linkedlist.h"
+
+LinkedList linked_list_create()
+{
+ return (LinkedList) {NULL};
+}
+
+void linked_list_clear(LinkedList *list)
+{
+ for (LinkedListPair *pair = list->first; pair != NULL;) {
+ LinkedListPair *next = pair->next;
+ free(pair);
+ pair = next;
+ }
+ list->first = NULL;
+}
--- /dev/null
+#ifndef _LINKEDLIST_H_
+#define _LINKEDLIST_H_
+
+#define ITERATE_LINKEDLIST(list, pair) for (LinkedListPair *pair = list->first; pair != NULL; pair = pair->next)
+
+typedef struct LinkedListPair
+{
+ struct LinkedListPair *next;
+ const char *key;
+ const char *value;
+} LinkedListPair;
+
+typedef struct
+{
+ LinkedListPair *first;
+} LinkedList;
+
+LinkedList linked_list_create();
+void linked_list_clear(LinkedList *list);
+
+void linked_list_put(LinkedList *list, const char *key, const char *value); // ToDo
+void linked_list_get(LinkedList *list, const char *key); // ToDo
+void linked_list_delete(LinkedList *list, const char *key); // ToDo
+
+void linked_list_serialize(int fd); // ToDo
+void linked_list_deserialize(int fd, LinkedList *); // ToDo
+
+#endif
--- /dev/null
+#include <stdlib.h>
+#include <stdbool.h>
+#include "map.h"
+#include "binsearch.h"
+
+#define CMPBOUNDS(x) x == 0 ? 0 : x > 0 ? 1 : -1
+
+static void map_raw_delete_block(MapBlock *block)
+{
+ ITERATE_MAPBLOCK map_node_clear(&block->data[x][y][z]);
+ free(block);
+}
+
+static s8 sector_compare(void *hash, void *sector)
+{
+ s64 d = *((u64 *) hash) - ((MapSector *) sector)->hash;
+ return CMPBOUNDS(d);
+}
+
+MapSector *map_get_sector(Map *map, v2s32 pos, bool create)
+{
+ u64 hash = ((u64) pos.x << 32) + (u64) pos.y;
+ BinsearchResult res = binsearch(&hash, map->sectors.ptr, map->sectors.siz, §or_compare);
+
+ if (res.success)
+ return map->sectors.ptr[res.index];
+ if (! create)
+ return NULL;
+
+ MapSector *sector = malloc(sizeof(MapSector));
+ sector->pos = pos;
+ sector->hash = hash;
+ sector->blocks = array_create();
+
+ array_insert(&map->sectors, sector, res.index);
+
+ return sector;
+}
+
+static s8 block_compare(void *level, void *block)
+{
+ s32 d = *((s32 *) level) - ((MapSector *) block)->pos.y;
+ return CMPBOUNDS(d);
+}
+
+MapBlock *map_get_block(Map *map, v3s32 pos, bool create)
+{
+ MapSector *sector = map_get_sector(map, (v2s32) {pos.x, pos.z}, create);
+ if (! sector)
+ return NULL;
+
+ BinsearchResult res = binsearch(&pos.y, sector->blocks.ptr, sector->blocks.siz, &block_compare);
+
+ if (res.success)
+ return sector->blocks.ptr[res.index];
+ if (! create)
+ return NULL;
+
+ MapBlock *block = malloc(sizeof(MapBlock));
+ block->pos = pos;
+
+ MapNode air = map_node_create(NODE_AIR);
+ ITERATE_MAPBLOCK block->data[x][y][z] = air;
+
+ array_insert(§or->blocks, block, res.index);
+
+ return block;
+}
+
+MapNode map_get_node(Map *map, v3s32 pos)
+{
+ MapBlock *block = map_get_block(map, (v3s32) {pos.x / 16, pos.y / 16, pos.z / 16}, false);
+ if (! block)
+ return map_node_create(NODE_UNLOADED);
+ return block->data[pos.x % 16][pos.y % 16][pos.z % 16];
+}
+
+void map_set_node(Map *map, v3s32 pos, MapNode node)
+{
+ MapBlock *block = map_get_block(map, (v3s32) {pos.x / 16, pos.y / 16, pos.z / 16}, true);
+ MapNode *current_node = &block->data[pos.x % 16][pos.y % 16][pos.z % 16];
+ map_node_clear(current_node);
+ *current_node = node;
+}
+
+MapNode map_node_create(Node type)
+{
+ return (MapNode) {type, linked_list_create()};
+}
+
+void map_node_clear(MapNode *node)
+{
+ linked_list_clear(&node->meta);
+}
+
+Map *map_create(FILE *file)
+{
+ Map *map = malloc(sizeof(Map));
+ map->file = file;
+ map->sectors = array_create();
+
+ return map;
+}
+
+void map_delete(Map *map)
+{
+ for (size_t s = 0; s < map->sectors.siz; s++) {
+ MapSector *sector = map->sectors.ptr[s];
+ for (size_t b = 0; b < sector->blocks.siz; b++)
+ map_raw_delete_block(sector->blocks.ptr[b]);
+ if (sector->blocks.ptr)
+ free(sector->blocks.ptr);
+ free(sector);
+ }
+ if (map->sectors.ptr)
+ free(map->sectors.ptr);
+ free(map);
+}
--- /dev/null
+#ifndef _MAP_H_
+#define _MAP_H_
+
+#include <stdio.h>
+#include <stdbool.h>
+#include "array.h"
+#include "linkedlist.h"
+#include "node.h"
+#include "types.h"
+
+#define ITERATE_MAPBLOCK for (u8 x = 0; x < 16; x++) for (u8 y = 0; y < 16; y++) for (u8 z = 0; z < 16; z++)
+
+typedef struct
+{
+ Node type;
+ LinkedList meta;
+} MapNode;
+
+typedef struct
+{
+ MapNode data[16][16][16];
+ v3s32 pos;
+} MapBlock;
+
+typedef struct
+{
+ Array blocks;
+ v2s32 pos;
+ u64 hash;
+} MapSector;
+
+typedef struct
+{
+ Array sectors;
+ FILE *file;
+} Map;
+
+MapSector *map_get_sector(Map *map, v2s32 pos, bool create);
+MapBlock *map_get_block(Map *map, v3s32 pos, bool create);
+void map_create_block(Map *map, v3s32 pos, MapBlock *block);
+
+void map_serialize_block(int fd, MapBlock *); // ToDo
+MapBlock *map_deserialize_block(int fd); // ToDo
+
+void map_delete_block(MapBlock *); // ToDo
+void map_unload_block(MapBlock *); // ToDo
+
+MapNode map_get_node(Map *map, v3s32 pos);
+void map_set_node(Map *map, v3s32 pos, MapNode node);
+MapNode map_node_create(Node type);
+void map_node_clear(MapNode *node);
+
+Map *map_create(FILE *file);
+void map_delete(Map *map);
+
+#endif
--- /dev/null
+#ifndef _NODE_H_
+#define _NODE_H_
+
+typedef enum
+{
+ NODE_UNLOADED, // Used for nodes in unloaded blocks
+ NODE_AIR,
+ NODE_GRASS,
+ NODE_DIRT,
+ NODE_STONE,
+} Node;
+
+#endif
--- /dev/null
+#include "map.h"
+
+int main()
+{
+ Map *map = map_create(NULL);
+ map_set_node(map, (v3s32) {0, 0, 0}, map_node_create(NODE_STONE));
+ MapBlock *block = map_get_block(map, (v3s32) {0, 0, 0}, false);
+ if (! block) {
+ fprintf(stderr, "Map error\n");
+ return 1;
+ }
+ ITERATE_MAPBLOCK printf("%d", block->data[x][y][z].type);
+ map_delete(map);
+}
--- /dev/null
+#ifndef _TYPES_H_
+#define _TYPES_H_
+
+#include <stdint.h>
+
+#define DEFVEC(type) typedef struct {type x, y;} v2 ## type; typedef struct {type x, y, z;} v3 ## type;
+#define DEFTYP(from, to) typedef from to; DEFVEC(to)
+#define DEFTYPES(bytes) DEFTYP(int ## bytes ## _t, s ## bytes) DEFTYP(uint ## bytes ## _t, u ## bytes)
+
+DEFTYPES(8)
+DEFTYPES(16)
+DEFTYPES(32)
+DEFTYPES(64)
+
+typedef float f32;
+typedef double f64;
+
+DEFVEC(f32)
+DEFVEC(f64)
+
+typedef v2f32 v2f;
+typedef v3f32 v3f;
+
+#undef DEFVEC
+#undef DEFTYP
+#undef DEFTYPES
+
+#endif