Server tile type registry

This commit is contained in:
Vftdan 2024-10-25 17:47:24 +02:00
parent 05ae5bb258
commit b119dbc129
7 changed files with 274 additions and 1 deletions

View File

@ -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

57
src/common/world.c Normal file
View File

@ -0,0 +1,57 @@
#include "world.h"
void
tile_type_forward_init_interned(TileTypeForwardInternation *reg)
{
if (!reg) {
return;
}
hash_table_init(&reg->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(&reg->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(&reg->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(&reg->table, hash_table_key_from_cstr(name));
}
void
tile_type_forward_clear_interned(TileTypeForwardInternation *reg)
{
if (!reg) {
return;
}
hash_table_deinit(&reg->table);
}

20
src/common/world.h Normal file
View File

@ -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_ */

View File

@ -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_ */

View File

@ -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;
}

124
src/server/world.c Normal file
View File

@ -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;
}

38
src/server/world.h Normal file
View File

@ -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_ */