Compare commits

...

5 Commits

Author SHA1 Message Date
Vladyslav Hrytsenko b032db0acd new iteration of draft 2023-03-12 14:19:59 +02:00
Vladyslav Hrytsenko ac6b44eb0a updated draft 2023-03-12 10:52:44 +02:00
Vladyslav Hrytsenko 74f0956b66 updated draft 2023-03-08 19:11:56 +02:00
Vladyslav Hrytsenko 17951f329f
Update foundation.md 2023-02-13 10:15:46 +02:00
Vladyslav Hrytsenko 1a5ef9e8fc meta: foundation draft 2023-02-13 10:12:32 +02:00
7 changed files with 741 additions and 161 deletions

View File

@ -1,5 +1,5 @@
add_executable(minimal
src/main.c
src/oldmain.c
src/platform.c
src/worldgen.c
src/texgen.c

View File

@ -1,82 +1,5 @@
#define ZPL_IMPL
#include "zpl.h"
#include "platform/system.h"
#include "core/game.h"
#include "models/entity.h"
#include "world/entity_view.h"
#include "utils/options.h"
#include "platform/signal_handling.h"
#include "platform/profiler.h"
typedef int efd_main;
#include "flecs.h"
#include "flecs/flecs_os_api_stdcpp.h"
#include "models/components.h"
#include "systems/systems.h"
#include "platform/arch.h"
#define DEFAULT_WORLD_SEED 302097
#define DEFAULT_CHUNK_SIZE 16 /* amount of blocks within a chunk (single axis) */
#define DEFAULT_WORLD_SIZE 5 /* amount of chunks within a world (single axis) */
int main(int argc, char** argv) {
zpl_opts opts={0};
zpl_opts_init(&opts, zpl_heap(), argv[0]);
zpl_opts_add(&opts, "?", "help", "the HELP section", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "v", "viewer-only", "run viewer-only client", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "d", "server-only", "run dedicated server", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "p", "preview-map", "draw world preview", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "s", "seed", "world seed", ZPL_OPTS_INT);
zpl_opts_add(&opts, "r", "random-seed", "generate random world seed", ZPL_OPTS_FLAG);
//zpl_opts_add(&opts, "cs", "chunk-size", "amount of blocks within a chunk (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ws", "world-size", "amount of chunks within a world (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ip", "host", "host IP address", ZPL_OPTS_STRING);
zpl_opts_add(&opts, "port", "port", "port number", ZPL_OPTS_INT);
uint32_t ok = zpl_opts_compile(&opts, argc, argv);
if (!ok) {
zpl_opts_print_errors(&opts);
zpl_opts_print_help(&opts);
return -1;
}
int8_t is_viewer_only = zpl_opts_has_arg(&opts, "viewer-only");
int8_t is_server_only = zpl_opts_has_arg(&opts, "server-only");
int32_t seed = (int32_t)zpl_opts_integer(&opts, "seed", DEFAULT_WORLD_SEED);
uint16_t world_size = (uint16_t)zpl_opts_integer(&opts, "world-size", DEFAULT_WORLD_SIZE);
uint16_t chunk_size = DEFAULT_CHUNK_SIZE; //zpl_opts_integer(&opts, "chunk-size", DEFAULT_CHUNK_SIZE);
zpl_string host = zpl_opts_string(&opts, "host", NULL);
uint16_t port = (uint16_t)zpl_opts_integer(&opts, "port", 0);
game_kind play_mode = GAMEKIND_SINGLE;
if (is_viewer_only) play_mode = GAMEKIND_CLIENT;
if (is_server_only) play_mode = GAMEKIND_HEADLESS;
if (zpl_opts_has_arg(&opts, "random-seed")) {
zpl_random rnd={0};
zpl_random_init(&rnd);
seed = zpl_random_gen_u32(&rnd);
zpl_printf("Seed: %u\n", seed);
}
if (zpl_opts_has_arg(&opts, "preview-map")) {
generate_minimap(seed, WORLD_BLOCK_SIZE, chunk_size, world_size);
return 0;
}
sighandler_register();
game_init(host, port, play_mode, 1, seed, chunk_size, world_size, 0);
game_run();
game_shutdown();
sighandler_unregister();
zpl_string_free(host);
zpl_opts_free(&opts);
efd_main start() {
return 0;
}

View File

@ -0,0 +1,82 @@
#define ZPL_IMPL
#include "zpl.h"
#include "platform/system.h"
#include "core/game.h"
#include "models/entity.h"
#include "world/entity_view.h"
#include "utils/options.h"
#include "platform/signal_handling.h"
#include "platform/profiler.h"
#include "flecs.h"
#include "flecs/flecs_os_api_stdcpp.h"
#include "models/components.h"
#include "systems/systems.h"
#include "platform/arch.h"
#define DEFAULT_WORLD_SEED 302097
#define DEFAULT_CHUNK_SIZE 16 /* amount of blocks within a chunk (single axis) */
#define DEFAULT_WORLD_SIZE 5 /* amount of chunks within a world (single axis) */
int main(int argc, char** argv) {
zpl_opts opts={0};
zpl_opts_init(&opts, zpl_heap(), argv[0]);
zpl_opts_add(&opts, "?", "help", "the HELP section", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "v", "viewer-only", "run viewer-only client", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "d", "server-only", "run dedicated server", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "p", "preview-map", "draw world preview", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "s", "seed", "world seed", ZPL_OPTS_INT);
zpl_opts_add(&opts, "r", "random-seed", "generate random world seed", ZPL_OPTS_FLAG);
//zpl_opts_add(&opts, "cs", "chunk-size", "amount of blocks within a chunk (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ws", "world-size", "amount of chunks within a world (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ip", "host", "host IP address", ZPL_OPTS_STRING);
zpl_opts_add(&opts, "port", "port", "port number", ZPL_OPTS_INT);
uint32_t ok = zpl_opts_compile(&opts, argc, argv);
if (!ok) {
zpl_opts_print_errors(&opts);
zpl_opts_print_help(&opts);
return -1;
}
int8_t is_viewer_only = zpl_opts_has_arg(&opts, "viewer-only");
int8_t is_server_only = zpl_opts_has_arg(&opts, "server-only");
int32_t seed = (int32_t)zpl_opts_integer(&opts, "seed", DEFAULT_WORLD_SEED);
uint16_t world_size = (uint16_t)zpl_opts_integer(&opts, "world-size", DEFAULT_WORLD_SIZE);
uint16_t chunk_size = DEFAULT_CHUNK_SIZE; //zpl_opts_integer(&opts, "chunk-size", DEFAULT_CHUNK_SIZE);
zpl_string host = zpl_opts_string(&opts, "host", NULL);
uint16_t port = (uint16_t)zpl_opts_integer(&opts, "port", 0);
game_kind play_mode = GAMEKIND_SINGLE;
if (is_viewer_only) play_mode = GAMEKIND_CLIENT;
if (is_server_only) play_mode = GAMEKIND_HEADLESS;
if (zpl_opts_has_arg(&opts, "random-seed")) {
zpl_random rnd={0};
zpl_random_init(&rnd);
seed = zpl_random_gen_u32(&rnd);
zpl_printf("Seed: %u\n", seed);
}
if (zpl_opts_has_arg(&opts, "preview-map")) {
generate_minimap(seed, WORLD_BLOCK_SIZE, chunk_size, world_size);
return 0;
}
sighandler_register();
game_init(host, port, play_mode, 1, seed, chunk_size, world_size, 0);
game_run();
game_shutdown();
sighandler_unregister();
zpl_string_free(host);
zpl_opts_free(&opts);
return 0;
}

View File

@ -1,5 +1,5 @@
add_executable(survival
src/main.c
src/oldmain.c
src/platform.c
src/worldgen.c
src/texgen.c

View File

@ -1,101 +1,462 @@
#define ZPL_IMPL
#include "zpl.h"
#include "platform/system.h"
#include "core/game.h"
#include "game.h"
#include "models/entity.h"
#include "world/entity_view.h"
#include "utils/options.h"
#include "platform/signal_handling.h"
#include "platform/profiler.h"
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "flecs.h"
#include "flecs/flecs_os_api_stdcpp.h"
/// lib.c
#include "models/components.h"
#include "systems/systems.h"
// core
#include "platform/arch.h"
typedef int efd_app;
typedef uint16_t efd_entity_type;
typedef int32_t efd_result;
typedef void * efd_world;
typedef int efd_entid;
ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(0)
#include "tinyc2.h"
ZPL_DIAGNOSTIC_POP
// define amount of memeory reserved for???
// custom data within COMMAND (cli->ser) and SNAPSHOT (ser->cli)
#define EFD_COMMAND_SIZE 64 * 1024
#define EFD_SNAPSHOT_SIZE 128 * 1024
#define DEFAULT_WORLD_SEED 302097
#define DEFAULT_CHUNK_SIZE 16 /* amount of blocks within a chunk (single axis) */
#define DEFAULT_WORLD_SIZE 5 /* amount of chunks within a world (single axis) */
#define EFD_TYPE_SHIFT 16
#define EFD_ID(type) (((type) << EFD_TYPE_SHIFT) + 1)
#define EFD_TYPE(id) ((id - 1) >> EFD_TYPE_SHIFT)
#define EFD_END 0
/*
TODO
- monster spawner
- the longer we survive, the more and stronger enemies we spawn
- player grows HP by leveling up
- XP increases by killing mobs
- player can pick an "ability" upon reaching level milestones
- abilities: armor/shield, TODO ...
- enemies damage player when close to him in ticks (damage effects, ...)
- basic projectile pooling (flecs)
- somewhat believable world gen, small hamlets with cols, etc
*/
typedef enum efd_instance_type {
EFD_TYPE_NONE = 0,
/* chunk */
EFD_TYPE_TILE,
EFD_TYPE_BLOCK,
EFD_TYPE_CHUNK,
/* entities */
EFD_TYPE_ITEM,
EFD_TYPE_OBJECT,
EFD_TYPE_DEVICE,
EFD_TYPE_VEHICLE,
EFD_TYPE_MOB,
EFD_TYPE_PLAYER,
/* other */
EFD_TYPE_OTHER,
/* utils */
EFD_TYPE_LAST,
EFD_TYPE_MAX = 0xFFFF,
} efd_instance_type;
typedef enum efd_flags {
EFD_FLAG_COLLISION = (1 << 1),
EFD_FLAG_HAZARD = (1 << 2),
EFD_FLAG_ESSENTIAL = (1 << 3),
EFD_FLAG_DESTROY_ON_COLLISION = (1 << 4),
} efd_flags;
// assets
typedef enum efd_asset_type {
EFD_NONE = 0,
EFD_TEXTURE,
EFD_ANIMATION,
EFD_SOUND,
EFD_FONT,
EFD_SHADER,
} efd_asset_type;
typedef enum efd_asset_flags {
EFD_FLAG_ATLAS = (1 << 1), // texture is an atlas and has multiple frames
EFD_FLAG_LOOPED = (1 << 2), // frames are looped sequentially (requrires EFD_FLAG_ATLAS, can be combined with EFD_FLAG_RANDOM)
EFD_FLAG_RANDOM = (1 << 3), // one of the frames is randomly chosen (requrires EFD_FLAG_ATLAS, can be combined with EFD_FLAG_LOOPED)
EFD_FLAG_COMPLEX = (1 << 4), // frames have a complex state system and require a separate asset with EFD_ANIMATION type
} efd_asset_flags;
typedef struct efd_asset {
efd_asset_type type;
int id;
const char *path;
int32_t flags;
struct {
int size_x;
int size_y;
} atlas;
void *data;
} efd_asset;
// objects
typedef struct efd_tile {
int id;
int flags;
float drag;
float friction;
} efd_tile;
typedef struct efd_block {
int id;
int flags;
float bounce;
int velx;
int vely;
} efd_block;
typedef struct efd_item_list {
int id;
int qty;
} efd_item_list;
typedef struct efd_craft {
int producer;
int ticks;
efd_item_list *input;
efd_item_list *output;
} efd_craft;
typedef struct efd_tooltip {
const char *title;
const char *description;
} efd_tooltip;
typedef struct efd_entity {
int id;
int flags;
int stack;
union {
int durability;
int health;
};
efd_result (*spawn_cb)(efd_entid);
efd_item_list *drop;
} efd_entity;
typedef struct efd_app_desc {
const char *name;
int debug_ui;
int width;
int height;
int fullscreen;
int vsync;
int server_only;
int viewer_only;
int viewer_amount;
int world_seed;
int world_seed_random;
efd_result (*init_cb)();
efd_result (*system_cb)();
efd_result (*update_cb)();
efd_result (*render_cb)(efd_entity_type type);
efd_result (*player_join_cb)(efd_entid player_id);
efd_result (*player_leave_cb)(efd_entid player_id);
efd_result (*cleanup_cb)();
struct {
float item_pickup_radius;
float item_merge_radius;
float item_drop_radius;
float item_attract_radius;
float item_attract_force;
} rules;
efd_asset *assets;
efd_tile *tiles;
efd_block *blocks;
efd_entity *entities;
efd_craft *crafting;
efd_tooltip *tooltips;
} efd_app_desc;
/// app.c
enum {
/* textures */
TILE_AIR = EFD_ID(EFD_TYPE_TILE),
TILE_DIRT,
TILE_GRASS,
TILE_STONE,
TILE_WATER,
TILE_LAVA,
BLOCK_AIR = EFD_ID(EFD_TYPE_BLOCK),
BLOCK_WOOD,
BLOCK_HILL,
BLOCK_HILL_SNOW,
BLOCK_FENCE_LEFT,
BLOCK_FENCE_RIGHT,
BLOCK_FENCE_UP,
BLOCK_FENCE_DOWN,
BLOCK_WALL_LEFT,
BLOCK_WALL_RIGHT,
BLOCK_WALL_UP,
BLOCK_WALL_DOWN,
BLOCK_BELT_LEFT,
BLOCK_BELT_RIGHT,
BLOCK_BELT_UP,
BLOCK_BELT_DOWN,
ENTITY_IRON_ORE = EFD_ID(EFD_TYPE_ITEM),
ENTITY_IRON_INGOT,
ENTITY_IRON_PLATE,
ENTITY_SCREW,
ENTITY_BELT,
ENTITY_FIR_TREE = EFD_ID(EFD_TYPE_OBJECT),
ENTITY_OAK_TREE,
ENTITY_CHEST = EFD_ID(EFD_TYPE_DEVICE),
ENTITY_FURNACE,
ENTITY_CRAFTBENCH,
ENTITY_ASSEMBLER,
ENTITY_MONSTER = EFD_ID(EFD_TYPE_MOB),
ENTITY_RABBIT,
ENTITY_BOAR,
ENTITY_BIZON,
ENTITY_BEAR,
ENTITY_TRUCK = EFD_ID(EFD_TYPE_VEHICLE),
ENTITY_CAR,
ENTITY_PLAYER = EFD_ID(EFD_TYPE_PLAYER),
};
efd_result init() {
return 0;
}
efd_result systems(efd_world *w) {
// ECS_SYSTEM(w, Move, EcsOnUpdate, Position, [in] Velocity);
return 0;
}
efd_result update() {
return 0;
}
efd_result render(efd_entity_type type) {
// switch (type) {
// case ENTITY_PLAYER:
// /* additional/replacable rendering code on top of what EFD provides for built-in types */
// efd_render_texture(ENTITY_PLAYER, 0, 0, 0, 0, 0, 0, 0, 0);
// return 1; /* we handled the rendering, don't render with the default renderer */
// break;
// case ENTITY_MONSTER:
// /* our custom rendering code for monster */
// efd_render_texture(ENTITY_MONSTER, 0, 0, 0, 0, 0, 0, 0, 0);
// break;
// case ENTITY_WEAPON:
// /* our custom rendering code for weapon */
// break;
// }
return 0;
}
efd_result player_join(efd_entid player) {
// efd_notify_push(player, "Test", "Welcome to the game!", 5.0f);
return 0;
}
efd_result player_leave(efd_entid player) {
return 0;
}
efd_result cleanup() {
return 0;
}
efd_result chest_spawn(efd_entid id) {
return 0;
}
efd_result furnace_spawn(efd_entid id) {
return 0;
}
efd_app_desc efd_main() {
return (efd_app_desc){
.name = "Survival",
.debug_ui = true,
/* these are defaults, with zpl_option/config files overrides */
.width = 1280,
.height = 720,
.fullscreen = 0,
.vsync = 1,
/* these are code overrides for zpl_option flags (not defaults) */
.server_only = false,
.viewer_only = false,
.viewer_amount = 1,
.world_seed = 0,
.world_seed_random = true,
/* primary callbacks */
.init_cb = init,
.system_cb = systems,
.update_cb = update,
.render_cb = render,
.player_join_cb = player_join,
.player_leave_cb = player_leave,
.cleanup_cb = cleanup,
.rules = {
.item_pickup_radius = 25.0f,
.item_merge_radius = 75.0f,
.item_drop_radius = 15.0f,
.item_attract_radius = 75.0f,
.item_attract_force = 0.1f,
},
.assets = (efd_asset[]){
{EFD_TEXTURE, TILE_GRASS, "assets/grass.png", EFD_FLAG_ATLAS | EFD_FLAG_RANDOM, .atlas = {4, 1}},
{EFD_TEXTURE, TILE_DIRT, "assets/dirt.png", EFD_FLAG_ATLAS | EFD_FLAG_RANDOM, .atlas = {4, 1}},
{EFD_TEXTURE, TILE_LAVA, "assets/lava.png", EFD_FLAG_ATLAS | EFD_FLAG_LOOPED, .atlas = {4, 1}},
{EFD_TEXTURE, TILE_WATER, "assets/water.png", EFD_FLAG_ATLAS | EFD_FLAG_RANDOM | EFD_FLAG_LOOPED, .atlas = {4, 1}},
{EFD_TEXTURE, ENTITY_OAK_TREE, "assets/tree.png"},
{EFD_TEXTURE, ENTITY_CHEST, "assets/chest.png"},
{EFD_TEXTURE, ENTITY_FURNACE, "assets/furnace.png"},
{EFD_TEXTURE, ENTITY_PLAYER, "assets/player.png", EFD_FLAG_ATLAS | EFD_FLAG_COMPLEX},
{EFD_TEXTURE, ENTITY_MONSTER, "assets/monster.png"},
/* animations */
{EFD_ANIMATION, ENTITY_PLAYER, "assets/player.anim"},
/* sounds */
{EFD_SOUND, ENTITY_PLAYER, "assets/player.wav"},
{EFD_END},
},
.tiles = (efd_tile[]){
{TILE_AIR},
{TILE_DIRT, .drag = 1.0f, .friction = 1.0f},
{TILE_GRASS, .drag = 1.0f, .friction = 1.0f},
{TILE_WATER, .drag = 0.11f , .friction = 10.0f},
{TILE_LAVA, EFD_FLAG_HAZARD, .drag = 6.2f , .friction = 40.0f},
{EFD_END},
},
.blocks = (efd_block[]){
{BLOCK_AIR},
{BLOCK_HILL, EFD_FLAG_COLLISION},
{BLOCK_HILL_SNOW, EFD_FLAG_COLLISION},
{BLOCK_WOOD, EFD_FLAG_COLLISION, .bounce = 0.0f},
{BLOCK_WALL_LEFT, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_WALL_RIGHT, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_WALL_UP, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_WALL_DOWN, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_FENCE_LEFT, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_FENCE_RIGHT, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_FENCE_UP, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_FENCE_DOWN, EFD_FLAG_COLLISION, .bounce = 1.0f},
{BLOCK_BELT_LEFT, .velx = -150.0f},
{BLOCK_BELT_RIGHT, .velx = 150.0f},
{BLOCK_BELT_UP, .vely = -150.0f},
{BLOCK_BELT_DOWN, .vely = 150.0f},
{EFD_END},
},
.entities = (efd_entity[]){
{ENTITY_IRON_ORE, .stack = 32},
{ENTITY_IRON_PLATE, .stack = 32},
{ENTITY_SCREW, .stack = 256},
{ENTITY_OAK_TREE, EFD_FLAG_DESTROY_ON_COLLISION, .drop = (efd_item_list[]){
{ENTITY_SCREW, 1},
{EFD_END},
}},
{ENTITY_CHEST, .spawn_cb = chest_spawn},
{ENTITY_FURNACE, .spawn_cb = furnace_spawn},
{ENTITY_MONSTER, .health = 256},
{ENTITY_TRUCK},
{ENTITY_PLAYER},
{EFD_END},
},
.crafting = (efd_craft[]){
{
.producer = ENTITY_FURNACE,
.ticks = 20,
.input = (efd_item_list[]){
{ENTITY_IRON_ORE, 1},
{EFD_END},
},
.output = (efd_item_list[]){
{ENTITY_IRON_PLATE, 4},
{EFD_END},
},
},
{
.producer = ENTITY_CRAFTBENCH,
.ticks = 40,
.input = (efd_item_list[]){
{ENTITY_IRON_PLATE, 1},
{EFD_END},
},
.output = (efd_item_list[]){
{ENTITY_SCREW, 8},
{EFD_END},
},
},
{
.producer = ENTITY_ASSEMBLER,
.ticks = 120,
.input = (efd_item_list[]){
{ENTITY_SCREW, 4},
{ENTITY_IRON_PLATE, 2},
{EFD_END},
},
.output = (efd_item_list[]){
{ENTITY_BELT, 1},
{EFD_END},
},
},
{EFD_END},
},
.tooltips = (efd_tooltip[]){
{"BLOCK_STONE", "It's a block of stone, what did you expect?"},
{"BLOCK_BRICK", "It's a block of brick, what did you expect?"},
{EFD_END},
},
};
}
/// test.c
#include <stdio.h>
void test(efd_entity_type type) { printf("type: %d\n", type); }
int main(int argc, char **argv) {
zpl_opts opts={0};
zpl_opts_init(&opts, zpl_heap(), argv[0]);
efd_app_desc desc = efd_main();
printf("value: %f\n", desc.rules.item_pickup_radius);
printf("TILE_DIRT: %d\n", TILE_DIRT);
printf("TILE_GRASS: %d\n", TILE_GRASS);
printf("ENTITY_PLAYER: %d, is_valid type: %d\n", ENTITY_PLAYER, EFD_TYPE(ENTITY_PLAYER) == EFD_TYPE_PLAYER);
printf("ENTITY_CHEST: %d, is_valid type: %d\n", ENTITY_CHEST, EFD_TYPE(ENTITY_CHEST) == EFD_TYPE_DEVICE);
zpl_opts_add(&opts, "?", "help", "the HELP section", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "v", "viewer-only", "run viewer-only client", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "d", "server-only", "run dedicated server", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "p", "preview-map", "draw world preview", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "s", "seed", "world seed", ZPL_OPTS_INT);
zpl_opts_add(&opts, "r", "random-seed", "generate random world seed", ZPL_OPTS_FLAG);
//zpl_opts_add(&opts, "cs", "chunk-size", "amount of blocks within a chunk (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ws", "world-size", "amount of chunks within a world (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ip", "host", "host IP address", ZPL_OPTS_STRING);
zpl_opts_add(&opts, "port", "port", "port number", ZPL_OPTS_INT);
desc.init_cb();
uint32_t ok = zpl_opts_compile(&opts, argc, argv);
if (!ok) {
zpl_opts_print_errors(&opts);
zpl_opts_print_help(&opts);
return -1;
}
int8_t is_viewer_only = zpl_opts_has_arg(&opts, "viewer-only");
int8_t is_server_only = zpl_opts_has_arg(&opts, "server-only");
int32_t seed = (int32_t)zpl_opts_integer(&opts, "seed", DEFAULT_WORLD_SEED);
uint16_t world_size = (uint16_t)zpl_opts_integer(&opts, "world-size", DEFAULT_WORLD_SIZE);
uint16_t chunk_size = DEFAULT_CHUNK_SIZE; //zpl_opts_integer(&opts, "chunk-size", DEFAULT_CHUNK_SIZE);
zpl_string host = zpl_opts_string(&opts, "host", NULL);
uint16_t port = (uint16_t)zpl_opts_integer(&opts, "port", 0);
game_kind play_mode = GAMEKIND_SINGLE;
if (is_viewer_only) play_mode = GAMEKIND_CLIENT;
if (is_server_only) play_mode = GAMEKIND_HEADLESS;
if (zpl_opts_has_arg(&opts, "random-seed")) {
zpl_random rnd={0};
zpl_random_init(&rnd);
seed = zpl_random_gen_u32(&rnd);
zpl_printf("Seed: %u\n", seed);
}
if (zpl_opts_has_arg(&opts, "preview-map")) {
generate_minimap(seed, WORLD_BLOCK_SIZE, chunk_size, world_size);
return 0;
}
sighandler_register();
game_init(host, port, play_mode, 1, seed, chunk_size, world_size, 0);
game_setup_ecs();
game_run();
game_shutdown();
sighandler_unregister();
zpl_string_free(host);
zpl_opts_free(&opts);
return 0;
}

View File

@ -0,0 +1,101 @@
#define ZPL_IMPL
#include "zpl.h"
#include "platform/system.h"
#include "core/game.h"
#include "game.h"
#include "models/entity.h"
#include "world/entity_view.h"
#include "utils/options.h"
#include "platform/signal_handling.h"
#include "platform/profiler.h"
#include "flecs.h"
#include "flecs/flecs_os_api_stdcpp.h"
#include "models/components.h"
#include "systems/systems.h"
#include "platform/arch.h"
ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(0)
#include "tinyc2.h"
ZPL_DIAGNOSTIC_POP
#define DEFAULT_WORLD_SEED 302097
#define DEFAULT_CHUNK_SIZE 16 /* amount of blocks within a chunk (single axis) */
#define DEFAULT_WORLD_SIZE 5 /* amount of chunks within a world (single axis) */
/*
TODO
- monster spawner
- the longer we survive, the more and stronger enemies we spawn
- player grows HP by leveling up
- XP increases by killing mobs
- player can pick an "ability" upon reaching level milestones
- abilities: armor/shield, TODO ...
- enemies damage player when close to him in ticks (damage effects, ...)
- basic projectile pooling (flecs)
- somewhat believable world gen, small hamlets with cols, etc
*/
int main(int argc, char** argv) {
zpl_opts opts={0};
zpl_opts_init(&opts, zpl_heap(), argv[0]);
zpl_opts_add(&opts, "?", "help", "the HELP section", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "v", "viewer-only", "run viewer-only client", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "d", "server-only", "run dedicated server", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "p", "preview-map", "draw world preview", ZPL_OPTS_FLAG);
zpl_opts_add(&opts, "s", "seed", "world seed", ZPL_OPTS_INT);
zpl_opts_add(&opts, "r", "random-seed", "generate random world seed", ZPL_OPTS_FLAG);
//zpl_opts_add(&opts, "cs", "chunk-size", "amount of blocks within a chunk (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ws", "world-size", "amount of chunks within a world (single axis)", ZPL_OPTS_INT);
zpl_opts_add(&opts, "ip", "host", "host IP address", ZPL_OPTS_STRING);
zpl_opts_add(&opts, "port", "port", "port number", ZPL_OPTS_INT);
uint32_t ok = zpl_opts_compile(&opts, argc, argv);
if (!ok) {
zpl_opts_print_errors(&opts);
zpl_opts_print_help(&opts);
return -1;
}
int8_t is_viewer_only = zpl_opts_has_arg(&opts, "viewer-only");
int8_t is_server_only = zpl_opts_has_arg(&opts, "server-only");
int32_t seed = (int32_t)zpl_opts_integer(&opts, "seed", DEFAULT_WORLD_SEED);
uint16_t world_size = (uint16_t)zpl_opts_integer(&opts, "world-size", DEFAULT_WORLD_SIZE);
uint16_t chunk_size = DEFAULT_CHUNK_SIZE; //zpl_opts_integer(&opts, "chunk-size", DEFAULT_CHUNK_SIZE);
zpl_string host = zpl_opts_string(&opts, "host", NULL);
uint16_t port = (uint16_t)zpl_opts_integer(&opts, "port", 0);
game_kind play_mode = GAMEKIND_SINGLE;
if (is_viewer_only) play_mode = GAMEKIND_CLIENT;
if (is_server_only) play_mode = GAMEKIND_HEADLESS;
if (zpl_opts_has_arg(&opts, "random-seed")) {
zpl_random rnd={0};
zpl_random_init(&rnd);
seed = zpl_random_gen_u32(&rnd);
zpl_printf("Seed: %u\n", seed);
}
if (zpl_opts_has_arg(&opts, "preview-map")) {
generate_minimap(seed, WORLD_BLOCK_SIZE, chunk_size, world_size);
return 0;
}
sighandler_register();
game_init(host, port, play_mode, 1, seed, chunk_size, world_size, 0);
game_setup_ecs();
game_run();
game_shutdown();
sighandler_unregister();
zpl_string_free(host);
zpl_opts_free(&opts);
return 0;
}

113
foundation.md 100644
View File

@ -0,0 +1,113 @@
## Foundation:
* platform
* viewer system ??
* camera
* game
* debug ui
* packet utils
* arch
* input
* profiler
* renderer
* signal handling
* zpl options
* gen/textgen -> assets
* items
* inventory
* crafting
* notifications
* tooltips
* chunk
* blocks
* tiles (and chunk baker)
* systems (core systems)
* components
* net
* packets (but add custom messaging, and security)
* compression
* world
* wrold_view
* entity_view
## Components
-------
* app - thing that runs game
* game - the game stuff, includes client and server
* packet - structure that has data written/read by client/server
* asset - structure that describes tile/block/object/entity, something that can be visualized
* module - a thing that uses a set of ecs components and systems to create a self-contained ecs module
------------
* world - a map of chunks within the game world
* world-view - a representation of the world recreated by the client
----------
* chunk - entity that contains set of tiles and blocks
* tile - basic thing that makes up the chunks
* block - 2nd level of things that make up the chunk
* entity - an grid-independant static or dynamic entity that can exist in the world and has some systems controlling it
primary archetypes:
* item - an entity in the world, that can have a different state when its picked up
* object - an item that can be placed in the world
* device - an object that can be interacted with
* mob - an entity that can be controlled by ai
* player - an entity that can be controlled by a player
* vehicle - an entity that can be used to transport other entities
* craft - a recipe that can be used to craft an item
## Naming
* zpl.eco
* foundation
* sandbox
* survival
* prefix: efd_
## Concepts
* tile
* block
* entity
* item
* object
* device
* mob
* player
* vehicle
* craft
## Transitions
* item -> tile (item destroyed, tile replaced)
* item -> block (item destroyed, block created)
* item -> entity (item hidden and untracked, entity component added) // item becomes entity, just changes state
* item -> item (crafting) (item destroyed, item created)
* tile -> item (tile replaced, item created)
* block -> item (block destroyed, item created)
* block -> block (crafting) (block destroyed, block created)
* entity -> item (entity component removed, item shown and tracked) // entity becomes item, just changes state
## Features
* In-memory lists
* assets
* items
* crafting recepies
* prafabs for entities (pipeline for entities)
* built in server->client RPC
*
// // register game specific input bindings
// // pre-defined bindings and controlsets
// efd_controlset_apply(EFD_ACTION_MOVE, EFD_CONTROLSET_WASD | EFD_CONTROLSET_ARROWS | EFD_CONTROLSET_GAMEPAD_LEFT);
// efd_controlset_apply(EFD_ACTION_POINT, EFD_CONTROLSET_MOUSE | EFD_CONTROLSET_GAMEPAD_RIGHT);
// // custom bindings and controlsets
// efd_controlset_keyboard(CONTROLSET_ACCELERATE, EFD_KEY_DOWN, EFD_KEY_SHIFT_LEFT | EFD_KEY_SHIFT_RIGHT);
// efd_controlset_gamepad(CONTROLSET_ACCELERATE, EFD_GAMEPAD_LEFT_TRIGGER, 0.5f);
// efd_controlset_apply(EFD_ACTION_SPRINT, CONTROLSET_ACCERLATE);
// // custom input bindings for custom actions
// efd_controlset_register(ACTION_USE);
// efd_controlset_keyboard(CONTROLSET_USE, EFD_KEY_DOWN, EFD_KEY_E);
// efd_controlset_gamepad(CONTROLSET_USE, EFD_GAMEPAD_BUTTON_A, 0.5f);
// efd_controlset_apply(ACTION_USE, CONTROLSET_USE);