Merge remote-tracking branch 'origin/master'
commit
9a1e4bef96
|
@ -1,5 +1,10 @@
|
|||
build
|
||||
build_rel
|
||||
build_web
|
||||
emsdk
|
||||
deploy_web
|
||||
run_web
|
||||
butler
|
||||
screenshots
|
||||
build.bat
|
||||
run.bat
|
||||
|
@ -12,7 +17,6 @@ GPATH
|
|||
GRTAGS
|
||||
GTAGS
|
||||
/run_release.bat
|
||||
/package.bat
|
||||
pkg
|
||||
pkg.zip
|
||||
eco2d.zip
|
||||
eco2d.zip
|
||||
|
|
|
@ -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_DEBUG ${CMAKE_BINARY_DIR})
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR})
|
||||
SET(CMAKE_USE_RELATIVE_PATHS OFF)
|
||||
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
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(cmake/FindRaylib.cmake)
|
||||
|
|
31
README.md
31
README.md
|
@ -1,11 +1,12 @@
|
|||
<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>
|
||||
|
||||
<br />
|
||||
|
||||
<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://zaklaus.itch.io/eco2d"><img src="https://static.itch.io/images/badge-color.svg" alt="play" height="28px"/></a>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
|
@ -51,6 +52,30 @@ In the abstract sense, we call the Server the game master hosting all gameplay r
|
|||
|
||||
# Build the project
|
||||
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:
|
||||
```sh
|
||||
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:
|
||||
```sh
|
||||
Windows:
|
||||
build\Debug\eco2d.exe -?
|
||||
|
||||
Linux:
|
||||
build\eco2d.exe -?
|
||||
```
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@ function(link_system_libs target_name)
|
|||
target_link_libraries(${target_name} winmm)
|
||||
elseif (APPLE)
|
||||
target_link_libraries(${target_name} pthread m dl)
|
||||
elseif (EMSCRIPTEN)
|
||||
target_link_libraries(${target_name} pthread m dl)
|
||||
elseif (UNIX)
|
||||
target_link_libraries(${target_name} pthread m dl atomic)
|
||||
endif()
|
||||
|
|
|
@ -43,5 +43,6 @@ add_executable(eco2d
|
|||
target_compile_definitions(eco2d PRIVATE CLIENT)
|
||||
include_directories(src ../modules ../../art/gen)
|
||||
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)
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
// can use it in other systems
|
||||
|
||||
// NOTE(zaklaus): Register a block
|
||||
#include "blocks/blocks_list.c"
|
||||
#include "world/blocks_list.c"
|
||||
|
||||
// NOTE(zaklaus): Register an item
|
||||
#include "items_list.c"
|
||||
|
|
|
@ -23,6 +23,8 @@ typedef struct {
|
|||
static int64_t assets_frame_counter = 1;
|
||||
static double assets_frame_next_draw = 0.0;
|
||||
|
||||
#include <time.h>
|
||||
|
||||
int32_t assets_setup(void) {
|
||||
for (uint32_t i=0; i<ASSETS_COUNT; i++) {
|
||||
asset *b = &assets[i];
|
||||
|
@ -43,13 +45,12 @@ int32_t assets_setup(void) {
|
|||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
assets_frame_next_draw = zpl_time_rel() + ASSET_FRAME_RENDER_MS;
|
||||
assets_frame_next_draw = get_cached_time() + ASSET_FRAME_RENDER_MS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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++) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ static asset assets[] = {
|
|||
ASSET_TEX(ASSET_DEV),
|
||||
ASSET_TEX(ASSET_GROUND),
|
||||
ASSET_TEX(ASSET_DIRT),
|
||||
ASSET_ANI(ASSET_WATER),
|
||||
ASSET_TEX(ASSET_WATER),
|
||||
ASSET_TEX(ASSET_LAVA),
|
||||
ASSET_TEX(ASSET_WALL),
|
||||
ASSET_TEX(ASSET_HILL),
|
||||
|
|
|
@ -116,7 +116,7 @@ void debug_replay_start(void) {
|
|||
if (records) zpl_array_free(records);
|
||||
zpl_array_init_reserve(records, zpl_heap(), UINT16_MAX);
|
||||
|
||||
last_record_time = zpl_time_rel();
|
||||
last_record_time = get_cached_time();
|
||||
SetTargetFPS(60);
|
||||
}
|
||||
|
||||
|
@ -155,7 +155,7 @@ void debug_replay_run(void) {
|
|||
if (mime) return;
|
||||
is_playing = true;
|
||||
record_pos = 0;
|
||||
playback_time = zpl_time_rel();
|
||||
playback_time = get_cached_time();
|
||||
zpl_array_init(temp_actors, zpl_heap());
|
||||
|
||||
plr = camera_get().ent_id;
|
||||
|
@ -181,10 +181,10 @@ void ActSpawnBelt(void);
|
|||
|
||||
void debug_replay_update(void) {
|
||||
if (!is_playing) return;
|
||||
if (playback_time >= zpl_time_rel()) return;
|
||||
if (playback_time >= get_cached_time()) return;
|
||||
|
||||
replay_record *r = &records[record_pos];
|
||||
playback_time = zpl_time_rel() + r->delay;
|
||||
playback_time = get_cached_time() + r->delay;
|
||||
|
||||
switch (r->kind) {
|
||||
case RPKIND_KEY: {
|
||||
|
@ -249,7 +249,7 @@ void debug_replay_update(void) {
|
|||
|
||||
void debug_replay_record_keystate(pkt_send_keystate state) {
|
||||
if (!is_recording) return;
|
||||
double record_time = zpl_time_rel();
|
||||
double record_time = get_cached_time();
|
||||
|
||||
replay_record rec = {
|
||||
.kind = RPKIND_KEY,
|
||||
|
@ -258,13 +258,13 @@ void debug_replay_record_keystate(pkt_send_keystate state) {
|
|||
};
|
||||
|
||||
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) {
|
||||
ZPL_ASSERT(kind != RPKIND_KEY);
|
||||
if (!is_recording || is_playing) return;
|
||||
double record_time = zpl_time_rel();
|
||||
double record_time = get_cached_time();
|
||||
|
||||
replay_record rec = {
|
||||
.kind = kind,
|
||||
|
@ -272,5 +272,5 @@ void debug_replay_special_action(replay_kind kind) {
|
|||
};
|
||||
|
||||
zpl_array_append(records, rec);
|
||||
last_record_time = zpl_time_rel();
|
||||
last_record_time = get_cached_time();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ typedef struct {
|
|||
#define DBG_FONT_SIZE 22
|
||||
#define DBG_FONT_SPACING DBG_FONT_SIZE * 1.2f
|
||||
#define DBG_START_XPOS 15
|
||||
#define DBG_START_YPOS 200
|
||||
#define DBG_START_YPOS 30
|
||||
#define DBG_LIST_XPOS_OFFSET 10
|
||||
#define DBG_SHADOW_OFFSET_XPOS 1
|
||||
#define DBG_SHADOW_OFFSET_YPOS 1
|
||||
|
@ -92,6 +92,7 @@ static debug_item items[] = {
|
|||
.kind = DITEM_LIST,
|
||||
.name = "general",
|
||||
.list = {
|
||||
.is_collapsed = true,
|
||||
.items = (debug_item[]) {
|
||||
{ .kind = DITEM_TEXT, .name = "delta time", .proc = DrawDeltaTime },
|
||||
{ .kind = DITEM_TEXT, .name = "pos", .proc = DrawCameraPos },
|
||||
|
@ -104,6 +105,7 @@ static debug_item items[] = {
|
|||
.kind = DITEM_LIST,
|
||||
.name = "world simulation",
|
||||
.list = {
|
||||
.is_collapsed = true,
|
||||
.items = (debug_item[]) {
|
||||
{ .kind = DITEM_COND, .on_success = CondIsWorldRunning },
|
||||
{ .kind = DITEM_BUTTON, .name = "pause", .on_click = ActWorldToggleSim },
|
||||
|
@ -127,6 +129,7 @@ static debug_item items[] = {
|
|||
.kind = DITEM_LIST,
|
||||
.name = "debug actions",
|
||||
.list = {
|
||||
.is_collapsed = true,
|
||||
.items = (debug_item[]) {
|
||||
{ .kind = DITEM_BUTTON, .name = "spawn car", .on_click = ActSpawnCar },
|
||||
{ .kind = DITEM_BUTTON, .name = "place ice rink", .on_click = ActPlaceIceRink },
|
||||
|
@ -157,6 +160,7 @@ static debug_item items[] = {
|
|||
.kind = DITEM_LIST,
|
||||
.name = "conn metrics",
|
||||
.list = {
|
||||
.is_collapsed = true,
|
||||
.items = (debug_item[]) {
|
||||
{ .kind = DITEM_COND, .on_success = CondClientDisconnected },
|
||||
{ .kind = DITEM_TEXT, .name = "status", .proc = DrawLiteral, .text = "disconnected" },
|
||||
|
@ -172,6 +176,7 @@ static debug_item items[] = {
|
|||
},
|
||||
.limit_to = L_MP,
|
||||
},
|
||||
#if !defined(PLATFORM_WEB)
|
||||
{
|
||||
.kind = DITEM_LIST,
|
||||
.name = "replay system",
|
||||
|
@ -209,6 +214,7 @@ static debug_item items[] = {
|
|||
},
|
||||
.limit_to = L_SP,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.kind = DITEM_LIST,
|
||||
.name = "profilers",
|
||||
|
@ -226,11 +232,13 @@ static debug_item items[] = {
|
|||
.is_collapsed = 1
|
||||
}
|
||||
},
|
||||
#if !defined(PLATFORM_WEB)
|
||||
{
|
||||
.kind = DITEM_BUTTON,
|
||||
.name = "exit game",
|
||||
.on_click = ActExitGame,
|
||||
},
|
||||
#endif
|
||||
{.kind = DITEM_END},
|
||||
};
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ ActSpawnCar(void) {
|
|||
Position const* origin = ecs_get(world_ecs(), plr, Position);
|
||||
Position * dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
*dest = *origin;
|
||||
entity_set_position(e, dest->x, dest->y);
|
||||
|
||||
debug_replay_special_action(RPKIND_SPAWN_CAR);
|
||||
}
|
||||
|
@ -28,6 +29,7 @@ ActSpawnIcemaker(void) {
|
|||
Position const* origin = ecs_get(world_ecs(), plr, Position);
|
||||
Position * dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
*dest = *origin;
|
||||
entity_set_position(e, dest->x, dest->y);
|
||||
|
||||
debug_replay_special_action(RPKIND_SPAWN_ICEMAKER_ITEM);
|
||||
}
|
||||
|
@ -40,6 +42,7 @@ ActSpawnChest(void) {
|
|||
Position const* origin = ecs_get(world_ecs(), plr, Position);
|
||||
Position * dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
*dest = *origin;
|
||||
entity_set_position(e, dest->x, dest->y);
|
||||
|
||||
debug_replay_special_action(RPKIND_SPAWN_CHEST);
|
||||
}
|
||||
|
@ -52,6 +55,7 @@ ActSpawnBelt(void) {
|
|||
Position const* origin = ecs_get(world_ecs(), plr, Position);
|
||||
Position * dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
*dest = *origin;
|
||||
entity_set_position(e, dest->x, dest->y);
|
||||
|
||||
debug_replay_special_action(RPKIND_SPAWN_BELT);
|
||||
}
|
||||
|
@ -67,6 +71,8 @@ ActSpawnCirclingDriver(void) {
|
|||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
*veh_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);
|
||||
zpl_zero_item(input);
|
||||
|
|
|
@ -23,6 +23,7 @@ uint64_t entity_spawn(uint16_t class_id) {
|
|||
#if 1
|
||||
pos->x=(float)(rand() % world_dim());
|
||||
pos->y=(float)(rand() % world_dim());
|
||||
entity_set_position(e, pos->x, pos->y);
|
||||
#else
|
||||
pos->x=350.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);
|
||||
p->x = x;
|
||||
p->y = y;
|
||||
|
||||
librg_entity_chunk_set(world_tracker(), ent_id, librg_chunk_from_realpos(world_tracker(), x, y, 0));
|
||||
entity_wake(ent_id);
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ void entity_update_action_timers() {
|
|||
static double last_update_time = 0.0f;
|
||||
if (!ecs_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);
|
||||
|
@ -86,18 +87,18 @@ void entity_update_action_timers() {
|
|||
while (ecs_query_next(&it)) {
|
||||
StreamInfo *si = ecs_field(&it, StreamInfo, 1);
|
||||
|
||||
for (size_t i = 0; i < it.count; i++) {
|
||||
if (si[i].last_update < zpl_time_rel()) {
|
||||
si[i].last_update = zpl_time_rel() + si[i].tick_delay;
|
||||
si[i].tick_delay += (zpl_time_rel() - last_update_time) * 0.5f;
|
||||
for (int32_t i = 0; i < it.count; i++) {
|
||||
if (si[i].last_update < get_cached_time()) {
|
||||
si[i].last_update = get_cached_time() + si[i].tick_delay;
|
||||
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) {
|
||||
StreamInfo *si = ecs_get_mut(world_ecs(), ent_id, StreamInfo);
|
||||
return (si->last_update < zpl_time_rel());
|
||||
return (si->last_update < get_cached_time());
|
||||
}
|
||||
|
|
|
@ -50,10 +50,10 @@ pkt_desc pkt_entity_view_desc[] = {
|
|||
{ 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_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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
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);
|
||||
|
||||
void entity_view_mark_for_removal(entity_view_tbl *map, uint64_t ent_id);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "profiler.h"
|
||||
|
||||
#include "flecs/flecs_os_api_stdcpp.h"
|
||||
#include "flecs/flecs.h"
|
||||
|
||||
#include "modules/components.h"
|
||||
#include "modules/systems.h"
|
||||
|
@ -72,7 +73,7 @@ void world_viewers_init(uint32_t num_viewers) {
|
|||
}
|
||||
|
||||
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]);
|
||||
}
|
||||
zpl_buffer_free(world_viewers);
|
||||
|
@ -114,12 +115,14 @@ size_t game_world_view_count(void) {
|
|||
}
|
||||
|
||||
void flecs_dash_init() {
|
||||
#if !defined(ZPL_SYSTEM_EMSCRIPTEN)
|
||||
ecs_singleton_set(world_ecs(), EcsRest, {0});
|
||||
ECS_IMPORT(world_ecs(), FlecsMonitor);
|
||||
#endif
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -229,15 +232,15 @@ void game_update() {
|
|||
if (game_mode == GAMEKIND_HEADLESS) {
|
||||
network_server_tick();
|
||||
|
||||
static uint64_t ms_report = 2500;
|
||||
if (ms_report < zpl_time_rel_ms()) {
|
||||
ms_report = zpl_time_rel_ms() + 5000;
|
||||
zpl_printf("delta: %f ms.\n", (zpl_time_rel() - last_update)*1000.0f);
|
||||
static float ms_report = 2.5f;
|
||||
if (ms_report < get_cached_time()) {
|
||||
ms_report = get_cached_time() + 5.f;
|
||||
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() {
|
||||
|
|
|
@ -33,11 +33,11 @@ Texture2D GenColorEco(Color color) {
|
|||
Texture2D texgen_build_anim(asset_id id, int64_t counter) {
|
||||
(void)counter;
|
||||
switch (id) {
|
||||
case ASSET_WATER: {
|
||||
Image img = LoadImageEco("water");
|
||||
ImageColorBrightness(&img, zpl_abs((counter % 64 - 32)*2));
|
||||
return Image2TexEco(img);
|
||||
}break;
|
||||
// case ASSET_WATER: {
|
||||
// Image img = LoadImageEco("water");
|
||||
// ImageColorBrightness(&img, zpl_abs((counter % 64 - 32)*2));
|
||||
// return Image2TexEco(img);
|
||||
// }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_WOOD: return LoadTexEco("wood");
|
||||
case ASSET_TREE: return LoadTexEco("tree");
|
||||
|
||||
case ASSET_WATER: return LoadTexEco("water");
|
||||
|
||||
case ASSET_BELT:
|
||||
case ASSET_BELT_RIGHT: return LoadTexEco("belt_right");
|
||||
case ASSET_BELT_LEFT: return LoadTexEco("belt_left");
|
||||
|
|
|
@ -45,7 +45,7 @@ void buildmode_draw(void) {
|
|||
|
||||
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;
|
||||
uint16_t item_id = 0;
|
||||
if (!build_is_deletion_mode){
|
||||
|
@ -127,4 +127,4 @@ void buildmode_draw(void) {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,14 +26,14 @@ static inline asset_id item_fix_kind(asset_id id) {
|
|||
|
||||
uint64_t item_spawn(asset_id kind, uint32_t qty) {
|
||||
ecs_entity_t e = entity_spawn(EKIND_ITEM);
|
||||
|
||||
|
||||
ItemDrop *d = ecs_get_mut(world_ecs(), e, ItemDrop);
|
||||
*d = (ItemDrop){
|
||||
.kind = item_fix_kind(kind),
|
||||
.quantity = qty,
|
||||
.merger_time = 0,
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
item_id item_asset_id = item_find(item_asset);
|
||||
if (item_asset_id == ASSET_INVALID) return;
|
||||
|
||||
|
||||
// NOTE(zaklaus): If we replace the same item, refund 1 qty and let it replace it
|
||||
if (item_asset_id == it_id) {
|
||||
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));
|
||||
it->quantity--;
|
||||
}break;
|
||||
|
||||
|
||||
case UKIND_PLACE_ITEM:{
|
||||
world_block_lookup l = world_block_from_realpos(p.x, p.y);
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
ecs_entity_t e = entity_spawn_id(desc->place_item.id);
|
||||
ZPL_ASSERT(world_entity_valid(e));
|
||||
Position *pos = ecs_get_mut(ecs, e, Position);
|
||||
pos->x = p.x;
|
||||
pos->y = p.y;
|
||||
|
||||
entity_set_position(e, p.x, p.y);
|
||||
|
||||
it->quantity--;
|
||||
}break;
|
||||
|
||||
|
||||
case UKIND_DELETE:
|
||||
case UKIND_END_PLACE:
|
||||
case UKIND_PROXY:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
#include "modules/components.h"
|
||||
#include "modules/systems.h"
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
#include <emscripten/emscripten.h>
|
||||
void UpdateDrawFrame(void);
|
||||
#endif
|
||||
|
||||
#define DEFAULT_WORLD_SEED 302097
|
||||
#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) */
|
||||
|
@ -73,7 +78,9 @@ int main(int argc, char** argv) {
|
|||
sighandler_register();
|
||||
game_init(host, port, play_mode, num_viewers, seed, chunk_size, world_size, is_dash_enabled);
|
||||
|
||||
#if !defined(PLATFORM_WEB)
|
||||
while (game_is_running()) {
|
||||
reset_cached_time();
|
||||
profile (PROF_MAIN_LOOP) {
|
||||
game_input();
|
||||
game_update();
|
||||
|
@ -82,6 +89,9 @@ int main(int argc, char** argv) {
|
|||
|
||||
profiler_collate();
|
||||
}
|
||||
#else
|
||||
emscripten_set_main_loop(UpdateDrawFrame, 0, 1);
|
||||
#endif
|
||||
|
||||
game_shutdown();
|
||||
sighandler_unregister();
|
||||
|
@ -90,3 +100,25 @@ int main(int argc, char** argv) {
|
|||
zpl_opts_free(&opts);
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -120,7 +120,7 @@ network_client_fetch_stats(void) {
|
|||
static float incoming_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
|
||||
static uint64_t last_total_sent = 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;
|
||||
outgoing_bandwidth = stats.outgoing_bandwidth /= MAX_RATE_SAMPLES;
|
||||
|
||||
next_measure = zpl_time_rel() + 1.0;
|
||||
next_measure = get_cached_time() + 1.0;
|
||||
} else {
|
||||
stats.incoming_bandwidth = incoming_bandwidth;
|
||||
stats.outgoing_bandwidth = outgoing_bandwidth;
|
||||
|
|
|
@ -17,16 +17,16 @@ typedef struct {
|
|||
uint64_t total_received;
|
||||
uint32_t outgoing_total;
|
||||
uint64_t total_sent;
|
||||
|
||||
|
||||
// NOTE(zaklaus): bandwidth (bytes/sec)
|
||||
float incoming_bandwidth;
|
||||
float outgoing_bandwidth;
|
||||
|
||||
|
||||
// NOTE(zaklaus): packet integrity
|
||||
uint64_t packets_sent;
|
||||
uint32_t packets_lost;
|
||||
float packet_loss;
|
||||
|
||||
|
||||
// NOTE(zaklaus): ping
|
||||
uint32_t ping;
|
||||
uint32_t low_ping;
|
||||
|
|
|
@ -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) {
|
||||
(void)blob_size;
|
||||
uint8_t *blob = (uint8_t*)raw_blob;
|
||||
for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field) {
|
||||
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)blob_size;
|
||||
uint8_t *blob = (uint8_t*)raw_blob;
|
||||
zpl_printf("{\n");
|
||||
for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "entity_view.h"
|
||||
#include "camera.h"
|
||||
#include "player.h"
|
||||
#include "entity.h"
|
||||
|
||||
#include "modules/components.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);
|
||||
|
||||
#if 0
|
||||
pos->x = world_dim()/2.0f + rand()%15*15.0f;
|
||||
pos->y = world_dim()/2.0f + rand()%15*15.0f;
|
||||
#if 1
|
||||
entity_set_position(ent_id, world_dim()/2.0f + rand()%15*15.0f, world_dim()/2.0f + rand()%15*15.0f);
|
||||
#else
|
||||
pos->x = rand()%world_dim();
|
||||
pos->y = rand()%world_dim();
|
||||
|
|
|
@ -29,7 +29,7 @@ int32_t pkt_01_welcome_handler(pkt_header *header) {
|
|||
|
||||
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);
|
||||
game_world_view_set_active(view);
|
||||
return 0;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
#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) {
|
||||
cw_unpack_context uc = {0};
|
||||
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);
|
||||
if (state < 0) zpl_printf("[ERROR] world read error: %d\n", state);
|
||||
|
||||
float now = (float)zpl_time_rel();
|
||||
view->delta_time[layer_id] = now - view->last_update[layer_id];
|
||||
float now = (float)get_cached_time();
|
||||
view->delta_time[layer_id] = smooth_time(now - view->last_update[layer_id]);
|
||||
view->last_update[layer_id] = now;
|
||||
|
||||
return state;
|
||||
|
|
|
@ -13,9 +13,20 @@
|
|||
#include "debug_ui.h"
|
||||
#include "utils/raylib_helpers.h"
|
||||
|
||||
static uint16_t screenWidth = 1600;
|
||||
static uint16_t screenHeight = 900;
|
||||
static float target_zoom = 1.5f;
|
||||
#if defined(PLATFORM_WEB)
|
||||
#include <emscripten.h>
|
||||
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;
|
||||
|
||||
#define GFX_KIND 2
|
||||
|
@ -27,14 +38,22 @@ static bool request_shutdown;
|
|||
|
||||
void platform_init() {
|
||||
SetTraceLogLevel(LOG_ERROR);
|
||||
|
||||
#if defined(PLATFORM_WEB)
|
||||
screenWidth = (uint16_t)canvas_get_width();
|
||||
screenHeight = (uint16_t)canvas_get_height();
|
||||
#endif
|
||||
|
||||
InitWindow(screenWidth, screenHeight, "eco2d");
|
||||
SetWindowState(/*FLAG_WINDOW_UNDECORATED|*/FLAG_WINDOW_MAXIMIZED|FLAG_WINDOW_RESIZABLE|FLAG_MSAA_4X_HINT);
|
||||
|
||||
|
||||
#if !defined(PLATFORM_WEB)
|
||||
screenWidth = (uint16_t)GetScreenWidth();
|
||||
screenHeight = (uint16_t)GetScreenHeight();
|
||||
#endif
|
||||
// ToggleFullscreen();
|
||||
// SetTargetFPS(60.0);
|
||||
|
||||
|
||||
renderer_init();
|
||||
}
|
||||
|
||||
|
@ -85,13 +104,13 @@ inline static
|
|||
void platform_input_update_input_frame(game_keystate_data data) {
|
||||
float mx = 0, my = 0;
|
||||
platform_get_block_realpos(&mx, &my);
|
||||
|
||||
|
||||
if (mx != last_blockpos_data.mx || my != last_blockpos_data.my){
|
||||
last_blockpos_data.mx = mx;
|
||||
last_blockpos_data.my = my;
|
||||
game_action_send_blockpos(mx, my);
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): Test if there are any changes
|
||||
if (data.x != last_input_data.x) 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 (zpl_memcompare(data.placements, last_input_data.placements, zpl_size_of(data.placements))) goto send_data;
|
||||
return;
|
||||
|
||||
|
||||
send_data:
|
||||
last_input_data = data;
|
||||
game_action_send_keystate(&data);
|
||||
|
@ -117,11 +136,11 @@ void platform_input_update_input_frame(game_keystate_data data) {
|
|||
|
||||
void platform_input() {
|
||||
float mouse_z = (GetMouseWheelMove()*0.5f);
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
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_UP) || IsKeyDown(KEY_W)) y += 1.0f;
|
||||
if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) y -= 1.0f;
|
||||
|
||||
|
||||
use = IsKeyPressed(KEY_SPACE);
|
||||
sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
|
||||
ctrl = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);
|
||||
drop = IsKeyPressed(KEY_G) || player_inv.drop_item || storage_inv.drop_item;
|
||||
|
||||
|
||||
// NOTE(zaklaus): NEW! mouse movement
|
||||
Vector2 mouse_pos = GetMousePosition();
|
||||
mouse_pos.x /= screenWidth;
|
||||
|
@ -143,18 +162,18 @@ void platform_input() {
|
|||
mouse_pos.x -= 0.5f;
|
||||
mouse_pos.y -= 0.5f;
|
||||
mouse_pos = Vector2Normalize(mouse_pos);
|
||||
|
||||
|
||||
if (game_get_kind() == GAMEKIND_SINGLE && IsMouseButtonDown(MOUSE_MIDDLE_BUTTON)) {
|
||||
x = mouse_pos.x;
|
||||
y = -mouse_pos.y;
|
||||
}
|
||||
|
||||
|
||||
inv_keystate *inv = (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
|
||||
pick = (inv_is_inside||inv->item_is_held||inv2->item_is_held) ? false : IsMouseButtonDown(MOUSE_LEFT_BUTTON);
|
||||
|
||||
|
||||
game_keystate_data in_data = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
|
@ -164,7 +183,7 @@ void platform_input() {
|
|||
.sprint = sprint,
|
||||
.ctrl = ctrl,
|
||||
.pick = pick,
|
||||
|
||||
|
||||
.drop = drop,
|
||||
.storage_action = inv_is_storage_action,
|
||||
.selected_item = player_inv.selected_item,
|
||||
|
@ -173,18 +192,18 @@ void platform_input() {
|
|||
.swap_storage = inv_swap_storage,
|
||||
.swap_from = inv->swap_from,
|
||||
.swap_to = inv->swap_to,
|
||||
|
||||
|
||||
.deletion_mode = build_is_deletion_mode,
|
||||
};
|
||||
|
||||
|
||||
if (build_submit_placements) {
|
||||
in_data.placement_num = build_num_placements;
|
||||
zpl_memcopy(in_data.placements, build_placements, build_num_placements*zpl_size_of(item_placement));
|
||||
}
|
||||
|
||||
|
||||
platform_input_update_input_frame(in_data);
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): cycle through viewers
|
||||
{
|
||||
if (IsKeyPressed(KEY_Q)) {
|
||||
|
@ -194,14 +213,14 @@ void platform_input() {
|
|||
game_world_view_cycle_active(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): switch render modes
|
||||
{
|
||||
if (IsKeyPressed(KEY_O)) {
|
||||
renderer_switch(1-gfx_kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): toggle debug drawing
|
||||
#ifndef ECO2D_PROD
|
||||
{
|
||||
|
@ -218,13 +237,13 @@ void draw_selected_item() {
|
|||
if (oe) {
|
||||
// NOTE(zaklaus): sel item
|
||||
entity_view *e = game_world_view_active_get_entity(oe->sel_ent);
|
||||
|
||||
|
||||
if (e && e->kind == EKIND_DEVICE) {
|
||||
renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.4f));
|
||||
}else{
|
||||
// NOTE(zaklaus): hover item
|
||||
entity_view *e = game_world_view_active_get_entity(oe->pick_ent);
|
||||
|
||||
|
||||
if (e && e->kind == EKIND_DEVICE) {
|
||||
renderer_draw_single(e->x, e->y, ASSET_BLANK, ColorAlpha(RED, 0.1f));
|
||||
}
|
||||
|
@ -233,16 +252,26 @@ void draw_selected_item() {
|
|||
}
|
||||
|
||||
void platform_render() {
|
||||
#if !defined(PLATFORM_WEB)
|
||||
screenWidth = (uint16_t)GetScreenWidth();
|
||||
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) {
|
||||
game_world_view_active_entity_map(lerp_entity_positions);
|
||||
game_world_view_active_entity_map(do_entity_fadeinout);
|
||||
}
|
||||
|
||||
|
||||
assets_frame();
|
||||
|
||||
|
||||
BeginDrawing();
|
||||
{
|
||||
profile (PROF_RENDER) {
|
||||
|
@ -259,7 +288,7 @@ void platform_render() {
|
|||
debug_draw();
|
||||
}
|
||||
EndDrawing();
|
||||
|
||||
|
||||
if (request_shutdown) {
|
||||
CloseWindow();
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ void predict_receive_update(entity_view *d, entity_view *data) {
|
|||
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)key;
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#define PROF_COLLATE_WINDOW 0.5
|
||||
|
||||
static float profiler_warmup = 3.0f;
|
||||
|
||||
// NOTE(zaklaus): KEEP ORDER IN SYNC WITH profiler_kind ENUM !!!
|
||||
static profiler profilers[] = {
|
||||
{ .id = PROF_TOTAL_TIME, .name = "measured time" },
|
||||
|
@ -33,6 +35,13 @@ void profiler_stop(profiler_kind id) {
|
|||
}
|
||||
|
||||
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 uint64_t frames = 0;
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
static Camera3D render_camera_3d;
|
||||
static float cam_zoom = 1.5f;
|
||||
|
||||
#define CAM_OVERLAY_ZOOM_LEVEL 0.80f
|
||||
|
||||
float zpl_lerp(float,float,float);
|
||||
float zpl_to_degrees(float);
|
||||
|
||||
void DEBUG_draw_ground_3d(uint64_t key, entity_view * data) {
|
||||
(void)key;
|
||||
switch (data->kind) {
|
||||
case EKIND_CHUNK: {
|
||||
world_view *view = game_world_view_get_active();
|
||||
|
@ -145,7 +142,7 @@ void renderer_debug_draw_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) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
static Camera2D render_camera;
|
||||
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)
|
||||
|
||||
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();
|
||||
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;
|
||||
|
||||
|
||||
RenderTexture2D tex = GetChunkTexture(key);
|
||||
float scale = (size)/(float)(tex.texture.width);
|
||||
tex.texture.width *= (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));
|
||||
|
||||
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 tx = 0; tx < 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;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -47,12 +58,12 @@ void DEBUG_draw_ground(uint64_t key, entity_view * data) {
|
|||
extern bool inv_is_open;
|
||||
|
||||
void DEBUG_draw_entities(uint64_t key, entity_view * data) {
|
||||
uint16_t size = 16;
|
||||
uint16_t font_size = (uint16_t)lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom);
|
||||
float size = 16.f;
|
||||
float font_size = lerp(4.0f, 32.0f, 0.5f/(float)render_camera.zoom);
|
||||
float font_spacing = 1.1f;
|
||||
float title_bg_offset = 4;
|
||||
float fixed_title_offset = 8;
|
||||
|
||||
float fixed_title_offset = 8.f;
|
||||
|
||||
switch (data->kind) {
|
||||
case EKIND_DEMO_NPC: {
|
||||
float x = data->x;
|
||||
|
@ -64,12 +75,12 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
|
|||
float y = data->y;
|
||||
float health = (data->hp / data->max_hp);
|
||||
const char *title = TextFormat("Player %d", key);
|
||||
int 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-title_bg_offset/2, 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);
|
||||
float title_w = MeasureTextEco(title, font_size, font_spacing);
|
||||
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.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.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));
|
||||
|
||||
|
||||
if (data->has_items && !data->inside_vehicle) {
|
||||
float ix = data->x;
|
||||
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;
|
||||
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));
|
||||
|
||||
|
||||
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;
|
||||
|
@ -87,16 +98,16 @@ void DEBUG_draw_entities(uint64_t key, entity_view * data) {
|
|||
float x = data->x;
|
||||
float y = data->y;
|
||||
const char *title = TextFormat("Bot %d", key);
|
||||
int 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));
|
||||
DrawTextEco(title, x-title_w/2, y-size-font_size-fixed_title_offset, font_size, ColorAlpha(BLACK, data->tran_time), font_spacing);
|
||||
float title_w = MeasureTextEco(title, font_size, font_spacing);
|
||||
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.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));
|
||||
}break;
|
||||
case EKIND_ITEM: {
|
||||
float x = data->x - 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));
|
||||
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;
|
||||
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)key;
|
||||
|
||||
|
||||
switch (data->kind) {
|
||||
case EKIND_VEHICLE: {
|
||||
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.zoom = zpl_lerp(render_camera.zoom, target_zoom, GetFrameTime()*2.9978f);
|
||||
camera_update();
|
||||
|
||||
|
||||
camera game_camera = camera_get();
|
||||
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);
|
||||
|
||||
|
||||
|
||||
|
||||
ClearBackground(GetColor(0x222034));
|
||||
BeginMode2D(render_camera);
|
||||
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);
|
||||
|
||||
if (zoom_overlay_tran > 0.02f) {
|
||||
game_world_view_active_entity_map(DEBUG_draw_overlay);
|
||||
}
|
||||
EndMode2D();
|
||||
}
|
||||
|
||||
|
@ -149,18 +164,18 @@ void renderer_init_v0(void) {
|
|||
render_camera.offset = (Vector2){(float)(screenWidth >> 1), (float)(screenHeight >> 1)};
|
||||
render_camera.rotation = 0.0f;
|
||||
render_camera.zoom = 1.5f;
|
||||
|
||||
|
||||
// NOTE(zaklaus): Paint the screen before we load the game
|
||||
// TODO(zaklaus): Render a cool loading screen background maybe? :wink: :wink:
|
||||
|
||||
|
||||
BeginDrawing();
|
||||
ClearBackground(GetColor(0x222034));
|
||||
|
||||
|
||||
char const *loading_text = "zpl.eco2d is loading...";
|
||||
int text_w = MeasureText(loading_text, 120);
|
||||
DrawText(loading_text, GetScreenWidth()-text_w-15, GetScreenHeight()-135, 120, RAYWHITE);
|
||||
EndDrawing();
|
||||
|
||||
|
||||
blocks_setup();
|
||||
assets_setup();
|
||||
}
|
||||
|
@ -173,11 +188,11 @@ void renderer_shutdown_v0(void) {
|
|||
void renderer_debug_draw_v0(void) {
|
||||
BeginMode2D(render_camera);
|
||||
debug_draw_queue *que = debug_draw_samples();
|
||||
|
||||
|
||||
for (size_t i = 0; i < que->num_entries; i += 1) {
|
||||
debug_draw_entry *e = &que->entries[i];
|
||||
Color color = GetColor(e->color);
|
||||
|
||||
|
||||
switch (e->kind) {
|
||||
case DDRAW_LINE: {
|
||||
float x = e->a.x;
|
||||
|
@ -186,13 +201,13 @@ void renderer_debug_draw_v0(void) {
|
|||
float y2 = e->b.y;
|
||||
DrawLineV((Vector2){x, y}, (Vector2){x2, y2}, color);
|
||||
}break;
|
||||
|
||||
|
||||
case DDRAW_CIRCLE:{
|
||||
float x = e->a.x;
|
||||
float y = e->a.y;
|
||||
DrawCircleLinesEco(x, y, e->radius, color);
|
||||
}break;
|
||||
|
||||
|
||||
case DDRAW_RECT:{
|
||||
float x = e->bmin.x;
|
||||
float y = e->bmin.y;
|
||||
|
@ -200,23 +215,23 @@ void renderer_debug_draw_v0(void) {
|
|||
float h = e->bmax.y - e->bmin.y;
|
||||
DrawRectangleLinesEco(x, y, w, h, color);
|
||||
}break;
|
||||
|
||||
|
||||
default: {
|
||||
|
||||
|
||||
}break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
EndMode2D();
|
||||
}
|
||||
|
||||
void renderer_draw_single_v0(float x, float y, asset_id id, Color color) {
|
||||
BeginMode2D(render_camera);
|
||||
|
||||
|
||||
x -= 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);
|
||||
|
||||
|
||||
EndMode2D();
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ static BOOL WINAPI _sighandler_win32_control_handler(DWORD control_type)
|
|||
#else //POSIX complaint
|
||||
#include <sys/types.h>
|
||||
static void _sighandler_posix_signal_handler(int sig) {
|
||||
(void)sig;
|
||||
game_request_close();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -10,8 +10,11 @@
|
|||
#define ZPL_ENABLE_MATH
|
||||
#include "zpl.h"
|
||||
|
||||
float get_cached_time(void);
|
||||
void reset_cached_time(void);
|
||||
|
||||
#define defer_var ZPL_CONCAT(_i_,__LINE__)
|
||||
#define defer(s,e) for ( \
|
||||
uint32_t defer_var = (s, 0); \
|
||||
!defer_var; \
|
||||
(defer_var += 1), e)
|
||||
(defer_var += 1), e)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "utils/options.h"
|
||||
|
||||
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);
|
||||
|
||||
block_id const *world;
|
||||
|
|
|
@ -9,47 +9,47 @@
|
|||
|
||||
static inline float lerp(float a, float b, float t) { return a * (1.0f - t) + b * t; }
|
||||
|
||||
static inline
|
||||
void DrawTextEco(const char *text, float posX, float posY, int fontSize, Color color, float spacing) {
|
||||
static inline
|
||||
void DrawTextEco(const char *text, float posX, float posY, float fontSize, Color color, float spacing) {
|
||||
#if 1
|
||||
// Check if default font has been loaded
|
||||
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 new_spacing = spacing == 0.0f ? (float)fontSize/defaultFontSize : spacing;
|
||||
|
||||
DrawTextEx(GetFontDefault(), text, position, (float)fontSize , (float)new_spacing , color);
|
||||
float new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing;
|
||||
|
||||
DrawTextEx(GetFontDefault(), text, position, fontSize , new_spacing , color);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline
|
||||
int MeasureTextEco(const char *text, int fontSize, float spacing) {
|
||||
static inline
|
||||
float MeasureTextEco(const char *text, float fontSize, float spacing) {
|
||||
#if 1
|
||||
Vector2 vec = { 0.0f, 0.0f };
|
||||
|
||||
|
||||
// Check if default font has been loaded
|
||||
if (GetFontDefault().texture.id != 0) {
|
||||
float defaultFontSize = 10.0; // Default Font chars height in pixel
|
||||
float new_spacing = spacing == 0.0f ? (float)fontSize/defaultFontSize : spacing;
|
||||
|
||||
vec = MeasureTextEx(GetFontDefault(), text, (float)fontSize, (float)new_spacing);
|
||||
float new_spacing = spacing == 0.0f ? fontSize/defaultFontSize : spacing;
|
||||
|
||||
vec = MeasureTextEx(GetFontDefault(), text, fontSize, (float)new_spacing);
|
||||
}
|
||||
|
||||
return (int)vec.x;
|
||||
|
||||
return vec.x;
|
||||
#else
|
||||
return 0;
|
||||
return 0.f;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline
|
||||
static inline
|
||||
void DrawCircleEco(float centerX, float centerY, float radius, Color 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)
|
||||
{
|
||||
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 y = 0.0f;
|
||||
float z = 0.0f;
|
||||
|
||||
|
||||
rlCheckRenderBatchLimit(36);
|
||||
|
||||
|
||||
rlPushMatrix();
|
||||
// NOTE: Transformation is applied in inverse order (scale -> rotate -> translate)
|
||||
rlTranslatef(position.x, position.y, position.z);
|
||||
rlRotatef(heading, 0, 1, 0);
|
||||
//rlScalef(1.0f, 1.0f, 1.0f); // NOTE: Vertices are directly scaled on definition
|
||||
|
||||
|
||||
rlBegin(RL_TRIANGLES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
||||
// 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 Right
|
||||
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 Left
|
||||
rlVertex3f(x + width/2, y - height/2, z + length/2); // Bottom Right
|
||||
|
||||
|
||||
// Back face
|
||||
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); // Bottom 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); // Top Left
|
||||
|
||||
|
||||
// Top face
|
||||
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 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); // Bottom Right
|
||||
|
||||
|
||||
// Bottom face
|
||||
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 Left
|
||||
|
||||
|
||||
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); // Top Left
|
||||
|
||||
|
||||
// Right face
|
||||
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 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); // Top Left
|
||||
|
||||
|
||||
// Left face
|
||||
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 Right
|
||||
|
||||
|
||||
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); // 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
|
||||
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
|
||||
// Character index position in sprite font
|
||||
// NOTE: In case a codepoint is not available in the font, index returned points to '?'
|
||||
int index = GetGlyphIndex(font, codepoint);
|
||||
float scale = fontSize/(float)font.baseSize;
|
||||
|
||||
|
||||
// Character destination rectangle on screen
|
||||
// NOTE: We consider charsPadding on drawing
|
||||
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;
|
||||
|
||||
|
||||
// Character source rectangle from font texture atlas
|
||||
// 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,
|
||||
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 height = (float)(font.recs[index].height + 2.0f*font.charsPadding)/(float)font.baseSize*scale;
|
||||
|
||||
|
||||
if (font.texture.id > 0)
|
||||
{
|
||||
const float x = 0.0f;
|
||||
const float y = 0.0f;
|
||||
const float z = 0.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 ty = srcRec.y/font.texture.height;
|
||||
const float tw = (srcRec.x+srcRec.width)/font.texture.width;
|
||||
const float th = (srcRec.y+srcRec.height)/font.texture.height;
|
||||
|
||||
|
||||
{
|
||||
#if defined(RAYLIB_NEW_RLGL)
|
||||
}
|
||||
|
@ -199,17 +205,17 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
|
|||
#endif
|
||||
rlPushMatrix();
|
||||
rlTranslatef(position.x, position.y, position.z);
|
||||
|
||||
|
||||
rlBegin(RL_QUADS);
|
||||
rlColor4ub(tint.r, tint.g, tint.b, tint.a);
|
||||
|
||||
|
||||
// Front Face
|
||||
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, 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, ty); rlVertex3f(x + width, y, z); // Top Right Of The Texture and Quad
|
||||
|
||||
|
||||
if (backface)
|
||||
{
|
||||
// Back Face
|
||||
|
@ -221,7 +227,7 @@ void DrawTextCodepoint3D(Font font, int codepoint, Vector3 position, float fontS
|
|||
}
|
||||
rlEnd();
|
||||
rlPopMatrix();
|
||||
|
||||
|
||||
#if defined(RAYLIB_NEW_RLGL)
|
||||
rlSetTexture(0);
|
||||
#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) {
|
||||
#if 0
|
||||
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 textOffsetX = 0.0f; // Offset X to next character to draw
|
||||
|
||||
|
||||
float scale = fontSize/(float)font.baseSize;
|
||||
|
||||
|
||||
for (int i = 0; i < length;)
|
||||
{
|
||||
// Get next codepoint from byte string and glyph index in font
|
||||
int codepointByteCount = 0;
|
||||
int codepoint = GetCodepoint(&text[i], &codepointByteCount);
|
||||
int index = GetGlyphIndex(font, codepoint);
|
||||
|
||||
|
||||
// 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
|
||||
if (codepoint == 0x3f) codepointByteCount = 1;
|
||||
|
||||
|
||||
if (codepoint == '\n')
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
i += codepointByteCount; // Move text bytes counter to next codepoint
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector3 MeasureText3D(Font font, const char* text, float fontSize, float fontSpacing, float lineSpacing) {
|
||||
|
||||
#if 0
|
||||
|
||||
#if 0
|
||||
int len = TextLength(text);
|
||||
int tempLen = 0; // Used to count longer text line num chars
|
||||
int lenCounter = 0;
|
||||
|
||||
|
||||
float tempTextWidth = 0.0f; // Used to count longer text line width
|
||||
|
||||
|
||||
float scale = fontSize/(float)font.baseSize;
|
||||
float textHeight = scale;
|
||||
float textWidth = 0.0f;
|
||||
|
||||
|
||||
int letter = 0; // Current character
|
||||
int index = 0; // Index position in sprite font
|
||||
|
||||
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
lenCounter++;
|
||||
|
||||
|
||||
int next = 0;
|
||||
letter = GetCodepoint(&text[i], &next);
|
||||
index = GetGlyphIndex(font, letter);
|
||||
|
||||
|
||||
// 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
|
||||
if (letter == 0x3f) next = 1;
|
||||
i += next - 1;
|
||||
|
||||
|
||||
if (letter != '\n')
|
||||
{
|
||||
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;
|
||||
textHeight += scale + lineSpacing/(float)font.baseSize*scale;
|
||||
}
|
||||
|
||||
|
||||
if (tempLen < lenCounter) tempLen = lenCounter;
|
||||
}
|
||||
|
||||
|
||||
if (tempTextWidth < textWidth) tempTextWidth = textWidth;
|
||||
|
||||
|
||||
Vector3 vec = { 0 };
|
||||
vec.x = tempTextWidth + (float)((tempLen - 1)*fontSpacing/(float)font.baseSize*scale); // Adds chars spacing to measure
|
||||
vec.y = 0.25f;
|
||||
vec.z = textHeight;
|
||||
|
||||
|
||||
return vec;
|
||||
#endif
|
||||
Vector3 todo = {0};
|
||||
|
@ -346,10 +352,10 @@ Color GenerateRandomColor(float s, float v) {
|
|||
void DrawCircleLinesEco(float centerX, float centerY, float radius, Color color)
|
||||
{
|
||||
rlCheckRenderBatchLimit(2*36);
|
||||
|
||||
|
||||
rlBegin(RL_LINES);
|
||||
rlColor4ub(color.r, color.g, color.b, color.a);
|
||||
|
||||
|
||||
// NOTE: Circle outline is drawn pixel by pixel every degree (0 to 360)
|
||||
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);
|
||||
rlVertex2f(posX + 1, posY + 1);
|
||||
rlVertex2f(posX + width, posY + 1);
|
||||
|
||||
|
||||
rlVertex2f(posX + width, posY + 1);
|
||||
rlVertex2f(posX + width, posY + height);
|
||||
|
||||
|
||||
rlVertex2f(posX + width, posY + height);
|
||||
rlVertex2f(posX + 1, posY + height);
|
||||
|
||||
|
||||
rlVertex2f(posX + 1, posY + height);
|
||||
rlVertex2f(posX + 1, posY + 1);
|
||||
rlEnd();
|
||||
|
|
|
@ -6,6 +6,7 @@ typedef enum {
|
|||
BLOCK_FLAG_COLLISION = (1 << 1),
|
||||
BLOCK_FLAG_HAZARD = (1 << 2),
|
||||
BLOCK_FLAG_ESSENTIAL = (1 << 3),
|
||||
BLOCK_FLAG_DESTROY_ON_COLLISION = (1 << 4),
|
||||
} block_flags;
|
||||
|
||||
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_get_chunk_tex(uint64_t id);
|
||||
void blocks_remove_chunk_tex(uint64_t id);
|
||||
void blocks_remove_chunk_tex(uint64_t id);
|
||||
|
|
|
@ -16,12 +16,12 @@ static block blocks[] = {
|
|||
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_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_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_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)");
|
||||
|
|
|
@ -14,88 +14,90 @@
|
|||
|
||||
#include "packets/pkt_send_librg_update.h"
|
||||
|
||||
#define ECO2D_STREAM_ACTIONFILTER 1
|
||||
|
||||
ZPL_TABLE(static, world_snapshot, world_snapshot_, entity_view);
|
||||
|
||||
static world_data world = {0};
|
||||
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);
|
||||
if (cached_ev) return *cached_ev;
|
||||
|
||||
if (cached_ev) return cached_ev;
|
||||
|
||||
entity_view view = {0};
|
||||
|
||||
|
||||
const Classify *classify = ecs_get(world_ecs(), e, Classify);
|
||||
ZPL_ASSERT(classify);
|
||||
|
||||
|
||||
view.kind = classify->id;
|
||||
|
||||
|
||||
const Position *pos = ecs_get(world_ecs(), e, Position);
|
||||
if (pos) {
|
||||
view.x = pos->x;
|
||||
view.y = pos->y;
|
||||
}
|
||||
|
||||
|
||||
const Velocity *vel = ecs_get(world_ecs(), e, Velocity);
|
||||
if (vel) {
|
||||
view.flag |= EFLAG_INTERP;
|
||||
view.vx = vel->x;
|
||||
view.vy = vel->y;
|
||||
}
|
||||
|
||||
|
||||
const Health *health = ecs_get(world_ecs(), e, Health);
|
||||
if (health) {
|
||||
view.hp = health->hp;
|
||||
view.max_hp = health->max_hp;
|
||||
}
|
||||
|
||||
|
||||
if (ecs_get(world_ecs(), e, Vehicle)) {
|
||||
Vehicle const* veh = ecs_get(world_ecs(), e, Vehicle);
|
||||
view.heading = veh->heading;
|
||||
}
|
||||
|
||||
|
||||
if (ecs_get(world_ecs(), e, ItemDrop)) {
|
||||
ItemDrop const* dr = ecs_get(world_ecs(), e, ItemDrop);
|
||||
view.asset = dr->kind;
|
||||
view.quantity = dr->quantity;
|
||||
}
|
||||
|
||||
|
||||
if (ecs_get(world_ecs(), e, Device)) {
|
||||
Device const* dev = ecs_get(world_ecs(), e, Device);
|
||||
view.asset = dev->asset;
|
||||
}
|
||||
|
||||
|
||||
view.inside_vehicle = ecs_get(world_ecs(), e, IsInVehicle) != 0 ? true : false;
|
||||
|
||||
|
||||
Inventory *inv = 0;
|
||||
if ((inv = ecs_get_mut_if(world_ecs(), e, Inventory))) {
|
||||
view.has_items = true;
|
||||
|
||||
|
||||
for (int i = 0; i < ITEMS_INVENTORY_SIZE; i += 1) {
|
||||
view.items[i] = inv->items[i];
|
||||
}
|
||||
|
||||
|
||||
const Input *in = ecs_get(world_ecs(), e, Input);
|
||||
if (in){
|
||||
view.selected_item = in->selected_item;
|
||||
view.pick_ent = (uint64_t)in->pick_ent;
|
||||
view.sel_ent = (uint64_t)in->sel_ent;
|
||||
|
||||
|
||||
if (world_entity_valid(in->storage_ent)){
|
||||
ItemContainer *ic = 0;
|
||||
if ((ic = ecs_get_mut_if(world_ecs(), in->storage_ent, ItemContainer))){
|
||||
view.has_storage_items = true;
|
||||
|
||||
|
||||
for (int i = 0; i < ITEMS_CONTAINER_SIZE; i += 1) {
|
||||
view.storage_items[i] = ic->items[i];
|
||||
}
|
||||
|
||||
|
||||
view.storage_selected_item = in->storage_selected_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Chunk *chunk = 0;
|
||||
if ((chunk = ecs_get_mut_if(world_ecs(), e, Chunk))) {
|
||||
view.x = chunk->x;
|
||||
|
@ -103,18 +105,18 @@ entity_view world_build_entity_view(int64_t e) {
|
|||
view.blocks_used = 1;
|
||||
view.is_dirty = chunk->is_dirty;
|
||||
chunk->is_dirty = false;
|
||||
|
||||
|
||||
for (int i = 0; i < world.chunk_size*world.chunk_size; i += 1) {
|
||||
view.blocks[i] = world.block_mapping[chunk->id][i];
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < world.chunk_size*world.chunk_size; i += 1) {
|
||||
view.outer_blocks[i] = world.outer_block_mapping[chunk->id][i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
|
@ -127,7 +129,7 @@ int32_t tracker_write_create(librg_world *w, librg_event *e) {
|
|||
#endif
|
||||
size_t actual_length = librg_event_size_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));
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
size_t actual_length = librg_event_size_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
|
||||
{
|
||||
if (view.kind == EKIND_CHUNK && !view.is_dirty) {
|
||||
if (view->kind == EKIND_CHUNK && !view->is_dirty) {
|
||||
return LIBRG_WRITE_REJECT;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): action-based updates
|
||||
#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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
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));
|
||||
chunk->id = i;
|
||||
chunk->is_dirty = false;
|
||||
|
||||
|
||||
for (int y = 0; y < world.chunk_size; y += 1) {
|
||||
for (int x = 0; x < world.chunk_size; x += 1) {
|
||||
int chk_x = chunk->x * world.chunk_size;
|
||||
int chk_y = chunk->y * world.chunk_size;
|
||||
|
||||
|
||||
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.outer_block_mapping[i][(y*world.chunk_size)+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
|
||||
void world_configure_tracker(void) {
|
||||
world.tracker = librg_world_create();
|
||||
|
||||
|
||||
ZPL_ASSERT_MSG(world.tracker, "[ERROR] An error occurred while trying to create a server world.");
|
||||
|
||||
|
||||
/* 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_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_REMOVE, tracker_write_remove);
|
||||
librg_event_set(world.tracker, LIBRG_WRITE_UPDATE, tracker_write_update);
|
||||
|
@ -223,14 +225,14 @@ static inline
|
|||
void world_init_worldgen_data(void) {
|
||||
world.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);
|
||||
}
|
||||
|
||||
static inline
|
||||
void world_setup_ecs(void) {
|
||||
world.ecs = ecs_init();
|
||||
|
||||
|
||||
ECS_IMPORT(world.ecs, Components);
|
||||
ECS_IMPORT(world.ecs, Systems);
|
||||
world.ecs_update = ecs_query_new(world.ecs, "components.ClientInfo, components.Position");
|
||||
|
@ -249,7 +251,7 @@ static inline
|
|||
void world_generate_instance(void) {
|
||||
int32_t world_build_status = worldgen_test(&world);
|
||||
ZPL_ASSERT(world_build_status >= 0);
|
||||
|
||||
|
||||
for (int i = 0; i < zpl_square(world.dim); ++i) {
|
||||
if (world.data[i] == 0) {
|
||||
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.chunk_size = chunk_size;
|
||||
world.chunk_amount = chunk_amount;
|
||||
|
||||
|
||||
world.dim = (world.chunk_size * world.chunk_amount);
|
||||
world.size = world.dim * world.dim;
|
||||
|
||||
|
||||
world_configure_tracker();
|
||||
world_setup_ecs();
|
||||
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_chunk_setup_grid();
|
||||
world_free_worldgen_data();
|
||||
|
||||
|
||||
zpl_printf("[INFO] Created a new server world\n");
|
||||
|
||||
|
||||
return WORLD_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
@ -307,35 +309,35 @@ int32_t world_destroy(void) {
|
|||
#define WORLD_LIBRG_BUFSIZ 2000000
|
||||
|
||||
static void world_tracker_update(uint8_t ticker, float freq, uint8_t radius) {
|
||||
if (world.tracker_update[ticker] > (float)zpl_time_rel()) return;
|
||||
world.tracker_update[ticker] = (float)zpl_time_rel() + freq;
|
||||
|
||||
if (world.tracker_update[ticker] > (float)(get_cached_time())) return;
|
||||
world.tracker_update[ticker] = (float)(get_cached_time()) + freq;
|
||||
|
||||
profile(PROF_WORLD_WRITE) {
|
||||
ecs_iter_t it = ecs_query_iter(world_ecs(), world.ecs_update);
|
||||
static char buffer[WORLD_LIBRG_BUFSIZ] = {0};
|
||||
world.active_layer_id = ticker;
|
||||
|
||||
|
||||
while (ecs_query_next(&it)) {
|
||||
ClientInfo *p = ecs_field(&it, ClientInfo, 1);
|
||||
|
||||
|
||||
for (int i = 0; i < it.count; i++) {
|
||||
size_t datalen = WORLD_LIBRG_BUFSIZ;
|
||||
|
||||
|
||||
if (!p[i].active)
|
||||
continue;
|
||||
|
||||
|
||||
int32_t result = librg_world_write(world_tracker(), it.entities[i], radius, buffer, &datalen, NULL);
|
||||
|
||||
|
||||
if (result > 0) {
|
||||
zpl_printf("[info] buffer size was not enough, please increase it by at least: %d\n", result);
|
||||
} else if (result < 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): clear out our streaming snapshot
|
||||
// TODO(zaklaus): move this to zpl
|
||||
{
|
||||
|
@ -349,21 +351,23 @@ int32_t world_update() {
|
|||
profile (PROF_UPDATE_SYSTEMS) {
|
||||
ecs_progress(world.ecs, 0.0f);
|
||||
}
|
||||
|
||||
float fast_ms = WORLD_TRACKER_UPDATE_FAST_MS;
|
||||
float normal_ms = WORLD_TRACKER_UPDATE_NORMAL_MS;
|
||||
float slow_ms = WORLD_TRACKER_UPDATE_SLOW_MS;
|
||||
|
||||
if (game_get_kind() != GAMEKIND_SINGLE) {
|
||||
fast_ms = WORLD_TRACKER_UPDATE_MP_FAST_MS;
|
||||
normal_ms = WORLD_TRACKER_UPDATE_MP_NORMAL_MS;
|
||||
slow_ms = WORLD_TRACKER_UPDATE_MP_SLOW_MS;
|
||||
|
||||
float fast_ms = WORLD_TRACKER_UPDATE_MP_FAST_MS;
|
||||
float normal_ms = WORLD_TRACKER_UPDATE_MP_NORMAL_MS;
|
||||
float slow_ms = WORLD_TRACKER_UPDATE_MP_SLOW_MS;
|
||||
|
||||
#if 1
|
||||
if (game_get_kind() == GAMEKIND_SINGLE) {
|
||||
fast_ms = WORLD_TRACKER_UPDATE_FAST_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(1, normal_ms, 2);
|
||||
world_tracker_update(2, slow_ms, 3);
|
||||
|
||||
|
||||
entity_update_action_timers();
|
||||
debug_replay_update();
|
||||
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;
|
||||
int16_t chunk_x, chunk_y;
|
||||
librg_chunk_to_chunkpos(world.tracker, chunk_id, &chunk_x, &chunk_y, NULL);
|
||||
|
||||
|
||||
// NOTE(zaklaus): pos relative to chunk
|
||||
float chx = x - chunk_x * size;
|
||||
float chy = y - chunk_y * size;
|
||||
|
||||
|
||||
uint16_t bx = (uint16_t)chx / WORLD_BLOCK_SIZE;
|
||||
uint16_t by = (uint16_t)chy / WORLD_BLOCK_SIZE;
|
||||
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];
|
||||
is_outer = false;
|
||||
}
|
||||
|
||||
|
||||
// NOTE(zaklaus): pos relative to block's center
|
||||
float box = chx - bx * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f;
|
||||
float boy = chy - by * WORLD_BLOCK_SIZE - WORLD_BLOCK_SIZE/2.0f;
|
||||
|
||||
|
||||
world_block_lookup lookup = {
|
||||
.id = block_idx,
|
||||
.bid = bid,
|
||||
|
@ -487,7 +491,7 @@ world_block_lookup world_block_from_realpos(float x, float y) {
|
|||
.oy = boy,
|
||||
.is_outer = is_outer,
|
||||
};
|
||||
|
||||
|
||||
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);
|
||||
if (blocks_get_flags(l.bid) & BLOCK_FLAG_ESSENTIAL) return;
|
||||
world_chunk_replace_block(l.chunk_id, l.id, 0);
|
||||
|
||||
|
||||
if (l.is_outer && l.bid > 0 && drop_item) {
|
||||
asset_id item_asset = blocks_get_asset(l.bid);
|
||||
if (item_find(item_asset) == ASSET_INVALID) return;
|
||||
uint64_t e = item_spawn(item_asset, 1);
|
||||
|
||||
|
||||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
dest->x = x;
|
||||
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) {
|
||||
bid = world.block_mapping[id][block_idx];
|
||||
}
|
||||
|
||||
|
||||
world_block_lookup lookup = {
|
||||
.id = block_idx,
|
||||
.bid = bid,
|
||||
.chunk_id = id,
|
||||
.chunk_e = world.chunk_mapping[id],
|
||||
};
|
||||
|
||||
|
||||
return lookup;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "world/perlin.h"
|
||||
|
||||
#include "modules/components.h"
|
||||
#include "entity.h"
|
||||
#include "vehicle.h"
|
||||
#include "items.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;
|
||||
}
|
||||
|
||||
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
|
||||
static WORLD_BLOCK_OBSERVER(shaper_noise80) {
|
||||
return rand()%10 < 8 ? shaper(id, block_idx) : BLOCK_INVALID;
|
||||
|
@ -177,7 +181,7 @@ int32_t worldgen_test(world_data *wld) {
|
|||
// ground
|
||||
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->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
|
||||
#if 1
|
||||
|
@ -215,6 +219,7 @@ int32_t worldgen_test(world_data *wld) {
|
|||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
dest->x = 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
|
||||
|
||||
|
@ -226,6 +231,7 @@ int32_t worldgen_test(world_data *wld) {
|
|||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
dest->x = 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++) {
|
||||
|
@ -234,6 +240,7 @@ int32_t worldgen_test(world_data *wld) {
|
|||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
dest->x = 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++) {
|
||||
|
@ -242,6 +249,7 @@ int32_t worldgen_test(world_data *wld) {
|
|||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
dest->x = 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++) {
|
||||
|
@ -250,6 +258,7 @@ int32_t worldgen_test(world_data *wld) {
|
|||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
dest->x = 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++) {
|
||||
|
@ -258,6 +267,7 @@ int32_t worldgen_test(world_data *wld) {
|
|||
Position *dest = ecs_get_mut(world_ecs(), e, Position);
|
||||
dest->x = 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
|
||||
|
|
|
@ -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);
|
||||
#if 1
|
||||
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);
|
||||
}
|
||||
// NOTE(zaklaus): reject updates from slower layers
|
||||
|
@ -34,7 +34,7 @@ int32_t tracker_read_update(librg_world *w, librg_event *e) {
|
|||
}
|
||||
#endif
|
||||
|
||||
data.last_update = zpl_time_rel_ms();
|
||||
data.last_update = get_cached_time()*1000.0f;
|
||||
data.layer_id = view->active_layer_id;
|
||||
predict_receive_update(d, &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_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_REMOVE, tracker_read_remove);
|
||||
|
|
|
@ -25,40 +25,44 @@ void IntegratePositions(ecs_iter_t *it) {
|
|||
profile(PROF_INTEGRATE_POS) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Velocity *v = ecs_field(it, Velocity, 2);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
// NOTE(zaklaus): world bounds
|
||||
{
|
||||
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 (ecs_get(it->world, it->entities[i], IsInVehicle)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
#if PHY_BLOCK_COLLISION==1
|
||||
// NOTE(zaklaus): X axis
|
||||
{
|
||||
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);
|
||||
float bounce = blocks_get_bounce(lookup.bid);
|
||||
if (flags & BLOCK_FLAG_COLLISION) {
|
||||
v[i].x = physics_correction(lookup.ox, v[i].x, bounce);
|
||||
if (zpl_abs(v[i].x) >= 0.001f || zpl_abs(v[i].y) >= 0.001f) {
|
||||
// NOTE(zaklaus): world bounds
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
#if PHY_BLOCK_COLLISION==1
|
||||
// NOTE(zaklaus): X axis
|
||||
{
|
||||
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);
|
||||
float bounce = blocks_get_bounce(lookup.bid);
|
||||
if (flags & BLOCK_FLAG_COLLISION) {
|
||||
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 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_DMG 5.0f
|
||||
|
||||
void HurtOnHazardBlock(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Health *h = ecs_field(it, Health, 2);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y);
|
||||
if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) {
|
||||
if (h->pain_time < 0.0f) {
|
||||
h->pain_time = HAZARD_BLOCK_TIME;
|
||||
if (h->pain_time < 0.0f) {
|
||||
h->pain_time = HAZARD_BLOCK_TIME;
|
||||
world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y);
|
||||
if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) {
|
||||
h->hp -= HAZARD_BLOCK_DMG;
|
||||
h->hp = zpl_max(0.0f, h->hp);
|
||||
}
|
||||
|
@ -107,7 +97,7 @@ void HurtOnHazardBlock(ecs_iter_t *it) {
|
|||
|
||||
void RegenerateHP(ecs_iter_t *it) {
|
||||
Health *h = ecs_field(it, Health, 1);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
if (h[i].pain_time < 0.0f) {
|
||||
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) {
|
||||
Input *in = ecs_field(it, Input, 1);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
in[i].use = false;
|
||||
in[i].swap = false;
|
||||
|
@ -139,8 +129,12 @@ void ResetActivators(ecs_iter_t *it) {
|
|||
void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Velocity *v = ecs_field(it, Velocity, 2);
|
||||
|
||||
|
||||
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);
|
||||
float drag = zpl_clamp(blocks_get_drag(lookup.bid), 0.0f, 1.0f);
|
||||
float friction = blocks_get_friction(lookup.bid);
|
||||
|
@ -148,7 +142,7 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
|
|||
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].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
|
||||
|| zpl_abs(v[i].y) > ENTITY_ACTION_VELOCITY_THRESHOLD) {
|
||||
entity_wake(it->entities[i]);
|
||||
|
@ -160,18 +154,18 @@ void ApplyWorldDragOnVelocity(ecs_iter_t *it) {
|
|||
|
||||
void PlayerClosestInteractable(ecs_iter_t *it){
|
||||
Input *in = ecs_field(it, Input, 1);
|
||||
|
||||
|
||||
for (int i = 0; i < it->count; ++i) {
|
||||
size_t ents_count;
|
||||
int64_t *ents = world_chunk_fetch_entities_realpos(in[i].bx, in[i].by, &ents_count);
|
||||
|
||||
|
||||
ecs_entity_t closest_pick = 0;
|
||||
float min_pick = ZPL_F32_MAX;
|
||||
|
||||
|
||||
for (size_t j = 0; j < ents_count; j++) {
|
||||
const Position *p2 = ecs_get(it->world, ents[j], Position);
|
||||
if (!p2) continue;
|
||||
|
||||
|
||||
float dx = p2->x - in[i].bx;
|
||||
float dy = p2->y - in[i].by;
|
||||
float range = zpl_sqrt(dx*dx + dy*dy);
|
||||
|
@ -180,9 +174,9 @@ void PlayerClosestInteractable(ecs_iter_t *it){
|
|||
closest_pick = ents[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
in[i].pick_ent = closest_pick;
|
||||
|
||||
|
||||
if (in[i].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) {
|
||||
ECS_MODULE(ecs, Systems);
|
||||
|
||||
|
||||
ECS_SYSTEM(ecs, EnableWorldEdit, EcsOnLoad);
|
||||
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, ApplyWorldDragOnVelocity, EcsOnUpdate, components.Position, components.Velocity);
|
||||
ECS_SYSTEM(ecs, HurtOnHazardBlock, EcsOnUpdate, components.Position, components.Health);
|
||||
ECS_SYSTEM(ecs, RegenerateHP, EcsOnUpdate, components.Health);
|
||||
ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, 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, LeaveVehicle, EcsPostUpdate, components.Input, components.IsInVehicle, components.Velocity);
|
||||
|
||||
|
||||
ECS_SYSTEM(ecs, PlayerClosestInteractable, EcsPostUpdate, components.Input);
|
||||
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);
|
||||
|
@ -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, InspectContainers, EcsPostUpdate, components.Input, !components.IsInVehicle);
|
||||
ECS_SYSTEM(ecs, HarvestIntoContainers, EcsPostUpdate, components.ItemContainer, components.Position);
|
||||
|
||||
|
||||
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, DisableWorldEdit, EcsPostUpdate);
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#define ITEM_PICK_RADIUS 25.0f
|
||||
#define ITEM_MERGER_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
|
||||
|
||||
|
@ -13,6 +13,7 @@ void PickItem(ecs_iter_t *it) {
|
|||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
if (inv[i].pickup_time > game_time()) continue;
|
||||
inv[i].pickup_time = game_time() + 0.5f;
|
||||
size_t ents_count;
|
||||
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;
|
||||
if ((drop = ecs_get_mut_if(it->world, ents[j], ItemDrop))) {
|
||||
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 dy = p2->y - p[i].y;
|
||||
|
@ -43,9 +45,8 @@ void PickItem(ecs_iter_t *it) {
|
|||
}
|
||||
}
|
||||
} else if (range <= ITEM_ATTRACT_RADIUS) {
|
||||
entity_set_position(ents[j],
|
||||
zpl_lerp(p2->x, p[i].x, ITEM_ATTRACT_FORCE*it->delta_time),
|
||||
zpl_lerp(p2->y, p[i].y, ITEM_ATTRACT_FORCE*it->delta_time));
|
||||
v2->x = (p[i].x - p2->x) * ITEM_ATTRACT_FORCE;
|
||||
v2->y = (p[i].y - p2->y) * ITEM_ATTRACT_FORCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,10 +143,17 @@ void VehicleHandling(ecs_iter_t *it) {
|
|||
v[i].y += ((fr_y + bk_y) / 2.0f - p[i].y);
|
||||
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);
|
||||
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++) {
|
||||
|
@ -155,11 +162,9 @@ void VehicleHandling(ecs_iter_t *it) {
|
|||
|
||||
// NOTE(zaklaus): Update passenger position
|
||||
{
|
||||
Position *p2 = ecs_get_mut(it->world, pe, Position);
|
||||
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];
|
||||
entity_wake(pe);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,3 +7,4 @@ file(GLOB SRCS *.h
|
|||
)
|
||||
|
||||
add_library(flecs-bundle STATIC ${SRCS})
|
||||
target_compile_options(flecs-bundle PRIVATE "-Wno-enum-constexpr-conversion")
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -xe
|
||||
|
||||
cmake --build build_web --target clean
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
// Hack to enforce CLOCK_REALTIME, which is significantly faster for our purposes.
|
||||
_emscripten_get_now = () => Date.now();
|
|
@ -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>
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/bash
|
||||
|
||||
set -xe
|
||||
|
||||
python -m http.server --directory build_web --bind 127.0.0.1
|
|
@ -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
|
|
@ -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
|
||||
)
|
Loading…
Reference in New Issue