diff options
| author | Franklin Wei <git@fwei.tk> | 2016-04-16 21:16:44 -0400 |
|---|---|---|
| committer | Franklin Wei <git@fwei.tk> | 2016-04-16 21:16:44 -0400 |
| commit | a305a931726bc13c604afca1209a656a8fbedc46 (patch) | |
| tree | e8ce29b2354aca21dae1bb1f0b1bc227b34adf17 | |
| parent | cfe28eb7eda17e4a604749fe2f027153a2ac5b6e (diff) | |
| download | netcosm-a305a931726bc13c604afca1209a656a8fbedc46.zip netcosm-a305a931726bc13c604afca1209a656a8fbedc46.tar.gz netcosm-a305a931726bc13c604afca1209a656a8fbedc46.tar.bz2 netcosm-a305a931726bc13c604afca1209a656a8fbedc46.tar.xz | |
allow for modular world loading
| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | Makefile | 22 | ||||
| -rw-r--r-- | SOURCES | 16 | ||||
| -rw-r--r-- | src/SOURCES | 15 | ||||
| -rw-r--r-- | src/globals.h | 1 | ||||
| -rw-r--r-- | src/obj.c | 3 | ||||
| -rw-r--r-- | src/server.c | 83 | ||||
| -rw-r--r-- | src/world.c | 21 | ||||
| -rw-r--r-- | src/world.h | 16 | ||||
| -rw-r--r-- | tools/worldgen.c | 122 | ||||
| -rw-r--r-- | worlds/SOURCES | 2 | ||||
| -rw-r--r-- | worlds/netcosm_default.c (renamed from worlds/test.c) | 0 | ||||
| -rw-r--r-- | worlds/template.c | 99 |
13 files changed, 354 insertions, 47 deletions
@@ -6,3 +6,4 @@ a.out *~ *.d netcosm.log +build @@ -27,19 +27,22 @@ PLATFORM = unix OUT = $(BUILDDIR)/$(PLATFORM).bin PREFIX = /usr/local -SRC = $(shell cat SOURCES) -OBJ = $(patsubst %.c,$(BUILDDIR)/%.o,$(SRC)) +SRC = $(shell cat src/SOURCES) +OBJ = $(patsubst %.c,$(BUILDDIR)/src/%.o,$(SRC)) + +WORLD_SRC = $(shell cat worlds/SOURCES) +WORLD_OBJ = $(patsubst %.c,$(BUILDDIR)/worlds/%.so,$(WORLD_SRC)) INCLUDES = -I src/ -I export/include/ WARNFLAGS = -Wall -Wextra -Wshadow -fno-strict-aliasing OPTFLAGS = -O2 -DEBUGFLAGS = -g -fstack-protector -D_FORTIFY_SOURCE=2 +DEBUGFLAGS = -g -fstack-protector CFLAGS = $(OPTFLAGS) $(DEBUGFLAGS) $(WARNFLAGS) -std=c99 $(INCLUDES) -LDFLAGS = -lev -lcrypto +LDFLAGS = -lev -lcrypto -ldl HEADERS = src/*.h export/include/*.h @@ -49,11 +52,11 @@ DEPS = $(patsubst %.c,$(BUILDDIR)/%.d,$(SRC)) ################################################################################ .PHONY: all -all: | $(OUT) +all: | $(OUT) $(WORLD_OBJ) $(OUT): $(OBJ) @echo "LD $@" - @$(CC) $(OBJ) $(CFLAGS) -o $@ $(LDFLAGS) + @$(CC) $(OBJ) $(CFLAGS) -o $@ $(LDFLAGS) -rdynamic $(OBJ): | $(BUILDDIR) @@ -65,6 +68,11 @@ $(BUILDDIR)/%.o: %.c $(BUILDDIR)/%.d Makefile @mkdir -p `dirname $@` @$(CC) -c $< $(CFLAGS) -o $@ +$(BUILDDIR)/%.so: %.c $(BUILDDIR)/%.d Makefile + @echo "CC $<" + @mkdir -p `dirname $@` + @$(CC) $< $(CFLAGS) -shared -o $@ -D_WORLD_MODULE_ -fPIC + # Dependencies ################################################################################ @@ -86,7 +94,7 @@ setcap: .PHONY: clean clean: @echo "Cleaning build directory..." - @rm -f $(OBJ) $(OUT) + @rm -f $(OBJ) $(OUT) $(WORLD_OBJ) .PHONY: veryclean veryclean: diff --git a/SOURCES b/SOURCES deleted file mode 100644 index 289b682..0000000 --- a/SOURCES +++ /dev/null @@ -1,16 +0,0 @@ -src/auth.c -src/client.c -src/client_reqs.c -src/hash.c -src/main.c -src/multimap.c -src/obj.c -src/room.c -src/server.c -src/server_reqs.c -src/telnet.c -src/userdb.c -src/util.c -src/verb.c -src/world.c -worlds/test.c diff --git a/src/SOURCES b/src/SOURCES new file mode 100644 index 0000000..5cb3c9b --- /dev/null +++ b/src/SOURCES @@ -0,0 +1,15 @@ +auth.c +client.c +client_reqs.c +hash.c +main.c +multimap.c +obj.c +room.c +server.c +server_reqs.c +telnet.c +userdb.c +util.c +verb.c +world.c diff --git a/src/globals.h b/src/globals.h index 193bed4..6e050ee 100644 --- a/src/globals.h +++ b/src/globals.h @@ -30,6 +30,7 @@ #include <arpa/telnet.h> #include <assert.h> #include <ctype.h> +#include <dlfcn.h> #include <errno.h> #include <fcntl.h> #include <inttypes.h> @@ -21,6 +21,7 @@ #include "hash.h" #include "multimap.h" #include "obj.h" +#include "world.h" /* map of class names -> object classes */ static void *obj_class_map = NULL; @@ -41,8 +42,6 @@ struct object_t *obj_new(const char *class_name) { if(!obj_class_map) { - extern const struct obj_class_t netcosm_obj_classes[]; - extern const size_t netcosm_obj_classes_sz; obj_class_map = hash_init(netcosm_obj_classes_sz / 2 + 1, hash_djb, compare_strings); diff --git a/src/server.c b/src/server.c index a4558bc..55cb1f3 100644 --- a/src/server.c +++ b/src/server.c @@ -41,6 +41,8 @@ static uint16_t port = DEFAULT_PORT; static int server_socket; +static char *world_module = "build/worlds/netcosm_default.so"; + #define SAVE_INTERVAL 10 /* saves state periodically */ @@ -179,10 +181,28 @@ static void check_userfile(void) static void load_worldfile(void) { - extern const struct roomdata_t netcosm_world[]; - extern const size_t netcosm_world_sz; + /* load the world module */ + void *handle = dlopen(world_module, RTLD_NOW); + if(!handle) + error("cannot load world module `%s' (%s)", world_module, dlerror()); + + /* load symbols */ + size_t *ptr; + + netcosm_verb_classes = dlsym(handle, "netcosm_verb_classes"); + ptr = dlsym(handle, "netcosm_verb_classes_sz"); + netcosm_verb_classes_sz = *ptr; - extern const char *netcosm_world_name; + netcosm_obj_classes = dlsym(handle, "netcosm_obj_classes"); + ptr = dlsym(handle, "netcosm_obj_classes_sz"); + netcosm_obj_classes_sz = *ptr; + + netcosm_world = dlsym(handle, "netcosm_world"); + ptr = dlsym(handle, "netcosm_world_sz"); + netcosm_world_sz = *ptr; + + char **tmp = dlsym(handle, "netcosm_world_name"); + netcosm_world_name = *tmp; if(access(WORLDFILE, F_OK) < 0) { @@ -375,6 +395,21 @@ static void init_signals(void) error("sigaction"); } +static void __attribute__((noreturn)) print_help(char *argv[]) +{ + debugf("Usage: %s [OPTION]...\n", argv[0]); + debugf("NetCosm MUD server\n"); + debugf("\n"); + debugf(" -a USER PASS\tautomatic setup with USER/PASS\n"); + debugf(" -d PREFIX\tcreate and change to PREFIX before writing data files\n"); + debugf(" -h, -?\t\tshow this help\n"); + debugf(" -p PORT\tlisten on PORT\n"); + debugf(" -w MODULE\tuse a different world module\n"); + exit(0); +} + +static char *data_prefix = NULL; + static void parse_args(int argc, char *argv[]) { for(int i = 1; i < argc; ++i) @@ -388,20 +423,29 @@ static void parse_args(int argc, char *argv[]) switch(c) { case 'h': /* help */ - debugf("Usage: %s [-d PREFIX] [-a <username> <password>]\n", argv[0]); - exit(0); + case '?': + print_help(argv); case 'a': /* automatic first-run config */ autoconfig = true; + if(i + 2 > argc) + print_help(argv); autouser = argv[++i]; autopass = argv[++i]; break; case 'd': /* set data prefix */ - mkdir(argv[++i], 0700); - if(chdir(argv[i]) < 0) - { - debugf("Cannot access data prefix.\n"); - exit(0); - } + if(i + 1 > argc) + print_help(argv); + data_prefix = argv[++i]; + break; + case 'p': /* set port */ + if(i + 1 > argc) + print_help(argv); + port = strtol(argv[++i], NULL, 10); + break; + case 'w': /* world */ + if(i + 1 > argc) + print_help(argv); + world_module = argv[++i]; break; default: c = 'h'; @@ -409,8 +453,6 @@ static void parse_args(int argc, char *argv[]) } } } - else - port = strtol(argv[i], NULL, 10); } } @@ -431,13 +473,24 @@ int server_main(int argc, char *argv[]) parse_args(argc, argv); + /* this must be done before any world module data is used */ + load_worldfile(); + + if(data_prefix) + { + mkdir(data_prefix, 0700); + if(chdir(data_prefix) < 0) + { + debugf("Cannot access data prefix.\n"); + exit(0); + } + } + userdb_init(USERFILE); /* also performs first-time setup: */ check_userfile(); - load_worldfile(); - /* initialize request map */ reqmap_init(); diff --git a/src/world.c b/src/world.c index b3bb4b3..d7c3590 100644 --- a/src/world.c +++ b/src/world.c @@ -23,6 +23,20 @@ #include "room.h" #include "world.h" +/* verb classes */ +const struct verb_class_t *netcosm_verb_classes; +size_t netcosm_verb_classes_sz; + +/* object classes */ +const struct obj_class_t *netcosm_obj_classes; +size_t netcosm_obj_classes_sz; + +/* rooms */ +const struct roomdata_t *netcosm_world; +size_t netcosm_world_sz; + +const char *netcosm_world_name; + /* processed world data */ static struct room_t *world; @@ -184,7 +198,10 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz read(fd, &world_sz, sizeof(world_sz)); if(world_sz != data_sz) + { + debugf("Incompatible world state.\n"); return false; + } world = calloc(world_sz, sizeof(struct room_t)); @@ -192,10 +209,12 @@ bool world_load(const char *fname, const struct roomdata_t *data, size_t data_sz if(strcmp(name, world_name)) { free(world_name); - debugf("Incompatible world state.\n"); + debugf("Incompatible world state (%s %s).\n", name, world_name); return false; } + debugf("Loading world `%s'.\n", world_name); + obj_set_idcounter(1); size_t n_global_verbs = read_size(fd); diff --git a/src/world.h b/src/world.h index 50f9769..5dcd85d 100644 --- a/src/world.h +++ b/src/world.h @@ -26,19 +26,23 @@ /* the world module MUST define all of the following: */ +#ifndef _WORLD_MODULE_ +/* note that these are now dynamically loaded */ + /* verb classes */ -extern const struct verb_class_t netcosm_verb_classes[]; -extern const size_t netcosm_verb_classes_sz; +extern const struct verb_class_t *netcosm_verb_classes; +extern size_t netcosm_verb_classes_sz; /* object classes */ -extern const struct obj_class_t netcosm_obj_classes[]; -extern const size_t netcosm_obj_classes_sz; +extern const struct obj_class_t *netcosm_obj_classes; +extern size_t netcosm_obj_classes_sz; /* rooms */ -extern const struct roomdata_t netcosm_world[]; -extern const size_t netcosm_world_sz; +extern const struct roomdata_t *netcosm_world; +extern size_t netcosm_world_sz; extern const char *netcosm_world_name; +#endif /*** loads the world into RAM for the first time, resets the game state ***/ void world_init(const struct roomdata_t *data, size_t sz, const char *name); diff --git a/tools/worldgen.c b/tools/worldgen.c new file mode 100644 index 0000000..e0cd947 --- /dev/null +++ b/tools/worldgen.c @@ -0,0 +1,122 @@ +/* generates a 3d world with no content */ + +#include <globals.h> +#include <hash.h> +#include <room.h> + +/* x and y are horizontal and forward-back axes, respectively */ +/* z is the vertical axis */ + +struct direction_info_t { + enum direction_t dir; + int off_x, off_y, off_z; +} dirs[] = { + { DIR_N, 0, 1, 0 }, + { DIR_NE, 1, 1, 0 }, + { DIR_E, 1, 0, 0 }, + { DIR_SE, 1, -1, 0 }, + { DIR_S, 0, -1, 0 }, + { DIR_SW, -1, -1, 0 }, + { DIR_W, -1, 0, 0 }, + { DIR_NW, -1, 1, 0 }, + { DIR_UP, 0, 0, 1 }, + { DIR_DN, 0, 0, -1 }, +}; + +int main() +{ + printf("#include <world_api.h>\n"); + printf("const struct roomdata_t netcosm_world[] = {\n"); + + for(int x = 0; x < WORLD_DIM; ++x) + for(int y = 0; y < WORLD_DIM; ++y) + for(int z = 0; z < WORLD_DIM; ++z) + { + printf("{\n"); + printf("\"room_%d_%d_%d\",\n", x, y, z); + printf("\"Room (%d,%d,%d)\",\n", x, y, z); + printf("\"You are in a room...\","); + + char *adj[ARRAYLEN(dirs)]; + for(int i = 0; i < ARRAYLEN(dirs); ++i) + { + int new_x = x + dirs[i].off_x, + new_y = y + dirs[i].off_y, + new_z = z + dirs[i].off_z; + + if(new_x < 0 || new_x >= WORLD_DIM || + new_y < 0 || new_y >= WORLD_DIM || + new_z < 0 || new_z >= WORLD_DIM) + asprintf(adj + i, "NULL"); + else + asprintf(adj + i, "\"room_%d_%d_%d\"", + new_x, + new_y, + new_z); + } + + printf("{ "); + for(int i = 0; i < ARRAYLEN(dirs); ++i) + { + printf("%s, ", adj[i]); + free(adj[i]); + } + printf("NONE_IN, NONE_OT },\n"); + + for(int i = 0; i < 6; ++i) + printf("NULL,\n"); + + printf("},\n"); + } + + printf("};\n"); + printf("const size_t netcosm_world_sz = ARRAYLEN(netcosm_world);\n"); + printf("const char *netcosm_world_name = \"World Name Here\";\n"); + + printf("static void generic_ser(int fd, struct object_t *obj)\n"); + printf("{\n"); + printf(" write_string(fd, obj->userdata);\n"); + printf("}\n"); + + printf("static void generic_deser(int fd, struct object_t *obj)\n"); + printf("{\n"); + printf(" obj->userdata = read_string(fd);\n"); + printf("}\n"); + + printf("static void generic_destroy(struct object_t *obj)\n"); + printf("{\n"); + printf(" free(obj->userdata);\n"); + printf("}\n"); + + printf("static const char *generic_desc(struct object_t *obj, user_t *user)\n"); + printf("{\n"); + printf(" (void) user;\n"); + printf(" return obj->userdata;\n"); + printf("}\n"); + + printf("static void *generic_dup(struct object_t *obj)\n"); + printf("{\n"); + printf(" return strdup(obj->userdata);\n"); + printf("}\n"); + + printf("const struct obj_class_t netcosm_obj_classes[] = {\n"); + printf(" {\n"); + printf(" \"/generic\",\n"); + printf(" generic_ser,\n"); + printf(" generic_deser,\n"); + printf(" NULL,\n"); + printf(" NULL,\n"); + printf(" generic_destroy,\n"); + printf(" generic_desc,\n"); + printf(" generic_dup,\n"); + printf(" },\n"); + printf("};\n"); + printf("const size_t netcosm_obj_classes_sz = ARRAYLEN(netcosm_obj_classes);\n"); + + printf("const struct verb_class_t netcosm_verb_classes[] = {\n"); + printf("\n"); + printf("};\n"); + printf("\n"); + printf("const size_t netcosm_verb_classes_sz = ARRAYLEN(netcosm_verb_classes);\n"); + +}; diff --git a/worlds/SOURCES b/worlds/SOURCES new file mode 100644 index 0000000..1fcc434 --- /dev/null +++ b/worlds/SOURCES @@ -0,0 +1,2 @@ +netcosm_default.c +template.c diff --git a/worlds/test.c b/worlds/netcosm_default.c index 11096df..11096df 100644 --- a/worlds/test.c +++ b/worlds/netcosm_default.c diff --git a/worlds/template.c b/worlds/template.c new file mode 100644 index 0000000..d22ecb4 --- /dev/null +++ b/worlds/template.c @@ -0,0 +1,99 @@ +/* + * NetCosm - a MUD server + * Copyright (C) 2016 Franklin Wei + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <world_api.h> + +/* This is a sample world implemented in NetCosm. */ + +/* A world is composed of rooms, object classes, and verb classes. For + * now they are defined as global arrays, but this is subject to change. + */ + +/* This is our array of rooms. Each contains multiple callbacks and + strings pointing to other rooms, see room.h for details */ +const struct roomdata_t netcosm_world [] = { + { + "uniq_id", // this must be globally unique + "Room name", + "Initial description", + + /* these can be replaced with strings identifying other rooms */ + { NONE_N, NONE_NE, NONE_E, NONE_SE, NONE_S, NONE_SW, NONE_W, NONE_NW, NONE_UP, NONE_DN, NONE_IN, NONE_OT }, + + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + }, +}; + +const size_t netcosm_world_sz = ARRAYLEN(netcosm_world); +const char *netcosm_world_name = "World Name Here"; + +/********* OBJECTS *********/ + +static void generic_ser(int fd, struct object_t *obj) +{ + write_string(fd, obj->userdata); +} + +static void generic_deser(int fd, struct object_t *obj) +{ + obj->userdata = read_string(fd); +} + +static void generic_destroy(struct object_t *obj) +{ + free(obj->userdata); +} + +static const char *generic_desc(struct object_t *obj, user_t *user) +{ + (void) user; + return obj->userdata; +} + +static void *generic_dup(struct object_t *obj) +{ + return strdup(obj->userdata); +} + +const struct obj_class_t netcosm_obj_classes[] = { + { + "/generic", + generic_ser, + generic_deser, + NULL, + NULL, + generic_destroy, + generic_desc, + generic_dup, + }, +}; + +const size_t netcosm_obj_classes_sz = ARRAYLEN(netcosm_obj_classes); + +/********* VERBS *********/ + +const struct verb_class_t netcosm_verb_classes[] = { + +}; + +const size_t netcosm_verb_classes_sz = ARRAYLEN(netcosm_verb_classes); |