[RELEASE] u22-v03
This version is submitted to U22 breau.
This commit is contained in:
27
core/loworld/CMakeLists.txt
Normal file
27
core/loworld/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
add_library(loworld
|
||||
chunk.c
|
||||
environment.c
|
||||
generator.c
|
||||
poolset.c
|
||||
store.c
|
||||
template.c
|
||||
view.c
|
||||
)
|
||||
target_link_libraries(loworld
|
||||
msgpackc
|
||||
|
||||
chaos
|
||||
container
|
||||
jukebox
|
||||
math
|
||||
memory
|
||||
mpkutil
|
||||
|
||||
lobullet
|
||||
locharacter
|
||||
locommon
|
||||
loentity
|
||||
loground
|
||||
loresource
|
||||
loshader
|
||||
)
|
159
core/loworld/chunk.c
Normal file
159
core/loworld/chunk.c
Normal file
@@ -0,0 +1,159 @@
|
||||
#include "./chunk.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include "util/container/array.h"
|
||||
#include "util/mpkutil/get.h"
|
||||
#include "util/mpkutil/pack.h"
|
||||
|
||||
#include "core/loentity/entity.h"
|
||||
|
||||
#include "./poolset.h"
|
||||
|
||||
static void loworld_chunk_pack_entities_(
|
||||
const loworld_chunk_t* chunk, msgpack_packer* packer) {
|
||||
assert(chunk != NULL);
|
||||
assert(packer != NULL);
|
||||
|
||||
const size_t len = container_array_get_length(chunk->entities);
|
||||
msgpack_pack_array(packer, len);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
loentity_pack(chunk->entities[i], packer);
|
||||
}
|
||||
}
|
||||
|
||||
const char* loworld_chunk_biome_stringify(loworld_chunk_biome_t biome) {
|
||||
# define each_(NAME, name) \
|
||||
if (biome == LOWORLD_CHUNK_BIOME_##NAME) return #name;
|
||||
|
||||
LOWORLD_CHUNK_BIOME_EACH_(each_);
|
||||
|
||||
assert(false);
|
||||
return NULL;
|
||||
|
||||
# undef each_
|
||||
}
|
||||
|
||||
bool loworld_chunk_biome_unstringify(
|
||||
loworld_chunk_biome_t* biome, const char* str, size_t len) {
|
||||
assert(biome != NULL);
|
||||
assert(str != NULL || len == 0);
|
||||
|
||||
# define each_(NAME, name) do { \
|
||||
if (strncmp(str, #name, len) == 0 && #name[len] == 0) { \
|
||||
*biome = LOWORLD_CHUNK_BIOME_##NAME; \
|
||||
return true; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
LOWORLD_CHUNK_BIOME_EACH_(each_);
|
||||
return false;
|
||||
|
||||
# undef each_
|
||||
}
|
||||
|
||||
void loworld_chunk_initialize(loworld_chunk_t* chunk) {
|
||||
assert(chunk != NULL);
|
||||
|
||||
*chunk = (typeof(*chunk)) {0};
|
||||
}
|
||||
|
||||
void loworld_chunk_deinitialize(loworld_chunk_t* chunk) {
|
||||
if (chunk == NULL) return;
|
||||
|
||||
loworld_chunk_clear(chunk);
|
||||
container_array_delete(chunk->entities);
|
||||
}
|
||||
|
||||
void loworld_chunk_add_entity(loworld_chunk_t* chunk, loentity_t* entity) {
|
||||
assert(chunk != NULL);
|
||||
assert(entity != NULL);
|
||||
|
||||
const size_t index = container_array_get_length(chunk->entities);
|
||||
container_array_insert(chunk->entities, index);
|
||||
chunk->entities[index] = entity;
|
||||
}
|
||||
|
||||
void loworld_chunk_clear(loworld_chunk_t* chunk) {
|
||||
assert(chunk != NULL);
|
||||
|
||||
const size_t len = container_array_get_length(chunk->entities);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
loentity_delete(chunk->entities[i]);
|
||||
}
|
||||
container_array_resize(chunk->entities, 0);
|
||||
}
|
||||
|
||||
void loworld_chunk_pack(const loworld_chunk_t* chunk, msgpack_packer* packer) {
|
||||
assert(chunk != NULL);
|
||||
assert(packer != NULL);
|
||||
|
||||
msgpack_pack_map(packer, 3);
|
||||
|
||||
mpkutil_pack_str(packer, "pos");
|
||||
msgpack_pack_array(packer, 2);
|
||||
msgpack_pack_int32(packer, chunk->pos.x);
|
||||
msgpack_pack_int32(packer, chunk->pos.y);
|
||||
|
||||
mpkutil_pack_str(packer, "biome");
|
||||
mpkutil_pack_str(packer, loworld_chunk_biome_stringify(chunk->biome));
|
||||
|
||||
mpkutil_pack_str(packer, "entities");
|
||||
loworld_chunk_pack_entities_(chunk, packer);
|
||||
}
|
||||
|
||||
bool loworld_chunk_unpack(
|
||||
loworld_chunk_t* chunk,
|
||||
const msgpack_object* obj,
|
||||
const loworld_poolset_t* pools) {
|
||||
assert(chunk != NULL);
|
||||
assert(obj != NULL);
|
||||
assert(pools != NULL);
|
||||
|
||||
const msgpack_object_map* root = mpkutil_get_map(obj);
|
||||
if (root == NULL) return false;
|
||||
|
||||
#define item_(name) mpkutil_get_map_item_by_str(root, name)
|
||||
|
||||
const msgpack_object_array* pos = mpkutil_get_array(item_("pos"));
|
||||
if (pos == NULL || pos->size != 2 ||
|
||||
!mpkutil_get_int32(&pos->ptr[0], &chunk->pos.x) ||
|
||||
!mpkutil_get_int32(&pos->ptr[1], &chunk->pos.y)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* biome;
|
||||
size_t biome_len;
|
||||
if (!mpkutil_get_str(item_("biome"), &biome, &biome_len) ||
|
||||
!loworld_chunk_biome_unstringify(&chunk->biome, biome, biome_len)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const msgpack_object_array* entities = mpkutil_get_array(item_("entities"));
|
||||
if (entities != NULL) {
|
||||
container_array_reserve(chunk->entities, entities->size);
|
||||
for (size_t i = 0; i < entities->size; ++i) {
|
||||
loentity_t* e = loworld_poolset_unpack_entity(pools, &entities->ptr[i]);
|
||||
if (e != NULL) loworld_chunk_add_entity(chunk, e);
|
||||
}
|
||||
}
|
||||
|
||||
#undef item_
|
||||
return true;
|
||||
}
|
||||
|
||||
void loworld_chunk_build_filename(
|
||||
const loworld_chunk_t* chunk, char* filename, size_t length) {
|
||||
assert(chunk != NULL);
|
||||
assert(filename != NULL || length == 0);
|
||||
|
||||
snprintf(filename, length,
|
||||
"%"PRId32"_%"PRId32".msgpack", chunk->pos.x, chunk->pos.y);
|
||||
}
|
98
core/loworld/chunk.h
Normal file
98
core/loworld/chunk.h
Normal file
@@ -0,0 +1,98 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include "util/container/array.h"
|
||||
|
||||
#include "core/loentity/entity.h"
|
||||
|
||||
#include "./poolset.h"
|
||||
|
||||
#define LOWORLD_CHUNK_FILENAME_MAX 64
|
||||
|
||||
/* dont forget to change EACH macro */
|
||||
typedef enum {
|
||||
LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE,
|
||||
LOWORLD_CHUNK_BIOME_CAVIAS_CAMP,
|
||||
LOWORLD_CHUNK_BIOME_LABORATORY,
|
||||
LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD,
|
||||
LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER,
|
||||
LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST,
|
||||
} loworld_chunk_biome_t;
|
||||
|
||||
#define LOWORLD_CHUNK_BIOME_EACH_(PROC) do { \
|
||||
PROC(METAPHYSICAL_GATE, metaphysical-gate); \
|
||||
PROC(CAVIAS_CAMP, cavias-camp); \
|
||||
PROC(LABORATORY, laboratory); \
|
||||
PROC(BOSS_THEISTS_CHILD, boss-theists-child); \
|
||||
PROC(BOSS_BIG_WARDER, boss-big-warder); \
|
||||
PROC(BOSS_GREEDY_SCIENTIST, boss-greedy-scientist); \
|
||||
} while (0)
|
||||
|
||||
typedef struct {
|
||||
struct {
|
||||
int32_t x;
|
||||
int32_t y;
|
||||
} pos;
|
||||
|
||||
loworld_chunk_biome_t biome;
|
||||
|
||||
CONTAINER_ARRAY loentity_t** entities;
|
||||
} loworld_chunk_t;
|
||||
|
||||
const char*
|
||||
loworld_chunk_biome_stringify(
|
||||
loworld_chunk_biome_t biome
|
||||
);
|
||||
|
||||
bool
|
||||
loworld_chunk_biome_unstringify(
|
||||
loworld_chunk_biome_t* biome,
|
||||
const char* str,
|
||||
size_t len
|
||||
);
|
||||
|
||||
void
|
||||
loworld_chunk_initialize(
|
||||
loworld_chunk_t* chunk
|
||||
);
|
||||
|
||||
void
|
||||
loworld_chunk_deinitialize(
|
||||
loworld_chunk_t* chunk
|
||||
);
|
||||
|
||||
void
|
||||
loworld_chunk_add_entity(
|
||||
loworld_chunk_t* chunk,
|
||||
loentity_t* entity /* OWNERSHIP */
|
||||
);
|
||||
|
||||
void
|
||||
loworld_chunk_clear(
|
||||
loworld_chunk_t* chunk
|
||||
);
|
||||
|
||||
void
|
||||
loworld_chunk_pack(
|
||||
const loworld_chunk_t* chunk,
|
||||
msgpack_packer* packer
|
||||
);
|
||||
|
||||
bool
|
||||
loworld_chunk_unpack(
|
||||
loworld_chunk_t* chunk, /* should be cleared */
|
||||
const msgpack_object* obj,
|
||||
const loworld_poolset_t* pools
|
||||
);
|
||||
|
||||
void
|
||||
loworld_chunk_build_filename(
|
||||
const loworld_chunk_t* chunk,
|
||||
char* filename,
|
||||
size_t length
|
||||
);
|
254
core/loworld/environment.c
Normal file
254
core/loworld/environment.c
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "./environment.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/jukebox/amp.h"
|
||||
#include "util/jukebox/decoder.h"
|
||||
#include "util/math/rational.h"
|
||||
|
||||
#include "core/locommon/easing.h"
|
||||
#include "core/locommon/ticker.h"
|
||||
#include "core/loplayer/event.h"
|
||||
#include "core/loplayer/player.h"
|
||||
#include "core/loresource/music.h"
|
||||
#include "core/loresource/set.h"
|
||||
#include "core/loresource/text.h"
|
||||
#include "core/loshader/set.h"
|
||||
#include "core/loshader/backwall.h"
|
||||
#include "core/loshader/fog.h"
|
||||
|
||||
#include "./view.h"
|
||||
|
||||
static const char* loworld_environment_get_chunk_name_(
|
||||
loresource_language_t lang, loworld_chunk_biome_t b) {
|
||||
switch (b) {
|
||||
case LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE:
|
||||
return loresource_text_get(lang, "biome_metaphysical_gate");
|
||||
case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP:
|
||||
return loresource_text_get(lang, "biome_cavias_camp");
|
||||
case LOWORLD_CHUNK_BIOME_LABORATORY:
|
||||
return loresource_text_get(lang, "biome_laboratory");
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD:
|
||||
return loresource_text_get(lang, "biome_boss_theists_child");
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER:
|
||||
return loresource_text_get(lang, "biome_boss_big_warder");
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST:
|
||||
return loresource_text_get(lang, "biome_boss_greedy_scientist");
|
||||
}
|
||||
assert(false);
|
||||
return "unknown biome";
|
||||
}
|
||||
|
||||
static loshader_backwall_type_t loworld_environment_get_backwall_type_(
|
||||
loworld_chunk_biome_t b) {
|
||||
switch (b) {
|
||||
case LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE:
|
||||
return LOSHADER_BACKWALL_TYPE_INFINITE_BOXES;
|
||||
case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP:
|
||||
return LOSHADER_BACKWALL_TYPE_HOLLOW_MOUNTAINS;
|
||||
case LOWORLD_CHUNK_BIOME_LABORATORY:
|
||||
return LOSHADER_BACKWALL_TYPE_FABRIC;
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD:
|
||||
return LOSHADER_BACKWALL_TYPE_HOLLOW_MOUNTAINS_RED;
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER:
|
||||
return LOSHADER_BACKWALL_TYPE_JAIL;
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST:
|
||||
return LOSHADER_BACKWALL_TYPE_INFINITE_BOXES;
|
||||
}
|
||||
assert(false);
|
||||
return LOSHADER_BACKWALL_TYPE_WHITE;
|
||||
}
|
||||
|
||||
static loshader_fog_type_t loworld_environment_get_fog_type_(
|
||||
loworld_chunk_biome_t b) {
|
||||
switch (b) {
|
||||
case LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE:
|
||||
case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP:
|
||||
case LOWORLD_CHUNK_BIOME_LABORATORY:
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD:
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER:
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST:
|
||||
return LOSHADER_FOG_TYPE_WHITE_CLOUD;
|
||||
}
|
||||
assert(false);
|
||||
return LOSHADER_FOG_TYPE_NONE;
|
||||
}
|
||||
|
||||
static loresource_music_player_t* loworld_environment_get_music_(
|
||||
loworld_chunk_biome_t b, loresource_music_t* m) {
|
||||
switch (b) {
|
||||
case LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE:
|
||||
return &m->biome_metaphysical_gate;
|
||||
case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP:
|
||||
return &m->biome_cavias_camp;
|
||||
case LOWORLD_CHUNK_BIOME_LABORATORY:
|
||||
return &m->biome_laboratory;
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD:
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER:
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST:
|
||||
return &m->biome_boss;
|
||||
}
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void loworld_environment_stop_music_(loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
if (env->music != NULL && env->music_control) {
|
||||
jukebox_amp_change_volume(&env->music->amp, 0, &rational(1, 1));
|
||||
jukebox_decoder_stop_after(env->music->decoder, &rational(1, 1));
|
||||
}
|
||||
env->music = NULL;
|
||||
}
|
||||
|
||||
static void loworld_environment_update_hud_(loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
|
||||
if (env->transition > 0) return;
|
||||
|
||||
loplayer_hud_set_biome_text(
|
||||
env->player->hud,
|
||||
loworld_environment_get_chunk_name_(env->res->lang, env->biome));
|
||||
}
|
||||
|
||||
static void loworld_environment_update_backwall_(loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
|
||||
loshader_backwall_type_t prev = env->backwall.prev_type;
|
||||
|
||||
if (env->transition == 0) prev = env->backwall.type;
|
||||
|
||||
env->backwall = (loshader_backwall_drawer_param_t) {
|
||||
.prev_type = prev,
|
||||
.type = LOSHADER_BACKWALL_TYPE_WHITE,
|
||||
.transition = env->transition,
|
||||
};
|
||||
if (!env->config.disable_heavy_backwall) {
|
||||
env->backwall.type = loworld_environment_get_backwall_type_(env->biome);
|
||||
}
|
||||
}
|
||||
|
||||
static void loworld_environment_update_fog_(loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
|
||||
if (env->transition == 0) env->fog.prev_type = env->fog.type;
|
||||
|
||||
env->fog.type = LOSHADER_FOG_TYPE_NONE;
|
||||
if (!env->config.disable_heavy_fog) {
|
||||
env->fog.type = loworld_environment_get_fog_type_(env->biome);
|
||||
}
|
||||
env->fog.transition = env->transition;
|
||||
|
||||
/* ---- bounds fog ---- */
|
||||
const loplayer_event_param_t* e =
|
||||
loplayer_event_get_param(env->player->event);
|
||||
if (e != NULL && vec2_pow_length(&e->area_size) > 0) {
|
||||
env->fog.bounds_pos = e->area_pos;
|
||||
env->fog.bounds_size = e->area_size;
|
||||
|
||||
locommon_easing_smooth_float(
|
||||
&env->fog.bounds_fog, 1, env->ticker->delta_f);
|
||||
} else {
|
||||
locommon_easing_smooth_float(
|
||||
&env->fog.bounds_fog, 0, env->ticker->delta_f);
|
||||
}
|
||||
}
|
||||
|
||||
static void loworld_environment_update_music_(loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
|
||||
bool control = true;
|
||||
loresource_music_player_t* music =
|
||||
loworld_environment_get_music_(env->biome, &env->res->music);
|
||||
|
||||
const loplayer_event_param_t* e =
|
||||
loplayer_event_get_param(env->player->event);
|
||||
if (e != NULL) {
|
||||
music = e->music;
|
||||
control = false;
|
||||
|
||||
if (!env->sound_attenuation) {
|
||||
loresource_sound_change_master_volume(
|
||||
env->res->sound, .2f, &rational(1, 1));
|
||||
env->sound_attenuation = true;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (env->sound_attenuation) {
|
||||
loresource_sound_change_master_volume(
|
||||
env->res->sound, 1, &rational(1, 1));
|
||||
env->sound_attenuation = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (music != env->music) {
|
||||
loworld_environment_stop_music_(env);
|
||||
env->music = music;
|
||||
env->music_control = control;
|
||||
if (env->music != NULL && env->music_control) {
|
||||
jukebox_amp_change_volume(&env->music->amp, .6f, &rational(1, 1));
|
||||
jukebox_decoder_resume(env->music->decoder, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_environment_initialize(
|
||||
loworld_environment_t* env,
|
||||
loresource_set_t* res,
|
||||
loshader_set_t* shaders,
|
||||
const locommon_ticker_t* ticker,
|
||||
const loworld_view_t* view,
|
||||
loplayer_t* player,
|
||||
const loworld_environment_config_t* config) {
|
||||
assert(env != NULL);
|
||||
assert(res != NULL);
|
||||
assert(shaders != NULL);
|
||||
assert(ticker != NULL);
|
||||
assert(view != NULL);
|
||||
assert(player != NULL);
|
||||
assert(config != NULL);
|
||||
|
||||
*env = (typeof(*env)) {
|
||||
.res = res,
|
||||
.shaders = shaders,
|
||||
.ticker = ticker,
|
||||
.view = view,
|
||||
.player = player,
|
||||
|
||||
.config = *config,
|
||||
};
|
||||
}
|
||||
|
||||
void loworld_environment_deinitialize(loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
|
||||
loworld_environment_stop_music_(env);
|
||||
}
|
||||
|
||||
void loworld_environment_update(loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
|
||||
const loworld_chunk_t* chunk = loworld_view_get_looking_chunk(env->view);
|
||||
|
||||
if (env->transition == 1 && env->biome != chunk->biome) {
|
||||
env->biome = chunk->biome;
|
||||
env->transition = 0;
|
||||
}
|
||||
loworld_environment_update_hud_(env);
|
||||
loworld_environment_update_backwall_(env);
|
||||
loworld_environment_update_fog_(env);
|
||||
loworld_environment_update_music_(env);
|
||||
|
||||
locommon_easing_linear_float(&env->transition, 1, env->ticker->delta_f);
|
||||
}
|
||||
|
||||
void loworld_environment_draw(const loworld_environment_t* env) {
|
||||
assert(env != NULL);
|
||||
|
||||
loshader_backwall_drawer_set_param(
|
||||
env->shaders->drawer.backwall, &env->backwall);
|
||||
loshader_fog_drawer_set_param(
|
||||
env->shaders->drawer.fog, &env->fog);
|
||||
}
|
66
core/loworld/environment.h
Normal file
66
core/loworld/environment.h
Normal file
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "core/locommon/ticker.h"
|
||||
#include "core/loplayer/player.h"
|
||||
#include "core/loresource/music.h"
|
||||
#include "core/loresource/set.h"
|
||||
#include "core/loshader/set.h"
|
||||
|
||||
#include "./view.h"
|
||||
|
||||
typedef struct {
|
||||
bool disable_heavy_backwall;
|
||||
bool disable_heavy_fog;
|
||||
} loworld_environment_config_t;
|
||||
|
||||
typedef struct {
|
||||
/* injected deps */
|
||||
loresource_set_t* res;
|
||||
loshader_set_t* shaders;
|
||||
const locommon_ticker_t* ticker;
|
||||
const loworld_view_t* view;
|
||||
loplayer_t* player;
|
||||
|
||||
/* immutable params */
|
||||
loworld_environment_config_t config;
|
||||
|
||||
/* read-only mutable params */
|
||||
float transition;
|
||||
loworld_chunk_biome_t biome;
|
||||
|
||||
loresource_music_player_t* music;
|
||||
bool music_control;
|
||||
bool sound_attenuation;
|
||||
|
||||
loshader_backwall_drawer_param_t backwall;
|
||||
loshader_fog_drawer_param_t fog;
|
||||
} loworld_environment_t;
|
||||
|
||||
void
|
||||
loworld_environment_initialize(
|
||||
loworld_environment_t* env,
|
||||
loresource_set_t* res,
|
||||
loshader_set_t* shaders,
|
||||
const locommon_ticker_t* ticker,
|
||||
const loworld_view_t* view,
|
||||
loplayer_t* player,
|
||||
const loworld_environment_config_t* config
|
||||
);
|
||||
|
||||
void
|
||||
loworld_environment_deinitialize(
|
||||
loworld_environment_t* env
|
||||
);
|
||||
|
||||
void
|
||||
loworld_environment_update(
|
||||
loworld_environment_t* env
|
||||
);
|
||||
|
||||
void
|
||||
loworld_environment_draw(
|
||||
const loworld_environment_t* env
|
||||
);
|
245
core/loworld/generator.c
Normal file
245
core/loworld/generator.c
Normal file
@@ -0,0 +1,245 @@
|
||||
#include "./generator.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include "util/chaos/xorshift.h"
|
||||
#include "util/math/algorithm.h"
|
||||
#include "util/memory/memory.h"
|
||||
#include "util/mpkutil/get.h"
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./poolset.h"
|
||||
#include "./template.h"
|
||||
|
||||
struct loworld_generator_t {
|
||||
/* injected deps */
|
||||
const loworld_poolset_t* pools;
|
||||
|
||||
/* parameters */
|
||||
uint64_t seed;
|
||||
};
|
||||
|
||||
#define LOWORLD_GENERATOR_BLOCK_SIZE 8
|
||||
|
||||
static uint64_t loworld_generator_rand_(
|
||||
const loworld_generator_t* gen, int32_t x, int32_t y) {
|
||||
assert(gen != NULL);
|
||||
|
||||
const uint64_t ux = (uint64_t) x - INT32_MIN;
|
||||
const uint64_t uy = (uint64_t) y - INT32_MIN;
|
||||
|
||||
/* multiply prime numbers */
|
||||
return ux*400206850629133 + uy*890206850629189 + gen->seed;
|
||||
}
|
||||
|
||||
static loworld_chunk_biome_t loworld_generator_decide_chunk_biome_(
|
||||
const loworld_generator_t* gen, int32_t x, int32_t y) {
|
||||
assert(gen != NULL);
|
||||
|
||||
static const loworld_chunk_biome_t base_biomes[] = {
|
||||
LOWORLD_CHUNK_BIOME_CAVIAS_CAMP,
|
||||
LOWORLD_CHUNK_BIOME_LABORATORY,
|
||||
};
|
||||
static const size_t base_biomes_length =
|
||||
sizeof(base_biomes)/sizeof(base_biomes[0]);
|
||||
|
||||
/* random seed which depends the block */
|
||||
uint64_t bs = loworld_generator_rand_(gen, x/LOWORLD_GENERATOR_BLOCK_SIZE, y);
|
||||
const loworld_chunk_biome_t base =
|
||||
base_biomes[(bs = chaos_xorshift(bs))%base_biomes_length];
|
||||
|
||||
uint64_t fx = x + (y == 0? 0: loworld_generator_rand_(gen, 0, y));
|
||||
fx = MATH_ABS(fx)%LOWORLD_GENERATOR_BLOCK_SIZE;
|
||||
|
||||
if (fx == 0) return LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE;
|
||||
if (fx == LOWORLD_GENERATOR_BLOCK_SIZE/2) {
|
||||
switch (base) {
|
||||
case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP:
|
||||
return LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD;
|
||||
case LOWORLD_CHUNK_BIOME_LABORATORY:
|
||||
return x%2?
|
||||
LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER:
|
||||
LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
return base;
|
||||
}
|
||||
|
||||
static void loworld_generator_generate_for_metaphysical_gate_(
|
||||
const loworld_generator_t* gen, loworld_chunk_t* chunk) {
|
||||
assert(gen != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
const loworld_template_building_param_t param = {
|
||||
.target = chunk,
|
||||
.pools = gen->pools,
|
||||
.seed = loworld_generator_rand_(gen, chunk->pos.x, chunk->pos.y),
|
||||
};
|
||||
loworld_template_metaphysical_gate_build_chunk(¶m);
|
||||
}
|
||||
|
||||
static void loworld_generator_generate_for_cavias_camp_(
|
||||
const loworld_generator_t* gen, loworld_chunk_t* chunk) {
|
||||
assert(gen != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
static void (*funcs[])(const loworld_template_building_param_t* p) = {
|
||||
loworld_template_open_space_build_chunk,
|
||||
loworld_template_broken_open_space_build_chunk,
|
||||
loworld_template_passage_build_chunk,
|
||||
loworld_template_broken_passage_build_chunk,
|
||||
};
|
||||
static const size_t funcs_len = sizeof(funcs)/sizeof(funcs[0]);
|
||||
|
||||
uint64_t s = loworld_generator_rand_(gen, chunk->pos.x, chunk->pos.y);
|
||||
|
||||
const uint64_t r = (s = chaos_xorshift(s))%funcs_len;
|
||||
|
||||
const loworld_template_building_param_t param = {
|
||||
.target = chunk,
|
||||
.pools = gen->pools,
|
||||
.seed = chaos_xorshift(s),
|
||||
};
|
||||
return funcs[r](¶m);
|
||||
}
|
||||
|
||||
static void loworld_generator_generate_for_laboratory_(
|
||||
const loworld_generator_t* gen, loworld_chunk_t* chunk) {
|
||||
assert(gen != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
static void (*funcs[])(const loworld_template_building_param_t* p) = {
|
||||
loworld_template_passage_build_chunk,
|
||||
loworld_template_broken_passage_build_chunk,
|
||||
loworld_template_stairs_build_chunk,
|
||||
};
|
||||
static const size_t funcs_len = sizeof(funcs)/sizeof(funcs[0]);
|
||||
|
||||
uint64_t s = loworld_generator_rand_(gen, chunk->pos.x, chunk->pos.y);
|
||||
|
||||
const uint64_t r = (s = chaos_xorshift(s))%funcs_len;
|
||||
|
||||
const loworld_template_building_param_t param = {
|
||||
.target = chunk,
|
||||
.pools = gen->pools,
|
||||
.seed = chaos_xorshift(s),
|
||||
};
|
||||
return funcs[r](¶m);
|
||||
}
|
||||
|
||||
static void loworld_generator_generate_for_boss_theists_child_(
|
||||
const loworld_generator_t* gen, loworld_chunk_t* chunk) {
|
||||
assert(gen != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
const loworld_template_building_param_t param = {
|
||||
.target = chunk,
|
||||
.pools = gen->pools,
|
||||
.seed = loworld_generator_rand_(gen, chunk->pos.x, chunk->pos.y),
|
||||
};
|
||||
loworld_template_boss_theists_child_build_chunk(¶m);
|
||||
}
|
||||
|
||||
static void loworld_generator_generate_for_boss_big_warder_(
|
||||
const loworld_generator_t* gen, loworld_chunk_t* chunk) {
|
||||
assert(gen != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
const loworld_template_building_param_t param = {
|
||||
.target = chunk,
|
||||
.pools = gen->pools,
|
||||
.seed = loworld_generator_rand_(gen, chunk->pos.x, chunk->pos.y),
|
||||
};
|
||||
loworld_template_boss_big_warder_build_chunk(¶m);
|
||||
}
|
||||
|
||||
static void loworld_generator_generate_for_boss_greedy_scientist_(
|
||||
const loworld_generator_t* gen, loworld_chunk_t* chunk) {
|
||||
assert(gen != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
const loworld_template_building_param_t param = {
|
||||
.target = chunk,
|
||||
.pools = gen->pools,
|
||||
.seed = loworld_generator_rand_(gen, chunk->pos.x, chunk->pos.y),
|
||||
};
|
||||
loworld_template_boss_greedy_scientist_build_chunk(¶m);
|
||||
}
|
||||
|
||||
loworld_generator_t* loworld_generator_new(
|
||||
const loworld_poolset_t* pools, uint64_t seed) {
|
||||
assert(pools != NULL);
|
||||
|
||||
loworld_generator_t* gen = memory_new(sizeof(*gen));
|
||||
*gen = (typeof(*gen)) {
|
||||
.pools = pools,
|
||||
};
|
||||
loworld_generator_randomize(gen, seed);
|
||||
return gen;
|
||||
}
|
||||
|
||||
void loworld_generator_delete(loworld_generator_t* gen) {
|
||||
assert(gen != NULL);
|
||||
|
||||
memory_delete(gen);
|
||||
}
|
||||
|
||||
void loworld_generator_randomize(loworld_generator_t* gen, uint64_t seed) {
|
||||
assert(gen != NULL);
|
||||
|
||||
gen->seed = seed;
|
||||
}
|
||||
|
||||
void loworld_generator_generate(
|
||||
const loworld_generator_t* gen, loworld_chunk_t* chunk) {
|
||||
assert(gen != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
chunk->biome =
|
||||
loworld_generator_decide_chunk_biome_(gen, chunk->pos.x, chunk->pos.y);
|
||||
|
||||
switch (chunk->biome) {
|
||||
case LOWORLD_CHUNK_BIOME_METAPHYSICAL_GATE:
|
||||
loworld_generator_generate_for_metaphysical_gate_(gen, chunk);
|
||||
break;
|
||||
case LOWORLD_CHUNK_BIOME_CAVIAS_CAMP:
|
||||
loworld_generator_generate_for_cavias_camp_(gen, chunk);
|
||||
break;
|
||||
case LOWORLD_CHUNK_BIOME_LABORATORY:
|
||||
loworld_generator_generate_for_laboratory_(gen, chunk);
|
||||
break;
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_THEISTS_CHILD:
|
||||
loworld_generator_generate_for_boss_theists_child_(gen, chunk);
|
||||
break;
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_BIG_WARDER:
|
||||
loworld_generator_generate_for_boss_big_warder_(gen, chunk);
|
||||
break;
|
||||
case LOWORLD_CHUNK_BIOME_BOSS_GREEDY_SCIENTIST:
|
||||
loworld_generator_generate_for_boss_greedy_scientist_(gen, chunk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_generator_pack(
|
||||
const loworld_generator_t* gen, msgpack_packer* packer) {
|
||||
assert(gen != NULL);
|
||||
assert(packer != NULL);
|
||||
|
||||
msgpack_pack_uint64(packer, gen->seed);
|
||||
}
|
||||
|
||||
bool loworld_generator_unpack(
|
||||
loworld_generator_t* gen, const msgpack_object* obj) {
|
||||
assert(gen != NULL);
|
||||
assert(obj != NULL);
|
||||
|
||||
uint64_t seed;
|
||||
if (!mpkutil_get_uint64(obj, &seed)) return false;
|
||||
|
||||
loworld_generator_randomize(gen, seed);
|
||||
return true;
|
||||
}
|
47
core/loworld/generator.h
Normal file
47
core/loworld/generator.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./poolset.h"
|
||||
|
||||
struct loworld_generator_t;
|
||||
typedef struct loworld_generator_t loworld_generator_t;
|
||||
|
||||
loworld_generator_t*
|
||||
loworld_generator_new(
|
||||
const loworld_poolset_t* pools,
|
||||
uint64_t seed
|
||||
);
|
||||
|
||||
void
|
||||
loworld_generator_delete(
|
||||
loworld_generator_t* gen
|
||||
);
|
||||
|
||||
void
|
||||
loworld_generator_randomize(
|
||||
loworld_generator_t* gen,
|
||||
uint64_t seed
|
||||
);
|
||||
|
||||
void
|
||||
loworld_generator_generate(
|
||||
const loworld_generator_t* gen,
|
||||
loworld_chunk_t* chunk
|
||||
);
|
||||
|
||||
void
|
||||
loworld_generator_pack(
|
||||
const loworld_generator_t* gen,
|
||||
msgpack_packer* packer
|
||||
);
|
||||
|
||||
bool
|
||||
loworld_generator_unpack(
|
||||
loworld_generator_t* gen,
|
||||
const msgpack_object* obj
|
||||
);
|
38
core/loworld/poolset.c
Normal file
38
core/loworld/poolset.c
Normal file
@@ -0,0 +1,38 @@
|
||||
#include "./poolset.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
#include <msgpack/sbuffer.h>
|
||||
|
||||
#include "core/lobullet/pool.h"
|
||||
#include "core/locharacter/pool.h"
|
||||
#include "core/loground/pool.h"
|
||||
|
||||
#include "./test.h"
|
||||
|
||||
loentity_t* loworld_poolset_unpack_entity(
|
||||
const loworld_poolset_t* pools, const msgpack_object* obj) {
|
||||
assert(pools != NULL);
|
||||
assert(obj != NULL);
|
||||
|
||||
loentity_t* e;
|
||||
|
||||
e = (typeof(e)) loground_pool_unpack_item(pools->ground, obj);
|
||||
if (e != NULL) return e;
|
||||
|
||||
e = (typeof(e)) lobullet_pool_unpack_item(pools->bullet, obj);
|
||||
if (e != NULL) return e;
|
||||
|
||||
e = (typeof(e)) locharacter_pool_unpack_item(pools->character, obj);
|
||||
if (e != NULL) return e;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void loworld_poolset_test_packing(const loworld_poolset_t* pools) {
|
||||
assert(pools != NULL);
|
||||
|
||||
loworld_test_packing(pools);
|
||||
}
|
29
core/loworld/poolset.h
Normal file
29
core/loworld/poolset.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
|
||||
#include "core/lobullet/pool.h"
|
||||
#include "core/locharacter/pool.h"
|
||||
#include "core/loground/pool.h"
|
||||
|
||||
typedef struct {
|
||||
loground_pool_t* ground;
|
||||
lobullet_pool_t* bullet;
|
||||
locharacter_pool_t* character;
|
||||
} loworld_poolset_t;
|
||||
|
||||
/* Initialize and Deinitialize each member manually
|
||||
* because of a dependency issue. */
|
||||
|
||||
loentity_t* /* NULLABLE/OWNERSHIP */
|
||||
loworld_poolset_unpack_entity(
|
||||
const loworld_poolset_t* pools,
|
||||
const msgpack_object* obj
|
||||
);
|
||||
|
||||
void
|
||||
loworld_poolset_test_packing(
|
||||
const loworld_poolset_t* pools
|
||||
);
|
265
core/loworld/store.c
Normal file
265
core/loworld/store.c
Normal file
@@ -0,0 +1,265 @@
|
||||
#include "./store.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
#include <msgpack/fbuffer.h>
|
||||
|
||||
#include "util/memory/memory.h"
|
||||
#include "util/mpkutil/file.h"
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./generator.h"
|
||||
#include "./poolset.h"
|
||||
|
||||
#define LOWORLD_STORE_PATH_MAX_LENGTH 256
|
||||
#define LOWORLD_STORE_UNPACKER_BUFFER_SIZE (1024*1024)
|
||||
|
||||
typedef struct {
|
||||
loworld_chunk_t data;
|
||||
|
||||
bool loaded;
|
||||
bool used;
|
||||
|
||||
uint64_t last_tick;
|
||||
} loworld_store_chunk_t;
|
||||
|
||||
struct loworld_store_t {
|
||||
char path[LOWORLD_STORE_PATH_MAX_LENGTH+LOWORLD_CHUNK_FILENAME_MAX];
|
||||
size_t basepath_length;
|
||||
|
||||
const loworld_poolset_t* pools;
|
||||
const loworld_generator_t* generator;
|
||||
|
||||
msgpack_unpacker unpacker;
|
||||
msgpack_unpacked unpacked;
|
||||
|
||||
uint64_t tick;
|
||||
bool error;
|
||||
|
||||
size_t chunks_length;
|
||||
loworld_store_chunk_t chunks[1];
|
||||
};
|
||||
|
||||
static bool loworld_store_find_chunk_index_(
|
||||
const loworld_store_t* store, size_t* index, int32_t x, int32_t y) {
|
||||
assert(store != NULL);
|
||||
assert(index != NULL);
|
||||
|
||||
for (size_t i = 0; i < store->chunks_length; ++i) {
|
||||
if (!store->chunks[i].loaded) continue;
|
||||
|
||||
const loworld_chunk_t* chunk = &store->chunks[i].data;
|
||||
if (chunk->pos.x == x && chunk->pos.y == y) {
|
||||
*index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool loworld_store_find_unused_chunk_index_(
|
||||
const loworld_store_t* store, size_t* index) {
|
||||
assert(store != NULL);
|
||||
assert(index != NULL);
|
||||
|
||||
for (size_t i = 0; i < store->chunks_length; ++i) {
|
||||
if (!store->chunks[i].loaded) {
|
||||
*index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
uint64_t oldest = UINT64_MAX;
|
||||
for (size_t i = 0; i < store->chunks_length; ++i) {
|
||||
const loworld_store_chunk_t* chunk = &store->chunks[i];
|
||||
if (!chunk->used && chunk->last_tick <= oldest) {
|
||||
*index = i;
|
||||
oldest = chunk->last_tick;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/* Builds filename on the store->path as zero-terminated string. */
|
||||
static void loworld_store_build_chunk_filename_(
|
||||
loworld_store_t* store, const loworld_chunk_t* chunk) {
|
||||
assert(store != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
loworld_chunk_build_filename(chunk,
|
||||
&store->path[store->basepath_length], LOWORLD_CHUNK_FILENAME_MAX);
|
||||
}
|
||||
|
||||
static bool loworld_store_load_chunk_from_file_(
|
||||
loworld_store_t* store, loworld_chunk_t* chunk) {
|
||||
assert(store != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
loworld_store_build_chunk_filename_(store, chunk);
|
||||
|
||||
FILE* fp = fopen(store->path, "rb");
|
||||
if (fp == NULL) return false;
|
||||
|
||||
bool success = false;
|
||||
|
||||
msgpack_unpacker_reset(&store->unpacker);
|
||||
if (mpkutil_file_unpack_with_unpacker(
|
||||
&store->unpacked, fp, &store->unpacker)) {
|
||||
loworld_chunk_clear(chunk);
|
||||
success = loworld_chunk_unpack(chunk, &store->unpacked.data, store->pools);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
if (!success) {
|
||||
fprintf(stderr,
|
||||
"failed to load chunk (%"PRId32", %"PRId32")\n",
|
||||
chunk->pos.x, chunk->pos.y);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool loworld_store_save_chunk_to_file_(
|
||||
loworld_store_t* store, const loworld_chunk_t* chunk) {
|
||||
assert(store != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
loworld_store_build_chunk_filename_(store, chunk);
|
||||
|
||||
FILE* fp = fopen(store->path, "wb");
|
||||
if (fp == NULL) return false;
|
||||
|
||||
msgpack_packer packer;
|
||||
msgpack_packer_init(&packer, fp, msgpack_fbuffer_write);
|
||||
|
||||
loworld_chunk_pack(chunk, &packer);
|
||||
|
||||
const bool success = (ferror(fp) == 0);
|
||||
fclose(fp);
|
||||
return success;
|
||||
}
|
||||
|
||||
loworld_store_t* loworld_store_new(
|
||||
const loworld_poolset_t* pools,
|
||||
const loworld_generator_t* generator,
|
||||
size_t chunks_length,
|
||||
const char* basepath,
|
||||
size_t basepath_length) {
|
||||
assert(pools != NULL);
|
||||
assert(generator != NULL);
|
||||
assert(chunks_length > 0);
|
||||
|
||||
if (basepath_length >= LOWORLD_STORE_PATH_MAX_LENGTH) {
|
||||
fprintf(stderr, "too long path name\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
loworld_store_t* store = memory_new(
|
||||
sizeof(*store) + (chunks_length-1)*sizeof(store->chunks[0]));
|
||||
*store = (typeof(*store)) {
|
||||
.basepath_length = basepath_length,
|
||||
.pools = pools,
|
||||
.generator = generator,
|
||||
.chunks_length = chunks_length,
|
||||
};
|
||||
strncpy(store->path, basepath, LOWORLD_STORE_PATH_MAX_LENGTH);
|
||||
|
||||
if (!msgpack_unpacker_init(
|
||||
&store->unpacker, LOWORLD_STORE_UNPACKER_BUFFER_SIZE)) {
|
||||
fprintf(stderr, "failed to initialize unpacker\n");
|
||||
abort();
|
||||
}
|
||||
msgpack_unpacked_init(&store->unpacked);
|
||||
|
||||
for (size_t i = 0; i < store->chunks_length; ++i) {
|
||||
loworld_store_chunk_t* chunk = &store->chunks[i];
|
||||
*chunk = (typeof(*chunk)) {0};
|
||||
loworld_chunk_initialize(&chunk->data);
|
||||
}
|
||||
return store;
|
||||
}
|
||||
|
||||
void loworld_store_delete(loworld_store_t* store) {
|
||||
if (store == NULL) return;
|
||||
|
||||
msgpack_unpacker_destroy(&store->unpacker);
|
||||
msgpack_unpacked_destroy(&store->unpacked);
|
||||
|
||||
for (size_t i = 0; i < store->chunks_length; ++i) {
|
||||
loworld_chunk_deinitialize(&store->chunks[i].data);
|
||||
}
|
||||
memory_delete(store);
|
||||
}
|
||||
|
||||
loworld_chunk_t* loworld_store_load_chunk(
|
||||
loworld_store_t* store, int32_t chunk_x, int32_t chunk_y) {
|
||||
assert(store != NULL);
|
||||
|
||||
size_t index;
|
||||
if (!loworld_store_find_chunk_index_(store, &index, chunk_x, chunk_y)) {
|
||||
if (!loworld_store_find_unused_chunk_index_(store, &index)) {
|
||||
fprintf(stderr, "world store chunk overflow\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
loworld_store_chunk_t* chunk = &store->chunks[index];
|
||||
|
||||
if (chunk->loaded &&
|
||||
(chunk->data.pos.x != chunk_x || chunk->data.pos.y != chunk_y)) {
|
||||
assert(!chunk->used);
|
||||
store->error = !loworld_store_save_chunk_to_file_(store, &chunk->data);
|
||||
chunk->loaded = false;
|
||||
}
|
||||
if (!chunk->loaded) {
|
||||
chunk->data.pos.x = chunk_x;
|
||||
chunk->data.pos.y = chunk_y;
|
||||
|
||||
if (!loworld_store_load_chunk_from_file_(store, &chunk->data)) {
|
||||
loworld_chunk_clear(&chunk->data);
|
||||
loworld_generator_generate(store->generator, &chunk->data);
|
||||
}
|
||||
chunk->loaded = true;
|
||||
}
|
||||
|
||||
chunk->used = true;
|
||||
chunk->last_tick = store->tick++;
|
||||
return &chunk->data;
|
||||
}
|
||||
|
||||
void loworld_store_unload_chunk(
|
||||
loworld_store_t* store, loworld_chunk_t* chunk) {
|
||||
assert(store != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
loworld_store_chunk_t* c = (typeof(c)) chunk;
|
||||
assert(store->chunks <= c && c < store->chunks+store->chunks_length);
|
||||
|
||||
c->used = false;
|
||||
}
|
||||
|
||||
void loworld_store_flush(loworld_store_t* store) {
|
||||
assert(store != NULL);
|
||||
|
||||
for (size_t i = 0; i < store->chunks_length; ++i) {
|
||||
loworld_store_chunk_t* chunk = &store->chunks[i];
|
||||
if (!chunk->loaded) continue;
|
||||
|
||||
store->error = !loworld_store_save_chunk_to_file_(store, &chunk->data);
|
||||
}
|
||||
}
|
||||
|
||||
bool loworld_store_is_error_happened(const loworld_store_t* store) {
|
||||
assert(store != NULL);
|
||||
|
||||
return store->error;
|
||||
}
|
52
core/loworld/store.h
Normal file
52
core/loworld/store.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./generator.h"
|
||||
#include "./poolset.h"
|
||||
|
||||
struct loworld_store_t;
|
||||
typedef struct loworld_store_t loworld_store_t;
|
||||
|
||||
/* TODO(catfoot): make it possible to specify a path to chunk dir */
|
||||
loworld_store_t* /* OWNERSHIP */
|
||||
loworld_store_new(
|
||||
const loworld_poolset_t* pools,
|
||||
const loworld_generator_t* gen,
|
||||
size_t chunks_length,
|
||||
const char* basepath, /* must be terminated with slash */
|
||||
size_t basepath_length
|
||||
);
|
||||
|
||||
void
|
||||
loworld_store_delete(
|
||||
loworld_store_t* store /* OWNERSHIP */
|
||||
);
|
||||
|
||||
loworld_chunk_t* /* NULLABLE */
|
||||
loworld_store_load_chunk(
|
||||
loworld_store_t* store,
|
||||
int32_t chunk_x,
|
||||
int32_t chunk_y
|
||||
);
|
||||
|
||||
void
|
||||
loworld_store_unload_chunk(
|
||||
loworld_store_t* store,
|
||||
loworld_chunk_t* chunk
|
||||
);
|
||||
|
||||
/* If there is an instance of loworld_view_t, this function may flush broken
|
||||
chunks. So use loworld_view_flush_store function insteadly. */
|
||||
void
|
||||
loworld_store_flush(
|
||||
loworld_store_t* store
|
||||
);
|
||||
|
||||
bool
|
||||
loworld_store_is_error_happened(
|
||||
const loworld_store_t* store
|
||||
);
|
287
core/loworld/template.c
Normal file
287
core/loworld/template.c
Normal file
@@ -0,0 +1,287 @@
|
||||
#include "./template.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "util/chaos/xorshift.h"
|
||||
#include "util/math/algorithm.h"
|
||||
#include "util/math/vector.h"
|
||||
|
||||
#include "core/locharacter/base.h"
|
||||
#include "core/locharacter/big_warder.h"
|
||||
#include "core/locharacter/cavia.h"
|
||||
#include "core/locharacter/encephalon.h"
|
||||
#include "core/locharacter/scientist.h"
|
||||
#include "core/locharacter/greedy_scientist.h"
|
||||
#include "core/locharacter/theists_child.h"
|
||||
#include "core/locharacter/warder.h"
|
||||
#include "core/locommon/position.h"
|
||||
#include "core/loentity/entity.h"
|
||||
#include "core/loground/base.h"
|
||||
#include "core/loground/island.h"
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./poolset.h"
|
||||
|
||||
static loentity_id_t loworld_template_add_ground_island_(
|
||||
const loworld_template_building_param_t* param,
|
||||
const vec2_t* pos,
|
||||
const vec2_t* sz) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
assert(vec2_valid(pos));
|
||||
assert(vec2_valid(sz));
|
||||
assert(sz->x >= 0 && sz->y >= 0);
|
||||
|
||||
const locommon_position_t p = locommon_position(
|
||||
param->target->pos.x, param->target->pos.y, *pos);
|
||||
|
||||
loground_base_t* island = loground_pool_create(param->pools->ground);
|
||||
loground_island_build(island, &p, sz);
|
||||
loworld_chunk_add_entity(param->target, &island->super.super);
|
||||
return island->super.super.id;
|
||||
}
|
||||
|
||||
static loentity_id_t loworld_template_add_character_random_enemy_(
|
||||
const loworld_template_building_param_t* param,
|
||||
uint64_t seed,
|
||||
loentity_id_t ground,
|
||||
float pos) {
|
||||
assert(param != NULL);
|
||||
|
||||
locharacter_base_t* base = locharacter_pool_create(param->pools->character);
|
||||
|
||||
bool built = false;
|
||||
const uint64_t type = (seed = chaos_xorshift(seed))%3;
|
||||
switch (type) {
|
||||
case 1:
|
||||
locharacter_warder_build(base, &(locharacter_warder_param_t) {
|
||||
.ground = ground,
|
||||
.pos = pos,
|
||||
});
|
||||
built = true;
|
||||
break;
|
||||
case 2:
|
||||
locharacter_scientist_build(base, &(locharacter_scientist_param_t) {
|
||||
.ground = ground,
|
||||
.pos = pos,
|
||||
.direction = (seed = chaos_xorshift(seed))%2? 1: -1,
|
||||
});
|
||||
built = true;
|
||||
break;
|
||||
}
|
||||
if (!built) {
|
||||
locharacter_cavia_build(base, &(locharacter_cavia_param_t) {
|
||||
.ground = ground,
|
||||
.pos = pos,
|
||||
.direction = (seed = chaos_xorshift(seed))%2? 1: -1,
|
||||
});
|
||||
}
|
||||
loworld_chunk_add_entity(param->target, &base->super.super);
|
||||
return base->super.super.id;
|
||||
}
|
||||
|
||||
bool loworld_template_building_param_valid(
|
||||
const loworld_template_building_param_t* param) {
|
||||
return
|
||||
param != NULL &&
|
||||
param->target != NULL &&
|
||||
param->pools != NULL;
|
||||
}
|
||||
|
||||
void loworld_template_metaphysical_gate_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .2f), &vec2(.5f, .1f));
|
||||
|
||||
const loentity_id_t ground = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .45f), &vec2(.2f, .02f));
|
||||
|
||||
locharacter_base_t* encephalon =
|
||||
locharacter_pool_create(param->pools->character);
|
||||
locharacter_encephalon_build(encephalon, ground);
|
||||
loworld_chunk_add_entity(param->target, &encephalon->super.super);
|
||||
}
|
||||
|
||||
void loworld_template_open_space_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
uint64_t s = param->seed;
|
||||
|
||||
const size_t enemy_count = (s = chaos_xorshift(s))%3+1;
|
||||
|
||||
const loentity_id_t ground = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .2f), &vec2(.47f, .01f));
|
||||
|
||||
for (size_t i = 0; i < enemy_count; ++i) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), ground, (2.0f/enemy_count*i - 1)*.75f);
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_template_broken_open_space_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
uint64_t s = param->seed;
|
||||
|
||||
const loentity_id_t floor1 = loworld_template_add_ground_island_(
|
||||
param, &vec2(.2f, .2f), &vec2(.18f, .01f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor1, .5f);
|
||||
}
|
||||
|
||||
const loentity_id_t floor2 = loworld_template_add_ground_island_(
|
||||
param, &vec2(.8f, .2f), &vec2(.18f, .01f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor2, .5f);
|
||||
}
|
||||
|
||||
loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .05f), &vec2(.15f, .01f));
|
||||
}
|
||||
|
||||
void loworld_template_passage_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
uint64_t s = param->seed;
|
||||
|
||||
const loentity_id_t floor = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .25f), &vec2(.5f, .01f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor, .5f);
|
||||
}
|
||||
|
||||
const loentity_id_t ceiling = loworld_template_add_ground_island_(
|
||||
param, &vec2(.55f, .4f), &vec2(.3f, .007f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), ceiling, .2f);
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_template_broken_passage_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
uint64_t s = param->seed;
|
||||
|
||||
const loentity_id_t floor1 = loworld_template_add_ground_island_(
|
||||
param, &vec2(.15f, .25f), &vec2(.15f, .01f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor1, .5f);
|
||||
}
|
||||
|
||||
const loentity_id_t floor2 = loworld_template_add_ground_island_(
|
||||
param, &vec2(.45f, .25f), &vec2(.1f, .01f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor2, .5f);
|
||||
}
|
||||
|
||||
const loentity_id_t floor3 = loworld_template_add_ground_island_(
|
||||
param, &vec2(.85f, .25f), &vec2(.15f, .01f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor3, .5f);
|
||||
}
|
||||
|
||||
const uint64_t layout = (s = chaos_xorshift(s))%3;
|
||||
if (layout == 0 || layout == 1) {
|
||||
const loentity_id_t ceiling = loworld_template_add_ground_island_(
|
||||
param, &vec2(.2f, .4f), &vec2(.15f, .007f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), ceiling, .5f);
|
||||
}
|
||||
}
|
||||
if (layout == 0 || layout == 2) {
|
||||
const loentity_id_t ceiling = loworld_template_add_ground_island_(
|
||||
param, &vec2(.7f, .38f), &vec2(.12f, .007f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), ceiling, .5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_template_stairs_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
uint64_t s = param->seed;
|
||||
|
||||
const loentity_id_t floor1 = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .3f), &vec2(.5f, .015f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor1, .5f);
|
||||
}
|
||||
|
||||
bool layout = (s = chaos_xorshift(s))%2;
|
||||
const loentity_id_t floor2 = loworld_template_add_ground_island_(
|
||||
param, &vec2(layout? .3f: .6f, .5f), &vec2(.2f, .015f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor2, .5f);
|
||||
}
|
||||
|
||||
layout = !layout;
|
||||
const loentity_id_t floor3 = loworld_template_add_ground_island_(
|
||||
param, &vec2(layout? .2f: .8f, .7f), &vec2(.18f, .007f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor3, .5f);
|
||||
}
|
||||
|
||||
const loentity_id_t floor4 = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .9f), &vec2(.32f, .007f));
|
||||
if ((s = chaos_xorshift(s))%2) {
|
||||
loworld_template_add_character_random_enemy_(
|
||||
param, (s = chaos_xorshift(s)), floor4, .5f);
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_template_boss_theists_child_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
const loentity_id_t ground = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .1f), &vec2(.5f, .05f));
|
||||
|
||||
locharacter_base_t* boss = locharacter_pool_create(param->pools->character);
|
||||
locharacter_theists_child_build(boss, ground);
|
||||
loworld_chunk_add_entity(param->target, &boss->super.super);
|
||||
}
|
||||
|
||||
void loworld_template_boss_big_warder_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
const loentity_id_t ground = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .1f), &vec2(.5f, .05f));
|
||||
|
||||
locharacter_base_t* boss = locharacter_pool_create(param->pools->character);
|
||||
locharacter_big_warder_build(boss, ground);
|
||||
loworld_chunk_add_entity(param->target, &boss->super.super);
|
||||
}
|
||||
|
||||
void loworld_template_boss_greedy_scientist_build_chunk(
|
||||
const loworld_template_building_param_t* param) {
|
||||
assert(loworld_template_building_param_valid(param));
|
||||
|
||||
const loentity_id_t ground = loworld_template_add_ground_island_(
|
||||
param, &vec2(.5f, .1f), &vec2(.5f, .05f));
|
||||
|
||||
locharacter_base_t* boss = locharacter_pool_create(param->pools->character);
|
||||
locharacter_greedy_scientist_build(boss, ground);
|
||||
loworld_chunk_add_entity(param->target, &boss->super.super);
|
||||
}
|
138
core/loworld/template.h
Normal file
138
core/loworld/template.h
Normal file
@@ -0,0 +1,138 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./poolset.h"
|
||||
|
||||
#define LOWORLD_TEMPLATE_MAX_CHARACTERS_PER_CHUNK 5
|
||||
#define LOWORLD_TEMPLATE_MAX_GROUNDS_PER_CHUNK 5
|
||||
|
||||
typedef struct {
|
||||
loworld_chunk_t* target;
|
||||
|
||||
const loworld_poolset_t* pools;
|
||||
uint64_t seed;
|
||||
} loworld_template_building_param_t;
|
||||
|
||||
bool
|
||||
loworld_template_building_param_valid(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [metaphysical gate]
|
||||
* 2 grounds (=) and the one encephalon statue (E)
|
||||
*
|
||||
* E
|
||||
* ======
|
||||
*
|
||||
* ==================
|
||||
*/
|
||||
void
|
||||
loworld_template_metaphysical_gate_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [open space]
|
||||
* 1 ground (=) and 0~3 enemies (E)
|
||||
*
|
||||
*
|
||||
* E E E
|
||||
* ==================
|
||||
*/
|
||||
void
|
||||
loworld_template_open_space_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [broken open space]
|
||||
* 1 ground (=) and 0~2 enemies (E)
|
||||
*
|
||||
*
|
||||
* E E
|
||||
* ======== ========
|
||||
*
|
||||
* ======
|
||||
*/
|
||||
void
|
||||
loworld_template_broken_open_space_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [passage]
|
||||
* 1 ground (=), ceiling (-), and 0~2 enemies (E)
|
||||
*
|
||||
* E
|
||||
* ----------
|
||||
* E
|
||||
* =================
|
||||
*/
|
||||
void
|
||||
loworld_template_passage_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [broken passage]
|
||||
* 3 grounds (=), 1 or 2 ceilings (-), and 0~5 enemies (E)
|
||||
*
|
||||
* E E
|
||||
* ---- ----
|
||||
* E E E
|
||||
* ==== ==== =====
|
||||
*/
|
||||
void
|
||||
loworld_template_broken_passage_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [stairs]
|
||||
* 4 grounds (=), and 0~4 enemies (E)
|
||||
*
|
||||
* E
|
||||
* =========
|
||||
* E
|
||||
* ======
|
||||
* E
|
||||
* =========
|
||||
* E
|
||||
* ==================
|
||||
*/
|
||||
void
|
||||
loworld_template_stairs_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [BOSS: thiest's child]
|
||||
* 1 ground (=), and The Theist's Child (E)
|
||||
*
|
||||
* E
|
||||
* =================
|
||||
*/
|
||||
void
|
||||
loworld_template_boss_theists_child_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [BOSS: big warder]
|
||||
* 1 ground (=), and The Big Warder (E)
|
||||
*
|
||||
* E
|
||||
* =================
|
||||
*/
|
||||
void
|
||||
loworld_template_boss_big_warder_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
||||
|
||||
/* [BOSS: greedy scientist]
|
||||
* 1 ground (=), and The Greedy Scientist (E)
|
||||
*
|
||||
* E
|
||||
* =================
|
||||
*/
|
||||
void
|
||||
loworld_template_boss_greedy_scientist_build_chunk(
|
||||
const loworld_template_building_param_t* param
|
||||
);
|
146
core/loworld/test.h
Normal file
146
core/loworld/test.h
Normal file
@@ -0,0 +1,146 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <msgpack.h>
|
||||
#include <msgpack/sbuffer.h>
|
||||
|
||||
#include "core/lobullet/base.h"
|
||||
#include "core/lobullet/bomb.h"
|
||||
#include "core/lobullet/linear.h"
|
||||
#include "core/locharacter/base.h"
|
||||
#include "core/locharacter/big_warder.h"
|
||||
#include "core/locharacter/cavia.h"
|
||||
#include "core/locharacter/encephalon.h"
|
||||
#include "core/locharacter/greedy_scientist.h"
|
||||
#include "core/locharacter/theists_child.h"
|
||||
#include "core/locharacter/scientist.h"
|
||||
#include "core/locharacter/warder.h"
|
||||
#include "core/locharacter/pool.h"
|
||||
#include "core/loentity/entity.h"
|
||||
#include "core/loground/base.h"
|
||||
#include "core/loground/island.h"
|
||||
#include "core/loground/pool.h"
|
||||
|
||||
#include "./poolset.h"
|
||||
|
||||
# define pack_and_unpack_(type, name) do { \
|
||||
msgpack_sbuffer_clear(buf); \
|
||||
loentity_pack(&base->super.super, &packer); \
|
||||
loentity_delete(&base->super.super); \
|
||||
\
|
||||
size_t offset = 0; \
|
||||
const msgpack_unpack_return r = \
|
||||
msgpack_unpack_next(upk, buf->data, buf->size, &offset); \
|
||||
if (r != MSGPACK_UNPACK_SUCCESS) { \
|
||||
fprintf(stderr, #type"_"#name": invalid msgpack format\n"); \
|
||||
abort(); \
|
||||
} \
|
||||
if (!type##_base_unpack(base, &upk->data)) { \
|
||||
fprintf(stderr, #type"_"#name": failed to unpack\n"); \
|
||||
abort(); \
|
||||
} \
|
||||
loentity_delete(&base->super.super); \
|
||||
printf(#type"_"#name": pack test passed\n"); \
|
||||
} while (0)
|
||||
|
||||
static inline void loworld_test_packing_grounds(
|
||||
loground_base_t* base, msgpack_sbuffer* buf, msgpack_unpacked* upk) {
|
||||
assert(base != NULL);
|
||||
assert(buf != NULL);
|
||||
assert(upk != NULL);
|
||||
|
||||
msgpack_packer packer;
|
||||
msgpack_packer_init(&packer, buf, msgpack_sbuffer_write);
|
||||
|
||||
loground_island_build(
|
||||
base, &locommon_position(0, 0, vec2(0, 0)), &vec2(1, 1));
|
||||
pack_and_unpack_(loground, island);
|
||||
}
|
||||
|
||||
static inline void loworld_test_packing_bullets(
|
||||
lobullet_base_t* base, msgpack_sbuffer* buf, msgpack_unpacked* upk) {
|
||||
assert(base != NULL);
|
||||
assert(buf != NULL);
|
||||
assert(upk != NULL);
|
||||
|
||||
msgpack_packer packer;
|
||||
msgpack_packer_init(&packer, buf, msgpack_sbuffer_write);
|
||||
|
||||
lobullet_bomb_square_build(
|
||||
base, &((lobullet_bomb_param_t) { .step = 1, }));
|
||||
pack_and_unpack_(lobullet, bomb);
|
||||
|
||||
lobullet_bomb_triangle_build(
|
||||
base, &((lobullet_bomb_param_t) { .step = 1, }));
|
||||
pack_and_unpack_(lobullet, bomb);
|
||||
|
||||
lobullet_linear_light_build(
|
||||
base, &((lobullet_linear_param_t) { .duration = 1, }));
|
||||
pack_and_unpack_(lobullet, linear);
|
||||
|
||||
lobullet_linear_triangle_build(
|
||||
base, &((lobullet_linear_param_t) { .duration = 1, }));
|
||||
pack_and_unpack_(lobullet, linear);
|
||||
}
|
||||
|
||||
static inline void loworld_test_packing_characters(
|
||||
locharacter_base_t* base, msgpack_sbuffer* buf, msgpack_unpacked* upk) {
|
||||
assert(base != NULL);
|
||||
assert(buf != NULL);
|
||||
assert(upk != NULL);
|
||||
|
||||
msgpack_packer packer;
|
||||
msgpack_packer_init(&packer, buf, msgpack_sbuffer_write);
|
||||
|
||||
locharacter_big_warder_build(base, 0);
|
||||
pack_and_unpack_(locharacter, big_warder);
|
||||
|
||||
locharacter_cavia_build(
|
||||
base, &((locharacter_cavia_param_t) { .direction = 1, }));
|
||||
pack_and_unpack_(locharacter, cavia);
|
||||
|
||||
locharacter_encephalon_build(base, 0);
|
||||
pack_and_unpack_(locharacter, encephalon);
|
||||
|
||||
locharacter_theists_child_build(base, 0);
|
||||
pack_and_unpack_(locharacter, theists_child);
|
||||
|
||||
locharacter_greedy_scientist_build(base, 0);
|
||||
pack_and_unpack_(locharacter, greedy_scientist);
|
||||
|
||||
locharacter_scientist_build(base, &((locharacter_scientist_param_t) {0}));
|
||||
pack_and_unpack_(locharacter, scientist);
|
||||
|
||||
locharacter_warder_build(base, &((locharacter_warder_param_t) {0}));
|
||||
pack_and_unpack_(locharacter, warder);
|
||||
}
|
||||
|
||||
# undef pack_and_unpack_
|
||||
|
||||
static inline void loworld_test_packing(const loworld_poolset_t* pools) {
|
||||
assert(pools != NULL);
|
||||
|
||||
msgpack_sbuffer buf;
|
||||
msgpack_sbuffer_init(&buf);
|
||||
|
||||
msgpack_unpacked upk;
|
||||
msgpack_unpacked_init(&upk);
|
||||
|
||||
loground_base_t* ground = loground_pool_create(pools->ground);
|
||||
loworld_test_packing_grounds(ground, &buf, &upk);
|
||||
loentity_delete(&ground->super.super);
|
||||
|
||||
lobullet_base_t* bullet = lobullet_pool_create(pools->bullet);
|
||||
loworld_test_packing_bullets(bullet, &buf, &upk);
|
||||
loentity_delete(&bullet->super.super);
|
||||
|
||||
locharacter_base_t* chara = locharacter_pool_create(pools->character);
|
||||
loworld_test_packing_characters(chara, &buf, &upk);
|
||||
loentity_delete(&chara->super.super);
|
||||
|
||||
msgpack_unpacked_destroy(&upk);
|
||||
msgpack_sbuffer_destroy(&buf);
|
||||
}
|
171
core/loworld/view.c
Normal file
171
core/loworld/view.c
Normal file
@@ -0,0 +1,171 @@
|
||||
#include "./view.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "util/math/vector.h"
|
||||
#include "util/memory/memory.h"
|
||||
|
||||
#include "core/locommon/position.h"
|
||||
#include "core/loentity/store.h"
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./store.h"
|
||||
|
||||
#define LOWORLD_VIEW_CHUNK_LOAD_RANGE 2
|
||||
|
||||
struct loworld_view_t {
|
||||
loworld_store_t* world;
|
||||
loentity_store_t* entities;
|
||||
|
||||
locommon_position_t looking;
|
||||
|
||||
loworld_chunk_t* chunks
|
||||
[LOWORLD_VIEW_CHUNK_LOAD_RANGE*2+1][LOWORLD_VIEW_CHUNK_LOAD_RANGE*2+1];
|
||||
};
|
||||
|
||||
static void loworld_view_stage_chunk_(
|
||||
loworld_view_t* view, loworld_chunk_t* chunk) {
|
||||
assert(view != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
const size_t len = container_array_get_length(chunk->entities);
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
/* moving ownership from the chunk to the store */
|
||||
loentity_store_add(view->entities, chunk->entities[i]);
|
||||
}
|
||||
container_array_resize(chunk->entities, 0);
|
||||
}
|
||||
|
||||
static void loworld_view_unstage_chunk_(
|
||||
loworld_view_t* view, loworld_chunk_t* chunk) {
|
||||
assert(view != NULL);
|
||||
assert(chunk != NULL);
|
||||
|
||||
loentity_store_iterator_t itr = {0};
|
||||
while (loentity_store_iterate_next(view->entities, &itr)) {
|
||||
if (itr.entity->dont_save ||
|
||||
itr.entity->pos.chunk.x != chunk->pos.x ||
|
||||
itr.entity->pos.chunk.y != chunk->pos.y) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const size_t index = container_array_get_length(chunk->entities);
|
||||
container_array_insert(chunk->entities, index);
|
||||
|
||||
/* moving ownership from the store to the chunk */
|
||||
chunk->entities[index] = loentity_store_remove(view->entities, &itr);
|
||||
}
|
||||
}
|
||||
|
||||
static void loworld_view_load_all_chunks_(loworld_view_t* view) {
|
||||
assert(view != NULL);
|
||||
|
||||
/* Unload all chunks before calling this function. */
|
||||
|
||||
static const int32_t r = LOWORLD_VIEW_CHUNK_LOAD_RANGE;
|
||||
|
||||
for (int32_t x = -r; x <= r; ++x) {
|
||||
for (int32_t y = -r; y <= r; ++y) {
|
||||
loworld_chunk_t* chunk = loworld_store_load_chunk(
|
||||
view->world, view->looking.chunk.x + x, view->looking.chunk.y + y);
|
||||
view->chunks[y+r][x+r] = chunk;
|
||||
loworld_view_stage_chunk_(view, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void loworld_view_unload_all_chunks_(loworld_view_t* view) {
|
||||
assert(view != NULL);
|
||||
|
||||
static const int32_t r = LOWORLD_VIEW_CHUNK_LOAD_RANGE;
|
||||
|
||||
for (int32_t x = -r; x <= r; ++x) {
|
||||
for (int32_t y = -r; y <= r; ++y) {
|
||||
loworld_chunk_t* chunk = view->chunks[y+r][x+r];
|
||||
if (chunk == NULL) continue;
|
||||
|
||||
loworld_view_unstage_chunk_(view, chunk);
|
||||
loworld_store_unload_chunk(view->world, chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loworld_view_t* loworld_view_new(
|
||||
loworld_store_t* world,
|
||||
loentity_store_t* entities,
|
||||
const locommon_position_t* looking) {
|
||||
assert(world != NULL);
|
||||
assert(entities != NULL);
|
||||
assert(locommon_position_valid(looking));
|
||||
|
||||
loworld_view_t* view = memory_new(sizeof(*view));
|
||||
*view = (typeof(*view)) {
|
||||
.world = world,
|
||||
.entities = entities,
|
||||
.looking = *looking,
|
||||
};
|
||||
|
||||
loworld_view_load_all_chunks_(view);
|
||||
return view;
|
||||
}
|
||||
|
||||
void loworld_view_delete(loworld_view_t* view) {
|
||||
if (view == NULL) return;
|
||||
|
||||
loworld_view_unload_all_chunks_(view);
|
||||
|
||||
memory_delete(view);
|
||||
}
|
||||
|
||||
void loworld_view_update(loworld_view_t* view) {
|
||||
assert(view != NULL);
|
||||
|
||||
loentity_store_iterator_t itr = {0};
|
||||
while (loentity_store_iterate_next(view->entities, &itr)) {
|
||||
if (!loentity_update(itr.entity)) {
|
||||
loentity_delete(loentity_store_remove(view->entities, &itr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_view_draw(loworld_view_t* view) {
|
||||
assert(view != NULL);
|
||||
|
||||
loentity_store_iterator_t itr = {0};
|
||||
while (loentity_store_iterate_next(view->entities, &itr)) {
|
||||
loentity_draw(itr.entity, &view->looking);
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_view_look(loworld_view_t* view, const locommon_position_t* pos) {
|
||||
assert(view != NULL);
|
||||
assert(locommon_position_valid(pos));
|
||||
|
||||
const bool chunk_moved =
|
||||
view->looking.chunk.x != pos->chunk.x ||
|
||||
view->looking.chunk.y != pos->chunk.y;
|
||||
|
||||
view->looking = *pos;
|
||||
|
||||
if (chunk_moved) {
|
||||
loworld_view_unload_all_chunks_(view);
|
||||
loworld_view_load_all_chunks_(view);
|
||||
}
|
||||
}
|
||||
|
||||
void loworld_view_flush_store(loworld_view_t* view) {
|
||||
assert(view != NULL);
|
||||
|
||||
loworld_view_unload_all_chunks_(view);
|
||||
loworld_store_flush(view->world);
|
||||
loworld_view_load_all_chunks_(view);
|
||||
}
|
||||
|
||||
const loworld_chunk_t* loworld_view_get_looking_chunk(
|
||||
const loworld_view_t* view) {
|
||||
assert(view != NULL);
|
||||
|
||||
static const int32_t r = LOWORLD_VIEW_CHUNK_LOAD_RANGE;
|
||||
return view->chunks[r][r];
|
||||
}
|
49
core/loworld/view.h
Normal file
49
core/loworld/view.h
Normal file
@@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include "core/locommon/position.h"
|
||||
#include "core/loentity/store.h"
|
||||
|
||||
#include "./chunk.h"
|
||||
#include "./store.h"
|
||||
|
||||
struct loworld_view_t;
|
||||
typedef struct loworld_view_t loworld_view_t;
|
||||
|
||||
loworld_view_t* /* OWNERSHIP */
|
||||
loworld_view_new(
|
||||
loworld_store_t* world,
|
||||
loentity_store_t* entities,
|
||||
const locommon_position_t* looking
|
||||
);
|
||||
|
||||
void
|
||||
loworld_view_delete(
|
||||
loworld_view_t* view /* OWNERSHIP */
|
||||
);
|
||||
|
||||
void
|
||||
loworld_view_update(
|
||||
loworld_view_t* view
|
||||
);
|
||||
|
||||
void
|
||||
loworld_view_draw(
|
||||
loworld_view_t* view
|
||||
);
|
||||
|
||||
void
|
||||
loworld_view_look(
|
||||
loworld_view_t* view,
|
||||
const locommon_position_t* pos
|
||||
);
|
||||
|
||||
/* Flushes all chunks safely including currently staged ones. */
|
||||
void
|
||||
loworld_view_flush_store(
|
||||
loworld_view_t* view
|
||||
);
|
||||
|
||||
const loworld_chunk_t* /* ALIVES UNTIL NEXT OPERATION */
|
||||
loworld_view_get_looking_chunk(
|
||||
const loworld_view_t* view
|
||||
);
|
Reference in New Issue
Block a user