Server tile type registry
This commit is contained in:
parent
05ae5bb258
commit
b119dbc129
2
Makefile
2
Makefile
|
@ -5,7 +5,7 @@ all: server
|
||||||
$(BUILD_DIR)/common/util/thread.o: $(BUILD_DIR)/common/util/thread.std.o
|
$(BUILD_DIR)/common/util/thread.o: $(BUILD_DIR)/common/util/thread.std.o
|
||||||
cp $< $@
|
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)
|
$(COMPILE_EXE)
|
||||||
|
|
||||||
run: server
|
run: server
|
||||||
|
|
|
@ -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/byte_serdes.h"
|
||||||
#include "common/util/thread.h"
|
#include "common/util/thread.h"
|
||||||
#include "common/util/spin_lock.h"
|
#include "common/util/spin_lock.h"
|
||||||
|
#include "server/world.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
|
@ -12,5 +13,28 @@ main(int argc, char **argv)
|
||||||
(void) argc;
|
(void) argc;
|
||||||
(void) argv;
|
(void) argv;
|
||||||
printf("Hello, server!\n");
|
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;
|
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