Merge remote-tracking branch 'origin/master'

isolation_bkp/dynres
Dominik Madarász 2022-09-15 22:52:00 +02:00
commit 9a1e4bef96
58 changed files with 18534 additions and 18030 deletions

8
.gitignore vendored
View File

@ -1,5 +1,10 @@
build build
build_rel build_rel
build_web
emsdk
deploy_web
run_web
butler
screenshots screenshots
build.bat build.bat
run.bat run.bat
@ -12,7 +17,6 @@ GPATH
GRTAGS GRTAGS
GTAGS GTAGS
/run_release.bat /run_release.bat
/package.bat
pkg pkg
pkg.zip pkg.zip
eco2d.zip eco2d.zip

View File

@ -8,11 +8,17 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
SET(CMAKE_USE_RELATIVE_PATHS OFF)
if(MSVC) if(MSVC)
add_definitions(-D_CRT_SECURE_NO_WARNINGS) add_definitions(-D_CRT_SECURE_NO_WARNINGS)
endif() endif()
if (EMSCRIPTEN)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s USE_GLFW=3 --profiling -s ASSERTIONS=1 -s WASM=1 -s INITIAL_MEMORY=268435456 -s FORCE_FILESYSTEM=1 --preload-file ${CMAKE_SOURCE_DIR}/art@art/ --shell-file ${CMAKE_SOURCE_DIR}/web/eco2d.html --post-js ${CMAKE_SOURCE_DIR}/web/eco2d-post.js")
set(CMAKE_EXECUTABLE_SUFFIX ".html")
endif ()
include_directories(code/common code/vendors code/vendors/flecs) include_directories(code/common code/vendors code/vendors/flecs)
include(cmake/FindRaylib.cmake) include(cmake/FindRaylib.cmake)

View File

@ -1,11 +1,12 @@
<div align="center"> <div align="center">
<a href="https://github.com/zpl-c/zpl"><img src="https://user-images.githubusercontent.com/2182108/111983468-d5593e80-8b12-11eb-9c59-8c78ecc0504e.png" alt="eco2d" /></a> <a href="https://zaklaus.itch.io/eco2d"><img src="https://user-images.githubusercontent.com/2182108/111983468-d5593e80-8b12-11eb-9c59-8c78ecc0504e.png" alt="eco2d" /></a>
</div> </div>
<br /> <br />
<div align="center"> <div align="center">
<a href="https://discord.gg/2fZVEym"><img src="https://img.shields.io/discord/354670964400848898?color=7289DA&style=for-the-badge" alt="discord" /></a> <a href="https://discord.gg/2fZVEym"><img src="https://img.shields.io/discord/354670964400848898?color=7289DA&style=for-the-badge" alt="discord" /></a>
<a href="https://zaklaus.itch.io/eco2d"><img src="https://static.itch.io/images/badge-color.svg" alt="play" height="28px"/></a>
</div> </div>
<br /> <br />
@ -51,6 +52,30 @@ In the abstract sense, we call the Server the game master hosting all gameplay r
# Build the project # Build the project
We use CMake to generate project files and manage builds. We use CMake to generate project files and manage builds.
## Web
We have a set of scripts ready for web development, these steps will get you up and running with a web build:
```sh
# Setup emsdk locally and configure a web project
web/setup.sh
# Build the web project
web/build.sh
# Host the files on a web server (Python3)
web/host.sh
```
## Desktop
### Pre-requisites
#### Linux
Follow [raylib-linux](https://github.com/raysan5/raylib/wiki/Working-on-GNU-Linux) guide to install dependencies on your system.
#### macOS
Follow [raylib-macos](https://github.com/raysan5/raylib/wiki/Working-on-macOS) guide to install dependencies on your system.
#### Windows
You need to have Visual Studio 2019+ installed on your system. Make sure to run the commands below in a VS Developer Command Prompt.
### Build
You can do the following on the command line to create and build this project: You can do the following on the command line to create and build this project:
```sh ```sh
git clone https://github.com/zpl-c/eco2d.git git clone https://github.com/zpl-c/eco2d.git
@ -61,10 +86,6 @@ cmake --build build
Run the following command to see all the options: Run the following command to see all the options:
```sh ```sh
Windows:
build\Debug\eco2d.exe -?
Linux:
build\eco2d.exe -? build\eco2d.exe -?
``` ```

View File

@ -3,6 +3,8 @@ function(link_system_libs target_name)
target_link_libraries(${target_name} winmm) target_link_libraries(${target_name} winmm)
elseif (APPLE) elseif (APPLE)
target_link_libraries(${target_name} pthread m dl) target_link_libraries(${target_name} pthread m dl)
elseif (EMSCRIPTEN)
target_link_libraries(${target_name} pthread m dl)
elseif (UNIX) elseif (UNIX)
target_link_libraries(${target_name} pthread m dl atomic) target_link_libraries(${target_name} pthread m dl atomic)
endif() endif()

View File

@ -43,5 +43,6 @@ add_executable(eco2d
target_compile_definitions(eco2d PRIVATE CLIENT) target_compile_definitions(eco2d PRIVATE CLIENT)
include_directories(src ../modules ../../art/gen) include_directories(src ../modules ../../art/gen)
target_link_libraries(eco2d raylib cwpack eco2d-modules flecs-bundle vendors-bundle) target_link_libraries(eco2d raylib cwpack eco2d-modules flecs-bundle vendors-bundle)
target_compile_options(eco2d PRIVATE -Werror -Wall -Wextra -Wno-unused-function -Wno-unknown-pragmas -Wno-unused-variable -Wno-unused-parameter)
link_system_libs(eco2d) link_system_libs(eco2d)

View File

@ -16,7 +16,7 @@
// can use it in other systems // can use it in other systems
// NOTE(zaklaus): Register a block // NOTE(zaklaus): Register a block
#include "blocks/blocks_list.c" #include "world/blocks_list.c"
// NOTE(zaklaus): Register an item // NOTE(zaklaus): Register an item
#include "items_list.c" #include "items_list.c"

View File

@ -23,6 +23,8 @@ typedef struct {
static int64_t assets_frame_counter = 1; static int64_t assets_frame_counter = 1;
static double assets_frame_next_draw = 0.0; static double assets_frame_next_draw = 0.0;
#include <time.h>
int32_t assets_setup(void) { int32_t assets_setup(void) {
for (uint32_t i=0; i<ASSETS_COUNT; i++) { for (uint32_t i=0; i<ASSETS_COUNT; i++) {
asset *b = &assets[i]; asset *b = &assets[i];
@ -43,13 +45,12 @@ int32_t assets_setup(void) {
default: break; default: break;
} }
} }
assets_frame_next_draw = get_cached_time() + ASSET_FRAME_RENDER_MS;
assets_frame_next_draw = zpl_time_rel() + ASSET_FRAME_RENDER_MS;
return 0; return 0;
} }
int32_t assets_frame(void) { int32_t assets_frame(void) {
if (assets_frame_next_draw < zpl_time_rel()) { if (assets_frame_next_draw < get_cached_time()) {
for (uint32_t i=0; i<ASSETS_COUNT; i++) { for (uint32_t i=0; i<ASSETS_COUNT; i++) {
asset *b = &assets[i]; asset *b = &assets[i];
@ -63,7 +64,7 @@ int32_t assets_frame(void) {
} }
} }
assets_frame_next_draw = zpl_time_rel() + ASSET_FRAME_RENDER_MS; assets_frame_next_draw = get_cached_time() + ASSET_FRAME_RENDER_MS;
assets_frame_counter += ASSET_FRAME_SKIP; assets_frame_counter += ASSET_FRAME_SKIP;
} }

View File

@ -22,7 +22,7 @@ static asset assets[] = {
ASSET_TEX(ASSET_DEV), ASSET_TEX(ASSET_DEV),
ASSET_TEX(ASSET_GROUND), ASSET_TEX(ASSET_GROUND),
ASSET_TEX(ASSET_DIRT), ASSET_TEX(ASSET_DIRT),
ASSET_ANI(ASSET_WATER), ASSET_TEX(ASSET_WATER),
ASSET_TEX(ASSET_LAVA), ASSET_TEX(ASSET_LAVA),
ASSET_TEX(ASSET_WALL), ASSET_TEX(ASSET_WALL),
ASSET_TEX(ASSET_HILL), ASSET_TEX(ASSET_HILL),

View File

@ -116,7 +116,7 @@ void debug_replay_start(void) {
if (records) zpl_array_free(records); if (records) zpl_array_free(records);
zpl_array_init_reserve(records, zpl_heap(), UINT16_MAX); zpl_array_init_reserve(records, zpl_heap(), UINT16_MAX);
last_record_time = zpl_time_rel(); last_record_time = get_cached_time();
SetTargetFPS(60); SetTargetFPS(60);
} }
@ -155,7 +155,7 @@ void debug_replay_run(void) {
if (mime) return; if (mime) return;
is_playing = true; is_playing = true;
record_pos = 0; record_pos = 0;
playback_time = zpl_time_rel(); playback_time = get_cached_time();
zpl_array_init(temp_actors, zpl_heap()); zpl_array_init(temp_actors, zpl_heap());
plr = camera_get().ent_id; plr = camera_get().ent_id;
@ -181,10 +181,10 @@ void ActSpawnBelt(void);
void debug_replay_update(void) { void debug_replay_update(void) {
if (!is_playing) return; if (!is_playing) return;
if (playback_time >= zpl_time_rel()) return; if (playback_time >= get_cached_time()) return;
replay_record *r = &records[record_pos]; replay_record *r = &records[record_pos];
playback_time = zpl_time_rel() + r->delay; playback_time = get_cached_time() + r->delay;
switch (r->kind) { switch (r->kind) {
case RPKIND_KEY: { case RPKIND_KEY: {
@ -249,7 +249,7 @@ void debug_replay_update(void) {
void debug_replay_record_keystate(pkt_send_keystate state) { void debug_replay_record_keystate(pkt_send_keystate state) {
if (!is_recording) return; if (!is_recording) return;
double record_time = zpl_time_rel(); double record_time = get_cached_time();
replay_record rec = { replay_record rec = {
.kind = RPKIND_KEY, .kind = RPKIND_KEY,
@ -258,13 +258,13 @@ void debug_replay_record_keystate(pkt_send_keystate state) {
}; };
zpl_array_append(records, rec); zpl_array_append(records, rec);
last_record_time = zpl_time_rel(); last_record_time = get_cached_time();
} }
void debug_replay_special_action(replay_kind kind) { void debug_replay_special_action(replay_kind kind) {
ZPL_ASSERT(kind != RPKIND_KEY); ZPL_ASSERT(kind != RPKIND_KEY);
if (!is_recording || is_playing) return; if (!is_recording || is_playing) return;
double record_time = zpl_time_rel(); double record_time = get_cached_time();
replay_record rec = { replay_record rec = {
.kind = kind, .kind = kind,
@ -272,5 +272,5 @@ void debug_replay_special_action(replay_kind kind) {
}; };
zpl_array_append(records, rec); zpl_array_append(records, rec);
last_record_time = zpl_time_rel(); last_record_time = get_cached_time();
} }

View File

@ -29,7 +29,7 @@ typedef struct {
#define DBG_FONT_SIZE 22 #define DBG_FONT_SIZE 22
#define DBG_FONT_SPACING DBG_FONT_SIZE * 1.2f #define DBG_FONT_SPACING DBG_FONT_SIZE * 1.2f
#define DBG_START_XPOS 15 #define DBG_START_XPOS 15
#define DBG_START_YPOS 200 #define DBG_START_YPOS 30
#define DBG_LIST_XPOS_OFFSET 10 #define DBG_LIST_XPOS_OFFSET 10
#define DBG_SHADOW_OFFSET_XPOS 1 #define DBG_SHADOW_OFFSET_XPOS 1
#define DBG_SHADOW_OFFSET_YPOS 1 #define DBG_SHADOW_OFFSET_YPOS 1
@ -92,6 +92,7 @@ static debug_item items[] = {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "general", .name = "general",
.list = { .list = {
.is_collapsed = true,
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_TEXT, .name = "delta time", .proc = DrawDeltaTime }, { .kind = DITEM_TEXT, .name = "delta time", .proc = DrawDeltaTime },
{ .kind = DITEM_TEXT, .name = "pos", .proc = DrawCameraPos }, { .kind = DITEM_TEXT, .name = "pos", .proc = DrawCameraPos },
@ -104,6 +105,7 @@ static debug_item items[] = {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "world simulation", .name = "world simulation",
.list = { .list = {
.is_collapsed = true,
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_COND, .on_success = CondIsWorldRunning }, { .kind = DITEM_COND, .on_success = CondIsWorldRunning },
{ .kind = DITEM_BUTTON, .name = "pause", .on_click = ActWorldToggleSim }, { .kind = DITEM_BUTTON, .name = "pause", .on_click = ActWorldToggleSim },
@ -127,6 +129,7 @@ static debug_item items[] = {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "debug actions", .name = "debug actions",
.list = { .list = {
.is_collapsed = true,
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar }, { .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar },
{ .kind = DITEM_BUTTON, .name = "place ice rink", .on_click = ActPlaceIceRink }, { .kind = DITEM_BUTTON, .name = "place ice rink", .on_click = ActPlaceIceRink },
@ -157,6 +160,7 @@ static debug_item items[] = {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "conn metrics", .name = "conn metrics",
.list = { .list = {
.is_collapsed = true,
.items = (debug_item[]) { .items = (debug_item[]) {
{ .kind = DITEM_COND, .on_success = CondClientDisconnected }, { .kind = DITEM_COND, .on_success = CondClientDisconnected },
{ .kind = DITEM_TEXT, .name = "status", .proc = DrawLiteral, .text = "disconnected" }, { .kind = DITEM_TEXT, .name = "status", .proc = DrawLiteral, .text = "disconnected" },
@ -172,6 +176,7 @@ static debug_item items[] = {
}, },
.limit_to = L_MP, .limit_to = L_MP,
}, },
#if !defined(PLATFORM_WEB)
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "replay system", .name = "replay system",
@ -209,6 +214,7 @@ static debug_item items[] = {
}, },
.limit_to = L_SP, .limit_to = L_SP,
}, },
#endif
{ {
.kind = DITEM_LIST, .kind = DITEM_LIST,
.name = "profilers", .name = "profilers",
@ -226,11 +232,13 @@ static debug_item items[] = {
.is_collapsed = 1 .is_collapsed = 1
} }
}, },
#if !defined(PLATFORM_WEB)
{ {
.kind = DITEM_BUTTON, .kind = DITEM_BUTTON,
.name = "exit game", .name = "exit game",
.on_click = ActExitGame, .on_click = ActExitGame,
}, },
#endif
{.kind = DITEM_END}, {.kind = DITEM_END},
}; };

View File

@ -16,6 +16,7 @@ ActSpawnCar(void) {
Position const* origin = ecs_get(world_ecs(), plr, Position); Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position); Position * dest = ecs_get_mut(world_ecs(), e, Position);
*dest = *origin; *dest = *origin;
entity_set_position(e, dest->x, dest->y);
debug_replay_special_action(RPKIND_SPAWN_CAR); debug_replay_special_action(RPKIND_SPAWN_CAR);
} }
@ -28,6 +29,7 @@ ActSpawnIcemaker(void) {
Position const* origin = ecs_get(world_ecs(), plr, Position); Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position); Position * dest = ecs_get_mut(world_ecs(), e, Position);
*dest = *origin; *dest = *origin;
entity_set_position(e, dest->x, dest->y);
debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM); debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM);
} }
@ -40,6 +42,7 @@ ActSpawnChest(void) {
Position const* origin = ecs_get(world_ecs(), plr, Position); Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position); Position * dest = ecs_get_mut(world_ecs(), e, Position);
*dest = *origin; *dest = *origin;
entity_set_position(e, dest->x, dest->y);
debug_replay_special_action(RPKIND_SPAWN_CHEST); debug_replay_special_action(RPKIND_SPAWN_CHEST);
} }
@ -52,6 +55,7 @@ ActSpawnBelt(void) {
Position const* origin = ecs_get(world_ecs(), plr, Position); Position const* origin = ecs_get(world_ecs(), plr, Position);
Position * dest = ecs_get_mut(world_ecs(), e, Position); Position * dest = ecs_get_mut(world_ecs(), e, Position);
*dest = *origin; *dest = *origin;
entity_set_position(e, dest->x, dest->y);
debug_replay_special_action(RPKIND_SPAWN_BELT); debug_replay_special_action(RPKIND_SPAWN_BELT);
} }
@ -67,6 +71,8 @@ ActSpawnCirclingDriver(void) {
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
*veh_dest = *origin; *veh_dest = *origin;
*dest = *origin; *dest = *origin;
entity_set_position(ve, veh_dest->x, veh_dest->y);
entity_set_position(e, dest->x, dest->y);
Input *input = ecs_get_mut(world_ecs(), e, Input); Input *input = ecs_get_mut(world_ecs(), e, Input);
zpl_zero_item(input); zpl_zero_item(input);

View File

@ -23,6 +23,7 @@ uint64_t entity_spawn(uint16_t class_id) {
#if 1 #if 1
pos->x=(float)(rand() % world_dim()); pos->x=(float)(rand() % world_dim());
pos->y=(float)(rand() % world_dim()); pos->y=(float)(rand() % world_dim());
entity_set_position(e, pos->x, pos->y);
#else #else
pos->x=350.0f; pos->x=350.0f;
pos->y=88.0f; pos->y=88.0f;
@ -62,7 +63,7 @@ void entity_set_position(uint64_t ent_id, float x, float y) {
Position *p = ecs_get_mut(world_ecs(), ent_id, Position); Position *p = ecs_get_mut(world_ecs(), ent_id, Position);
p->x = x; p->x = x;
p->y = y; p->y = y;
librg_entity_chunk_set(world_tracker(), ent_id, librg_chunk_from_realpos(world_tracker(), x, y, 0));
entity_wake(ent_id); entity_wake(ent_id);
} }
@ -78,7 +79,7 @@ void entity_update_action_timers() {
static double last_update_time = 0.0f; static double last_update_time = 0.0f;
if (!ecs_streaminfo) { if (!ecs_streaminfo) {
ecs_streaminfo = ecs_query_new(world_ecs(), "components.StreamInfo"); ecs_streaminfo = ecs_query_new(world_ecs(), "components.StreamInfo");
last_update_time = zpl_time_rel(); last_update_time = get_cached_time();
} }
ecs_iter_t it = ecs_query_iter(world_ecs(), ecs_streaminfo); ecs_iter_t it = ecs_query_iter(world_ecs(), ecs_streaminfo);
@ -86,18 +87,18 @@ void entity_update_action_timers() {
while (ecs_query_next(&it)) { while (ecs_query_next(&it)) {
StreamInfo *si = ecs_field(&it, StreamInfo, 1); StreamInfo *si = ecs_field(&it, StreamInfo, 1);
for (size_t i = 0; i < it.count; i++) { for (int32_t i = 0; i < it.count; i++) {
if (si[i].last_update < zpl_time_rel()) { if (si[i].last_update < get_cached_time()) {
si[i].last_update = zpl_time_rel() + si[i].tick_delay; si[i].last_update = get_cached_time() + si[i].tick_delay;
si[i].tick_delay += (zpl_time_rel() - last_update_time) * 0.5f; si[i].tick_delay += (get_cached_time() - last_update_time) * 0.5f;
} }
} }
} }
last_update_time = zpl_time_rel(); last_update_time = get_cached_time();
} }
bool entity_can_stream(uint64_t ent_id) { bool entity_can_stream(uint64_t ent_id) {
StreamInfo *si = ecs_get_mut(world_ecs(), ent_id, StreamInfo); StreamInfo *si = ecs_get_mut(world_ecs(), ent_id, StreamInfo);
return (si->last_update < zpl_time_rel()); return (si->last_update < get_cached_time());
} }

View File

@ -50,10 +50,10 @@ pkt_desc pkt_entity_view_desc[] = {
{ PKT_END }, { PKT_END },
}; };
size_t entity_view_pack_struct(void *data, size_t len, entity_view view) { size_t entity_view_pack_struct(void *data, size_t len, entity_view *view) {
cw_pack_context pc = {0}; cw_pack_context pc = {0};
cw_pack_context_init(&pc, data, (unsigned long)len, 0); cw_pack_context_init(&pc, data, (unsigned long)len, 0);
pkt_pack_struct(&pc, pkt_entity_view_desc, PKT_STRUCT_PTR(&view)); pkt_pack_struct(&pc, pkt_entity_view_desc, PKT_STRUCT_PTR(view));
return pc.current - pc.start; return pc.current - pc.start;
} }

View File

@ -96,7 +96,7 @@ void entity_view_destroy(entity_view_tbl *map, uint64_t ent_id);
entity_view *entity_view_get(entity_view_tbl *map, uint64_t ent_id); entity_view *entity_view_get(entity_view_tbl *map, uint64_t ent_id);
void entity_view_map(entity_view_tbl *map, void (*map_proc)(uint64_t key, entity_view *value)); void entity_view_map(entity_view_tbl *map, void (*map_proc)(uint64_t key, entity_view *value));
size_t entity_view_pack_struct(void *data, size_t len, entity_view view); size_t entity_view_pack_struct(void *data, size_t len, entity_view *view);
entity_view entity_view_unpack_struct(void *data, size_t len); entity_view entity_view_unpack_struct(void *data, size_t len);
void entity_view_mark_for_removal(entity_view_tbl *map, uint64_t ent_id); void entity_view_mark_for_removal(entity_view_tbl *map, uint64_t ent_id);

View File

@ -12,6 +12,7 @@
#include "profiler.h" #include "profiler.h"
#include "flecs/flecs_os_api_stdcpp.h" #include "flecs/flecs_os_api_stdcpp.h"
#include "flecs/flecs.h"
#include "modules/components.h" #include "modules/components.h"
#include "modules/systems.h" #include "modules/systems.h"
@ -72,7 +73,7 @@ void world_viewers_init(uint32_t num_viewers) {
} }
void world_viewers_destroy() { void world_viewers_destroy() {
for (uint32_t i = 0; i < zpl_buffer_count(world_viewers); i++) { for (zpl_isize i = 0; i < zpl_buffer_count(world_viewers); i++) {
world_view_destroy(&world_viewers[i]); world_view_destroy(&world_viewers[i]);
} }
zpl_buffer_free(world_viewers); zpl_buffer_free(world_viewers);
@ -114,12 +115,14 @@ size_t game_world_view_count(void) {
} }
void flecs_dash_init() { void flecs_dash_init() {
#if !defined(ZPL_SYSTEM_EMSCRIPTEN)
ecs_singleton_set(world_ecs(), EcsRest, {0}); ecs_singleton_set(world_ecs(), EcsRest, {0});
ECS_IMPORT(world_ecs(), FlecsMonitor); ECS_IMPORT(world_ecs(), FlecsMonitor);
#endif
} }
float game_time() { float game_time() {
return (float)zpl_time_rel(); return (float)get_cached_time();
} }
void game_init(const char *ip, uint16_t port, game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled) { void game_init(const char *ip, uint16_t port, game_kind play_mode, uint32_t num_viewers, int32_t seed, uint16_t chunk_size, uint16_t chunk_amount, int8_t is_dash_enabled) {
@ -229,15 +232,15 @@ void game_update() {
if (game_mode == GAMEKIND_HEADLESS) { if (game_mode == GAMEKIND_HEADLESS) {
network_server_tick(); network_server_tick();
static uint64_t ms_report = 2500; static float ms_report = 2.5f;
if (ms_report < zpl_time_rel_ms()) { if (ms_report < get_cached_time()) {
ms_report = zpl_time_rel_ms() + 5000; ms_report = get_cached_time() + 5.f;
zpl_printf("delta: %f ms.\n", (zpl_time_rel() - last_update)*1000.0f); zpl_printf("delta: %f ms.\n", (get_cached_time() - last_update)*1000.0f);
} }
} }
} }
last_update = zpl_time_rel(); last_update = get_cached_time();
} }
void game_render() { void game_render() {

View File

@ -33,11 +33,11 @@ Texture2D GenColorEco(Color color) {
Texture2D texgen_build_anim(asset_id id, int64_t counter) { Texture2D texgen_build_anim(asset_id id, int64_t counter) {
(void)counter; (void)counter;
switch (id) { switch (id) {
case ASSET_WATER: { // case ASSET_WATER: {
Image img = LoadImageEco("water"); // Image img = LoadImageEco("water");
ImageColorBrightness(&img, zpl_abs((counter % 64 - 32)*2)); // ImageColorBrightness(&img, zpl_abs((counter % 64 - 32)*2));
return Image2TexEco(img); // return Image2TexEco(img);
}break; // }break;
default: return GenColorEco(PINK); break; default: return GenColorEco(PINK); break;
} }
@ -61,7 +61,8 @@ Texture2D texgen_build_sprite(asset_id id) {
case ASSET_LAVA: return LoadTexEco("lava"); case ASSET_LAVA: return LoadTexEco("lava");
case ASSET_WOOD: return LoadTexEco("wood"); case ASSET_WOOD: return LoadTexEco("wood");
case ASSET_TREE: return LoadTexEco("tree"); case ASSET_TREE: return LoadTexEco("tree");
case ASSET_WATER: return LoadTexEco("water");
case ASSET_BELT: case ASSET_BELT:
case ASSET_BELT_RIGHT: return LoadTexEco("belt_right"); case ASSET_BELT_RIGHT: return LoadTexEco("belt_right");
case ASSET_BELT_LEFT: return LoadTexEco("belt_left"); case ASSET_BELT_LEFT: return LoadTexEco("belt_left");

View File

@ -45,7 +45,7 @@ void buildmode_draw(void) {
ItemDrop *item = &e->items[e->selected_item]; ItemDrop *item = &e->items[e->selected_item];
if (e->has_items && !e->inside_vehicle && item->quantity > 0 && !is_outside_range || build_is_deletion_mode) { if (e->has_items && !e->inside_vehicle && item->quantity > 0 && (!is_outside_range || build_is_deletion_mode)) {
item_usage usage = 0; item_usage usage = 0;
uint16_t item_id = 0; uint16_t item_id = 0;
if (!build_is_deletion_mode){ if (!build_is_deletion_mode){
@ -127,4 +127,4 @@ void buildmode_draw(void) {
} }
} }
} }

View File

@ -26,14 +26,14 @@ static inline asset_id item_fix_kind(asset_id id) {
uint64_t item_spawn(asset_id kind, uint32_t qty) { uint64_t item_spawn(asset_id kind, uint32_t qty) {
ecs_entity_t e = entity_spawn(EKIND_ITEM); ecs_entity_t e = entity_spawn(EKIND_ITEM);
ItemDrop *d = ecs_get_mut(world_ecs(), e, ItemDrop); ItemDrop *d = ecs_get_mut(world_ecs(), e, ItemDrop);
*d = (ItemDrop){ *d = (ItemDrop){
.kind = item_fix_kind(kind), .kind = item_fix_kind(kind),
.quantity = qty, .quantity = qty,
.merger_time = 0, .merger_time = 0,
}; };
return (uint64_t)e; return (uint64_t)e;
} }
@ -58,7 +58,7 @@ void item_use(ecs_world_t *ecs, ItemDrop *it, Position p, uint64_t udata) {
asset_id item_asset = blocks_get_asset(l.bid); asset_id item_asset = blocks_get_asset(l.bid);
item_id item_asset_id = item_find(item_asset); item_id item_asset_id = item_find(item_asset);
if (item_asset_id == ASSET_INVALID) return; if (item_asset_id == ASSET_INVALID) return;
// NOTE(zaklaus): If we replace the same item, refund 1 qty and let it replace it // NOTE(zaklaus): If we replace the same item, refund 1 qty and let it replace it
if (item_asset_id == it_id) { if (item_asset_id == it_id) {
it->quantity++; it->quantity++;
@ -73,7 +73,7 @@ void item_use(ecs_world_t *ecs, ItemDrop *it, Position p, uint64_t udata) {
world_chunk_replace_block(l.chunk_id, l.id, blocks_find(desc->place.kind + (asset_id)udata)); world_chunk_replace_block(l.chunk_id, l.id, blocks_find(desc->place.kind + (asset_id)udata));
it->quantity--; it->quantity--;
}break; }break;
case UKIND_PLACE_ITEM:{ case UKIND_PLACE_ITEM:{
world_block_lookup l = world_block_from_realpos(p.x, p.y); world_block_lookup l = world_block_from_realpos(p.x, p.y);
if (l.is_outer && l.bid > 0) { if (l.is_outer && l.bid > 0) {
@ -83,15 +83,19 @@ void item_use(ecs_world_t *ecs, ItemDrop *it, Position p, uint64_t udata) {
else if (l.bid > 0 && blocks_get_flags(l.bid) & (BLOCK_FLAG_COLLISION|BLOCK_FLAG_ESSENTIAL)) { else if (l.bid > 0 && blocks_get_flags(l.bid) & (BLOCK_FLAG_COLLISION|BLOCK_FLAG_ESSENTIAL)) {
return; return;
} }
ecs_entity_t e = entity_spawn_id(desc->place_item.id); ecs_entity_t e = entity_spawn_id(desc->place_item.id);
ZPL_ASSERT(world_entity_valid(e)); ZPL_ASSERT(world_entity_valid(e));
Position *pos = ecs_get_mut(ecs, e, Position); entity_set_position(e, p.x, p.y);
pos->x = p.x;
pos->y = p.y;
it->quantity--; it->quantity--;
}break; }break;
case UKIND_DELETE:
case UKIND_END_PLACE:
case UKIND_PROXY:
break;
} }
} }

View File

@ -14,6 +14,11 @@
#include "modules/components.h" #include "modules/components.h"
#include "modules/systems.h" #include "modules/systems.h"
#if defined(PLATFORM_WEB)
#include <emscripten/emscripten.h>
void UpdateDrawFrame(void);
#endif
#define DEFAULT_WORLD_SEED 302097 #define DEFAULT_WORLD_SEED 302097
#define DEFAULT_CHUNK_SIZE 16 /* amount of blocks within a chunk (single axis) */ #define DEFAULT_CHUNK_SIZE 16 /* amount of blocks within a chunk (single axis) */
#define DEFAULT_WORLD_SIZE 32 /* amount of chunks within a world (single axis) */ #define DEFAULT_WORLD_SIZE 32 /* amount of chunks within a world (single axis) */
@ -73,7 +78,9 @@ int main(int argc, char** argv) {
sighandler_register(); sighandler_register();
game_init(host, port, play_mode, num_viewers, seed, chunk_size, world_size, is_dash_enabled); game_init(host, port, play_mode, num_viewers, seed, chunk_size, world_size, is_dash_enabled);
#if !defined(PLATFORM_WEB)
while (game_is_running()) { while (game_is_running()) {
reset_cached_time();
profile (PROF_MAIN_LOOP) { profile (PROF_MAIN_LOOP) {
game_input(); game_input();
game_update(); game_update();
@ -82,6 +89,9 @@ int main(int argc, char** argv) {
profiler_collate(); profiler_collate();
} }
#else
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
#endif
game_shutdown(); game_shutdown();
sighandler_unregister(); sighandler_unregister();
@ -90,3 +100,25 @@ int main(int argc, char** argv) {
zpl_opts_free(&opts); zpl_opts_free(&opts);
return 0; return 0;
} }
#if defined(PLATFORM_WEB)
void UpdateDrawFrame(void) {
reset_cached_time();
profile (PROF_MAIN_LOOP) {
game_input();
game_update();
game_render();
}
profiler_collate();
}
#endif
static float temp_time = 0.0f;
float get_cached_time(void) {
return temp_time;
}
void reset_cached_time(void) {
temp_time = zpl_time_rel();
}

View File

@ -120,7 +120,7 @@ network_client_fetch_stats(void) {
static float incoming_bandwidth = 0.0f; static float incoming_bandwidth = 0.0f;
static float outgoing_bandwidth = 0.0f; static float outgoing_bandwidth = 0.0f;
if (next_measure < zpl_time_rel()) { if (next_measure < get_cached_time()) {
#define MAX_RATE_SAMPLES 8 #define MAX_RATE_SAMPLES 8
static uint64_t last_total_sent = 0; static uint64_t last_total_sent = 0;
static uint64_t last_total_recv = 0; static uint64_t last_total_recv = 0;
@ -145,7 +145,7 @@ network_client_fetch_stats(void) {
incoming_bandwidth = stats.incoming_bandwidth /= MAX_RATE_SAMPLES; incoming_bandwidth = stats.incoming_bandwidth /= MAX_RATE_SAMPLES;
outgoing_bandwidth = stats.outgoing_bandwidth /= MAX_RATE_SAMPLES; outgoing_bandwidth = stats.outgoing_bandwidth /= MAX_RATE_SAMPLES;
next_measure = zpl_time_rel() + 1.0; next_measure = get_cached_time() + 1.0;
} else { } else {
stats.incoming_bandwidth = incoming_bandwidth; stats.incoming_bandwidth = incoming_bandwidth;
stats.outgoing_bandwidth = outgoing_bandwidth; stats.outgoing_bandwidth = outgoing_bandwidth;

View File

@ -17,16 +17,16 @@ typedef struct {
uint64_t total_received; uint64_t total_received;
uint32_t outgoing_total; uint32_t outgoing_total;
uint64_t total_sent; uint64_t total_sent;
// NOTE(zaklaus): bandwidth (bytes/sec) // NOTE(zaklaus): bandwidth (bytes/sec)
float incoming_bandwidth; float incoming_bandwidth;
float outgoing_bandwidth; float outgoing_bandwidth;
// NOTE(zaklaus): packet integrity // NOTE(zaklaus): packet integrity
uint64_t packets_sent; uint64_t packets_sent;
uint32_t packets_lost; uint32_t packets_lost;
float packet_loss; float packet_loss;
// NOTE(zaklaus): ping // NOTE(zaklaus): ping
uint32_t ping; uint32_t ping;
uint32_t low_ping; uint32_t low_ping;

View File

@ -105,6 +105,7 @@ int32_t pkt_unpack_struct(cw_unpack_context *uc, pkt_desc *desc, void *raw_blob,
} }
int32_t pkt_pack_struct(cw_pack_context *pc, pkt_desc *desc, void *raw_blob, uint32_t blob_size) { int32_t pkt_pack_struct(cw_pack_context *pc, pkt_desc *desc, void *raw_blob, uint32_t blob_size) {
(void)blob_size;
uint8_t *blob = (uint8_t*)raw_blob; uint8_t *blob = (uint8_t*)raw_blob;
for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field) { for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field) {
if (field->skip_count != 0) { if (field->skip_count != 0) {
@ -158,6 +159,7 @@ int32_t pkt_pack_struct(cw_pack_context *pc, pkt_desc *desc, void *raw_blob, uin
} }
void pkt_dump_struct(pkt_desc *desc, void* raw_blob, uint32_t blob_size) { void pkt_dump_struct(pkt_desc *desc, void* raw_blob, uint32_t blob_size) {
(void)blob_size;
uint8_t *blob = (uint8_t*)raw_blob; uint8_t *blob = (uint8_t*)raw_blob;
zpl_printf("{\n"); zpl_printf("{\n");
for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field) { for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field) {

View File

@ -7,6 +7,7 @@
#include "entity_view.h" #include "entity_view.h"
#include "camera.h" #include "camera.h"
#include "player.h" #include "player.h"
#include "entity.h"
#include "modules/components.h" #include "modules/components.h"
#include "modules/systems.h" #include "modules/systems.h"
@ -30,9 +31,8 @@ int32_t pkt_00_init_handler(pkt_header *header) {
Position *pos = ecs_get_mut(world_ecs(), ent_id, Position); Position *pos = ecs_get_mut(world_ecs(), ent_id, Position);
#if 0 #if 1
pos->x = world_dim()/2.0f + rand()%15*15.0f; entity_set_position(ent_id, world_dim()/2.0f + rand()%15*15.0f, world_dim()/2.0f + rand()%15*15.0f);
pos->y = world_dim()/2.0f + rand()%15*15.0f;
#else #else
pos->x = rand()%world_dim(); pos->x = rand()%world_dim();
pos->y = rand()%world_dim(); pos->y = rand()%world_dim();

View File

@ -29,7 +29,7 @@ int32_t pkt_01_welcome_handler(pkt_header *header) {
world_view *view = game_world_view_get(header->view_id); world_view *view = game_world_view_get(header->view_id);
zpl_printf("[INFO] initializing read-only world view id: %d...\n", header->view_id); zpl_printf("[INFO] initializing read-only world view id: %d... (chunk_size: %d, world_size: %d)\n", header->view_id, table.chunk_size, table.world_size);
world_view_init(view, table.seed, table.ent_id, table.chunk_size, table.world_size); world_view_init(view, table.seed, table.ent_id, table.chunk_size, table.world_size);
game_world_view_set_active(view); game_world_view_set_active(view);
return 0; return 0;

View File

@ -20,6 +20,27 @@ size_t pkt_send_librg_update_encode(void *data, int32_t data_length, uint8_t lay
return pkt_pack_msg_size(&pc); return pkt_pack_msg_size(&pc);
} }
#define NUM_SAMPLES 128
static float smooth_time(float time) {
static float time_samples[NUM_SAMPLES] = {};
static int32_t curr_index = 0;
time_samples[curr_index] = time;
if (++curr_index == NUM_SAMPLES)
curr_index = 0;
float average = 0;
for (int32_t i = NUM_SAMPLES; i--; )
average += time_samples[i];
average /= NUM_SAMPLES;
time = zpl_min(time, average * 2);
return time;
}
#undef NUM_SAMPLES
int32_t pkt_send_librg_update_handler(pkt_header *header) { int32_t pkt_send_librg_update_handler(pkt_header *header) {
cw_unpack_context uc = {0}; cw_unpack_context uc = {0};
pkt_unpack_msg(&uc, header, 2); pkt_unpack_msg(&uc, header, 2);
@ -41,8 +62,8 @@ int32_t pkt_send_librg_update_handler(pkt_header *header) {
int32_t state = librg_world_read(view->tracker, header->view_id, uc.item.as.bin.start, uc.item.as.bin.length, NULL); int32_t state = librg_world_read(view->tracker, header->view_id, uc.item.as.bin.start, uc.item.as.bin.length, NULL);
if (state < 0) zpl_printf("[ERROR] world read error: %d\n", state); if (state < 0) zpl_printf("[ERROR] world read error: %d\n", state);
float now = (float)zpl_time_rel(); float now = (float)get_cached_time();
view->delta_time[layer_id] = now - view->last_update[layer_id]; view->delta_time[layer_id] = smooth_time(now - view->last_update[layer_id]);
view->last_update[layer_id] = now; view->last_update[layer_id] = now;
return state; return state;

View File

@ -13,9 +13,20 @@
#include "debug_ui.h" #include "debug_ui.h"
#include "utils/raylib_helpers.h" #include "utils/raylib_helpers.h"
static uint16_t screenWidth = 1600; #if defined(PLATFORM_WEB)
static uint16_t screenHeight = 900; #include <emscripten.h>
static float target_zoom = 1.5f; EM_JS(int, canvas_get_width, (), {
return canvas.width;
});
EM_JS(int, canvas_get_height, (), {
return canvas.height;
});
#endif
static uint16_t screenWidth = 1024;
static uint16_t screenHeight = 768;
static float target_zoom = 0.6f;
static bool request_shutdown; static bool request_shutdown;
#define GFX_KIND 2 #define GFX_KIND 2
@ -27,14 +38,22 @@ static bool request_shutdown;
void platform_init() { void platform_init() {
SetTraceLogLevel(LOG_ERROR); SetTraceLogLevel(LOG_ERROR);
#if defined(PLATFORM_WEB)
screenWidth = (uint16_t)canvas_get_width();
screenHeight = (uint16_t)canvas_get_height();
#endif
InitWindow(screenWidth, screenHeight, "eco2d"); InitWindow(screenWidth, screenHeight, "eco2d");
SetWindowState(/*FLAG_WINDOW_UNDECORATED|*/FLAG_WINDOW_MAXIMIZED|FLAG_WINDOW_RESIZABLE|FLAG_MSAA_4X_HINT); SetWindowState(/*FLAG_WINDOW_UNDECORATED|*/FLAG_WINDOW_MAXIMIZED|FLAG_WINDOW_RESIZABLE|FLAG_MSAA_4X_HINT);
#if !defined(PLATFORM_WEB)
screenWidth = (uint16_t)GetScreenWidth(); screenWidth = (uint16_t)GetScreenWidth();
screenHeight = (uint16_t)GetScreenHeight(); screenHeight = (uint16_t)GetScreenHeight();
#endif
// ToggleFullscreen(); // ToggleFullscreen();
// SetTargetFPS(60.0); // SetTargetFPS(60.0);
renderer_init(); renderer_init();
} }
@ -85,13 +104,13 @@ inline static
void platform_input_update_input_frame(game_keystate_data data) { void platform_input_update_input_frame(game_keystate_data data) {
float mx = 0, my = 0; float mx = 0, my = 0;
platform_get_block_realpos(&mx, &my); platform_get_block_realpos(&mx, &my);
if (mx != last_blockpos_data.mx || my != last_blockpos_data.my){ if (mx != last_blockpos_data.mx || my != last_blockpos_data.my){
last_blockpos_data.mx = mx; last_blockpos_data.mx = mx;
last_blockpos_data.my = my; last_blockpos_data.my = my;
game_action_send_blockpos(mx, my); game_action_send_blockpos(mx, my);
} }
// NOTE(zaklaus): Test if there are any changes // NOTE(zaklaus): Test if there are any changes
if (data.x != last_input_data.x) goto send_data; if (data.x != last_input_data.x) goto send_data;
if (data.y != last_input_data.y) goto send_data; if (data.y != last_input_data.y) goto send_data;
@ -109,7 +128,7 @@ void platform_input_update_input_frame(game_keystate_data data) {
if (data.deletion_mode != last_input_data.deletion_mode) goto send_data; if (data.deletion_mode != last_input_data.deletion_mode) goto send_data;
if (zpl_memcompare(data.placements, last_input_data.placements, zpl_size_of(data.placements))) goto send_data; if (zpl_memcompare(data.placements, last_input_data.placements, zpl_size_of(data.placements))) goto send_data;
return; return;
send_data: send_data:
last_input_data = data; last_input_data = data;
game_action_send_keystate(&data); game_action_send_keystate(&data);
@ -117,11 +136,11 @@ void platform_input_update_input_frame(game_keystate_data data) {
void platform_input() { void platform_input() {
float mouse_z = (GetMouseWheelMove()*0.5f); float mouse_z = (GetMouseWheelMove()*0.5f);
if (mouse_z != 0.0f) { if (mouse_z != 0.0f) {
target_zoom = zpl_clamp(target_zoom+mouse_z, 0.1f, 10.0f); target_zoom = zpl_clamp(target_zoom+mouse_z, 0.1f, 11.0f);
} }
// NOTE(zaklaus): keystate handling // NOTE(zaklaus): keystate handling
{ {
float x=0.0f, y=0.0f; float x=0.0f, y=0.0f;
@ -130,12 +149,12 @@ void platform_input() {
if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f; if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f;
if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f; if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f;
if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) y -= 1.0f; if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) y -= 1.0f;
use = IsKeyPressed(KEY_SPACE); use = IsKeyPressed(KEY_SPACE);
sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT); sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
ctrl = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL); ctrl = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);
drop = IsKeyPressed(KEY_G) || player_inv.drop_item || storage_inv.drop_item; drop = IsKeyPressed(KEY_G) || player_inv.drop_item || storage_inv.drop_item;
// NOTE(zaklaus): NEW! mouse movement // NOTE(zaklaus): NEW! mouse movement
Vector2 mouse_pos = GetMousePosition(); Vector2 mouse_pos = GetMousePosition();
mouse_pos.x /= screenWidth; mouse_pos.x /= screenWidth;
@ -143,18 +162,18 @@ void platform_input() {
mouse_pos.x -= 0.5f; mouse_pos.x -= 0.5f;
mouse_pos.y -= 0.5f; mouse_pos.y -= 0.5f;
mouse_pos = Vector2Normalize(mouse_pos); mouse_pos = Vector2Normalize(mouse_pos);
if (game_get_kind() == GAMEKIND_SINGLE && IsMouseButtonDown(MOUSE_MIDDLE_BUTTON)) { if (game_get_kind() == GAMEKIND_SINGLE && IsMouseButtonDown(MOUSE_MIDDLE_BUTTON)) {
x = mouse_pos.x; x = mouse_pos.x;
y = -mouse_pos.y; y = -mouse_pos.y;
} }
inv_keystate *inv = (inv_is_storage_action) ? &storage_inv : &player_inv; inv_keystate *inv = (inv_is_storage_action) ? &storage_inv : &player_inv;
inv_keystate *inv2 = (!inv_is_storage_action) ? &storage_inv : &player_inv; inv_keystate *inv2 = (!inv_is_storage_action) ? &storage_inv : &player_inv;
// NOTE(zaklaus): don't perform picking if we manipulate our inventories // NOTE(zaklaus): don't perform picking if we manipulate our inventories
pick = (inv_is_inside||inv->item_is_held||inv2->item_is_held) ? false : IsMouseButtonDown(MOUSE_LEFT_BUTTON); pick = (inv_is_inside||inv->item_is_held||inv2->item_is_held) ? false : IsMouseButtonDown(MOUSE_LEFT_BUTTON);
game_keystate_data in_data = { game_keystate_data in_data = {
.x = x, .x = x,
.y = y, .y = y,
@ -164,7 +183,7 @@ void platform_input() {
.sprint = sprint, .sprint = sprint,
.ctrl = ctrl, .ctrl = ctrl,
.pick = pick, .pick = pick,
.drop = drop, .drop = drop,
.storage_action = inv_is_storage_action, .storage_action = inv_is_storage_action,
.selected_item = player_inv.selected_item, .selected_item = player_inv.selected_item,
@ -173,18 +192,18 @@ void platform_input() {
.swap_storage = inv_swap_storage, .swap_storage = inv_swap_storage,
.swap_from = inv->swap_from, .swap_from = inv->swap_from,
.swap_to = inv->swap_to, .swap_to = inv->swap_to,
.deletion_mode = build_is_deletion_mode, .deletion_mode = build_is_deletion_mode,
}; };
if (build_submit_placements) { if (build_submit_placements) {
in_data.placement_num = build_num_placements; in_data.placement_num = build_num_placements;
zpl_memcopy(in_data.placements, build_placements, build_num_placements*zpl_size_of(item_placement)); zpl_memcopy(in_data.placements, build_placements, build_num_placements*zpl_size_of(item_placement));
} }
platform_input_update_input_frame(in_data); platform_input_update_input_frame(in_data);
} }
// NOTE(zaklaus): cycle through viewers // NOTE(zaklaus): cycle through viewers
{ {
if (IsKeyPressed(KEY_Q)) { if (IsKeyPressed(KEY_Q)) {
@ -194,14 +213,14 @@ void platform_input() {
game_world_view_cycle_active(1); game_world_view_cycle_active(1);
} }
} }
// NOTE(zaklaus): switch render modes // NOTE(zaklaus): switch render modes
{ {
if (IsKeyPressed(KEY_O)) { if (IsKeyPressed(KEY_O)) {
renderer_switch(1-gfx_kind); renderer_switch(1-gfx_kind);
} }
} }
// NOTE(zaklaus): toggle debug drawing // NOTE(zaklaus): toggle debug drawing
#ifndef ECO2D_PROD #ifndef ECO2D_PROD
{ {
@ -218,13 +237,13 @@ void draw_selected_item() {
if (oe) { if (oe) {
// NOTE(zaklaus): sel item // NOTE(zaklaus): sel item
entity_view *e = game_world_view_active_get_entity(oe->sel_ent); entity_view *e = game_world_view_active_get_entity(oe->sel_ent);
if (e && e->kind == EKIND_DEVICE) { if (e && e->kind == EKIND_DEVICE) {
renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.4f)); renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.4f));
}else{ }else{
// NOTE(zaklaus): hover item // NOTE(zaklaus): hover item
entity_view *e = game_world_view_active_get_entity(oe->pick_ent); entity_view *e = game_world_view_active_get_entity(oe->pick_ent);
if (e && e->kind == EKIND_DEVICE) { if (e && e->kind == EKIND_DEVICE) {
renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.1f)); renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.1f));
} }
@ -233,16 +252,26 @@ void draw_selected_item() {
} }
void platform_render() { void platform_render() {
#if !defined(PLATFORM_WEB)
screenWidth = (uint16_t)GetScreenWidth(); screenWidth = (uint16_t)GetScreenWidth();
screenHeight = (uint16_t)GetScreenHeight(); screenHeight = (uint16_t)GetScreenHeight();
#else
uint16_t newScreenWidth = (uint16_t)canvas_get_width();
uint16_t newScreenHeight = (uint16_t)canvas_get_height();
if (newScreenWidth != screenWidth || newScreenHeight != screenHeight) {
screenWidth = newScreenWidth;
screenHeight = newScreenHeight;
SetWindowSize(screenWidth, screenHeight);
}
#endif
profile(PROF_ENTITY_LERP) { profile(PROF_ENTITY_LERP) {
game_world_view_active_entity_map(lerp_entity_positions); game_world_view_active_entity_map(lerp_entity_positions);
game_world_view_active_entity_map(do_entity_fadeinout); game_world_view_active_entity_map(do_entity_fadeinout);
} }
assets_frame(); assets_frame();
BeginDrawing(); BeginDrawing();
{ {
profile (PROF_RENDER) { profile (PROF_RENDER) {
@ -259,7 +288,7 @@ void platform_render() {
debug_draw(); debug_draw();
} }
EndDrawing(); EndDrawing();
if (request_shutdown) { if (request_shutdown) {
CloseWindow(); CloseWindow();
} }

View File

@ -62,7 +62,7 @@ void predict_receive_update(entity_view *d, entity_view *data) {
data->tran_time = d->tran_time; data->tran_time = d->tran_time;
} }
#define ENTITY_DO_LERP_SP 0 #define ENTITY_DO_LERP_SP 1
void lerp_entity_positions(uint64_t key, entity_view *data) { void lerp_entity_positions(uint64_t key, entity_view *data) {
(void)key; (void)key;

View File

@ -4,6 +4,8 @@
#define PROF_COLLATE_WINDOW 0.5 #define PROF_COLLATE_WINDOW 0.5
static float profiler_warmup = 3.0f;
// NOTE(zaklaus): KEEP ORDER IN SYNC WITH profiler_kind ENUM !!! // NOTE(zaklaus): KEEP ORDER IN SYNC WITH profiler_kind ENUM !!!
static profiler profilers[] = { static profiler profilers[] = {
{ .id = PROF_TOTAL_TIME, .name = "measured time" }, { .id = PROF_TOTAL_TIME, .name = "measured time" },
@ -33,6 +35,13 @@ void profiler_stop(profiler_kind id) {
} }
void profiler_collate() { void profiler_collate() {
if (profiler_warmup > 0) {
profiler_warmup -= GetFrameTime();
for (uint32_t i = PROF_MAIN_LOOP; i < MAX_PROF; i += 1) {
profiler_reset(i);
}
return;
}
static double frame_counter = 0.0; static double frame_counter = 0.0;
static uint64_t frames = 0; static uint64_t frames = 0;

View File

@ -1,13 +1,10 @@
static Camera3D render_camera_3d; static Camera3D render_camera_3d;
static float cam_zoom = 1.5f; static float cam_zoom = 1.5f;
#define CAM_OVERLAY_ZOOM_LEVEL 0.80f
float zpl_lerp(float,float,float); float zpl_lerp(float,float,float);
float zpl_to_degrees(float); float zpl_to_degrees(float);
void DEBUG_draw_ground_3d(uint64_t key, entity_view * data) { void DEBUG_draw_ground_3d(uint64_t key, entity_view * data) {
(void)key;
switch (data->kind) { switch (data->kind) {
case EKIND_CHUNK: { case EKIND_CHUNK: {
world_view *view = game_world_view_get_active(); world_view *view = game_world_view_get_active();
@ -145,7 +142,7 @@ void renderer_debug_draw_3d(void) {
} }
float renderer_zoom_get_3d(void) { float renderer_zoom_get_3d(void) {
return 1.0f; return cam_zoom;
} }
void renderer_draw_single_3d(float x, float y, asset_id id, Color color) { void renderer_draw_single_3d(float x, float y, asset_id id, Color color) {

View File

@ -1,7 +1,7 @@
static Camera2D render_camera; static Camera2D render_camera;
static float zoom_overlay_tran = 0.0f; static float zoom_overlay_tran = 0.0f;
#define CAM_OVERLAY_ZOOM_LEVEL 0.80f #define CAM_OVERLAY_ZOOM_LEVEL 0.15f
#define ALPHA(x) ColorAlpha(x, data->tran_time) #define ALPHA(x) ColorAlpha(x, data->tran_time)
float zpl_lerp(float,float,float); float zpl_lerp(float,float,float);
@ -13,23 +13,16 @@ void DEBUG_draw_ground(uint64_t key, entity_view * data) {
world_view *view = game_world_view_get_active(); world_view *view = game_world_view_get_active();
float size = (float)(view->chunk_size * WORLD_BLOCK_SIZE); float size = (float)(view->chunk_size * WORLD_BLOCK_SIZE);
float offset = 0.0; float offset = 0.0;
float x = data->x * size + offset; float x = data->x * size + offset;
float y = data->y * size + offset; float y = data->y * size + offset;
RenderTexture2D tex = GetChunkTexture(key); RenderTexture2D tex = GetChunkTexture(key);
float scale = (size)/(float)(tex.texture.width); float scale = (size)/(float)(tex.texture.width);
tex.texture.width *= (int32_t)scale; tex.texture.width *= (int32_t)scale;
tex.texture.height *= (int32_t)scale; tex.texture.height *= (int32_t)scale;
DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time)); DrawTextureRec(tex.texture, (Rectangle){0, 0, size, -size}, (Vector2){x, y}, ColorAlpha(WHITE, data->tran_time));
if (zoom_overlay_tran > 0.02f) {
DrawRectangleEco(x, y, size-offset, size-offset, ColorAlpha(ColorFromHSV((float)data->color, 0.13f, 0.89f), data->tran_time*zoom_overlay_tran*0.75f));
DrawTextEco(TextFormat("%d %d", (int)data->x, (int)data->y), x+15.0f, y+15.0f, 200 , ColorAlpha(BLACK, data->tran_time*zoom_overlay_tran), 0.0);
}
for (size_t ty = 0; ty < view->chunk_size; ty++) { for (size_t ty = 0; ty < view->chunk_size; ty++) {
for (size_t tx = 0; tx < view->chunk_size; tx++) { for (size_t tx = 0; tx < view->chunk_size; tx++) {
block_id blk_id = data->outer_blocks[(ty*view->chunk_size)+tx]; block_id blk_id = data->outer_blocks[(ty*view->chunk_size)+tx];
@ -39,7 +32,25 @@ void DEBUG_draw_ground(uint64_t key, entity_view * data) {
} }
} }
}break; }break;
default:break;
}
}
void DEBUG_draw_overlay(uint64_t key, entity_view * data) {
switch (data->kind) {
case EKIND_CHUNK: {
world_view *view = game_world_view_get_active();
float size = (float)(view->chunk_size * WORLD_BLOCK_SIZE);
float offset = 0.0;
float x = data->x * size + offset;
float y = data->y * size + offset;
DrawRectangleEco(x, y, size-offset, size-offset, ColorAlpha(ColorFromHSV((float)data->color, 0.13f, 0.89f), data->tran_time*zoom_overlay_tran*0.75f));
DrawTextEco(TextFormat("%d %d", (int)data->x, (int)data->y), x+15.0f, y+15.0f, 200 , ColorAlpha(BLACK, data->tran_time*zoom_overlay_tran), 0.0);
}break;
default:break; default:break;
} }
} }
@ -47,12 +58,12 @@ void DEBUG_draw_ground(uint64_t key, entity_view * data) {
extern bool inv_is_open; extern bool inv_is_open;
void DEBUG_draw_entities(uint64_t key, entity_view * data) { void DEBUG_draw_entities(uint64_t key, entity_view * data) {
uint16_t size = 16; float size = 16.f;
uint16_t font_size = (uint16_t)lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom); float font_size = lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom);
float font_spacing = 1.1f; float font_spacing = 1.1f;
float title_bg_offset = 4; float title_bg_offset = 4;
float fixed_title_offset = 8; float fixed_title_offset = 8.f;
switch (data->kind) { switch (data->kind) {
case EKIND_DEMO_NPC: { case EKIND_DEMO_NPC: {
float x = data->x; float x = data->x;
@ -64,12 +75,12 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
float y = data->y; float y = data->y;
float health = (data->hp / data->max_hp); float health = (data->hp / data->max_hp);
const char *title = TextFormat("Player %d", key); const char *title = TextFormat("Player %d", key);
int title_w = MeasureTextEco(title, font_size, font_spacing); float title_w = MeasureTextEco(title, font_size, font_spacing);
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time)); DrawRectangleEco(x-title_w/2.f-title_bg_offset/2.f, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(BLACK, data->tran_time));
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time)); DrawRectangleEco(x-title_w/2.f-title_bg_offset/2.f, y-size-fixed_title_offset, title_w*health+title_bg_offset, font_size*0.2f, ColorAlpha(RED, data->tran_time));
DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing); DrawTextEco(title, x-title_w/2.f, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(RAYWHITE, data->tran_time), font_spacing);
DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time)); DrawCircleEco(x, y, size, ColorAlpha(YELLOW, data->tran_time));
if (data->has_items && !data->inside_vehicle) { if (data->has_items && !data->inside_vehicle) {
float ix = data->x; float ix = data->x;
float iy = data->y; float iy = data->y;
@ -77,9 +88,9 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
asset_id it_kind = data->items[data->selected_item].kind; asset_id it_kind = data->items[data->selected_item].kind;
uint32_t qty = data->items[data->selected_item].quantity; uint32_t qty = data->items[data->selected_item].quantity;
DrawTexturePro(GetSpriteTexture2D(assets_find(it_kind)), ASSET_SRC_RECT(), ((Rectangle){ix, iy, 32, 32}), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE)); DrawTexturePro(GetSpriteTexture2D(assets_find(it_kind)), ASSET_SRC_RECT(), ((Rectangle){ix, iy, 32, 32}), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
if (!inv_is_open) if (!inv_is_open)
DrawTextEco(zpl_bprintf("%d", qty), ix+24, iy+24, 8, RAYWHITE, 0.0f); DrawTextEco(zpl_bprintf("%d", qty), x+24, y+24, 8, RAYWHITE, 0.0f);
} }
} }
}break; }break;
@ -87,16 +98,16 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
float x = data->x; float x = data->x;
float y = data->y; float y = data->y;
const char *title = TextFormat("Bot %d", key); const char *title = TextFormat("Bot %d", key);
int title_w = MeasureTextEco(title, font_size, font_spacing); float title_w = MeasureTextEco(title, font_size, font_spacing);
DrawRectangleEco(x-title_w/2-title_bg_offset/2, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(GRAY, data->tran_time)); DrawRectangleEco(x-title_w/2.f-title_bg_offset/2.f, y-size-font_size-fixed_title_offset, title_w+title_bg_offset, font_size, ColorAlpha(GRAY, data->tran_time));
DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(BLACK, data->tran_time), font_spacing); DrawTextEco(title, x-title_w/2.f, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(BLACK, data->tran_time), font_spacing);
DrawCircleEco(x, y, size, ColorAlpha(PURPLE, data->tran_time)); DrawCircleEco(x, y, size, ColorAlpha(PURPLE, data->tran_time));
}break; }break;
case EKIND_ITEM: { case EKIND_ITEM: {
float x = data->x - 32.f; float x = data->x - 32.f;
float y = data->y - 32.f; float y = data->y - 32.f;
DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE)); DrawTexturePro(GetSpriteTexture2D(assets_find(data->asset)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, ALPHA(WHITE));
DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f); DrawTextEco(zpl_bprintf("%d", data->quantity), x, y, 10, ALPHA(RAYWHITE), 0.0f);
}break; }break;
default:break; default:break;
} }
@ -104,7 +115,7 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
void DEBUG_draw_entities_low(uint64_t key, entity_view * data) { void DEBUG_draw_entities_low(uint64_t key, entity_view * data) {
(void)key; (void)key;
switch (data->kind) { switch (data->kind) {
case EKIND_VEHICLE: { case EKIND_VEHICLE: {
float x = data->x; float x = data->x;
@ -126,17 +137,21 @@ void renderer_draw_v0(void) {
render_camera.offset = (Vector2){(float)(screenWidth >> 1), (float)(screenHeight >> 1)}; render_camera.offset = (Vector2){(float)(screenWidth >> 1), (float)(screenHeight >> 1)};
render_camera.zoom = zpl_lerp(render_camera.zoom, target_zoom, GetFrameTime()*2.9978f); render_camera.zoom = zpl_lerp(render_camera.zoom, target_zoom, GetFrameTime()*2.9978f);
camera_update(); camera_update();
camera game_camera = camera_get(); camera game_camera = camera_get();
render_camera.target = (Vector2){(float)game_camera.x, (float)game_camera.y}; render_camera.target = (Vector2){(float)game_camera.x, (float)game_camera.y};
zoom_overlay_tran = zpl_lerp(zoom_overlay_tran, (target_zoom <= CAM_OVERLAY_ZOOM_LEVEL) ? 1.0f : 0.0f, GetFrameTime()*2.0f); zoom_overlay_tran = zpl_lerp(zoom_overlay_tran, (target_zoom <= CAM_OVERLAY_ZOOM_LEVEL) ? 1.0f : 0.0f, GetFrameTime()*2.0f);
ClearBackground(GetColor(0x222034)); ClearBackground(GetColor(0x222034));
BeginMode2D(render_camera); BeginMode2D(render_camera);
game_world_view_active_entity_map(DEBUG_draw_ground); game_world_view_active_entity_map(DEBUG_draw_ground);
game_world_view_active_entity_map(DEBUG_draw_entities_low); game_world_view_active_entity_map(DEBUG_draw_entities_low);
game_world_view_active_entity_map(DEBUG_draw_entities); game_world_view_active_entity_map(DEBUG_draw_entities);
if (zoom_overlay_tran > 0.02f) {
game_world_view_active_entity_map(DEBUG_draw_overlay);
}
EndMode2D(); EndMode2D();
} }
@ -149,18 +164,18 @@ void renderer_init_v0(void) {
render_camera.offset = (Vector2){(float)(screenWidth >> 1), (float)(screenHeight >> 1)}; render_camera.offset = (Vector2){(float)(screenWidth >> 1), (float)(screenHeight >> 1)};
render_camera.rotation = 0.0f; render_camera.rotation = 0.0f;
render_camera.zoom = 1.5f; render_camera.zoom = 1.5f;
// NOTE(zaklaus): Paint the screen before we load the game // NOTE(zaklaus): Paint the screen before we load the game
// TODO(zaklaus): Render a cool loading screen background maybe? :wink: :wink: // TODO(zaklaus): Render a cool loading screen background maybe? :wink: :wink:
BeginDrawing(); BeginDrawing();
ClearBackground(GetColor(0x222034)); ClearBackground(GetColor(0x222034));
char const *loading_text = "zpl.eco2d is loading..."; char const *loading_text = "zpl.eco2d is loading...";
int text_w = MeasureText(loading_text, 120); int text_w = MeasureText(loading_text, 120);
DrawText(loading_text, GetScreenWidth()-text_w-15, GetScreenHeight()-135, 120, RAYWHITE); DrawText(loading_text, GetScreenWidth()-text_w-15, GetScreenHeight()-135, 120, RAYWHITE);
EndDrawing(); EndDrawing();
blocks_setup(); blocks_setup();
assets_setup(); assets_setup();
} }
@ -173,11 +188,11 @@ void renderer_shutdown_v0(void) {
void renderer_debug_draw_v0(void) { void renderer_debug_draw_v0(void) {
BeginMode2D(render_camera); BeginMode2D(render_camera);
debug_draw_queue *que = debug_draw_samples(); debug_draw_queue *que = debug_draw_samples();
for (size_t i = 0; i < que->num_entries; i += 1) { for (size_t i = 0; i < que->num_entries; i += 1) {
debug_draw_entry *e = &que->entries[i]; debug_draw_entry *e = &que->entries[i];
Color color = GetColor(e->color); Color color = GetColor(e->color);
switch (e->kind) { switch (e->kind) {
case DDRAW_LINE: { case DDRAW_LINE: {
float x = e->a.x; float x = e->a.x;
@ -186,13 +201,13 @@ void renderer_debug_draw_v0(void) {
float y2 = e->b.y; float y2 = e->b.y;
DrawLineV((Vector2){x, y}, (Vector2){x2, y2}, color); DrawLineV((Vector2){x, y}, (Vector2){x2, y2}, color);
}break; }break;
case DDRAW_CIRCLE:{ case DDRAW_CIRCLE:{
float x = e->a.x; float x = e->a.x;
float y = e->a.y; float y = e->a.y;
DrawCircleLinesEco(x, y, e->radius, color); DrawCircleLinesEco(x, y, e->radius, color);
}break; }break;
case DDRAW_RECT:{ case DDRAW_RECT:{
float x = e->bmin.x; float x = e->bmin.x;
float y = e->bmin.y; float y = e->bmin.y;
@ -200,23 +215,23 @@ void renderer_debug_draw_v0(void) {
float h = e->bmax.y - e->bmin.y; float h = e->bmax.y - e->bmin.y;
DrawRectangleLinesEco(x, y, w, h, color); DrawRectangleLinesEco(x, y, w, h, color);
}break; }break;
default: { default: {
}break; }break;
} }
} }
EndMode2D(); EndMode2D();
} }
void renderer_draw_single_v0(float x, float y, asset_id id, Color color) { void renderer_draw_single_v0(float x, float y, asset_id id, Color color) {
BeginMode2D(render_camera); BeginMode2D(render_camera);
x -= 32.0f; x -= 32.0f;
y -= 32.0f; y -= 32.0f;
DrawTexturePro(GetSpriteTexture2D(assets_find(id)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, color); DrawTexturePro(GetSpriteTexture2D(assets_find(id)), ASSET_SRC_RECT(), ASSET_DST_RECT(x,y), (Vector2){0.5f,0.5f}, 0.0f, color);
EndMode2D(); EndMode2D();
} }

View File

@ -25,6 +25,7 @@ static BOOL WINAPI _sighandler_win32_control_handler(DWORD control_type)
#else //POSIX complaint #else //POSIX complaint
#include <sys/types.h> #include <sys/types.h>
static void _sighandler_posix_signal_handler(int sig) { static void _sighandler_posix_signal_handler(int sig) {
(void)sig;
game_request_close(); game_request_close();
} }
#endif #endif

View File

@ -10,8 +10,11 @@
#define ZPL_ENABLE_MATH #define ZPL_ENABLE_MATH
#include "zpl.h" #include "zpl.h"
float get_cached_time(void);
void reset_cached_time(void);
#define defer_var ZPL_CONCAT(_i_,__LINE__) #define defer_var ZPL_CONCAT(_i_,__LINE__)
#define defer(s,e) for ( \ #define defer(s,e) for ( \
uint32_t defer_var = (s, 0); \ uint32_t defer_var = (s, 0); \
!defer_var; \ !defer_var; \
(defer_var += 1), e) (defer_var += 1), e)

View File

@ -5,6 +5,7 @@
#include "utils/options.h" #include "utils/options.h"
void generate_minimap(int32_t seed, uint16_t block_size, uint16_t chunk_size, uint16_t world_size) { void generate_minimap(int32_t seed, uint16_t block_size, uint16_t chunk_size, uint16_t world_size) {
(void)block_size;
world_init(seed, chunk_size, world_size); world_init(seed, chunk_size, world_size);
block_id const *world; block_id const *world;

View File

@ -9,47 +9,47 @@
static inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; } static inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; }
static inline static inline
void DrawTextEco(const char *text, float posX, float posY, int fontSize, Color color, float spacing) { void DrawTextEco(const char *text, float posX, float posY, float fontSize, Color color, float spacing) {
#if 1 #if 1
// Check if default font has been loaded // Check if default font has been loaded
if (GetFontDefault().texture.id != 0) { if (GetFontDefault().texture.id != 0) {
Vector2 position = { (float)posX , (float)posY }; Vector2 position = { posX , posY };
float defaultFontSize = 10.0; // Default Font chars height in pixel float defaultFontSize = 10.0; // Default Font chars height in pixel
float new_spacing = spacing == 0.0f ? (float)fontSize/defaultFontSize : spacing; float new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing;
DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , color); DrawTextEx(GetFontDefault(), text, position, fontSize , new_spacing , color);
} }
#endif #endif
} }
static inline static inline
int MeasureTextEco(const char *text, int fontSize, float spacing) { float MeasureTextEco(const char *text, float fontSize, float spacing) {
#if 1 #if 1
Vector2 vec = { 0.0f, 0.0f }; Vector2 vec = { 0.0f, 0.0f };
// Check if default font has been loaded // Check if default font has been loaded
if (GetFontDefault().texture.id != 0) { if (GetFontDefault().texture.id != 0) {
float defaultFontSize = 10.0; // Default Font chars height in pixel float defaultFontSize = 10.0; // Default Font chars height in pixel
float new_spacing = spacing == 0.0f ? (float)fontSize/defaultFontSize : spacing; float new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing;
vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing); vec = MeasureTextEx(GetFontDefault(), text, fontSize, (float)new_spacing);
} }
return (int)vec.x; return vec.x;
#else #else
return 0; return 0.f;
#endif #endif
} }
static inline static inline
void DrawCircleEco(float centerX, float centerY, float radius, Color color) void DrawCircleEco(float centerX, float centerY, float radius, Color color)
{ {
DrawCircleV((Vector2){ (float)centerX , (float)centerY }, radius , color); DrawCircleV((Vector2){ (float)centerX , (float)centerY }, radius , color);
} }
static inline static inline
void DrawRectangleEco(float posX, float posY, float width, float height, Color color) void DrawRectangleEco(float posX, float posY, float width, float height, Color color)
{ {
DrawRectangleV((Vector2){ (float)posX , (float)posY }, (Vector2){ width , height }, color); DrawRectangleV((Vector2){ (float)posX , (float)posY }, (Vector2){ width , height }, color);
@ -85,68 +85,68 @@ void EcoDrawCube(Vector3 position, float width, float height, float length, floa
float x = 0.0f; float x = 0.0f;
float y = 0.0f; float y = 0.0f;
float z = 0.0f; float z = 0.0f;
rlCheckRenderBatchLimit(36); rlCheckRenderBatchLimit(36);
rlPushMatrix(); rlPushMatrix();
// NOTE: Transformation is applied in inverse order (scale -> rotate -> translate) // NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
rlTranslatef(position.x, position.y, position.z); rlTranslatef(position.x, position.y, position.z);
rlRotatef(heading, 0, 1, 0); rlRotatef(heading, 0, 1, 0);
//rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition //rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition
rlBegin(RL_TRIANGLES); rlBegin(RL_TRIANGLES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
// Front face // Front face
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Right
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
// Back face // Back face
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Left
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
// Top face // Top face
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Left
rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y + height/2, z + length/2); // Bottom Right
// Bottom face // Bottom face
rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Top Right
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left rlVertex3f(x - width/2, y - height/2, z - length/2); // Top Left
// Right face // Right face
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x + width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x + width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x + width/2, y + height/2, z + length/2); // Top Left
// Left face // Left face
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right rlVertex3f(x - width/2, y + height/2, z - length/2); // Top Right
rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left rlVertex3f(x - width/2, y - height/2, z + length/2); // Bottom Left
rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left rlVertex3f(x - width/2, y + height/2, z + length/2); // Top Left
rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right rlVertex3f(x - width/2, y - height/2, z - length/2); // Bottom Right
@ -157,37 +157,43 @@ void EcoDrawCube(Vector3 position, float width, float height, float length, floa
// Draw codepoint at specified position in 3D space // Draw codepoint at specified position in 3D space
void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontSize, bool backface, Color tint) void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontSize, bool backface, Color tint)
{ {
(void)font;
(void)codepoint;
(void)position;
(void)fontSize;
(void)backface;
(void)tint;
#if 0 #if 0
// Character index position in sprite font // Character index position in sprite font
// NOTE: In case a codepoint is not available in the font, index returned points to '?' // NOTE: In case a codepoint is not available in the font, index returned points to '?'
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
float scale = fontSize/(float)font.baseSize; float scale = fontSize/(float)font.baseSize;
// Character destination rectangle on screen // Character destination rectangle on screen
// NOTE: We consider charsPadding on drawing // NOTE: We consider charsPadding on drawing
position.x += (float)(font.chars[index].offsetX - font.charsPadding)/(float)font.baseSize*scale; position.x += (float)(font.chars[index].offsetX - font.charsPadding)/(float)font.baseSize*scale;
position.z += (float)(font.chars[index].offsetY - font.charsPadding)/(float)font.baseSize*scale; position.z += (float)(font.chars[index].offsetY - font.charsPadding)/(float)font.baseSize*scale;
// Character source rectangle from font texture atlas // Character source rectangle from font texture atlas
// NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects // NOTE: We consider chars padding when drawing, it could be required for outline/glow shader effects
Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding, Rectangle srcRec = { font.recs[index].x - (float)font.charsPadding, font.recs[index].y - (float)font.charsPadding,
font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding }; font.recs[index].width + 2.0f*font.charsPadding, font.recs[index].height + 2.0f*font.charsPadding };
float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float width = (float)(font.recs[index].width + 2.0f*font.charsPadding)/(float)font.baseSize*scale;
float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale; float height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale;
if (font.texture.id > 0) if (font.texture.id > 0)
{ {
const float x = 0.0f; const float x = 0.0f;
const float y = 0.0f; const float y = 0.0f;
const float z = 0.0f; const float z = 0.0f;
// normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f) // normalized texture coordinates of the glyph inside the font texture (0.0f -> 1.0f)
const float tx = srcRec.x/font.texture.width; const float tx = srcRec.x/font.texture.width;
const float ty = srcRec.y/font.texture.height; const float ty = srcRec.y/font.texture.height;
const float tw = (srcRec.x+srcRec.width)/font.texture.width; const float tw = (srcRec.x+srcRec.width)/font.texture.width;
const float th = (srcRec.y+srcRec.height)/font.texture.height; const float th = (srcRec.y+srcRec.height)/font.texture.height;
{ {
#if defined(RAYLIB_NEW_RLGL) #if defined(RAYLIB_NEW_RLGL)
} }
@ -199,17 +205,17 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
#endif #endif
rlPushMatrix(); rlPushMatrix();
rlTranslatef(position.x, position.y, position.z); rlTranslatef(position.x, position.y, position.z);
rlBegin(RL_QUADS); rlBegin(RL_QUADS);
rlColor4ub(tint.r, tint.g, tint.b, tint.a); rlColor4ub(tint.r, tint.g, tint.b, tint.a);
// Front Face // Front Face
rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up rlNormal3f(0.0f, 1.0f, 0.0f); // Normal Pointing Up
rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Left Of The Texture and Quad rlTexCoord2f(tx, ty); rlVertex3f(x, y, z); // Top Left Of The Texture and Quad
rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Left Of The Texture and Quad rlTexCoord2f(tx, th); rlVertex3f(x, y, z + height); // Bottom Left Of The Texture and Quad
rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Right Of The Texture and Quad rlTexCoord2f(tw, th); rlVertex3f(x + width, y, z + height); // Bottom Right Of The Texture and Quad
rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad rlTexCoord2f(tw, ty); rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad
if (backface) if (backface)
{ {
// Back Face // Back Face
@ -221,7 +227,7 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
} }
rlEnd(); rlEnd();
rlPopMatrix(); rlPopMatrix();
#if defined(RAYLIB_NEW_RLGL) #if defined(RAYLIB_NEW_RLGL)
rlSetTexture(0); rlSetTexture(0);
#else #else
@ -234,23 +240,23 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, Color tint) { void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, float fontSpacing, float lineSpacing, bool backface, Color tint) {
#if 0 #if 0
int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop int length = TextLength(text); // Total length in bytes of the text, scanned by codepoints in loop
float textOffsetY = 0.0f; // Offset between lines (on line break '\n') float textOffsetY = 0.0f; // Offset between lines (on line break '\n')
float textOffsetX = 0.0f; // Offset X to next character to draw float textOffsetX = 0.0f; // Offset X to next character to draw
float scale = fontSize/(float)font.baseSize; float scale = fontSize/(float)font.baseSize;
for (int i = 0; i < length;) for (int i = 0; i < length;)
{ {
// Get next codepoint from byte string and glyph index in font // Get next codepoint from byte string and glyph index in font
int codepointByteCount = 0; int codepointByteCount = 0;
int codepoint = GetCodepoint(&text[i], &codepointByteCount); int codepoint = GetCodepoint(&text[i], &codepointByteCount);
int index = GetGlyphIndex(font, codepoint); int index = GetGlyphIndex(font, codepoint);
// NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: Normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol moving one byte // but we need to draw all of the bad bytes using the '?' symbol moving one byte
if (codepoint == 0x3f) codepointByteCount = 1; if (codepoint == 0x3f) codepointByteCount = 1;
if (codepoint == '\n') if (codepoint == '\n')
{ {
// NOTE: Fixed line spacing of 1.5 line-height // NOTE: Fixed line spacing of 1.5 line-height
@ -264,46 +270,46 @@ void DrawText3D(Font font, const char *text, Vector3 position, float fontSize, f
{ {
DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint); DrawTextCodepoint3D(font, codepoint, (Vector3){ position.x + textOffsetX, position.y, position.z + textOffsetY }, fontSize, backface, tint);
} }
if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale; if (font.chars[index].advanceX == 0) textOffsetX += (float)(font.recs[index].width + fontSpacing)/(float)font.baseSize*scale;
else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale; else textOffsetX += (float)(font.chars[index].advanceX + fontSpacing)/(float)font.baseSize*scale;
} }
i += codepointByteCount; // Move text bytes counter to next codepoint i += codepointByteCount; // Move text bytes counter to next codepoint
} }
#endif #endif
} }
Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) { Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) {
#if 0 #if 0
int len = TextLength(text); int len = TextLength(text);
int tempLen = 0; // Used to count longer text line num chars int tempLen = 0; // Used to count longer text line num chars
int lenCounter = 0; int lenCounter = 0;
float tempTextWidth = 0.0f; // Used to count longer text line width float tempTextWidth = 0.0f; // Used to count longer text line width
float scale = fontSize/(float)font.baseSize; float scale = fontSize/(float)font.baseSize;
float textHeight = scale; float textHeight = scale;
float textWidth = 0.0f; float textWidth = 0.0f;
int letter = 0; // Current character int letter = 0; // Current character
int index = 0; // Index position in sprite font int index = 0; // Index position in sprite font
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
{ {
lenCounter++; lenCounter++;
int next = 0; int next = 0;
letter = GetCodepoint(&text[i], &next); letter = GetCodepoint(&text[i], &next);
index = GetGlyphIndex(font, letter); index = GetGlyphIndex(font, letter);
// NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f) // NOTE: normally we exit the decoding sequence as soon as a bad byte is found (and return 0x3f)
// but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1 // but we need to draw all of the bad bytes using the '?' symbol so to not skip any we set next = 1
if (letter == 0x3f) next = 1; if (letter == 0x3f) next = 1;
i += next - 1; i += next - 1;
if (letter != '\n') if (letter != '\n')
{ {
if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale; if (font.chars[index].advanceX != 0) textWidth += (font.chars[index].advanceX+fontSpacing)/(float)font.baseSize*scale;
@ -316,17 +322,17 @@ Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpa
textWidth = 0.0f; textWidth = 0.0f;
textHeight += scale + lineSpacing/(float)font.baseSize*scale; textHeight += scale + lineSpacing/(float)font.baseSize*scale;
} }
if (tempLen < lenCounter) tempLen = lenCounter; if (tempLen < lenCounter) tempLen = lenCounter;
} }
if (tempTextWidth < textWidth) tempTextWidth = textWidth; if (tempTextWidth < textWidth) tempTextWidth = textWidth;
Vector3 vec = { 0 }; Vector3 vec = { 0 };
vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure
vec.y = 0.25f; vec.y = 0.25f;
vec.z = textHeight; vec.z = textHeight;
return vec; return vec;
#endif #endif
Vector3 todo = {0}; Vector3 todo = {0};
@ -346,10 +352,10 @@ Color GenerateRandomColor(float s, float v) {
void DrawCircleLinesEco(float centerX, float centerY, float radius, Color color) void DrawCircleLinesEco(float centerX, float centerY, float radius, Color color)
{ {
rlCheckRenderBatchLimit(2*36); rlCheckRenderBatchLimit(2*36);
rlBegin(RL_LINES); rlBegin(RL_LINES);
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360) // NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
for (int i = 0; i < 360; i += 10) for (int i = 0; i < 360; i += 10)
{ {
@ -365,13 +371,13 @@ void DrawRectangleLinesEco(float posX, float posY, float width, float height, Co
rlColor4ub(color.r, color.g, color.b, color.a); rlColor4ub(color.r, color.g, color.b, color.a);
rlVertex2f(posX + 1, posY + 1); rlVertex2f(posX + 1, posY + 1);
rlVertex2f(posX + width, posY + 1); rlVertex2f(posX + width, posY + 1);
rlVertex2f(posX + width, posY + 1); rlVertex2f(posX + width, posY + 1);
rlVertex2f(posX + width, posY + height); rlVertex2f(posX + width, posY + height);
rlVertex2f(posX + width, posY + height); rlVertex2f(posX + width, posY + height);
rlVertex2f(posX + 1, posY + height); rlVertex2f(posX + 1, posY + height);
rlVertex2f(posX + 1, posY + height); rlVertex2f(posX + 1, posY + height);
rlVertex2f(posX + 1, posY + 1); rlVertex2f(posX + 1, posY + 1);
rlEnd(); rlEnd();

View File

@ -6,6 +6,7 @@ typedef enum {
BLOCK_FLAG_COLLISION = (1 << 1), BLOCK_FLAG_COLLISION = (1 << 1),
BLOCK_FLAG_HAZARD = (1 << 2), BLOCK_FLAG_HAZARD = (1 << 2),
BLOCK_FLAG_ESSENTIAL = (1 << 3), BLOCK_FLAG_ESSENTIAL = (1 << 3),
BLOCK_FLAG_DESTROY_ON_COLLISION = (1 << 4),
} block_flags; } block_flags;
typedef uint16_t block_id; typedef uint16_t block_id;
@ -29,4 +30,4 @@ void *blocks_get_img(block_id id);
void blocks_build_chunk_tex(uint64_t id, block_id *blocks, void *view); void blocks_build_chunk_tex(uint64_t id, block_id *blocks, void *view);
void *blocks_get_chunk_tex(uint64_t id); void *blocks_get_chunk_tex(uint64_t id);
void blocks_remove_chunk_tex(uint64_t id); void blocks_remove_chunk_tex(uint64_t id);

View File

@ -16,12 +16,12 @@ static block blocks[] = {
BLOCK(ASSET_LAVA, BLOCK_FLAG_HAZARD, '!', .drag = 6.2f , .friction = 4.0f), BLOCK(ASSET_LAVA, BLOCK_FLAG_HAZARD, '!', .drag = 6.2f , .friction = 4.0f),
BLOCK(ASSET_FENCE, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 1.0f), BLOCK(ASSET_FENCE, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 1.0f),
BLOCK(ASSET_WOOD, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f), BLOCK(ASSET_WOOD, BLOCK_FLAG_COLLISION, '#', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f),
BLOCK(ASSET_TREE, BLOCK_FLAG_COLLISION, '@', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f), BLOCK(ASSET_TREE, BLOCK_FLAG_COLLISION|BLOCK_FLAG_DESTROY_ON_COLLISION, '@', .drag = 1.0f , .friction = 1.0f, .bounce = 0.0f),
BLOCK(ASSET_BELT_LEFT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = -150.0f), BLOCK(ASSET_BELT_LEFT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = -150.0f),
BLOCK(ASSET_BELT_RIGHT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = 150.0f), BLOCK(ASSET_BELT_RIGHT, 0, '@', .drag = 1.0f , .friction = 1.0f, .velx = 150.0f),
BLOCK(ASSET_BELT_UP, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = -150.0f), BLOCK(ASSET_BELT_UP, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = -150.0f),
BLOCK(ASSET_BELT_DOWN, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = 150.0f), BLOCK(ASSET_BELT_DOWN, 0, '@', .drag = 1.0f , .friction = 1.0f, .vely = 150.0f),
}; };
ZPL_STATIC_ASSERT(sizeof(blocks)/sizeof(block) < ZPL_U16_MAX, "too many registered blocks! (max. 65536)"); ZPL_STATIC_ASSERT(sizeof(blocks)/sizeof(block) < ZPL_U16_MAX, "too many registered blocks! (max. 65536)");

View File

@ -14,88 +14,90 @@
#include "packets/pkt_send_librg_update.h" #include "packets/pkt_send_librg_update.h"
#define ECO2D_STREAM_ACTIONFILTER 1
ZPL_TABLE(static, world_snapshot, world_snapshot_, entity_view); ZPL_TABLE(static, world_snapshot, world_snapshot_, entity_view);
static world_data world = {0}; static world_data world = {0};
static world_snapshot streamer_snapshot; static world_snapshot streamer_snapshot;
entity_view world_build_entity_view(int64_t e) { entity_view *world_build_entity_view(int64_t e) {
entity_view *cached_ev = world_snapshot_get(&streamer_snapshot, e); entity_view *cached_ev = world_snapshot_get(&streamer_snapshot, e);
if (cached_ev) return *cached_ev; if (cached_ev) return cached_ev;
entity_view view = {0}; entity_view view = {0};
const Classify *classify = ecs_get(world_ecs(), e, Classify); const Classify *classify = ecs_get(world_ecs(), e, Classify);
ZPL_ASSERT(classify); ZPL_ASSERT(classify);
view.kind = classify->id; view.kind = classify->id;
const Position *pos = ecs_get(world_ecs(), e, Position); const Position *pos = ecs_get(world_ecs(), e, Position);
if (pos) { if (pos) {
view.x = pos->x; view.x = pos->x;
view.y = pos->y; view.y = pos->y;
} }
const Velocity *vel = ecs_get(world_ecs(), e, Velocity); const Velocity *vel = ecs_get(world_ecs(), e, Velocity);
if (vel) { if (vel) {
view.flag |= EFLAG_INTERP; view.flag |= EFLAG_INTERP;
view.vx = vel->x; view.vx = vel->x;
view.vy = vel->y; view.vy = vel->y;
} }
const Health *health = ecs_get(world_ecs(), e, Health); const Health *health = ecs_get(world_ecs(), e, Health);
if (health) { if (health) {
view.hp = health->hp; view.hp = health->hp;
view.max_hp = health->max_hp; view.max_hp = health->max_hp;
} }
if (ecs_get(world_ecs(), e, Vehicle)) { if (ecs_get(world_ecs(), e, Vehicle)) {
Vehicle const* veh = ecs_get(world_ecs(), e, Vehicle); Vehicle const* veh = ecs_get(world_ecs(), e, Vehicle);
view.heading = veh->heading; view.heading = veh->heading;
} }
if (ecs_get(world_ecs(), e, ItemDrop)) { if (ecs_get(world_ecs(), e, ItemDrop)) {
ItemDrop const* dr = ecs_get(world_ecs(), e, ItemDrop); ItemDrop const* dr = ecs_get(world_ecs(), e, ItemDrop);
view.asset = dr->kind; view.asset = dr->kind;
view.quantity = dr->quantity; view.quantity = dr->quantity;
} }
if (ecs_get(world_ecs(), e, Device)) { if (ecs_get(world_ecs(), e, Device)) {
Device const* dev = ecs_get(world_ecs(), e, Device); Device const* dev = ecs_get(world_ecs(), e, Device);
view.asset = dev->asset; view.asset = dev->asset;
} }
view.inside_vehicle = ecs_get(world_ecs(), e, IsInVehicle) != 0 ? true : false; view.inside_vehicle = ecs_get(world_ecs(), e, IsInVehicle) != 0 ? true : false;
Inventory *inv = 0; Inventory *inv = 0;
if ((inv = ecs_get_mut_if(world_ecs(), e, Inventory))) { if ((inv = ecs_get_mut_if(world_ecs(), e, Inventory))) {
view.has_items = true; view.has_items = true;
for (int i = 0; i < ITEMS_INVENTORY_SIZE; i += 1) { for (int i = 0; i < ITEMS_INVENTORY_SIZE; i += 1) {
view.items[i] = inv->items[i]; view.items[i] = inv->items[i];
} }
const Input *in = ecs_get(world_ecs(), e, Input); const Input *in = ecs_get(world_ecs(), e, Input);
if (in){ if (in){
view.selected_item = in->selected_item; view.selected_item = in->selected_item;
view.pick_ent = (uint64_t)in->pick_ent; view.pick_ent = (uint64_t)in->pick_ent;
view.sel_ent = (uint64_t)in->sel_ent; view.sel_ent = (uint64_t)in->sel_ent;
if (world_entity_valid(in->storage_ent)){ if (world_entity_valid(in->storage_ent)){
ItemContainer *ic = 0; ItemContainer *ic = 0;
if ((ic = ecs_get_mut_if(world_ecs(), in->storage_ent, ItemContainer))){ if ((ic = ecs_get_mut_if(world_ecs(), in->storage_ent, ItemContainer))){
view.has_storage_items = true; view.has_storage_items = true;
for (int i = 0; i < ITEMS_CONTAINER_SIZE; i += 1) { for (int i = 0; i < ITEMS_CONTAINER_SIZE; i += 1) {
view.storage_items[i] = ic->items[i]; view.storage_items[i] = ic->items[i];
} }
view.storage_selected_item = in->storage_selected_item; view.storage_selected_item = in->storage_selected_item;
} }
} }
} }
} }
Chunk *chunk = 0; Chunk *chunk = 0;
if ((chunk = ecs_get_mut_if(world_ecs(), e, Chunk))) { if ((chunk = ecs_get_mut_if(world_ecs(), e, Chunk))) {
view.x = chunk->x; view.x = chunk->x;
@ -103,18 +105,18 @@ entity_view world_build_entity_view(int64_t e) {
view.blocks_used = 1; view.blocks_used = 1;
view.is_dirty = chunk->is_dirty; view.is_dirty = chunk->is_dirty;
chunk->is_dirty = false; chunk->is_dirty = false;
for (int i = 0; i < world.chunk_size*world.chunk_size; i += 1) { for (int i = 0; i < world.chunk_size*world.chunk_size; i += 1) {
view.blocks[i] = world.block_mapping[chunk->id][i]; view.blocks[i] = world.block_mapping[chunk->id][i];
} }
for (int i = 0; i < world.chunk_size*world.chunk_size; i += 1) { for (int i = 0; i < world.chunk_size*world.chunk_size; i += 1) {
view.outer_blocks[i] = world.outer_block_mapping[chunk->id][i]; view.outer_blocks[i] = world.outer_block_mapping[chunk->id][i];
} }
} }
world_snapshot_set(&streamer_snapshot, e, view); world_snapshot_set(&streamer_snapshot, e, view);
return view; return world_snapshot_get(&streamer_snapshot, e);
} }
int32_t tracker_write_create(librg_world *w, librg_event *e) { int32_t tracker_write_create(librg_world *w, librg_event *e) {
@ -127,7 +129,7 @@ int32_t tracker_write_create(librg_world *w, librg_event *e) {
#endif #endif
size_t actual_length = librg_event_size_get(w, e); size_t actual_length = librg_event_size_get(w, e);
char *buffer = librg_event_buffer_get(w, e); char *buffer = librg_event_buffer_get(w, e);
return (int32_t)entity_view_pack_struct(buffer, actual_length, world_build_entity_view(entity_id)); return (int32_t)entity_view_pack_struct(buffer, actual_length, world_build_entity_view(entity_id));
} }
@ -147,24 +149,24 @@ int32_t tracker_write_update(librg_world *w, librg_event *e) {
int64_t entity_id = librg_event_entity_get(w, e); int64_t entity_id = librg_event_entity_get(w, e);
size_t actual_length = librg_event_size_get(w, e); size_t actual_length = librg_event_size_get(w, e);
char *buffer = librg_event_buffer_get(w, e); char *buffer = librg_event_buffer_get(w, e);
entity_view view = world_build_entity_view(entity_id); entity_view *view = world_build_entity_view(entity_id);
// NOTE(zaklaus): exclude chunks from updates as they never move // NOTE(zaklaus): exclude chunks from updates as they never move
{ {
if (view.kind == EKIND_CHUNK && !view.is_dirty) { if (view->kind == EKIND_CHUNK && !view->is_dirty) {
return LIBRG_WRITE_REJECT; return LIBRG_WRITE_REJECT;
} }
} }
// NOTE(zaklaus): action-based updates // NOTE(zaklaus): action-based updates
#if ECO2D_STREAM_ACTIONFILTER #if ECO2D_STREAM_ACTIONFILTER
{ {
if (view.kind != EKIND_CHUNK && !entity_can_stream(entity_id)) { if (view->kind != EKIND_CHUNK && !entity_can_stream(entity_id)) {
return LIBRG_WRITE_REJECT; return LIBRG_WRITE_REJECT;
} }
} }
#endif #endif
return (int32_t)entity_view_pack_struct(buffer, actual_length, view); return (int32_t)entity_view_pack_struct(buffer, actual_length, view);
} }
@ -187,15 +189,15 @@ void world_chunk_setup_grid(void) {
world.outer_block_mapping[i] = zpl_malloc(sizeof(block_id)*zpl_square(world.chunk_size)); world.outer_block_mapping[i] = zpl_malloc(sizeof(block_id)*zpl_square(world.chunk_size));
chunk->id = i; chunk->id = i;
chunk->is_dirty = false; chunk->is_dirty = false;
for (int y = 0; y < world.chunk_size; y += 1) { for (int y = 0; y < world.chunk_size; y += 1) {
for (int x = 0; x < world.chunk_size; x += 1) { for (int x = 0; x < world.chunk_size; x += 1) {
int chk_x = chunk->x * world.chunk_size; int chk_x = chunk->x * world.chunk_size;
int chk_y = chunk->y * world.chunk_size; int chk_y = chunk->y * world.chunk_size;
block_id *c = &world.block_mapping[i][(y*world.chunk_size)+x]; block_id *c = &world.block_mapping[i][(y*world.chunk_size)+x];
*c = world.data[(chk_y+y)*world.dim + (chk_x+x)]; *c = world.data[(chk_y+y)*world.dim + (chk_x+x)];
c = &world.outer_block_mapping[i][(y*world.chunk_size)+x]; c = &world.outer_block_mapping[i][(y*world.chunk_size)+x];
*c = world.outer_data[(chk_y+y)*world.dim + (chk_x+x)]; *c = world.outer_data[(chk_y+y)*world.dim + (chk_x+x)];
} }
@ -206,14 +208,14 @@ void world_chunk_setup_grid(void) {
static inline static inline
void world_configure_tracker(void) { void world_configure_tracker(void) {
world.tracker = librg_world_create(); world.tracker = librg_world_create();
ZPL_ASSERT_MSG(world.tracker, "[ERROR] An error occurred while trying to create a server world."); ZPL_ASSERT_MSG(world.tracker, "[ERROR] An error occurred while trying to create a server world.");
/* config our world grid */ /* config our world grid */
librg_config_chunksize_set(world.tracker, WORLD_BLOCK_SIZE * world.chunk_size, WORLD_BLOCK_SIZE * world.chunk_size, 0); librg_config_chunksize_set(world.tracker, WORLD_BLOCK_SIZE * world.chunk_size, WORLD_BLOCK_SIZE * world.chunk_size, 1);
librg_config_chunkamount_set(world.tracker, world.chunk_amount, world.chunk_amount, 0); librg_config_chunkamount_set(world.tracker, world.chunk_amount, world.chunk_amount, 0);
librg_config_chunkoffset_set(world.tracker, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG); librg_config_chunkoffset_set(world.tracker, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG);
librg_event_set(world.tracker, LIBRG_WRITE_CREATE, tracker_write_create); librg_event_set(world.tracker, LIBRG_WRITE_CREATE, tracker_write_create);
librg_event_set(world.tracker, LIBRG_WRITE_REMOVE, tracker_write_remove); librg_event_set(world.tracker, LIBRG_WRITE_REMOVE, tracker_write_remove);
librg_event_set(world.tracker, LIBRG_WRITE_UPDATE, tracker_write_update); librg_event_set(world.tracker, LIBRG_WRITE_UPDATE, tracker_write_update);
@ -223,14 +225,14 @@ static inline
void world_init_worldgen_data(void) { void world_init_worldgen_data(void) {
world.data = zpl_malloc(sizeof(block_id)*world.size); world.data = zpl_malloc(sizeof(block_id)*world.size);
world.outer_data = zpl_malloc(sizeof(block_id)*world.size); world.outer_data = zpl_malloc(sizeof(block_id)*world.size);
ZPL_ASSERT(world.data && world.outer_data); ZPL_ASSERT(world.data && world.outer_data);
} }
static inline static inline
void world_setup_ecs(void) { void world_setup_ecs(void) {
world.ecs = ecs_init(); world.ecs = ecs_init();
ECS_IMPORT(world.ecs, Components); ECS_IMPORT(world.ecs, Components);
ECS_IMPORT(world.ecs, Systems); ECS_IMPORT(world.ecs, Systems);
world.ecs_update = ecs_query_new(world.ecs, "components.ClientInfo, components.Position"); world.ecs_update = ecs_query_new(world.ecs, "components.ClientInfo, components.Position");
@ -249,7 +251,7 @@ static inline
void world_generate_instance(void) { void world_generate_instance(void) {
int32_t world_build_status = worldgen_test(&world); int32_t world_build_status = worldgen_test(&world);
ZPL_ASSERT(world_build_status >= 0); ZPL_ASSERT(world_build_status >= 0);
for (int i = 0; i < zpl_square(world.dim); ++i) { for (int i = 0; i < zpl_square(world.dim); ++i) {
if (world.data[i] == 0) { if (world.data[i] == 0) {
ZPL_PANIC("Worldgen failure! Block %d is unset!\n", i); ZPL_PANIC("Worldgen failure! Block %d is unset!\n", i);
@ -271,10 +273,10 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) {
world.seed = seed; world.seed = seed;
world.chunk_size = chunk_size; world.chunk_size = chunk_size;
world.chunk_amount = chunk_amount; world.chunk_amount = chunk_amount;
world.dim = (world.chunk_size * world.chunk_amount); world.dim = (world.chunk_size * world.chunk_amount);
world.size = world.dim * world.dim; world.size = world.dim * world.dim;
world_configure_tracker(); world_configure_tracker();
world_setup_ecs(); world_setup_ecs();
world_init_worldgen_data(); world_init_worldgen_data();
@ -282,9 +284,9 @@ int32_t world_init(int32_t seed, uint16_t chunk_size, uint16_t chunk_amount) {
world_init_mapping(); world_init_mapping();
world_chunk_setup_grid(); world_chunk_setup_grid();
world_free_worldgen_data(); world_free_worldgen_data();
zpl_printf("[INFO] Created a new server world\n"); zpl_printf("[INFO] Created a new server world\n");
return WORLD_ERROR_NONE; return WORLD_ERROR_NONE;
} }
@ -307,35 +309,35 @@ int32_t world_destroy(void) {
#define WORLD_LIBRG_BUFSIZ 2000000 #define WORLD_LIBRG_BUFSIZ 2000000
static void world_tracker_update(uint8_t ticker, float freq, uint8_t radius) { static void world_tracker_update(uint8_t ticker, float freq, uint8_t radius) {
if (world.tracker_update[ticker] > (float)zpl_time_rel()) return; if (world.tracker_update[ticker] > (float)(get_cached_time())) return;
world.tracker_update[ticker] = (float)zpl_time_rel() + freq; world.tracker_update[ticker] = (float)(get_cached_time()) + freq;
profile(PROF_WORLD_WRITE) { profile(PROF_WORLD_WRITE) {
ecs_iter_t it = ecs_query_iter(world_ecs(), world.ecs_update); ecs_iter_t it = ecs_query_iter(world_ecs(), world.ecs_update);
static char buffer[WORLD_LIBRG_BUFSIZ] = {0}; static char buffer[WORLD_LIBRG_BUFSIZ] = {0};
world.active_layer_id = ticker; world.active_layer_id = ticker;
while (ecs_query_next(&it)) { while (ecs_query_next(&it)) {
ClientInfo *p = ecs_field(&it, ClientInfo, 1); ClientInfo *p = ecs_field(&it, ClientInfo, 1);
for (int i = 0; i < it.count; i++) { for (int i = 0; i < it.count; i++) {
size_t datalen = WORLD_LIBRG_BUFSIZ; size_t datalen = WORLD_LIBRG_BUFSIZ;
if (!p[i].active) if (!p[i].active)
continue; continue;
int32_t result = librg_world_write(world_tracker(), it.entities[i], radius, buffer, &datalen, NULL); int32_t result = librg_world_write(world_tracker(), it.entities[i], radius, buffer, &datalen, NULL);
if (result > 0) { if (result > 0) {
zpl_printf("[info] buffer size was not enough, please increase it by at least: %d\n", result); zpl_printf("[info] buffer size was not enough, please increase it by at least: %d\n", result);
} else if (result < 0) { } else if (result < 0) {
zpl_printf("[error] an error happened writing the world %d\n", result); zpl_printf("[error] an error happened writing the world %d\n", result);
} }
pkt_send_librg_update((uint64_t)p[i].peer, p[i].view_id, ticker, buffer, datalen); pkt_send_librg_update((uint64_t)p[i].peer, p[i].view_id, ticker, buffer, datalen);
} }
} }
// NOTE(zaklaus): clear out our streaming snapshot // NOTE(zaklaus): clear out our streaming snapshot
// TODO(zaklaus): move this to zpl // TODO(zaklaus): move this to zpl
{ {
@ -349,21 +351,23 @@ int32_t world_update() {
profile (PROF_UPDATE_SYSTEMS) { profile (PROF_UPDATE_SYSTEMS) {
ecs_progress(world.ecs, 0.0f); ecs_progress(world.ecs, 0.0f);
} }
float fast_ms = WORLD_TRACKER_UPDATE_FAST_MS; float fast_ms = WORLD_TRACKER_UPDATE_MP_FAST_MS;
float normal_ms = WORLD_TRACKER_UPDATE_NORMAL_MS; float normal_ms = WORLD_TRACKER_UPDATE_MP_NORMAL_MS;
float slow_ms = WORLD_TRACKER_UPDATE_SLOW_MS; float slow_ms = WORLD_TRACKER_UPDATE_MP_SLOW_MS;
if (game_get_kind() != GAMEKIND_SINGLE) { #if 1
fast_ms = WORLD_TRACKER_UPDATE_MP_FAST_MS; if (game_get_kind() == GAMEKIND_SINGLE) {
normal_ms = WORLD_TRACKER_UPDATE_MP_NORMAL_MS; fast_ms = WORLD_TRACKER_UPDATE_FAST_MS;
slow_ms = WORLD_TRACKER_UPDATE_MP_SLOW_MS; normal_ms = WORLD_TRACKER_UPDATE_NORMAL_MS;
slow_ms = WORLD_TRACKER_UPDATE_SLOW_MS;
} }
#endif
world_tracker_update(0, fast_ms, 1); world_tracker_update(0, fast_ms, 1);
world_tracker_update(1, normal_ms, 2); world_tracker_update(1, normal_ms, 2);
world_tracker_update(2, slow_ms, 3); world_tracker_update(2, slow_ms, 3);
entity_update_action_timers(); entity_update_action_timers();
debug_replay_update(); debug_replay_update();
return 0; return 0;
@ -459,11 +463,11 @@ world_block_lookup world_block_from_realpos(float x, float y) {
int32_t size = world.chunk_size * WORLD_BLOCK_SIZE; int32_t size = world.chunk_size * WORLD_BLOCK_SIZE;
int16_t chunk_x, chunk_y; int16_t chunk_x, chunk_y;
librg_chunk_to_chunkpos(world.tracker, chunk_id, &chunk_x, &chunk_y, NULL); librg_chunk_to_chunkpos(world.tracker, chunk_id, &chunk_x, &chunk_y, NULL);
// NOTE(zaklaus): pos relative to chunk // NOTE(zaklaus): pos relative to chunk
float chx = x - chunk_x * size; float chx = x - chunk_x * size;
float chy = y - chunk_y * size; float chy = y - chunk_y * size;
uint16_t bx = (uint16_t)chx / WORLD_BLOCK_SIZE; uint16_t bx = (uint16_t)chx / WORLD_BLOCK_SIZE;
uint16_t by = (uint16_t)chy / WORLD_BLOCK_SIZE; uint16_t by = (uint16_t)chy / WORLD_BLOCK_SIZE;
uint16_t block_idx = (by*world.chunk_size)+bx; uint16_t block_idx = (by*world.chunk_size)+bx;
@ -473,11 +477,11 @@ world_block_lookup world_block_from_realpos(float x, float y) {
bid = world.block_mapping[chunk_id][block_idx]; bid = world.block_mapping[chunk_id][block_idx];
is_outer = false; is_outer = false;
} }
// NOTE(zaklaus): pos relative to block's center // NOTE(zaklaus): pos relative to block's center
float box = chx - bx * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f; float box = chx - bx * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f;
float boy = chy - by * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f; float boy = chy - by * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f;
world_block_lookup lookup = { world_block_lookup lookup = {
.id = block_idx, .id = block_idx,
.bid = bid, .bid = bid,
@ -487,7 +491,7 @@ world_block_lookup world_block_from_realpos(float x, float y) {
.oy = boy, .oy = boy,
.is_outer = is_outer, .is_outer = is_outer,
}; };
return lookup; return lookup;
} }
@ -495,15 +499,16 @@ void world_chunk_destroy_block(float x, float y, bool drop_item) {
world_block_lookup l = world_block_from_realpos(x, y); world_block_lookup l = world_block_from_realpos(x, y);
if (blocks_get_flags(l.bid) & BLOCK_FLAG_ESSENTIAL) return; if (blocks_get_flags(l.bid) & BLOCK_FLAG_ESSENTIAL) return;
world_chunk_replace_block(l.chunk_id, l.id, 0); world_chunk_replace_block(l.chunk_id, l.id, 0);
if (l.is_outer && l.bid > 0 && drop_item) { if (l.is_outer && l.bid > 0 && drop_item) {
asset_id item_asset = blocks_get_asset(l.bid); asset_id item_asset = blocks_get_asset(l.bid);
if (item_find(item_asset) == ASSET_INVALID) return; if (item_find(item_asset) == ASSET_INVALID) return;
uint64_t e = item_spawn(item_asset, 1); uint64_t e = item_spawn(item_asset, 1);
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = x; dest->x = x;
dest->y = y; dest->y = y;
entity_set_position(e, dest->x, dest->y);
} }
} }
@ -512,14 +517,14 @@ world_block_lookup world_block_from_index(int64_t id, uint16_t block_idx) {
if (bid == 0) { if (bid == 0) {
bid = world.block_mapping[id][block_idx]; bid = world.block_mapping[id][block_idx];
} }
world_block_lookup lookup = { world_block_lookup lookup = {
.id = block_idx, .id = block_idx,
.bid = bid, .bid = bid,
.chunk_id = id, .chunk_id = id,
.chunk_e = world.chunk_mapping[id], .chunk_e = world.chunk_mapping[id],
}; };
return lookup; return lookup;
} }

View File

@ -8,6 +8,7 @@
#include "world/perlin.h" #include "world/perlin.h"
#include "modules/components.h" #include "modules/components.h"
#include "entity.h"
#include "vehicle.h" #include "vehicle.h"
#include "items.h" #include "items.h"
#include "world/blocks_info.h" #include "world/blocks_info.h"
@ -133,6 +134,9 @@ static WORLD_BLOCK_OBSERVER(shaper_noise05b) {
return world_perlin_cond_offset(block_idx, 0.05, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID; return world_perlin_cond_offset(block_idx, 0.05, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID;
} }
static WORLD_BLOCK_OBSERVER(shaper_noise01b) {
return world_perlin_cond_offset(block_idx, 0.01, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID;
}
#else #else
static WORLD_BLOCK_OBSERVER(shaper_noise80) { static WORLD_BLOCK_OBSERVER(shaper_noise80) {
return rand()%10 < 8 ? shaper(id, block_idx) : BLOCK_INVALID; return rand()%10 < 8 ? shaper(id, block_idx) : BLOCK_INVALID;
@ -177,7 +181,7 @@ int32_t worldgen_test(world_data *wld) {
// ground // ground
world_fill_rect(world->data, grnd_id, 1, 1, world->dim-2, world->dim-2, NULL); world_fill_rect(world->data, grnd_id, 1, 1, world->dim-2, world->dim-2, NULL);
world_fill_rect(world->data, dirt_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05); world_fill_rect(world->data, dirt_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05);
world_fill_rect(world->outer_data, tree_id, 1, 1, world->dim-2, world->dim-2, shaper_noise05b); world_fill_rect(world->outer_data, tree_id, 1, 1, world->dim-2, world->dim-2, shaper_noise01b);
// water // water
#if 1 #if 1
@ -215,6 +219,7 @@ int32_t worldgen_test(world_data *wld) {
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
entity_set_position(e, dest->x, dest->y);
} }
#endif #endif
@ -226,6 +231,7 @@ int32_t worldgen_test(world_data *wld) {
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
entity_set_position(e, dest->x, dest->y);
} }
for (int i=0; i<RAND_RANGE(328, 164); i++) { for (int i=0; i<RAND_RANGE(328, 164); i++) {
@ -234,6 +240,7 @@ int32_t worldgen_test(world_data *wld) {
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
entity_set_position(e, dest->x, dest->y);
} }
for (int i=0; i<RAND_RANGE(328, 164); i++) { for (int i=0; i<RAND_RANGE(328, 164); i++) {
@ -242,6 +249,7 @@ int32_t worldgen_test(world_data *wld) {
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
entity_set_position(e, dest->x, dest->y);
} }
for (int i=0; i<RAND_RANGE(128, 564); i++) { for (int i=0; i<RAND_RANGE(128, 564); i++) {
@ -250,6 +258,7 @@ int32_t worldgen_test(world_data *wld) {
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
entity_set_position(e, dest->x, dest->y);
} }
for (int i=0; i<RAND_RANGE(128, 964); i++) { for (int i=0; i<RAND_RANGE(128, 964); i++) {
@ -258,6 +267,7 @@ int32_t worldgen_test(world_data *wld) {
Position *dest = ecs_get_mut(world_ecs(), e, Position); Position *dest = ecs_get_mut(world_ecs(), e, Position);
dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->x = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE); dest->y = RAND_RANGEF(0, world->dim*WORLD_BLOCK_SIZE);
entity_set_position(e, dest->x, dest->y);
} }
#endif #endif

View File

@ -26,7 +26,7 @@ int32_t tracker_read_update(librg_world *w, librg_event *e) {
entity_view *d = entity_view_get(&view->entities, entity_id); entity_view *d = entity_view_get(&view->entities, entity_id);
#if 1 #if 1
if (d && d->layer_id < view->active_layer_id) { if (d && d->layer_id < view->active_layer_id) {
if (zpl_time_rel_ms() - d->last_update > WORLD_TRACKER_UPDATE_NORMAL_MS) { if ((get_cached_time()*1000.0f) - d->last_update > WORLD_TRACKER_UPDATE_NORMAL_MS) {
d->layer_id = zpl_min(WORLD_TRACKER_LAYERS-1, d->layer_id+1); d->layer_id = zpl_min(WORLD_TRACKER_LAYERS-1, d->layer_id+1);
} }
// NOTE(zaklaus): reject updates from slower layers // NOTE(zaklaus): reject updates from slower layers
@ -34,7 +34,7 @@ int32_t tracker_read_update(librg_world *w, librg_event *e) {
} }
#endif #endif
data.last_update = zpl_time_rel_ms(); data.last_update = get_cached_time()*1000.0f;
data.layer_id = view->active_layer_id; data.layer_id = view->active_layer_id;
predict_receive_update(d, &data); predict_receive_update(d, &data);
entity_view_update_or_create(&view->entities, entity_id, data); entity_view_update_or_create(&view->entities, entity_id, data);
@ -83,7 +83,7 @@ void world_view_init(world_view *view, uint32_t seed, uint64_t ent_id, uint16_t
librg_config_chunksize_set(view->tracker, WORLD_BLOCK_SIZE * chunk_size, WORLD_BLOCK_SIZE * chunk_size, 1); librg_config_chunksize_set(view->tracker, WORLD_BLOCK_SIZE * chunk_size, WORLD_BLOCK_SIZE * chunk_size, 1);
librg_config_chunkamount_set(view->tracker, chunk_amount, chunk_amount, 1); librg_config_chunkamount_set(view->tracker, chunk_amount, chunk_amount, 1);
librg_config_chunkoffset_set(view->tracker, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG, 0); librg_config_chunkoffset_set(view->tracker, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG, LIBRG_OFFSET_BEG);
librg_event_set(view->tracker, LIBRG_READ_CREATE, tracker_read_create); librg_event_set(view->tracker, LIBRG_READ_CREATE, tracker_read_create);
librg_event_set(view->tracker, LIBRG_READ_REMOVE, tracker_read_remove); librg_event_set(view->tracker, LIBRG_READ_REMOVE, tracker_read_remove);

View File

@ -25,40 +25,44 @@ void IntegratePositions(ecs_iter_t *it) {
profile(PROF_INTEGRATE_POS) { profile(PROF_INTEGRATE_POS) {
Position *p = ecs_field(it, Position, 1); Position *p = ecs_field(it, Position, 1);
Velocity *v = ecs_field(it, Velocity, 2); Velocity *v = ecs_field(it, Velocity, 2);
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
// NOTE(zaklaus): world bounds if (ecs_get(it->world, it->entities[i], IsInVehicle)) {
{ continue;
float w = (float)world_dim();
p[i].x = zpl_clamp(p[i].x, 0, w-1);
p[i].y = zpl_clamp(p[i].y, 0, w-1);
} }
if (zpl_abs(v[i].x) >= 0.001f || zpl_abs(v[i].y) >= 0.001f) {
#if PHY_BLOCK_COLLISION==1 // NOTE(zaklaus): world bounds
// NOTE(zaklaus): X axis {
{ float w = (float)world_dim();
world_block_lookup lookup = world_block_from_realpos(p[i].x+PHY_LOOKAHEAD(v[i].x), p[i].y); p[i].x = zpl_clamp(p[i].x, 0, w-1);
uint32_t flags = blocks_get_flags(lookup.bid); p[i].y = zpl_clamp(p[i].y, 0, w-1);
float bounce = blocks_get_bounce(lookup.bid);
if (flags & BLOCK_FLAG_COLLISION) {
v[i].x = physics_correction(lookup.ox, v[i].x, bounce);
} }
}
#if PHY_BLOCK_COLLISION==1
// NOTE(zaklaus): Y axis // NOTE(zaklaus): X axis
{ {
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y+PHY_LOOKAHEAD(v[i].y)); world_block_lookup lookup = world_block_from_realpos(p[i].x+PHY_LOOKAHEAD(v[i].x), p[i].y);
uint32_t flags = blocks_get_flags(lookup.bid); uint32_t flags = blocks_get_flags(lookup.bid);
float bounce = blocks_get_bounce(lookup.bid); float bounce = blocks_get_bounce(lookup.bid);
if (flags & BLOCK_FLAG_COLLISION) { if (flags & BLOCK_FLAG_COLLISION) {
v[i].y = physics_correction(lookup.oy, v[i].y, bounce); v[i].x = physics_correction(lookup.ox, v[i].x, bounce);
}
} }
// NOTE(zaklaus): Y axis
{
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y+PHY_LOOKAHEAD(v[i].y));
uint32_t flags = blocks_get_flags(lookup.bid);
float bounce = blocks_get_bounce(lookup.bid);
if (flags & BLOCK_FLAG_COLLISION) {
v[i].y = physics_correction(lookup.oy, v[i].y, bounce);
}
}
#endif
entity_set_position(it->entities[i], p[i].x+v[i].x*safe_dt(it), p[i].y+v[i].y*safe_dt(it));
} }
#endif
p[i].x += v[i].x * safe_dt(it);
p[i].y += v[i].y * safe_dt(it);
{ {
debug_v2 a = {p[i].x, p[i].y}; debug_v2 a = {p[i].x, p[i].y};
debug_v2 b = {p[i].x+v[i].x, p[i].y+v[i].y}; debug_v2 b = {p[i].x+v[i].x, p[i].y+v[i].y};
@ -68,32 +72,18 @@ void IntegratePositions(ecs_iter_t *it) {
} }
} }
void UpdateTrackerPos(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1);
for (int i = 0; i < it->count; i++){
librg_entity_chunk_set(world_tracker(), it->entities[i], librg_chunk_from_realpos(world_tracker(), p[i].x, p[i].y, 0));
{
debug_v2 a = {p[i].x-2.5f, p[i].y-2.5f};
debug_v2 b = {p[i].x+2.5f, p[i].y+2.5f};
debug_push_rect(a, b, 0x00FFFFFF);
}
}
}
#define HAZARD_BLOCK_TIME 1.0f #define HAZARD_BLOCK_TIME 1.0f
#define HAZARD_BLOCK_DMG 5.0f #define HAZARD_BLOCK_DMG 5.0f
void HurtOnHazardBlock(ecs_iter_t *it) { void HurtOnHazardBlock(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1); Position *p = ecs_field(it, Position, 1);
Health *h = ecs_field(it, Health, 2); Health *h = ecs_field(it, Health, 2);
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y); if (h->pain_time < 0.0f) {
if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) { h->pain_time = HAZARD_BLOCK_TIME;
if (h->pain_time < 0.0f) { world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y);
h->pain_time = HAZARD_BLOCK_TIME; if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) {
h->hp -= HAZARD_BLOCK_DMG; h->hp -= HAZARD_BLOCK_DMG;
h->hp = zpl_max(0.0f, h->hp); h->hp = zpl_max(0.0f, h->hp);
} }
@ -107,7 +97,7 @@ void HurtOnHazardBlock(ecs_iter_t *it) {
void RegenerateHP(ecs_iter_t *it) { void RegenerateHP(ecs_iter_t *it) {
Health *h = ecs_field(it, Health, 1); Health *h = ecs_field(it, Health, 1);
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
if (h[i].pain_time < 0.0f) { if (h[i].pain_time < 0.0f) {
if (h[i].heal_time < 0.0f && h[i].hp < h[i].max_hp) { if (h[i].heal_time < 0.0f && h[i].hp < h[i].max_hp) {
@ -126,7 +116,7 @@ void RegenerateHP(ecs_iter_t *it) {
void ResetActivators(ecs_iter_t *it) { void ResetActivators(ecs_iter_t *it) {
Input *in = ecs_field(it, Input, 1); Input *in = ecs_field(it, Input, 1);
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
in[i].use = false; in[i].use = false;
in[i].swap = false; in[i].swap = false;
@ -139,8 +129,12 @@ void ResetActivators(ecs_iter_t *it) {
void ApplyWorldDragOnVelocity(ecs_iter_t *it) { void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
Position *p = ecs_field(it, Position, 1); Position *p = ecs_field(it, Position, 1);
Velocity *v = ecs_field(it, Velocity, 2); Velocity *v = ecs_field(it, Velocity, 2);
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
if (zpl_abs(v[i].x) < 0.001f && zpl_abs(v[i].y) < 0.001f) continue;
if (ecs_get(it->world, it->entities[i], IsInVehicle)) {
continue;
}
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y); world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y);
float drag = zpl_clamp(blocks_get_drag(lookup.bid), 0.0f, 1.0f); float drag = zpl_clamp(blocks_get_drag(lookup.bid), 0.0f, 1.0f);
float friction = blocks_get_friction(lookup.bid); float friction = blocks_get_friction(lookup.bid);
@ -148,7 +142,7 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
float vely = blocks_get_vely(lookup.bid); float vely = blocks_get_vely(lookup.bid);
v[i].x = zpl_lerp(v[i].x, zpl_max(0.0f, zpl_abs(velx))*zpl_sign(velx), PHY_WALK_DRAG*drag*friction*safe_dt(it)); v[i].x = zpl_lerp(v[i].x, zpl_max(0.0f, zpl_abs(velx))*zpl_sign(velx), PHY_WALK_DRAG*drag*friction*safe_dt(it));
v[i].y = zpl_lerp(v[i].y, zpl_max(0.0f, zpl_abs(vely))*zpl_sign(vely), PHY_WALK_DRAG*drag*friction*safe_dt(it)); v[i].y = zpl_lerp(v[i].y, zpl_max(0.0f, zpl_abs(vely))*zpl_sign(vely), PHY_WALK_DRAG*drag*friction*safe_dt(it));
if ( zpl_abs(v[i].x) > ENTITY_ACTION_VELOCITY_THRESHOLD if ( zpl_abs(v[i].x) > ENTITY_ACTION_VELOCITY_THRESHOLD
|| zpl_abs(v[i].y) > ENTITY_ACTION_VELOCITY_THRESHOLD) { || zpl_abs(v[i].y) > ENTITY_ACTION_VELOCITY_THRESHOLD) {
entity_wake(it->entities[i]); entity_wake(it->entities[i]);
@ -160,18 +154,18 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
void PlayerClosestInteractable(ecs_iter_t *it){ void PlayerClosestInteractable(ecs_iter_t *it){
Input *in = ecs_field(it, Input, 1); Input *in = ecs_field(it, Input, 1);
for (int i = 0; i < it->count; ++i) { for (int i = 0; i < it->count; ++i) {
size_t ents_count; size_t ents_count;
int64_t *ents = world_chunk_fetch_entities_realpos(in[i].bx, in[i].by, &ents_count); int64_t *ents = world_chunk_fetch_entities_realpos(in[i].bx, in[i].by, &ents_count);
ecs_entity_t closest_pick = 0; ecs_entity_t closest_pick = 0;
float min_pick = ZPL_F32_MAX; float min_pick = ZPL_F32_MAX;
for (size_t j = 0; j < ents_count; j++) { for (size_t j = 0; j < ents_count; j++) {
const Position *p2 = ecs_get(it->world, ents[j], Position); const Position *p2 = ecs_get(it->world, ents[j], Position);
if (!p2) continue; if (!p2) continue;
float dx = p2->x - in[i].bx; float dx = p2->x - in[i].bx;
float dy = p2->y - in[i].by; float dy = p2->y - in[i].by;
float range = zpl_sqrt(dx*dx + dy*dy); float range = zpl_sqrt(dx*dx + dy*dy);
@ -180,9 +174,9 @@ void PlayerClosestInteractable(ecs_iter_t *it){
closest_pick = ents[j]; closest_pick = ents[j];
} }
} }
in[i].pick_ent = closest_pick; in[i].pick_ent = closest_pick;
if (in[i].pick) if (in[i].pick)
in[i].sel_ent = (in[i].sel_ent == closest_pick) ? 0 : closest_pick; in[i].sel_ent = (in[i].sel_ent == closest_pick) ? 0 : closest_pick;
} }
@ -199,21 +193,21 @@ void DisableWorldEdit(ecs_iter_t *it) {
void SystemsImport(ecs_world_t *ecs) { void SystemsImport(ecs_world_t *ecs) {
ECS_MODULE(ecs, Systems); ECS_MODULE(ecs, Systems);
ECS_SYSTEM(ecs, EnableWorldEdit, EcsOnLoad); ECS_SYSTEM(ecs, EnableWorldEdit, EcsOnLoad);
ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, components.Input, components.Velocity, components.Position, !components.IsInVehicle); ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, components.Input, components.Velocity, components.Position, !components.IsInVehicle);
ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.DemoNPC); ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.DemoNPC);
ECS_SYSTEM(ecs, ApplyWorldDragOnVelocity, EcsOnUpdate, components.Position, components.Velocity); ECS_SYSTEM(ecs, ApplyWorldDragOnVelocity, EcsOnUpdate, components.Position, components.Velocity);
ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health); ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health);
ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health); ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health);
ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity); ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity);
ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, components.Position, components.Velocity); ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, components.Position, components.Velocity);
ECS_SYSTEM(ecs, EnterVehicle, EcsPostUpdate, components.Input, components.Position, !components.IsInVehicle); ECS_SYSTEM(ecs, EnterVehicle, EcsPostUpdate, components.Input, components.Position, !components.IsInVehicle);
ECS_SYSTEM(ecs, LeaveVehicle, EcsPostUpdate, components.Input, components.IsInVehicle, components.Velocity); ECS_SYSTEM(ecs, LeaveVehicle, EcsPostUpdate, components.Input, components.IsInVehicle, components.Velocity);
ECS_SYSTEM(ecs, PlayerClosestInteractable, EcsPostUpdate, components.Input); ECS_SYSTEM(ecs, PlayerClosestInteractable, EcsPostUpdate, components.Input);
ECS_SYSTEM(ecs, PickItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle); ECS_SYSTEM(ecs, PickItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
ECS_SYSTEM(ecs, DropItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle); ECS_SYSTEM(ecs, DropItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
@ -222,13 +216,11 @@ void SystemsImport(ecs_world_t *ecs) {
ECS_SYSTEM(ecs, UseItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle); ECS_SYSTEM(ecs, UseItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
ECS_SYSTEM(ecs, InspectContainers, EcsPostUpdate, components.Input, !components.IsInVehicle); ECS_SYSTEM(ecs, InspectContainers, EcsPostUpdate, components.Input, !components.IsInVehicle);
ECS_SYSTEM(ecs, HarvestIntoContainers, EcsPostUpdate, components.ItemContainer, components.Position); ECS_SYSTEM(ecs, HarvestIntoContainers, EcsPostUpdate, components.ItemContainer, components.Position);
ECS_SYSTEM(ecs, ResetActivators, EcsPostUpdate, components.Input); ECS_SYSTEM(ecs, ResetActivators, EcsPostUpdate, components.Input);
ECS_SYSTEM(ecs, UpdateTrackerPos, EcsPostUpdate, components.Position, components.Velocity);
ECS_SYSTEM(ecs, ClearVehicle, EcsUnSet, components.Vehicle); ECS_SYSTEM(ecs, ClearVehicle, EcsUnSet, components.Vehicle);
ECS_SYSTEM(ecs, DisableWorldEdit, EcsPostUpdate); ECS_SYSTEM(ecs, DisableWorldEdit, EcsPostUpdate);
} }

View File

@ -3,7 +3,7 @@
#define ITEM_PICK_RADIUS 25.0f #define ITEM_PICK_RADIUS 25.0f
#define ITEM_MERGER_RADIUS 75.0f #define ITEM_MERGER_RADIUS 75.0f
#define ITEM_ATTRACT_RADIUS 75.0f #define ITEM_ATTRACT_RADIUS 75.0f
#define ITEM_ATTRACT_FORCE 0.63f #define ITEM_ATTRACT_FORCE 6.f
#define ITEM_CONTAINER_REACH_RADIUS 105.0f #define ITEM_CONTAINER_REACH_RADIUS 105.0f
@ -13,6 +13,7 @@ void PickItem(ecs_iter_t *it) {
for (int i = 0; i < it->count; i++) { for (int i = 0; i < it->count; i++) {
if (inv[i].pickup_time > game_time()) continue; if (inv[i].pickup_time > game_time()) continue;
inv[i].pickup_time = game_time() + 0.5f;
size_t ents_count; size_t ents_count;
int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2); int64_t *ents = world_chunk_query_entities(it->entities[i], &ents_count, 2);
@ -20,6 +21,7 @@ void PickItem(ecs_iter_t *it) {
ItemDrop *drop = 0; ItemDrop *drop = 0;
if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) { if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) {
Position *p2 = ecs_get_mut(it->world, ents[j], Position); Position *p2 = ecs_get_mut(it->world, ents[j], Position);
Velocity *v2 = ecs_get_mut(it->world, ents[j], Velocity);
float dx = p2->x - p[i].x; float dx = p2->x - p[i].x;
float dy = p2->y - p[i].y; float dy = p2->y - p[i].y;
@ -43,9 +45,8 @@ void PickItem(ecs_iter_t *it) {
} }
} }
} else if (range <= ITEM_ATTRACT_RADIUS) { } else if (range <= ITEM_ATTRACT_RADIUS) {
entity_set_position(ents[j], v2->x = (p[i].x - p2->x) * ITEM_ATTRACT_FORCE;
zpl_lerp(p2->x, p[i].x, ITEM_ATTRACT_FORCE*it->delta_time), v2->y = (p[i].y - p2->y) * ITEM_ATTRACT_FORCE;
zpl_lerp(p2->y, p[i].y, ITEM_ATTRACT_FORCE*it->delta_time));
} }
} }
} }

View File

@ -143,10 +143,17 @@ void VehicleHandling(ecs_iter_t *it) {
v[i].y += ((fr_y + bk_y) / 2.0f - p[i].y); v[i].y += ((fr_y + bk_y) / 2.0f - p[i].y);
car->heading = zpl_arctan2(fr_y - bk_y, fr_x - bk_x); car->heading = zpl_arctan2(fr_y - bk_y, fr_x - bk_x);
world_block_lookup lookahead = world_block_from_realpos(p[i].x+PHY_LOOKAHEAD(v[i].x), p[i].y+PHY_LOOKAHEAD(v[i].y)); float check_x = p[i].x+PHY_LOOKAHEAD(v[i].x);
float check_y = p[i].y+PHY_LOOKAHEAD(v[i].y);
world_block_lookup lookahead = world_block_from_realpos(check_x, check_y);
uint32_t flags = blocks_get_flags(lookahead.bid); uint32_t flags = blocks_get_flags(lookahead.bid);
if (flags & BLOCK_FLAG_COLLISION) { if (flags & BLOCK_FLAG_COLLISION) {
car->force = 0.0f; if (flags & BLOCK_FLAG_DESTROY_ON_COLLISION) {
world_chunk_destroy_block(check_x, check_y, true);
car->force *= 0.8f;
} else {
car->force = 0.0f;
}
} }
for (int j = 0; j < 4; j++) { for (int j = 0; j < 4; j++) {
@ -155,11 +162,9 @@ void VehicleHandling(ecs_iter_t *it) {
// NOTE(zaklaus): Update passenger position // NOTE(zaklaus): Update passenger position
{ {
Position *p2 = ecs_get_mut(it->world, pe, Position);
Velocity *v2 = ecs_get_mut(it->world, pe, Velocity); Velocity *v2 = ecs_get_mut(it->world, pe, Velocity);
*p2 = p[i]; entity_set_position(pe, p[i].x, p[i].y);
*v2 = v[i]; *v2 = v[i];
entity_wake(pe);
} }
} }

View File

@ -7,3 +7,4 @@ file(GLOB SRCS *.h
) )
add_library(flecs-bundle STATIC ${SRCS}) add_library(flecs-bundle STATIC ${SRCS})
target_compile_options(flecs-bundle PRIVATE "-Wno-enum-constexpr-conversion")

1868
code/vendors/librg.h vendored

File diff suppressed because it is too large Load Diff

33531
code/vendors/zpl.h vendored

File diff suppressed because it is too large Load Diff

10
web/bind.sh 100755
View File

@ -0,0 +1,10 @@
#!/bin/bash
# Symlink sources
if [ ! -d "build_web/map" ]; then
pushd build_web
mkdir -p "map/build_web"
ln -s "/workspaces/eco2d/code" "map/code"
ln -s "/workspaces/eco2d/build_web/_deps" "map/build_web/_deps"
popd
fi

14
web/build.sh 100755
View File

@ -0,0 +1,14 @@
#!/bin/bash
set -xe
pushd build_web
if [ -f "index.html" ]; then
rm -rf index.html
fi
cmake --build . --parallel
if [ -f "eco2d.html" ]; then
mv eco2d.html index.html
fi
popd

5
web/clean.sh 100755
View File

@ -0,0 +1,5 @@
#!/bin/bash
set -xe
cmake --build build_web --target clean

39
web/deploy.sh 100755
View File

@ -0,0 +1,39 @@
#!/bin/bash
set -xe
if [ ! -d "build_web" ]; then
echo "Build directory not found. Run setup_web.sh first."
exit 1
fi
if [ ! -d "butler" ]; then
mkdir butler
wget https://broth.itch.ovh/butler/linux-amd64/LATEST/archive/default -O butler.zip
mv butler.zip butler/
pushd butler/
unzip butler.zip
rm -rf butler.zip
chmod +x ./butler
./butler -V
popd
fi
# Build the project
web/build.sh
# Package all assets
if [ ! -f "build_web/index.html" ]; then
echo "Build data not found. Compilation errors?"
exit 1
fi
mkdir -p deploy_web
cp build_web/eco2d.* deploy_web/
cp build_web/index.html deploy_web/
# Deploy to itch.io
./butler/butler push deploy_web/ zaklaus/eco2d:html-latest
# Teardown
rm -rf deploy_web

View File

@ -0,0 +1,2 @@
// Hack to enforce CLOCK_REALTIME, which is significantly faster for our purposes.
_emscripten_get_now = () => Date.now();

107
web/eco2d.html 100644
View File

@ -0,0 +1,107 @@
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>eco2d web game</title>
<meta name="title" content="eco2d web game">
<meta name="description" content="Small C99 2D game engine with a focus on prototyping">
<meta name="keywords" content="eco2d, html5, ecs, C, librg, chunks">
<meta name="viewport" content="width=device-width">
<!-- Open Graph metatags for sharing -->
<meta property="og:title" content="eco2d web game">
<meta property="og:image:type" content="image/png">
<meta property="og:image" content="https://avatars.githubusercontent.com/u/31039603?s=400&u=371f601b81fd4c6843f910b4565a54704caaa374&v=4">
<meta property="og:site_name" content="zpl.pw">
<meta property="og:url" content="https://github.com/zpl-c/eco2d">
<meta property="og:description" content="Small C99 2D game engine with a focus on prototyping">
<!-- Twitter metatags for sharing -->
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@DMadarasz">
<meta name="twitter:title" content="eco2d web game">
<meta name="twitter:image" content="https://avatars.githubusercontent.com/u/31039603?s=400&u=371f601b81fd4c6843f910b4565a54704caaa374&v=4">
<meta name="twitter:url" content="https://github.com/zpl-c/eco2d">
<meta name="twitter:description" content="Small C99 2D game engine with a focus on prototyping">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-R1QS3P3D1T"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-R1QS3P3D1T');
</script>
<style>
html, body { margin: 0px; padding: 0px; background-color: black; width: 100%; height: 100%;}
canvas.emscripten {
border: 0px none; background-color: black;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
}
</style>
<script type='text/javascript' src="https://cdn.jsdelivr.net/gh/eligrey/FileSaver.js/dist/FileSaver.min.js"> </script>
<script type='text/javascript'>
function saveFileFromMEMFSToDisk(memoryFSname, localFSname) // This can be called by C/C++ code
{
var isSafari = false; // Not supported, navigator.userAgent access is being restricted
//var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
var data = FS.readFile(memoryFSname);
var blob;
if (isSafari) blob = new Blob([data.buffer], { type: "application/octet-stream" });
else blob = new Blob([data.buffer], { type: "application/octet-binary" });
// NOTE: SaveAsDialog is a browser setting. For example, in Google Chrome,
// in Settings/Advanced/Downloads section you have a setting:
// 'Ask where to save each file before downloading' - which you can set true/false.
// If you enable this setting it would always ask you and bring the SaveAsDialog
saveAs(blob, localFSname);
}
</script>
</head>
<body>
<canvas class=emscripten id=canvas oncontextmenu=event.preventDefault() tabindex=-1></canvas>
<script>
var Module = {
print: (function() {
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.log(text);
};
})(),
printErr: (function() {
return function(text) {
if (arguments.length > 1) text = Array.prototype.slice.call(arguments).join(' ');
console.error(text);
};
})(),
canvas: (function() {
var canvas = document.getElementById('canvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
})
canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
return canvas;
})()
};
</script>
{{{ SCRIPT }}}
</body>
</html>

5
web/host.sh 100755
View File

@ -0,0 +1,5 @@
#!/bin/bash
set -xe
python -m http.server --directory build_web --bind 127.0.0.1

20
web/setup.sh 100755
View File

@ -0,0 +1,20 @@
#!/bin/bash
set -xe
# Setup emsdk
if [ ! -d "emsdk" ]; then
wget https://github.com/emscripten-core/emsdk/archive/refs/heads/main.zip -O emscripten.zip
unzip emscripten.zip
mv emsdk-main emsdk
rm -rf emscripten.zip
fi
source ./emsdk/emsdk_env.sh
emsdk update
emsdk install latest
emsdk activate latest
source ./emsdk/emsdk_env.sh
# Setup web build
emcmake cmake -S . -B build_web -DCMAKE_BUILD_TYPE=Release -DPLATFORM=Web

18
win/package.bat 100644
View File

@ -0,0 +1,18 @@
@echo off
cmake --build build_rel --parallel 32 --config Release
if not %ERRORLEVEL% == 0 exit /B 1
@rd /S /Q pkg
mkdir pkg
copy build_rel\eco2d.exe pkg
rem tools\upx -9 pkg\eco2d.exe
robocopy art pkg\art /E
@del pkg\art\*.ecotex
IF NOT "%1"=="SKIP_DEPLOY" (
pushd pkg
..\tools\7za.exe a -r ..\eco2d.zip *.*
popd
butler push eco2d.zip zaklaus/eco2d:win64-latest
)