Compare commits
3 Commits
a3f00a7b22
...
b119dbc129
Author | SHA1 | Date |
---|---|---|
Vftdan | b119dbc129 | |
Vftdan | 05ae5bb258 | |
Vftdan | 1120424949 |
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ all: server
|
|||
$(BUILD_DIR)/common/util/thread.o: $(BUILD_DIR)/common/util/thread.std.o
|
||||
cp $< $@
|
||||
|
||||
server: $(BUILD_DIR)/server/main.o $(BUILD_DIR)/common/util/hash_table.o $(BUILD_DIR)/common/util/byte_stream.o $(BUILD_DIR)/common/util/thread.o
|
||||
server: $(BUILD_DIR)/server/main.o $(BUILD_DIR)/server/world.o $(BUILD_DIR)/common/world.o $(BUILD_DIR)/common/util/hash_table.o $(BUILD_DIR)/common/util/byte_stream.o $(BUILD_DIR)/common/util/thread.o
|
||||
$(COMPILE_EXE)
|
||||
|
||||
run: server
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
// Assuming child type has a field for the base type
|
||||
// So for structs it is usually actual downcast, but for unions it is an upcast
|
||||
#define DOWNCAST(contype, basename, ptr) containerof(ptr, contype, as_##basename)
|
||||
// Expects ptr to be of type srctype* or void*, returns (dsttype*)ptr
|
||||
#define EXPECT_AND_CAST(dsttype, srctype, ptr) (((union { typeof(srctype) *src; typeof(dsttype) *dst; }){.src = (ptr)}).dst)
|
||||
#define T_ALLOC(count, T) ((T*)calloc((count), sizeof(T)))
|
||||
#define HEADER_FN __attribute__((unused)) inline static
|
||||
|
||||
|
|
|
@ -61,9 +61,9 @@ hash_table_delete_by_key_impl(HashTableDynamicData * dyndata, const HashTableKey
|
|||
return hash_table_delete_at_index_impl(dyndata, hash_table_find_impl(dyndata, key));
|
||||
}
|
||||
|
||||
#define hash_table_init(ht, value_deinit) hash_table_init_impl(&(ht)->as_HashTableDynamicData, sizeof(*(ht)->value_array), IMPLICIT_CAST(void(void*), void(typeof((ht)->value_array)), value_deinit))
|
||||
#define hash_table_init(ht, value_deinit) hash_table_init_impl(&(ht)->as_HashTableDynamicData, sizeof(*(ht)->value_array), EXPECT_AND_CAST(void(void*), void(typeof((ht)->value_array)), value_deinit))
|
||||
#define hash_table_deinit(ht) hash_table_deinit_impl(&(ht)->as_HashTableDynamicData)
|
||||
#define hash_table_insert(ht, key, value_ptr) hash_table_insert_impl(&(ht)->as_HashTableDynamicData, key, IMPLICIT_CAST(const void, const typeof(*(ht)->value_array), value_ptr))
|
||||
#define hash_table_insert(ht, key, value_ptr) hash_table_insert_impl(&(ht)->as_HashTableDynamicData, key, EXPECT_AND_CAST(const void, const typeof(*(ht)->value_array), value_ptr))
|
||||
#define hash_table_find(ht, key) hash_table_find_impl(&(ht)->as_HashTableDynamicData, key)
|
||||
#define hash_table_delete_at_index(ht, index) hash_table_delete_at_index_impl(&(ht)->as_HashTableDynamicData, index)
|
||||
#define hash_table_delete_by_key(ht, key) hash_table_delete_by_key_impl(&(ht)->as_HashTableDynamicData, key)
|
||||
|
|
|
@ -11,11 +11,19 @@ typedef union {
|
|||
|
||||
typedef union {
|
||||
uint32_t value;
|
||||
void *pointer; // Bits outside of .value may be reset
|
||||
void *_pointer; // Bits outside of .value may be reset
|
||||
} ThreadResult;
|
||||
|
||||
#define THREAD_NONE (Thread) { .handle = 0, }
|
||||
|
||||
HEADER_FN ThreadResult
|
||||
thread_wrap_result(uint32_t value)
|
||||
{
|
||||
ThreadResult res = { ._pointer = NULL };
|
||||
res.value = value;
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef CLOSURE_T(ThreadResult) ThreadEntry;
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,13 +53,13 @@ run_entry(void *arg)
|
|||
assert(arg != NULL);
|
||||
NativeEntryArg casted_arg = *(NativeEntryArg*) arg;
|
||||
ThreadEntry entry = casted_arg.entry;
|
||||
void *error_result = casted_arg.error_result.pointer;
|
||||
void *error_result = casted_arg.error_result._pointer;
|
||||
free(arg);
|
||||
if (!entry.callback) {
|
||||
return error_result;
|
||||
}
|
||||
ThreadResult result = entry.callback(entry.env);
|
||||
return result.pointer;
|
||||
return result._pointer;
|
||||
}
|
||||
|
||||
Thread
|
||||
|
@ -106,7 +106,7 @@ thread_join(Thread th, ThreadResult *result_ptr)
|
|||
pthread_t handle = get_handle(th);
|
||||
void **retval = NULL;
|
||||
if (result_ptr) {
|
||||
retval = &result_ptr->pointer;
|
||||
retval = &result_ptr->_pointer;
|
||||
}
|
||||
int error = pthread_join(handle, retval);
|
||||
if (error) {
|
||||
|
@ -119,7 +119,7 @@ thread_join(Thread th, ThreadResult *result_ptr)
|
|||
void
|
||||
thread_exit(ThreadResult result)
|
||||
{
|
||||
pthread_exit(result.pointer);
|
||||
pthread_exit(result._pointer);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -111,7 +111,7 @@ thread_join(Thread th, ThreadResult *result_ptr)
|
|||
thrd_t handle = get_handle(th);
|
||||
int32_t *retval = NULL;
|
||||
if (result_ptr) {
|
||||
result_ptr->pointer = NULL;
|
||||
*result_ptr = thread_wrap_result(0);
|
||||
retval = (int32_t*) &result_ptr->value;
|
||||
}
|
||||
int error = thrd_join(handle, retval);
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
#include "world.h"
|
||||
|
||||
void
|
||||
tile_type_forward_init_interned(TileTypeForwardInternation *reg)
|
||||
{
|
||||
if (!reg) {
|
||||
return;
|
||||
}
|
||||
hash_table_init(®->table, NULL);
|
||||
}
|
||||
|
||||
bool
|
||||
tile_type_forward_intern_as(TileTypeForwardInternation *reg, const char *name, TileTypeId id)
|
||||
{
|
||||
if (!reg) {
|
||||
return false;
|
||||
}
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
HashTableIndex idx = hash_table_insert(®->table, hash_table_key_from_cstr(name), &id);
|
||||
return idx >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
tile_type_forward_get_interned(TileTypeForwardInternation *reg, const char *name, TileTypeId *outptr)
|
||||
{
|
||||
if (!reg) {
|
||||
return false;
|
||||
}
|
||||
HashTableIndex idx = hash_table_find(®->table, hash_table_key_from_cstr(name));
|
||||
if (idx < 0) {
|
||||
return false;
|
||||
}
|
||||
if (outptr) {
|
||||
*outptr = reg->table.value_array[idx];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
tile_type_forward_delete_interned(TileTypeForwardInternation *reg, const char *name)
|
||||
{
|
||||
if (!reg) {
|
||||
return false;
|
||||
}
|
||||
return hash_table_delete_by_key(®->table, hash_table_key_from_cstr(name));
|
||||
}
|
||||
|
||||
void
|
||||
tile_type_forward_clear_interned(TileTypeForwardInternation *reg)
|
||||
{
|
||||
if (!reg) {
|
||||
return;
|
||||
}
|
||||
hash_table_deinit(®->table);
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef COMMON_WORLD_H_
|
||||
#define COMMON_WORLD_H_
|
||||
|
||||
#include "common/defs.h"
|
||||
#include "common/util/hash_table.h"
|
||||
|
||||
typedef uint16_t TileTypeId;
|
||||
typedef uint16_t TileVariant;
|
||||
|
||||
typedef struct {
|
||||
TYPED_HASH_TABLE(TileTypeId) table;
|
||||
} TileTypeForwardInternation;
|
||||
|
||||
void tile_type_forward_init_interned(TileTypeForwardInternation *reg);
|
||||
bool tile_type_forward_intern_as(TileTypeForwardInternation *reg, const char *name, TileTypeId id);
|
||||
bool tile_type_forward_get_interned(TileTypeForwardInternation *reg, const char *name, TileTypeId *outptr);
|
||||
bool tile_type_forward_delete_interned(TileTypeForwardInternation *reg, const char *name);
|
||||
void tile_type_forward_clear_interned(TileTypeForwardInternation *reg);
|
||||
|
||||
#endif /* end of include guard: COMMON_WORLD_H_ */
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef SERVER_CLIENT_CONNECTION_H_
|
||||
#define SERVER_CLIENT_CONNECTION_H_
|
||||
|
||||
#include "common/defs.h"
|
||||
|
||||
typedef struct {
|
||||
uint64_t id;
|
||||
} ServerClientConnection;
|
||||
|
||||
#endif /* end of include guard: SERVER_CLIENT_CONNECTION_H_ */
|
|
@ -5,6 +5,7 @@
|
|||
#include "common/util/byte_serdes.h"
|
||||
#include "common/util/thread.h"
|
||||
#include "common/util/spin_lock.h"
|
||||
#include "server/world.h"
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
|
@ -12,5 +13,28 @@ main(int argc, char **argv)
|
|||
(void) argc;
|
||||
(void) argv;
|
||||
printf("Hello, server!\n");
|
||||
server_init_tile_type_registry();
|
||||
const char *name = "core:example";
|
||||
const char *name2 = "core:example2";
|
||||
ServerTileType example = {
|
||||
.name = name,
|
||||
.on_deregister = NULL,
|
||||
.read_tile = NULL,
|
||||
.write_tile = NULL,
|
||||
.send_tile = NULL,
|
||||
};
|
||||
TileTypeId example_id, example2_id, check_id;
|
||||
assert(server_register_tile_type(&example, &example_id));
|
||||
example.name = name2;
|
||||
assert(server_register_tile_type(&example, &example2_id));
|
||||
printf("%s registered as %d\n", name, example_id);
|
||||
printf("%s registered as %d\n", name2, example2_id);
|
||||
assert(server_tile_type_by_id(example_id)->name == name);
|
||||
assert(server_tile_type_by_id(example2_id)->name == name2);
|
||||
server_tile_id_by_name(name, &check_id);
|
||||
assert(check_id == example_id);
|
||||
server_tile_id_by_name(name2, &check_id);
|
||||
assert(check_id == example2_id);
|
||||
server_deinit_tile_type_registry();
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
#include "world.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include "common/util/spin_lock.h"
|
||||
|
||||
TileTypeId next_id = 0;
|
||||
TileTypeForwardInternation server_tile_type_internation;
|
||||
TYPED_HASH_TABLE(ServerTileType) server_tile_type_registry;
|
||||
SpinLock lock = SPIN_LOCK_UNLOCKED;
|
||||
|
||||
static void deinit_tile_type(ServerTileType *tile_type) __attribute__((nothrow));
|
||||
void
|
||||
deinit_tile_type(ServerTileType *tile_type)
|
||||
{
|
||||
if (!tile_type) {
|
||||
return;
|
||||
}
|
||||
if (!tile_type->on_deregister) {
|
||||
return;
|
||||
}
|
||||
tile_type->on_deregister(tile_type);
|
||||
}
|
||||
|
||||
void
|
||||
server_init_tile_type_registry()
|
||||
{
|
||||
spin_lock_acquire(&lock);
|
||||
tile_type_forward_init_interned(&server_tile_type_internation);
|
||||
hash_table_init(&server_tile_type_registry, &deinit_tile_type);
|
||||
spin_lock_release(&lock);
|
||||
}
|
||||
|
||||
void
|
||||
server_deinit_tile_type_registry()
|
||||
{
|
||||
spin_lock_acquire(&lock);
|
||||
hash_table_deinit(&server_tile_type_registry);
|
||||
tile_type_forward_clear_interned(&server_tile_type_internation);
|
||||
next_id = 0;
|
||||
spin_lock_release(&lock);
|
||||
}
|
||||
|
||||
bool
|
||||
server_register_tile_type(const ServerTileType *tile_type, TileTypeId *outptr)
|
||||
{
|
||||
if (!tile_type) {
|
||||
return false;
|
||||
}
|
||||
const char *name = tile_type->name;
|
||||
if (!name) {
|
||||
return false;
|
||||
}
|
||||
spin_lock_acquire(&lock);
|
||||
TileTypeId id = next_id;
|
||||
HashTableKey id_key = hash_table_key_from_bytes((void*) &id, sizeof(id));
|
||||
if (hash_table_find(&server_tile_type_registry, id_key) >= 0) {
|
||||
for(++id; id != next_id; ++id) {
|
||||
if (hash_table_find(&server_tile_type_registry, (id_key = hash_table_key_from_bytes((void*) &id, sizeof(id)))) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (id == next_id) {
|
||||
spin_lock_release(&lock);
|
||||
return false; // Ran out of ids
|
||||
}
|
||||
}
|
||||
next_id = id;
|
||||
if (!tile_type_forward_intern_as(&server_tile_type_internation, name, id)) {
|
||||
spin_lock_release(&lock);
|
||||
return false;
|
||||
}
|
||||
if (hash_table_insert(&server_tile_type_registry, id_key, tile_type) < 0) {
|
||||
tile_type_forward_delete_interned(&server_tile_type_internation, name);
|
||||
spin_lock_release(&lock);
|
||||
return false;
|
||||
}
|
||||
*outptr = id;
|
||||
++next_id;
|
||||
spin_lock_release(&lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
server_deregister_tile_type(TileTypeId id)
|
||||
{
|
||||
spin_lock_acquire(&lock);
|
||||
HashTableKey id_key = hash_table_key_from_bytes((void*) &id, sizeof(id));
|
||||
HashTableIndex reg_idx = hash_table_find(&server_tile_type_registry, id_key);
|
||||
if (reg_idx < 0) {
|
||||
spin_lock_release(&lock);
|
||||
return false;
|
||||
}
|
||||
const char *name = server_tile_type_registry.value_array[reg_idx].name;
|
||||
assert(name != NULL);
|
||||
tile_type_forward_delete_interned(&server_tile_type_internation, name);
|
||||
hash_table_delete_at_index(&server_tile_type_registry, reg_idx);
|
||||
spin_lock_release(&lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
server_tile_id_by_name(const char *name, TileTypeId *outptr)
|
||||
{
|
||||
spin_lock_acquire(&lock);
|
||||
bool result = tile_type_forward_get_interned(&server_tile_type_internation, name, outptr);
|
||||
spin_lock_release(&lock);
|
||||
return result;
|
||||
}
|
||||
|
||||
const ServerTileType*
|
||||
server_tile_type_by_id(TileTypeId id)
|
||||
{
|
||||
spin_lock_acquire(&lock);
|
||||
HashTableKey id_key = hash_table_key_from_bytes((void*) &id, sizeof(id));
|
||||
HashTableIndex reg_idx = hash_table_find(&server_tile_type_registry, id_key);
|
||||
if (reg_idx < 0) {
|
||||
spin_lock_release(&lock);
|
||||
return NULL;
|
||||
}
|
||||
const ServerTileType *tile_type = &server_tile_type_registry.value_array[reg_idx];
|
||||
spin_lock_release(&lock);
|
||||
return tile_type;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
#ifndef SERVER_WORLD_H_
|
||||
#define SERVER_WORLD_H_
|
||||
|
||||
#include "common/world.h"
|
||||
#include "common/util/byte_stream.h"
|
||||
#include "common/util/hash_table.h"
|
||||
#include "server/client_connection.h"
|
||||
|
||||
typedef struct server_tile_complex_data ServerTileComplexData;
|
||||
struct server_tile_complex_data {
|
||||
void (*destroy)(ServerTileComplexData *self); // Calls free
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
TileTypeId type;
|
||||
TileVariant variant;
|
||||
ServerTileComplexData *complex_data;
|
||||
} ServerTile;
|
||||
|
||||
// Relocateable
|
||||
typedef struct server_tile_type ServerTileType;
|
||||
struct server_tile_type {
|
||||
const char *name;
|
||||
void (*on_deregister)(const ServerTileType *self) __attribute__((nothrow));
|
||||
ServerTile (*read_tile)(AbstractInputByteStream *stream); // Full data
|
||||
void (*write_tile)(AbstractOutputByteStream *stream, ServerTile tile); // Full data
|
||||
void (*send_tile)(AbstractOutputByteStream *stream, ServerClientConnection *client, ServerTile tile); // Client data
|
||||
// Behavior handlers go here
|
||||
};
|
||||
|
||||
void server_init_tile_type_registry();
|
||||
void server_deinit_tile_type_registry();
|
||||
bool server_register_tile_type(const ServerTileType *tile_type, TileTypeId *outptr); // Relocates tile_type
|
||||
bool server_deregister_tile_type(TileTypeId id);
|
||||
bool server_tile_id_by_name(const char *name, TileTypeId *outptr);
|
||||
const ServerTileType *server_tile_type_by_id(TileTypeId id); // FIXME ensure thread safety?
|
||||
|
||||
#endif /* end of include guard: SERVER_WORLD_H_ */
|
Loading…
Reference in New Issue