├── code ├── foundation │ ├── src │ │ ├── dev │ │ │ ├── debug_renderer.h │ │ │ ├── debug_ui_helpers.c │ │ │ ├── debug_replay.h │ │ │ ├── debug_ui.h │ │ │ ├── debug_replay_compat_v2.c │ │ │ ├── debug_draw.h │ │ │ └── debug_draw.c │ │ ├── gui │ │ │ ├── notifications.h │ │ │ ├── spritesheet_viewer.c │ │ │ └── notifications.c │ │ ├── world │ │ │ ├── worldgen.h │ │ │ ├── perlin.h │ │ │ ├── prediction.h │ │ │ ├── blocks_info.h │ │ │ ├── blocks.h │ │ │ ├── world_view.h │ │ │ ├── perlin.c │ │ │ ├── prediction.c │ │ │ ├── entity_view.h │ │ │ └── worldgen_utils.h │ │ ├── platform │ │ │ ├── signal_handling.h │ │ │ ├── platform.h │ │ │ ├── system.h │ │ │ ├── input.h │ │ │ ├── renderer.h │ │ │ ├── profiler.h │ │ │ ├── signal_handling.c │ │ │ ├── profiler.c │ │ │ └── input.c │ │ ├── models │ │ │ ├── prefabs │ │ │ │ ├── player.h │ │ │ │ ├── vehicle.h │ │ │ │ ├── player.c │ │ │ │ ├── vehicle.c │ │ │ │ └── prefabs_list.c │ │ │ ├── device.h │ │ │ ├── item_placement.h │ │ │ ├── components.c │ │ │ ├── device.c │ │ │ ├── asset_setup.h │ │ │ ├── entity.h │ │ │ ├── database.h │ │ │ ├── assets.h │ │ │ ├── crafting.h │ │ │ ├── items.h │ │ │ └── assets.c │ │ ├── utils │ │ │ ├── options.h │ │ │ ├── compress.h │ │ │ ├── options.c │ │ │ └── compress.c │ │ ├── packets │ │ │ ├── pkt_00_init.h │ │ │ ├── pkt_switch_viewer.h │ │ │ ├── pkt_send_code.h │ │ │ ├── pkt_send_notif.h │ │ │ ├── pkt_send_librg_update.h │ │ │ ├── pkt_01_welcome.h │ │ │ ├── pkt_send_code.c │ │ │ ├── pkt_send_notif.c │ │ │ ├── pkt_send_keystate.h │ │ │ ├── pkt_00_init.c │ │ │ ├── pkt_switch_viewer.c │ │ │ ├── pkt_01_welcome.c │ │ │ ├── pkt_send_librg_update.c │ │ │ └── pkt_send_keystate.c │ │ ├── gen │ │ │ ├── texgen.h │ │ │ └── texgen_fallback.c │ │ ├── core │ │ │ ├── camera.h │ │ │ ├── rules_default.c │ │ │ ├── rules.h │ │ │ ├── camera.c │ │ │ └── game.h │ │ ├── systems │ │ │ ├── systems.h │ │ │ └── modules │ │ │ │ ├── system_onfoot.c │ │ │ │ ├── system_blueprint.c │ │ │ │ ├── system_health.c │ │ │ │ ├── system_phys.c │ │ │ │ └── system_producer.c │ │ ├── pkt │ │ │ └── packet.h │ │ ├── assets_ids.h │ │ └── net │ │ │ └── network.h │ └── CMakeLists.txt ├── vendors │ ├── raylib-nuklear │ │ ├── .gitignore │ │ ├── test │ │ │ ├── resources │ │ │ │ ├── test-image.png │ │ │ │ └── anonymous_pro_bold.ttf │ │ │ ├── CMakeLists.txt │ │ │ └── raylib-nuklear-test.c │ │ ├── examples │ │ │ ├── raylib-nuklear-example.png │ │ │ ├── resources │ │ │ │ ├── test-image.png │ │ │ │ └── anonymous_pro_bold.ttf │ │ │ ├── LICENSE │ │ │ ├── raylib-nuklear-texture.c │ │ │ └── CMakeLists.txt │ │ ├── .gitmodules │ │ ├── .editorconfig │ │ ├── include │ │ │ └── CMakeLists.txt │ │ ├── LICENSE │ │ └── CMakeLists.txt │ ├── flecs │ │ ├── flecs_os_api_posix.h │ │ ├── flecs_os_api_stdcpp.h │ │ ├── CMakeLists.txt │ │ ├── flecs-os_api-stdcpp.cpp │ │ └── flecs_os_api_posix.c │ ├── cwpack │ │ ├── CMakeLists.txt │ │ └── cwpack_config.h │ ├── CMakeLists.txt │ └── sfd.h └── games │ ├── minimal │ ├── src │ │ ├── rules.c │ │ ├── texgen.c │ │ ├── game.c │ │ ├── worldgen.c │ │ ├── main.c │ │ └── platform.c │ └── CMakeLists.txt │ ├── sandbox │ ├── src │ │ ├── rules.c │ │ ├── texgen.c │ │ ├── game.c │ │ └── main.c │ └── CMakeLists.txt │ ├── survival │ ├── src │ │ ├── rules.c │ │ ├── game.h │ │ ├── texgen.c │ │ ├── main.c │ │ └── platform.c │ └── CMakeLists.txt │ └── CMakeLists.txt ├── tools ├── 7za.dll ├── 7za.exe ├── upx.exe ├── 7zCon.sfx ├── 7zSD.sfx ├── 7zxa.dll ├── config.txt └── License.txt ├── art ├── dirt.ecotex ├── gen │ ├── log.png │ ├── chest.png │ ├── coal.png │ ├── dirt.png │ ├── enemy1.png │ ├── fence.png │ ├── grass.png │ ├── lava.png │ ├── plank.png │ ├── player.png │ ├── rock.png │ ├── screws.png │ ├── tree.png │ ├── water.png │ ├── water0.png │ ├── water1.png │ ├── water2.png │ ├── wood.png │ ├── asphalt.png │ ├── belt_up.png │ ├── bigtree.png │ ├── furnace.png │ ├── iron_ore.png │ ├── assembler.png │ ├── belt_down.png │ ├── belt_left.png │ ├── belt_right.png │ ├── blueprint.png │ ├── craftbench.png │ ├── iron_ingot.png │ ├── iron_plate.png │ ├── spritesheet.png │ ├── test-tall.png │ ├── demo_icemaker.png │ └── item_splitter.png ├── rock.ecotex ├── belt.aseprite ├── fence.aseprite ├── grass.ecotex ├── queries │ └── eco2d │ │ ├── readme.txt │ │ ├── recipes.sql │ │ ├── resources.sql │ │ ├── blocks.sql │ │ ├── tables.sql │ │ └── items.sql ├── skins │ └── gwen.png ├── tree.aseprite ├── wood.aseprite ├── furnace.aseprite ├── raw │ ├── log.aseprite │ ├── chest.aseprite │ ├── coal.aseprite │ ├── plank.aseprite │ ├── screws.aseprite │ ├── furnace.aseprite │ ├── iron_ore.aseprite │ ├── assembler.aseprite │ ├── craftbench.aseprite │ ├── iron_ingot.aseprite │ ├── iron_plate.aseprite │ └── item_splitter.aseprite ├── anonymous_pro_bold.ttf └── demo_icemaker.aseprite ├── win ├── run_client.bat ├── run_server.bat ├── run_client_release.bat ├── 4ed.bat ├── cmake_setup.bat ├── package_web.bat ├── survival_package_web.bat ├── package.bat ├── web.bat └── setup_cl_generic.bat ├── web ├── clean.sh ├── host.sh ├── eco2d-post.js ├── build.sh ├── bind.sh ├── setup.sh └── deploy.sh ├── dos2unix_conv.sh ├── CMakePresets.json ├── eco2d.sublime-project ├── .gitignore ├── .editorconfig ├── .github └── workflows │ └── web-build.yml ├── cmake ├── FindRaylib.cmake └── utils.cmake ├── CMakeLists.txt ├── docs └── entity_streamer.gvz ├── LICENSE ├── project.4coder ├── eco2d.10x └── README.md /code/foundation/src/dev/debug_renderer.h: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .vscode 3 | -------------------------------------------------------------------------------- /tools/7za.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/tools/7za.dll -------------------------------------------------------------------------------- /tools/7za.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/tools/7za.exe -------------------------------------------------------------------------------- /tools/upx.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/tools/upx.exe -------------------------------------------------------------------------------- /art/dirt.ecotex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/dirt.ecotex -------------------------------------------------------------------------------- /art/gen/log.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/log.png -------------------------------------------------------------------------------- /art/rock.ecotex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/rock.ecotex -------------------------------------------------------------------------------- /tools/7zCon.sfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/tools/7zCon.sfx -------------------------------------------------------------------------------- /tools/7zSD.sfx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/tools/7zSD.sfx -------------------------------------------------------------------------------- /tools/7zxa.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/tools/7zxa.dll -------------------------------------------------------------------------------- /art/belt.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/belt.aseprite -------------------------------------------------------------------------------- /art/fence.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/fence.aseprite -------------------------------------------------------------------------------- /art/gen/chest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/chest.png -------------------------------------------------------------------------------- /art/gen/coal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/coal.png -------------------------------------------------------------------------------- /art/gen/dirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/dirt.png -------------------------------------------------------------------------------- /art/gen/enemy1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/enemy1.png -------------------------------------------------------------------------------- /art/gen/fence.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/fence.png -------------------------------------------------------------------------------- /art/gen/grass.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/grass.png -------------------------------------------------------------------------------- /art/gen/lava.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/lava.png -------------------------------------------------------------------------------- /art/gen/plank.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/plank.png -------------------------------------------------------------------------------- /art/gen/player.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/player.png -------------------------------------------------------------------------------- /art/gen/rock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/rock.png -------------------------------------------------------------------------------- /art/gen/screws.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/screws.png -------------------------------------------------------------------------------- /art/gen/tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/tree.png -------------------------------------------------------------------------------- /art/gen/water.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/water.png -------------------------------------------------------------------------------- /art/gen/water0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/water0.png -------------------------------------------------------------------------------- /art/gen/water1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/water1.png -------------------------------------------------------------------------------- /art/gen/water2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/water2.png -------------------------------------------------------------------------------- /art/gen/wood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/wood.png -------------------------------------------------------------------------------- /art/grass.ecotex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/grass.ecotex -------------------------------------------------------------------------------- /art/queries/eco2d/readme.txt: -------------------------------------------------------------------------------- 1 | Only modify these for eco2d game specifically! 2 | -------------------------------------------------------------------------------- /art/skins/gwen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/skins/gwen.png -------------------------------------------------------------------------------- /art/tree.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/tree.aseprite -------------------------------------------------------------------------------- /art/wood.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/wood.aseprite -------------------------------------------------------------------------------- /win/run_client.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | call build.bat 4 | build\eco2d.exe -v %* 5 | -------------------------------------------------------------------------------- /art/furnace.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/furnace.aseprite -------------------------------------------------------------------------------- /art/gen/asphalt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/asphalt.png -------------------------------------------------------------------------------- /art/gen/belt_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/belt_up.png -------------------------------------------------------------------------------- /art/gen/bigtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/bigtree.png -------------------------------------------------------------------------------- /art/gen/furnace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/furnace.png -------------------------------------------------------------------------------- /art/gen/iron_ore.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/iron_ore.png -------------------------------------------------------------------------------- /art/raw/log.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/log.aseprite -------------------------------------------------------------------------------- /art/gen/assembler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/assembler.png -------------------------------------------------------------------------------- /art/gen/belt_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/belt_down.png -------------------------------------------------------------------------------- /art/gen/belt_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/belt_left.png -------------------------------------------------------------------------------- /art/gen/belt_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/belt_right.png -------------------------------------------------------------------------------- /art/gen/blueprint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/blueprint.png -------------------------------------------------------------------------------- /art/gen/craftbench.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/craftbench.png -------------------------------------------------------------------------------- /art/gen/iron_ingot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/iron_ingot.png -------------------------------------------------------------------------------- /art/gen/iron_plate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/iron_plate.png -------------------------------------------------------------------------------- /art/gen/spritesheet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/spritesheet.png -------------------------------------------------------------------------------- /art/gen/test-tall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/test-tall.png -------------------------------------------------------------------------------- /art/raw/chest.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/chest.aseprite -------------------------------------------------------------------------------- /art/raw/coal.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/coal.aseprite -------------------------------------------------------------------------------- /art/raw/plank.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/plank.aseprite -------------------------------------------------------------------------------- /art/raw/screws.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/screws.aseprite -------------------------------------------------------------------------------- /web/clean.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | cmake --build build_web --target clean 6 | -------------------------------------------------------------------------------- /art/gen/demo_icemaker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/demo_icemaker.png -------------------------------------------------------------------------------- /art/gen/item_splitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/gen/item_splitter.png -------------------------------------------------------------------------------- /art/raw/furnace.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/furnace.aseprite -------------------------------------------------------------------------------- /art/raw/iron_ore.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/iron_ore.aseprite -------------------------------------------------------------------------------- /code/vendors/flecs/flecs_os_api_posix.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void posix_set_os_api(void); 4 | -------------------------------------------------------------------------------- /art/anonymous_pro_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/anonymous_pro_bold.ttf -------------------------------------------------------------------------------- /art/demo_icemaker.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/demo_icemaker.aseprite -------------------------------------------------------------------------------- /art/raw/assembler.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/assembler.aseprite -------------------------------------------------------------------------------- /art/raw/craftbench.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/craftbench.aseprite -------------------------------------------------------------------------------- /art/raw/iron_ingot.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/iron_ingot.aseprite -------------------------------------------------------------------------------- /art/raw/iron_plate.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/iron_plate.aseprite -------------------------------------------------------------------------------- /code/foundation/src/dev/debug_ui_helpers.c: -------------------------------------------------------------------------------- 1 | #include "world/blocks.h" 2 | #include "world/world.h" 3 | -------------------------------------------------------------------------------- /code/games/minimal/src/rules.c: -------------------------------------------------------------------------------- 1 | #include "core/rules.h" 2 | 3 | void rules_setup() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /code/games/sandbox/src/rules.c: -------------------------------------------------------------------------------- 1 | #include "core/rules.h" 2 | 3 | void rules_setup() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /code/games/survival/src/rules.c: -------------------------------------------------------------------------------- 1 | #include "core/rules.h" 2 | 3 | void rules_setup() { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /code/vendors/cwpack/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SRCS *.h *.c) 2 | add_library(cwpack STATIC ${SRCS}) 3 | -------------------------------------------------------------------------------- /tools/config.txt: -------------------------------------------------------------------------------- 1 | ;!@Install@!UTF-8! 2 | Title="eco2d" 3 | RunProgram="eco2d.exe" 4 | ;!@InstallEnd@! -------------------------------------------------------------------------------- /win/run_server.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | call package.bat SKIP_DEPLOY 4 | cls 5 | pkg\eco2d.exe -d %* 6 | -------------------------------------------------------------------------------- /art/raw/item_splitter.aseprite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/art/raw/item_splitter.aseprite -------------------------------------------------------------------------------- /win/run_client_release.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | call package.bat SKIP_DEPLOY 4 | 5 | pkg\eco2d.exe -v %* 6 | -------------------------------------------------------------------------------- /code/games/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(sandbox) 2 | add_subdirectory(minimal) 3 | add_subdirectory(survival) 4 | -------------------------------------------------------------------------------- /web/host.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | python -m http.server --directory build_web --bind 127.0.0.1 6 | -------------------------------------------------------------------------------- /win/4ed.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | call %~dp0\setup_cl_generic.bat amd64 3 | cls 4 | pushd %~dp0\.. 5 | start "" 4ed . 6 | popd -------------------------------------------------------------------------------- /code/foundation/src/gui/notifications.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void notification_push(const char* title, const char* text); 4 | -------------------------------------------------------------------------------- /code/foundation/src/world/worldgen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | int32_t worldgen_build(void *world); 5 | -------------------------------------------------------------------------------- /code/foundation/src/platform/signal_handling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void sighandler_register(); 4 | void sighandler_unregister(); 5 | -------------------------------------------------------------------------------- /web/eco2d-post.js: -------------------------------------------------------------------------------- 1 | // Hack to enforce CLOCK_REALTIME, which is significantly faster for our purposes. 2 | //_emscripten_get_now = () => Date.now(); 3 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/test/resources/test-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/code/vendors/raylib-nuklear/test/resources/test-image.png -------------------------------------------------------------------------------- /win/cmake_setup.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | REM desktop 4 | cmake -B build -DCMAKE_BUILD_TYPE=Debug -G Ninja 5 | cmake -B build_rel -DCMAKE_BUILD_TYPE=Release -G Ninja 6 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/examples/raylib-nuklear-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/code/vendors/raylib-nuklear/examples/raylib-nuklear-example.png -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/examples/resources/test-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/code/vendors/raylib-nuklear/examples/resources/test-image.png -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/test/resources/anonymous_pro_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/code/vendors/raylib-nuklear/test/resources/anonymous_pro_bold.ttf -------------------------------------------------------------------------------- /code/foundation/src/models/prefabs/player.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | uint64_t player_spawn(char *name); 5 | void player_despawn(uint64_t ent_id); 6 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/nuklear"] 2 | path = vendor/nuklear 3 | url = https://github.com/Immediate-Mode-UI/Nuklear.git 4 | ignore = dirty 5 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/examples/resources/anonymous_pro_bold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zpl-c/eco2d/HEAD/code/vendors/raylib-nuklear/examples/resources/anonymous_pro_bold.ttf -------------------------------------------------------------------------------- /code/foundation/src/utils/options.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | void generate_minimap(int32_t seed, uint16_t block_size, uint16_t chunk_size, uint16_t world_size); 5 | -------------------------------------------------------------------------------- /code/foundation/src/models/device.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "models/assets.h" 4 | 5 | uint64_t device_spawn(asset_id id); 6 | void device_despawn(uint64_t ent_id); 7 | -------------------------------------------------------------------------------- /code/games/survival/src/game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | enum { 4 | SURV_CODE_SHOW_NOTIF, 5 | }; 6 | 7 | enum { 8 | ASSET_MOB = NEXT_FREE_ASSET, 9 | }; 10 | 11 | void game_setup_ecs(); 12 | -------------------------------------------------------------------------------- /code/vendors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_subdirectory(flecs) 2 | add_subdirectory(cwpack) 3 | add_subdirectory(raylib-nuklear) 4 | 5 | add_library(vendors-bundle STATIC 6 | sfd.c 7 | 3rd_sqlite3.c 8 | ) 9 | 10 | -------------------------------------------------------------------------------- /code/foundation/src/utils/compress.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "cwpack/cwpack.h" 3 | 4 | uint32_t compress_rle(void* data, uint32_t size, uint8_t *dest); 5 | uint32_t decompress_rle(void* data, uint32_t size, uint8_t *dest); 6 | -------------------------------------------------------------------------------- /code/foundation/src/dev/debug_replay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "packets/pkt_send_keystate.h" 4 | 5 | void debug_replay_record_keystate(pkt_send_keystate state); 6 | void debug_replay_update(void); 7 | -------------------------------------------------------------------------------- /code/foundation/src/models/item_placement.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define BUILD_MAX_PLACEMENTS 40 4 | 5 | typedef struct { 6 | float x; 7 | float y; 8 | float rot; 9 | int16_t kind; 10 | } item_placement; 11 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /code/foundation/src/world/perlin.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "platform/system.h" 4 | 5 | double perlin_noise2d(int32_t seed, double x, double y); 6 | double perlin_fbm(int32_t seed, double x, double y, double freq, uint32_t octaves); 7 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/examples/LICENSE: -------------------------------------------------------------------------------- 1 | Fonts used in examples are provided under a free and permissive license. 2 | Check individual licenses for details: 3 | 4 | - [Anonymous Pro] by Mark Simonson - https://fonts.google.com/specimen/Anonymous+Pro 5 | -------------------------------------------------------------------------------- /code/vendors/flecs/flecs_os_api_stdcpp.h: -------------------------------------------------------------------------------- 1 | #ifndef FLECS_OS_API_STDCPP_H 2 | #define FLECS_OS_API_STDCPP_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | extern void stdcpp_set_os_api(void); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/include/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # raylib_nuklear 2 | add_library(raylib_nuklear INTERFACE) 3 | target_include_directories(raylib_nuklear INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) 4 | install(FILES 5 | raylib-nuklear.h 6 | nuklear.h 7 | DESTINATION include 8 | ) 9 | -------------------------------------------------------------------------------- /code/foundation/src/models/prefabs/vehicle.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | enum { 5 | EVEH_CAR, 6 | EVEH_TRUCK, 7 | EVEH_FURNACEMOBILE, 8 | }; 9 | 10 | uint64_t vehicle_spawn(uint8_t veh_kind); 11 | void vehicle_despawn(uint64_t id); 12 | 13 | 14 | -------------------------------------------------------------------------------- /web/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | pushd build_web 6 | if [ -f "index.html" ]; then 7 | rm -rf index.html 8 | fi 9 | 10 | APP=${1:-eco2d} 11 | 12 | cmake --build . --parallel 13 | if [ -f "$APP.html" ]; then 14 | mv $APP.html index.html 15 | fi 16 | popd 17 | -------------------------------------------------------------------------------- /dos2unix_conv.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | script_path=$(cd -P -- "$(dirname -- "$0")" && pwd -P) 4 | cd "$script_path/" || exit 1 5 | 6 | find code/modules/ -type f -print0 | xargs -0 dos2unix -ic0 | xargs -0 dos2unix -b 7 | find code/game/ -type f -print0 | xargs -0 dos2unix -ic0 | xargs -0 dos2unix -b 8 | -------------------------------------------------------------------------------- /web/bind.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Symlink sources 4 | if [ ! -d "build_web/map" ]; then 5 | pushd build_web 6 | mkdir -p "map/build_web" 7 | ln -s "/workspaces/eco2d/code" "map/code" 8 | ln -s "/workspaces/eco2d/build_web/_deps" "map/build_web/_deps" 9 | popd 10 | fi 11 | -------------------------------------------------------------------------------- /code/vendors/flecs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | use_cxx11() 2 | 3 | file(GLOB SRCS *.h 4 | flecs.c 5 | 6 | flecs-os_api-stdcpp.cpp 7 | ) 8 | 9 | add_library(flecs-bundle STATIC ${SRCS}) 10 | 11 | if (NOT WIN32) 12 | target_compile_options(flecs-bundle PRIVATE "-Wno-enum-constexpr-conversion") 13 | endif() 14 | -------------------------------------------------------------------------------- /win/package_web.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem build web first 4 | call web.bat 5 | 6 | if not %ERRORLEVEL% == 0 exit /B 1 7 | @rd /S /Q pkg 8 | mkdir pkg 9 | copy ..\build_web\eco2d.* pkg 10 | copy ..\build_web\index.html pkg 11 | 12 | IF NOT "%1"=="SKIP_DEPLOY" ( 13 | butler push pkg zaklaus/eco2d:html-latest 14 | ) 15 | -------------------------------------------------------------------------------- /CMakePresets.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "buildPresets": [ 4 | { 5 | "name": "vs2022-debug", 6 | "displayName": "Visual Studio Community 2022 Release - x86_amd64 - Debug", 7 | "configurePreset": "vs2022", 8 | "configuration": "Debug" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /eco2d.sublime-project: -------------------------------------------------------------------------------- 1 | { 2 | "folders": 3 | [ 4 | { 5 | "path": "." 6 | } 7 | ], 8 | "build_systems": 9 | [ 10 | { 11 | "name": "eco2d", 12 | "cmd": ["build.bat"], 13 | "working_dir": "$project_path", 14 | "file_regex": "^(.*)\\((\\d+),?(\\d+)?\\)\\s?:\\s([^\n]+)", 15 | } 16 | ], 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | build.* 3 | build_* 4 | emsdk 5 | deploy_web 6 | run_web 7 | butler 8 | screenshots 9 | build.bat 10 | run.bat 11 | clean.bat 12 | work 13 | .vscode 14 | .ds_store 15 | 16 | GPATH 17 | GRTAGS 18 | GTAGS 19 | /run_release.bat 20 | pkg 21 | pkg.zip 22 | eco2d.zip 23 | eco2d.db 24 | eco2d.sublime-workspace 25 | 26 | .cache 27 | -------------------------------------------------------------------------------- /code/foundation/src/models/components.c: -------------------------------------------------------------------------------- 1 | #include "models/components.h" 2 | 3 | 4 | 5 | #define X(comp) ECS_COMPONENT_DECLARE(comp); 6 | _COMPS 7 | #undef X 8 | 9 | void ComponentsImport(ecs_world_t *ecs) { 10 | ECS_MODULE(ecs, Components); 11 | 12 | #define X(comp) ECS_COMPONENT_DEFINE(ecs, comp); 13 | _COMPS 14 | #undef X 15 | } 16 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_00_init.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "pkt/packet_utils.h" 4 | 5 | typedef struct { 6 | uint16_t view_id; 7 | } pkt_00_init; 8 | 9 | size_t pkt_00_init_send(uint16_t view_id); 10 | extern pkt_desc pkt_00_init_desc[]; 11 | 12 | PKT_HANDLER_PROC(pkt_00_init_handler); 13 | 14 | -------------------------------------------------------------------------------- /win/survival_package_web.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem build web first 4 | call web.bat 5 | 6 | if not %ERRORLEVEL% == 0 exit /B 1 7 | @rd /S /Q pkg 8 | mkdir pkg 9 | copy ..\build_web\survival.* pkg 10 | copy ..\build_web\survival.html pkg\index.html 11 | 12 | IF NOT "%1"=="SKIP_DEPLOY" ( 13 | butler push pkg zaklaus/chimera:html-latest 14 | ) 15 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_switch_viewer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "pkt/packet_utils.h" 4 | 5 | typedef struct { 6 | uint16_t view_id; 7 | } pkt_switch_viewer; 8 | 9 | size_t pkt_switch_viewer_send(uint16_t view_id); 10 | extern pkt_desc pkt_switch_viewer_desc[]; 11 | 12 | PKT_HANDLER_PROC(pkt_switch_viewer_handler); 13 | 14 | -------------------------------------------------------------------------------- /code/games/sandbox/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(eco2d 2 | src/main.c 3 | src/platform.c 4 | src/worldgen.c 5 | src/texgen.c 6 | src/rules.c 7 | src/game.c 8 | ) 9 | 10 | target_compile_definitions(eco2d PRIVATE CLIENT) 11 | include_directories(src ../../foundation/src ../../../art/gen) 12 | target_link_libraries(eco2d eco2d-foundation) 13 | 14 | link_system_libs(eco2d) 15 | -------------------------------------------------------------------------------- /code/games/minimal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(minimal 2 | src/main.c 3 | src/platform.c 4 | src/worldgen.c 5 | src/texgen.c 6 | src/rules.c 7 | src/game.c 8 | ) 9 | 10 | target_compile_definitions(minimal PRIVATE CLIENT) 11 | include_directories(src ../../foundation/src ../../../art/gen) 12 | target_link_libraries(minimal eco2d-foundation) 13 | 14 | link_system_libs(minimal) 15 | -------------------------------------------------------------------------------- /code/games/survival/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(survival 2 | src/main.c 3 | src/platform.c 4 | src/worldgen.c 5 | src/texgen.c 6 | src/rules.c 7 | src/game.c 8 | ) 9 | 10 | target_compile_definitions(minimal PRIVATE CLIENT) 11 | include_directories(src ../../foundation/src ../../../art/gen) 12 | target_link_libraries(survival eco2d-foundation) 13 | 14 | link_system_libs(survival) 15 | -------------------------------------------------------------------------------- /code/foundation/src/world/prediction.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "world/entity_view.h" 3 | 4 | float smooth_val(float cur, float tgt, float dt); 5 | float smooth_val_spherical(float cur, float tgt, float dt); 6 | void predict_receive_update(entity_view *d, entity_view *data); 7 | 8 | void do_entity_fadeinout(uint64_t key, entity_view * data); 9 | void lerp_entity_positions(uint64_t key, entity_view *data); 10 | -------------------------------------------------------------------------------- /code/foundation/src/platform/platform.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | void platform_init(void); 5 | void platform_shutdown(void); 6 | void platform_request_close(void); 7 | float platform_frametime(void); 8 | uint8_t platform_is_running(void); 9 | void platform_get_block_realpos(float *x, float *y); 10 | 11 | float platform_zoom_get(void); 12 | 13 | void platform_input(void); 14 | void platform_render(void); 15 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_code.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "pkt/packet_utils.h" 4 | 5 | typedef struct { 6 | uint64_t code; 7 | uint32_t params[4]; 8 | char data[128]; 9 | } pkt_send_code; 10 | 11 | size_t pkt_code_send(uint64_t peer_id, uint16_t view_id, pkt_send_code code_data); 12 | extern pkt_desc pkt_send_code_desc[]; 13 | 14 | PKT_HANDLER_PROC(pkt_send_code_handler); 15 | 16 | -------------------------------------------------------------------------------- /win/package.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | cmake --build build_rel --parallel 32 --config Release 4 | if not %ERRORLEVEL% == 0 exit /B 1 5 | @rd /S /Q pkg 6 | mkdir pkg 7 | copy build_rel\eco2d.exe pkg 8 | rem tools\upx -9 pkg\eco2d.exe 9 | robocopy art pkg\art /E 10 | @del pkg\art\*.ecotex 11 | 12 | IF NOT "%1"=="SKIP_DEPLOY" ( 13 | pushd pkg 14 | ..\tools\7za.exe a -r ..\eco2d.zip *.* 15 | popd 16 | 17 | butler push eco2d.zip zaklaus/eco2d:win64-latest 18 | ) 19 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_notif.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "pkt/packet_utils.h" 4 | 5 | typedef struct { 6 | char title[64]; 7 | char text[1024]; 8 | } pkt_send_notification; 9 | 10 | size_t pkt_notification_send(uint64_t peer_id, uint16_t view_id, const char *title, const char *text); 11 | extern pkt_desc pkt_send_notification_desc[]; 12 | 13 | PKT_HANDLER_PROC(pkt_send_notification_handler); 14 | 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | # Set default charset 12 | charset = utf-8 13 | 14 | # 4 space indentation 15 | indent_style = space 16 | indent_size = 4 17 | 18 | [Makefile] 19 | indent_style = tab 20 | 21 | [CMakeLists.txt] 22 | indent_size = 2 23 | -------------------------------------------------------------------------------- /code/foundation/src/dev/debug_ui.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "raylib.h" 4 | 5 | void debug_draw(void); 6 | 7 | typedef enum { 8 | DAREA_OUTSIDE, 9 | DAREA_HOVER, 10 | DAREA_HELD, 11 | DAREA_PRESS, 12 | 13 | DAREA_FORCE_UINT8 = UINT8_MAX 14 | } debug_area_status; 15 | 16 | debug_area_status check_mouse_area(float xpos, float ypos, float w, float h); 17 | bool is_btn_pressed(float xpos, float ypos, float w, float h, Color *color); 18 | -------------------------------------------------------------------------------- /code/foundation/src/gen/texgen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "raylib.h" 4 | #include "world/blocks.h" 5 | #include "models/assets.h" 6 | 7 | Texture2D texgen_build_anim(asset_id id, int64_t counter); 8 | Texture2D texgen_build_sprite(asset_id id); 9 | 10 | // NOTE(zak): this is a fallback for when the asset is not defined by the game 11 | Texture2D texgen_build_anim_fallback(asset_id id, int64_t counter); 12 | Texture2D texgen_build_sprite_fallback(asset_id id); 13 | -------------------------------------------------------------------------------- /code/games/minimal/src/texgen.c: -------------------------------------------------------------------------------- 1 | #include "gen/texgen.h" 2 | #include "world/world.h" 3 | #include "zpl.h" 4 | #include "utils/raylib_helpers.h" 5 | 6 | Texture2D texgen_build_anim(asset_id id, int64_t counter) { 7 | (void)counter; 8 | switch (id) { 9 | default: return texgen_build_anim_fallback(id, counter); break; 10 | } 11 | } 12 | 13 | Texture2D texgen_build_sprite(asset_id id) { 14 | switch (id) { 15 | default: return texgen_build_sprite_fallback(id); break; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /code/games/sandbox/src/texgen.c: -------------------------------------------------------------------------------- 1 | #include "gen/texgen.h" 2 | #include "world/world.h" 3 | #include "zpl.h" 4 | #include "utils/raylib_helpers.h" 5 | 6 | Texture2D texgen_build_anim(asset_id id, int64_t counter) { 7 | (void)counter; 8 | switch (id) { 9 | default: return texgen_build_anim_fallback(id, counter); break; 10 | } 11 | } 12 | 13 | Texture2D texgen_build_sprite(asset_id id) { 14 | switch (id) { 15 | default: return texgen_build_sprite_fallback(id); break; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.github/workflows/web-build.yml: -------------------------------------------------------------------------------- 1 | name: Build web and deploy 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 8 | BUILD_TYPE: Release 9 | BUTLER_API_KEY: ${{ secrets.BUTLER_KEY }} 10 | 11 | jobs: 12 | build: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v3 17 | 18 | - name: Set up emsdk 19 | run: web/setup.sh 20 | 21 | - name: Build and deploy eco2d 22 | run: web/deploy.sh 23 | -------------------------------------------------------------------------------- /web/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | # Setup emsdk 6 | if [ ! -d "emsdk" ]; then 7 | wget https://github.com/emscripten-core/emsdk/archive/refs/heads/main.zip -O emscripten.zip 8 | unzip emscripten.zip 9 | mv emsdk-main emsdk 10 | rm -rf emscripten.zip 11 | fi 12 | 13 | source ./emsdk/emsdk_env.sh 14 | emsdk update 15 | emsdk install latest 16 | emsdk activate latest 17 | source ./emsdk/emsdk_env.sh 18 | 19 | # Setup web build 20 | emcmake cmake -S . -B build_web -DCMAKE_BUILD_TYPE=Release -DPLATFORM=Web 21 | -------------------------------------------------------------------------------- /code/foundation/src/models/device.c: -------------------------------------------------------------------------------- 1 | #include "models/device.h" 2 | #include "models/entity.h" 3 | #include "world/entity_view.h" 4 | #include "world/world.h" 5 | 6 | #include "models/components.h" 7 | 8 | uint64_t device_spawn(asset_id id) { 9 | ecs_entity_t e = entity_spawn(EKIND_DEVICE); 10 | 11 | Device *dev = ecs_get_mut(world_ecs(), e, Device); 12 | zpl_zero_item(dev); 13 | dev->asset = id; 14 | 15 | return (uint64_t)e; 16 | } 17 | 18 | void device_despawn(uint64_t ent_id) { 19 | entity_despawn(ent_id); 20 | } 21 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_librg_update.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "pkt/packet_utils.h" 4 | 5 | size_t pkt_send_librg_update(uint64_t peer_id, 6 | uint16_t view_id, 7 | uint8_t ticker, 8 | void *data, 9 | size_t datalen); 10 | size_t pkt_send_librg_update_encode(void *data, int32_t data_length, uint8_t layer_id); 11 | 12 | PKT_HANDLER_PROC(pkt_send_librg_update_handler); 13 | 14 | -------------------------------------------------------------------------------- /code/foundation/src/platform/system.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define ZPL_NANO 10 | #define ZPL_ENABLE_MATH 11 | #define ZPL_ENABLE_PARSER 12 | #include "zpl.h" 13 | 14 | float get_cached_time(void); 15 | void reset_cached_time(void); 16 | 17 | #define defer_var ZPL_CONCAT(_i_,__LINE__) 18 | #define defer(s,e) for ( \ 19 | uint32_t defer_var = (s, 0); \ 20 | !defer_var; \ 21 | (defer_var += 1), e) 22 | 23 | #define PROT(...) __VA_ARGS__ 24 | -------------------------------------------------------------------------------- /code/foundation/src/world/blocks_info.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | typedef enum { 4 | BLOCK_KIND_EMPTY, 5 | BLOCK_KIND_DEV, 6 | BLOCK_KIND_GROUND, 7 | BLOCK_KIND_DIRT, 8 | BLOCK_KIND_WATER, 9 | BLOCK_KIND_LAVA, 10 | BLOCK_KIND_WALL, 11 | BLOCK_KIND_HILL, 12 | BLOCK_KIND_HILL_SNOW, 13 | BLOCK_KIND_HOLE, 14 | } block_kind; 15 | 16 | typedef enum { 17 | BLOCK_BIOME_DEV, 18 | BLOCK_BIOME_PLAIN, 19 | BLOCK_BIOME_FOREST, 20 | BLOCK_BIOME_DESERT, 21 | BLOCK_BIOME_ICE, 22 | BLOCK_BIOME_OCEAN, 23 | } block_biome; 24 | -------------------------------------------------------------------------------- /cmake/FindRaylib.cmake: -------------------------------------------------------------------------------- 1 | find_package(raylib 3.5 QUIET) 2 | 3 | if (NOT raylib_FOUND) 4 | include(FetchContent) 5 | 6 | FetchContent_Declare( 7 | raylib 8 | URL https://github.com/zpl-c/raylib/archive/master.tar.gz 9 | ) 10 | 11 | FetchContent_GetProperties(raylib) 12 | if (NOT raylib_POPULATED) 13 | set(FETCHCONTENT_QUIET NO) 14 | FetchContent_Populate(raylib) 15 | 16 | set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) 17 | 18 | add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) 19 | endif() 20 | endif() 21 | -------------------------------------------------------------------------------- /code/games/minimal/src/game.c: -------------------------------------------------------------------------------- 1 | #include "core/game.h" 2 | 3 | void game_init(bool new_db) { 4 | 5 | } 6 | 7 | void game_init_ecs() { 8 | 9 | } 10 | 11 | void game_input() { 12 | game_core_input(); 13 | } 14 | 15 | void game_update() { 16 | game_core_update(); 17 | } 18 | 19 | void game_render() { 20 | game_core_render(); 21 | } 22 | 23 | 24 | void game_player_joined(uint64_t ent) { 25 | 26 | } 27 | 28 | void game_player_departed(uint64_t ent) { 29 | 30 | } 31 | 32 | void game_player_died(uint64_t ent) { 33 | 34 | } 35 | 36 | void game_client_receive_code(pkt_send_code data) { 37 | 38 | } 39 | -------------------------------------------------------------------------------- /code/vendors/sfd.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2017 rxi 3 | * 4 | * This library is free software; you can redistribute it and/or modify it 5 | * under the terms of the MIT license. See `sfd.c` for details. 6 | */ 7 | 8 | #ifndef SFD_H 9 | #define SFD_H 10 | 11 | #define SFD_VERSION "0.1.0" 12 | 13 | typedef struct { 14 | const char *title; 15 | const char *path; 16 | const char *filter_name; 17 | const char *filter; 18 | const char *extension; 19 | } sfd_Options; 20 | 21 | const char* sfd_get_error(void); 22 | const char* sfd_open_dialog(sfd_Options *opt); 23 | const char* sfd_save_dialog(sfd_Options *opt); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /art/queries/eco2d/recipes.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO recipes (product, product_qty, process_ticks, producer) VALUES 2 | (asset('IRON_PLATES'), 4, 20, asset('FURNACE')), 3 | (asset('SCREWS'), 8, 40, asset('CRAFTBENCH')), 4 | (asset('BELT'), 1, 120, asset('ASSEMBLER')); 5 | 6 | INSERT INTO reagents (asset_id, qty) VALUES 7 | (asset('IRON_ORE'), 1), 8 | (asset('IRON_PLATES'), 1), 9 | (asset('FENCE'), 1), 10 | (asset('SCREWS'), 4), 11 | (asset('IRON_PLATES'), 2); 12 | 13 | INSERT INTO recipe_reagents (recipe_id, reagent_id) VALUES 14 | (1, 1), 15 | (2, 2), 16 | (3, 3), 17 | (3, 4), 18 | (3, 5); 19 | -------------------------------------------------------------------------------- /code/foundation/src/core/camera.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | typedef enum { 5 | CAMERA_MODE_STATIONARY, 6 | CAMERA_MODE_FOLLOW, 7 | CAMERA_MODE_FORCE_UINT8 = UINT8_MAX 8 | } camera_mode; 9 | 10 | typedef struct { 11 | camera_mode mode; 12 | uint64_t ent_id; 13 | double x, y; 14 | 15 | // HACK(zaklaus): Don't lerp if this is the first time we follow any entity. 16 | bool first_time; 17 | } camera; 18 | 19 | void camera_reset(void); 20 | void camera_update(void); 21 | void camera_set_follow(uint64_t ent_id); 22 | void camera_set_pos(double x, double y); 23 | camera camera_get(void); 24 | -------------------------------------------------------------------------------- /code/games/survival/src/texgen.c: -------------------------------------------------------------------------------- 1 | #include "gen/texgen.h" 2 | #include "world/world.h" 3 | #include "zpl.h" 4 | #include "utils/raylib_helpers.h" 5 | #include "game.h" 6 | 7 | Texture2D texgen_build_anim(asset_id id, int64_t counter) { 8 | (void)counter; 9 | switch (id) { 10 | 11 | // Mobs 12 | case ASSET_MOB: return LoadTexEco("enemy1"); 13 | default: return texgen_build_anim_fallback(id, counter); break; 14 | } 15 | } 16 | 17 | Texture2D texgen_build_sprite(asset_id id) { 18 | switch (id) { 19 | case ASSET_PLAYER: return LoadTexEco("player"); 20 | default: return texgen_build_sprite_fallback(id); break; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # raylib-nuklear-test 2 | add_executable(raylib-nuklear-test raylib-nuklear-test.c) 3 | target_compile_options(raylib-nuklear-test PRIVATE -Wall -Wextra -Wconversion -Wsign-conversion) 4 | target_link_libraries(raylib-nuklear-test PUBLIC 5 | raylib 6 | raylib_nuklear 7 | ) 8 | 9 | # Copy the resources 10 | file(GLOB resources resources/*) 11 | set(test_resources) 12 | list(APPEND test_resources ${resources}) 13 | file(COPY ${test_resources} DESTINATION "resources/") 14 | 15 | # Set up the test 16 | list(APPEND CMAKE_CTEST_ARGUMENTS "--output-on-failure") 17 | add_test(NAME raylib-nuklear-test COMMAND raylib-nuklear-test) 18 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_01_welcome.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "pkt/packet_utils.h" 4 | 5 | typedef struct { 6 | uint32_t seed; 7 | uint64_t ent_id; 8 | uint16_t chunk_size; 9 | uint16_t world_size; 10 | } pkt_01_welcome; 11 | 12 | size_t pkt_01_welcome_send(uint32_t seed, 13 | uint64_t peer_id, 14 | uint16_t view_id, 15 | uint64_t ent_id, 16 | uint16_t chunk_size, 17 | uint16_t world_size); 18 | extern pkt_desc pkt_01_welcome_desc[]; 19 | 20 | PKT_HANDLER_PROC(pkt_01_welcome_handler); 21 | 22 | -------------------------------------------------------------------------------- /code/games/sandbox/src/game.c: -------------------------------------------------------------------------------- 1 | #include "core/game.h" 2 | 3 | void game_init(bool new_db) { 4 | 5 | } 6 | 7 | void game_init_ecs() { 8 | 9 | } 10 | 11 | void game_input() { 12 | game_core_input(); 13 | } 14 | 15 | void game_update() { 16 | game_core_update(); 17 | } 18 | 19 | void game_render() { 20 | game_core_render(); 21 | } 22 | 23 | void game_player_joined(uint64_t ent) { 24 | ecs_set(world_ecs(), ent, Inventory, {0}); 25 | ecs_set(world_ecs(), ent, HealthRegen, {15.f}); 26 | } 27 | 28 | void game_player_departed(uint64_t ent) { 29 | 30 | } 31 | 32 | void game_player_died(uint64_t ent) { 33 | 34 | } 35 | 36 | void game_client_receive_code(pkt_send_code data) { 37 | 38 | } 39 | -------------------------------------------------------------------------------- /code/foundation/src/models/asset_setup.h: -------------------------------------------------------------------------------- 1 | #error DO NOT INCLUDE THIS FILE 2 | 3 | // NOTE(zaklaus): This file acts as a shortcut for setting up assets in the eco2d 4 | // use your favorite editor to quickly navigate between various files. 5 | 6 | // 1) Register a new Asset ID 7 | #include "models/assets.h" 8 | 9 | // 2) Add the asset to the asset list 10 | #include "assets_list.c" 11 | 12 | // 3) Assign a texture (if applicable) 13 | #include "texgen.c" 14 | 15 | // NOTE(zaklaus): Now that your asset is registered, we 16 | // can use it in other systems 17 | 18 | // NOTE(zaklaus): Register a block 19 | #include "world/blocks_list.c" 20 | 21 | // NOTE(zaklaus): Register an item 22 | #include "items_list.c" 23 | -------------------------------------------------------------------------------- /win/web.bat: -------------------------------------------------------------------------------- 1 | rem set up VS (to get ninja generator) 2 | call setup_cl_generic.bat amd64 3 | 4 | rem clone emscripten sdk 5 | if not exist "..\emsdk" ( 6 | git clone https://github.com/emscripten-core/emsdk ..\emsdk 7 | pushd ..\emsdk 8 | call emsdk install 3.0.0 && rem latest 9 | call emsdk activate 3.0.0 && rem latest 10 | popd 11 | ) 12 | if "%EMSDK%"=="" call ..\emsdk\emsdk_env.bat 13 | 14 | rem host webserver, compile and launch 15 | rem start "" python3 -m http.server --bind 127.0.0.1 8000 --directory build_web 16 | 17 | pushd .. 18 | call emcmake cmake -S . -B build_web -DCMAKE_BUILD_TYPE=Release -DPLATFORM=Web 19 | call cmake --build build_web --parallel 20 | move build_web\eco2d.html build_web\index.html 21 | popd 22 | -------------------------------------------------------------------------------- /code/foundation/src/utils/options.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "world/world.h" 4 | #include "world/blocks.h" 5 | #include "utils/options.h" 6 | 7 | void generate_minimap(int32_t seed, uint16_t block_size, uint16_t chunk_size, uint16_t world_size) { 8 | (void)block_size; 9 | world_init(seed, chunk_size, world_size); 10 | 11 | block_id const *world; 12 | uint32_t world_length = chunk_size * world_size; 13 | uint32_t len = world_buf(&world, NULL); 14 | 15 | for (block_id i=0; i 0 && i % world_length == 0) { 17 | putc('\n', stdout); 18 | } 19 | putc(blocks_get_symbol(world[i]), stdout); 20 | } 21 | 22 | putc('\n', stdout); 23 | world_destroy(); 24 | } 25 | -------------------------------------------------------------------------------- /code/foundation/src/platform/input.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "system.h" 3 | 4 | enum { 5 | IN_NONE, 6 | IN_LEFT, 7 | IN_RIGHT, 8 | IN_UP, 9 | IN_DOWN, 10 | IN_USE, 11 | IN_SPRINT, 12 | IN_DROP, 13 | IN_CTRL, 14 | IN_TOGGLE_INV, 15 | IN_TOGGLE_DEMOLITION, 16 | }; 17 | 18 | enum { 19 | DEV_NONE, 20 | DEV_KEYBOARD, 21 | DEV_MOUSE, 22 | DEV_JOYSTICK 23 | }; 24 | 25 | typedef struct { 26 | uint8_t device; 27 | uint32_t id; 28 | } input_bind; 29 | 30 | typedef struct { 31 | const char* name; 32 | uint8_t action; 33 | input_bind *binds; 34 | } input_map; 35 | 36 | uint8_t input_is_down(uint8_t action); 37 | uint8_t input_is_pressed(uint8_t action); 38 | uint8_t input_is_released(uint8_t action); 39 | 40 | -------------------------------------------------------------------------------- /code/foundation/src/dev/debug_replay_compat_v2.c: -------------------------------------------------------------------------------- 1 | typedef struct { 2 | float x; 3 | float y; 4 | uint8_t use; 5 | uint8_t sprint; 6 | } pkt_send_keystate_v2; 7 | 8 | typedef struct { 9 | replay_kind kind; 10 | pkt_send_keystate_v2 pkt; 11 | uint64_t delay; 12 | } replay_record_v2; 13 | 14 | void debug_replay_load_record_v2(replay_record *rec, void const *buf) { 15 | replay_record_v2 v2_rec; 16 | zpl_memcopy(&v2_rec, buf, sizeof(replay_record_v2)); 17 | 18 | pkt_send_keystate pkt = { 19 | .x = v2_rec.pkt.x, 20 | .y = v2_rec.pkt.y, 21 | .sprint = v2_rec.pkt.sprint, 22 | .use = v2_rec.pkt.use, 23 | }; 24 | 25 | rec->kind = v2_rec.kind; 26 | rec->pkt = pkt; 27 | rec->delay = (double)v2_rec.delay; 28 | } -------------------------------------------------------------------------------- /code/foundation/src/platform/renderer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "world/entity_view.h" 4 | #include "world/blocks.h" 5 | #include "raylib.h" 6 | 7 | typedef struct { 8 | uint64_t key; 9 | entity_view *data; 10 | float x; 11 | float y; 12 | float cy; 13 | block_id blk_id; 14 | } game_world_render_entry; 15 | 16 | void renderer_draw(void); 17 | void renderer_init(void); 18 | void renderer_shutdown(void); 19 | void renderer_debug_draw(void); 20 | float renderer_zoom_get(void); 21 | void renderer_draw_single(float x, float y, asset_id id, Color color); 22 | void renderer_draw_entry(uint64_t key, entity_view * data, game_world_render_entry* entry); 23 | void renderer_bake_chunk(uint64_t key, entity_view * data); 24 | void renderer_switch(int kind); 25 | -------------------------------------------------------------------------------- /code/foundation/src/gui/spritesheet_viewer.c: -------------------------------------------------------------------------------- 1 | void spritesheet_viewer(struct nk_context *ctx, struct nk_image spritesheet, Vector2 frameSize, int framesPerRow) { 2 | const int maxFrames = (int)((spritesheet.w*spritesheet.h) / (frameSize.x*frameSize.y)); 3 | nk_layout_row_static(ctx, 32, 32, (int)(nk_window_get_size(ctx).x / frameSize.x) -1); 4 | for(int frame = 0; frame < maxFrames; frame++) { 5 | float ox = (frame % framesPerRow) * frameSize.x; 6 | float oy = (int)(frame / framesPerRow) * frameSize.y; 7 | spritesheet.region[0] = (nk_ushort)ox; 8 | spritesheet.region[1] = (nk_ushort)oy; 9 | spritesheet.region[2] = (nk_ushort)frameSize.x; 10 | spritesheet.region[3] = (nk_ushort)frameSize.y; 11 | nk_image(ctx, spritesheet); 12 | nk_labelf(ctx, NK_TEXT_ALIGN_LEFT, "%d", frame); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /code/foundation/src/systems/systems.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "flecs.h" 3 | 4 | static inline float safe_dt(ecs_iter_t *it) { 5 | return zpl_min(it->delta_time, 0.03334f); 6 | } 7 | 8 | extern ecs_query_t *ecs_rigidbodies; 9 | extern ecs_entity_t ecs_timer; 10 | 11 | #define TICK_VAR(var) (var) = zpl_max((var)-1, 0) 12 | 13 | #define ECO2D_TICK_RATE (1.0f/20.f) 14 | 15 | #define ECS_SYSTEM_TICKED(world, id, stage, ...)\ 16 | ECS_SYSTEM(world, id, stage, __VA_ARGS__);\ 17 | ecs_set_tick_source(world, id, ecs_timer); 18 | 19 | #define ECS_SYSTEM_TICKED_EX(world, id, stage, time, ...)\ 20 | ECS_SYSTEM(world, id, stage, __VA_ARGS__);\ 21 | ecs_entity_t timer_##id = ecs_set_interval(ecs, 0, ECO2D_TICK_RATE*time);\ 22 | ecs_set_tick_source(world, id, timer_##id); 23 | 24 | 25 | void SystemsImport(ecs_world_t *ecs); 26 | -------------------------------------------------------------------------------- /code/foundation/src/systems/modules/system_onfoot.c: -------------------------------------------------------------------------------- 1 | #include "models/entity.h" 2 | 3 | void MovementImpulse(ecs_iter_t *it) { 4 | Input *in = ecs_field(it, Input, 1); 5 | Velocity *v = ecs_field(it, Velocity, 2); 6 | Position *p = ecs_field(it, Position, 3); 7 | 8 | for (int i = 0; i < it->count; i++) { 9 | world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y); 10 | float drag = zpl_clamp(blocks_get_drag(lookup.bid), 0.0f, 1.0f); 11 | float speed = game_rules.plr_move_speed * (in[i].sprint ? game_rules.plr_move_speed_mult : 1.0f); 12 | v[i].x += in[i].x*speed*drag*safe_dt(it); 13 | v[i].y -= in[i].y*speed*drag*safe_dt(it); 14 | 15 | if ( zpl_abs(v[i].x) > ENTITY_ACTION_VELOCITY_THRESHOLD 16 | || zpl_abs(v[i].y) > ENTITY_ACTION_VELOCITY_THRESHOLD) { 17 | entity_wake(it->entities[i]); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /code/foundation/src/core/rules_default.c: -------------------------------------------------------------------------------- 1 | #include "core/rules.h" 2 | 3 | game_rulesdef game_rules = { 4 | .phy_walk_drag = 4.23f, 5 | .demo_npc_move_speed = 500, 6 | .demo_npc_steer_speed = 300, 7 | .item_pick_radius = 25.0f, 8 | .item_merger_radius = 75.0f, 9 | .item_attract_radius = 75.0f, 10 | .item_attract_force = 1.98f, 11 | .item_container_reach_radius = 105.0f, 12 | .item_drop_pickup_time = 2.5f, 13 | .item_drop_merger_time = 6.5f, 14 | .plr_move_speed = 800.0f, 15 | .plr_move_speed_mult = 1.5f, 16 | .vehicle_force = 240.8f, 17 | .vehicle_accel = 0.032f, 18 | .vehicle_decel = 0.28f, 19 | .vehicle_steer = 35.89f, 20 | .vehicle_steer_compensation = 4.0f, 21 | .vehicle_steer_revert = 6.0941816f, 22 | .vehicle_power = 97.89f, 23 | .vehicle_brake_force = 0.84f, 24 | .veh_enter_radius = 45.0f, 25 | .blueprint_build_time = 1.5f, 26 | }; 27 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 Rob Loach (@RobLoach) 2 | 3 | This software is provided "as-is", without any express or implied warranty. In no event 4 | will the authors be held liable for any damages arising from the use of this software. 5 | 6 | Permission is granted to anyone to use this software for any purpose, including commercial 7 | applications, and to alter it and redistribute it freely, subject to the following restrictions: 8 | 9 | 1. The origin of this software must not be misrepresented; you must not claim that you 10 | wrote the original software. If you use this software in a product, an acknowledgment 11 | in the product documentation would be appreciated but is not required. 12 | 13 | 2. Altered source versions must be plainly marked as such, and must not be misrepresented 14 | as being the original software. 15 | 16 | 3. This notice may not be removed or altered from any source distribution. 17 | -------------------------------------------------------------------------------- /code/foundation/src/models/entity.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | #define ENTITY_ACTION_VELOCITY_THRESHOLD 0.001f 5 | 6 | uint64_t entity_spawn(uint16_t class_id /* 0 = no streaming */); 7 | uint64_t entity_spawn_id(uint16_t id); 8 | uint64_t entity_spawn_id_with_data(uint16_t id, void* udata); 9 | bool entity_spawn_provided(uint16_t id); 10 | void entity_batch_despawn(uint64_t *ids, size_t num_ids); 11 | void entity_despawn(uint64_t ent_id); 12 | void entity_set_position(uint64_t ent_id, float x, float y); 13 | 14 | // NOTE(zaklaus): spawndef manager 15 | 16 | void entity_add_spawndef(uint16_t id, uint64_t (*proc)()); 17 | void entity_add_spawndef_data(uint16_t id, uint64_t (*proc)(void*)); 18 | void entity_default_spawnlist(void); 19 | 20 | // NOTE(zaklaus): action-based entity stream throttling 21 | void entity_wake(uint64_t ent_id); 22 | void entity_update_action_timers(); 23 | bool entity_can_stream(uint64_t ent_id); 24 | 25 | -------------------------------------------------------------------------------- /code/foundation/src/core/rules.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | typedef struct { 5 | float phy_walk_drag; 6 | uint64_t demo_npc_move_speed; 7 | uint64_t demo_npc_steer_speed; 8 | float item_pick_radius; 9 | float item_merger_radius; 10 | float item_attract_radius; 11 | float item_attract_force; 12 | float item_container_reach_radius; 13 | float item_drop_pickup_time; 14 | float item_drop_merger_time; 15 | float plr_move_speed; 16 | float plr_move_speed_mult; 17 | float vehicle_force; 18 | float vehicle_accel; 19 | float vehicle_decel; 20 | float vehicle_steer; 21 | float vehicle_steer_compensation; 22 | float vehicle_steer_revert; 23 | float vehicle_power; 24 | float vehicle_brake_force; 25 | float veh_enter_radius; 26 | float blueprint_build_time; 27 | 28 | // survival rules 29 | } game_rulesdef; 30 | 31 | extern game_rulesdef game_rules; 32 | 33 | void rules_setup(); 34 | -------------------------------------------------------------------------------- /web/deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -xe 4 | 5 | if [ ! -d "build_web" ]; then 6 | echo "Build directory not found. Run setup_web.sh first." 7 | exit 1 8 | fi 9 | 10 | if [ ! -d "butler" ]; then 11 | mkdir butler 12 | wget https://broth.itch.ovh/butler/linux-amd64/LATEST/archive/default -O butler.zip 13 | mv butler.zip butler/ 14 | pushd butler/ 15 | unzip butler.zip 16 | rm -rf butler.zip 17 | chmod +x ./butler 18 | ./butler -V 19 | popd 20 | fi 21 | 22 | # Build the project 23 | web/build.sh 24 | 25 | # Package all assets 26 | if [ ! -f "build_web/index.html" ]; then 27 | echo "Build data not found. Compilation errors?" 28 | exit 1 29 | fi 30 | 31 | APP=${1:-eco2d} 32 | 33 | mkdir -p deploy_web 34 | cp build_web/$APP.* deploy_web/ 35 | cp build_web/index.html deploy_web/ 36 | 37 | # Deploy to itch.io 38 | ./butler/butler push deploy_web/ zaklaus/$APP:html-latest 39 | 40 | # Teardown 41 | rm -rf deploy_web 42 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.11) 2 | project(raylib_nuklear 3 | DESCRIPTION "raylib_nuklear: Nuklear immediate mode GUI for raylib." 4 | HOMEPAGE_URL "https://github.com/robloach/raylib-nuklear" 5 | VERSION 4.2.2 6 | LANGUAGES C 7 | ) 8 | 9 | # raylib-nuklear 10 | add_subdirectory(include) 11 | 12 | # Options 13 | if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") 14 | set(RAYLIB_NUKLEAR_IS_MAIN TRUE) 15 | else() 16 | set(RAYLIB_NUKLEAR_IS_MAIN FALSE) 17 | endif() 18 | option(RAYLIB_NUKLEAR_BUILD_EXAMPLES "Examples" ${RAYLIB_NUKLEAR_IS_MAIN}) 19 | 20 | # Examples 21 | if (RAYLIB_NUKLEAR_BUILD_EXAMPLES) 22 | add_subdirectory(examples) 23 | 24 | # Testing 25 | include(CTest) 26 | enable_testing() 27 | if (BUILD_TESTING) 28 | # set(CTEST_CUSTOM_TESTS_IGNORE 29 | # pkg-config--static 30 | # ) 31 | add_subdirectory(test) 32 | endif() 33 | endif() 34 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_code.c: -------------------------------------------------------------------------------- 1 | #include "packets/pkt_send_code.h" 2 | #include "pkt/packet.h" 3 | #include "world/world.h" 4 | #include "core/game.h" 5 | #include "world/entity_view.h" 6 | 7 | #include "models/components.h" 8 | #include "systems/systems.h" 9 | 10 | pkt_desc pkt_send_code_desc[] = { 11 | { PKT_UINT(pkt_send_code, code) }, 12 | { PKT_ARRAY(pkt_send_code, params) }, 13 | { PKT_ARRAY(pkt_send_code, data) }, 14 | { PKT_END }, 15 | }; 16 | 17 | size_t pkt_code_send(uint64_t peer_id, uint16_t view_id, pkt_send_code table) { 18 | return pkt_world_write(MSG_ID_SEND_CODE, pkt_table_encode(pkt_send_code_desc, PKT_STRUCT_PTR(&table)), 1, view_id, (void*)peer_id, 0); 19 | } 20 | 21 | int32_t pkt_send_code_handler(pkt_header *header) { 22 | pkt_send_code table = { 0 }; 23 | PKT_IF(pkt_msg_decode(header, pkt_send_code_desc, pkt_pack_desc_args(pkt_send_code_desc), PKT_STRUCT_PTR(&table))); 24 | 25 | game_client_receive_code(table); 26 | 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /code/foundation/src/models/database.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "zpl.h" 4 | 5 | bool db_init(); 6 | void db_shutdown(); 7 | 8 | // raw query data getters 9 | char *db_get(char *query, bool header); 10 | char *db_row(char *table, char *name); 11 | bool db_csv(zpl_csv_object *csv, char *query); 12 | bool db_row_csv(zpl_csv_object *csv, char *table, char *name); 13 | 14 | // csv backed data queries 15 | bool db_push(char *query); 16 | bool db_row_push(char *table, char *name); 17 | zpl_adt_node *db_field(char *field, int row); 18 | size_t db_rows(); 19 | #define db_str(fld, row) (db_field(fld, row)->string) 20 | #define db_flt(fld, row) (db_field(fld, row)->type == ZPL_ADT_TYPE_STRING ? 0.0f : db_field(fld, row)->real) 21 | #define db_int(fld, row) (db_field(fld, row)->type == ZPL_ADT_TYPE_STRING ? 0 : db_field(fld, row)->integer) 22 | zpl_csv_object *db_last(); 23 | void db_pop(); 24 | 25 | // sql execution 26 | bool db_exec_file(const char *sql); 27 | bool db_exec(const char *query); 28 | 29 | -------------------------------------------------------------------------------- /code/foundation/src/platform/profiler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | typedef enum { 5 | PROF_TOTAL_TIME, 6 | PROF_MAIN_LOOP, 7 | 8 | PROF_WORLD_WRITE, 9 | PROF_RENDER, 10 | PROF_UPDATE_SYSTEMS, 11 | PROF_ENTITY_LERP, 12 | PROF_INTEGRATE_POS, 13 | PROF_PHYS_BLOCK_COLS, 14 | PROF_PHYS_BODY_COLS, 15 | PROF_RENDER_PUSH_AND_SORT_ENTRIES, 16 | 17 | MAX_PROF, 18 | PROF_FORCE_UINT8 = UINT8_MAX 19 | } profiler_kind; 20 | 21 | typedef struct { 22 | profiler_kind id; 23 | char const *name; 24 | 25 | uint32_t num_invocations; 26 | double start_time; 27 | double delta_time; 28 | double total_time; 29 | } profiler; 30 | 31 | void profiler_reset(profiler_kind id); 32 | void profiler_start(profiler_kind id); 33 | void profiler_stop(profiler_kind id); 34 | void profiler_collate(void); 35 | 36 | double profiler_delta(profiler_kind id); 37 | char const *profiler_name(profiler_kind id); 38 | 39 | #define profile(id) defer(profiler_start(id), profiler_stop(id)) 40 | -------------------------------------------------------------------------------- /cmake/utils.cmake: -------------------------------------------------------------------------------- 1 | function(link_system_libs target_name) 2 | if (WIN32) 3 | target_link_libraries(${target_name} winmm) 4 | elseif (APPLE) 5 | target_link_libraries(${target_name} pthread m dl) 6 | elseif (EMSCRIPTEN) 7 | target_link_libraries(${target_name} pthread m dl) 8 | elseif (UNIX) 9 | target_link_libraries(${target_name} pthread m dl atomic) 10 | endif() 11 | 12 | if (WIN32) 13 | target_compile_options(${target_name} PRIVATE -WX -W3 -wd5105) 14 | else() 15 | target_compile_options(${target_name} PRIVATE -Werror -Wall -Wextra -Wno-unused-function -Wno-unknown-pragmas -Wno-unused-variable -Wno-unused-parameter) 16 | endif () 17 | endfunction() 18 | 19 | macro(use_cxx11) 20 | if (CMAKE_VERSION VERSION_LESS "3.1") 21 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 22 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") 23 | endif () 24 | else () 25 | set(CMAKE_CXX_STANDARD 11) 26 | endif () 27 | endmacro(use_cxx11) 28 | -------------------------------------------------------------------------------- /code/foundation/src/models/assets.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | #include "assets_ids.h" 5 | 6 | typedef enum { 7 | AKIND_TEXTURE, 8 | AKIND_ANIM, 9 | AKIND_SOUND, 10 | 11 | FORCE_AKIND_UINT8 = UINT8_MAX 12 | } asset_kind; 13 | 14 | void assets_db_init(void); 15 | void assets_db(void); 16 | void assets_new(const char *name); 17 | int32_t assets_setup(void); 18 | int32_t assets_frame(void); 19 | void assets_destroy(void); 20 | 21 | uint16_t assets_find(asset_id id); 22 | 23 | asset_kind assets_get_kind(uint16_t id); 24 | const char *assets_get_kind_name(uint16_t id); 25 | void *assets_get_snd(uint16_t id); 26 | void *assets_get_tex(uint16_t id); 27 | uint16_t assets_resolve_proxy(uint16_t id); 28 | 29 | // NOTE(zaklaus): client only 30 | #define ASSET_SRC_RECT() ((Rectangle){0, 0, 64, 64}) 31 | #define ASSET_DST_RECT(x,y) ((Rectangle){x, y, 64, 64}) 32 | #define ASSET_SRC_RECT_TEX(w,h) ((Rectangle){0, 0, (float)w, (float)h}) 33 | #define ASSET_DST_RECT_TEX(x,y,w,h) ((Rectangle){x, y, (float)w, (float)h}) 34 | -------------------------------------------------------------------------------- /code/foundation/src/models/prefabs/player.c: -------------------------------------------------------------------------------- 1 | #include "player.h" 2 | #include "world/entity_view.h" 3 | 4 | #include "world/world.h" 5 | 6 | #include "models/entity.h" 7 | #include "models/components.h" 8 | 9 | #include "core/game.h" 10 | 11 | #define PLAYER_MAX_HP 100.0f 12 | 13 | uint64_t player_spawn(char *name) { 14 | ecs_entity_t e = entity_spawn(EKIND_PLAYER); 15 | 16 | if (!name) { 17 | name = zpl_bprintf("player_%d", e); 18 | } 19 | 20 | ecs_set_name(world_ecs(), e, name); 21 | ecs_set(world_ecs(), e, ClientInfo, {0}); 22 | ecs_set(world_ecs(), e, Health, {.hp = PLAYER_MAX_HP, .max_hp = PLAYER_MAX_HP}); 23 | ecs_set(world_ecs(), e, Velocity, { 0 }); 24 | ecs_set(world_ecs(), e, PhysicsBody, { .kind = PHYS_AABB, .mass = INFINITE_MASS }); 25 | Input *i = ecs_get_mut(world_ecs(), e, Input); 26 | *i = (Input){ 0 }; 27 | i->hx = 1.0f; 28 | 29 | librg_entity_owner_set(world_tracker(), e, (int64_t)e); 30 | 31 | return (uint64_t)e; 32 | } 33 | 34 | void player_despawn(uint64_t ent_id) { 35 | game_player_departed(ent_id); 36 | entity_despawn(ent_id); 37 | } 38 | -------------------------------------------------------------------------------- /code/foundation/src/utils/compress.c: -------------------------------------------------------------------------------- 1 | #include "compress.h" 2 | 3 | uint32_t compress_rle(void* data, uint32_t size, uint8_t *dest) { 4 | if (size < 1) return 0; 5 | uint32_t total_size = 0; 6 | uint8_t *buf = (uint8_t*)data; 7 | uint8_t byte = buf[0]; 8 | uint16_t occurences = 1; 9 | for (uint32_t i = 1; i <= size; i += 1){ 10 | if (buf[i] != byte || i == size) { 11 | *(uint16_t*)dest = occurences; dest += 2; 12 | *dest++ = byte; 13 | byte = buf[i]; 14 | occurences = 1; 15 | total_size += 3; 16 | } 17 | else occurences++; 18 | } 19 | return total_size; 20 | } 21 | 22 | uint32_t decompress_rle(void* data, uint32_t size, uint8_t *dest) { 23 | if (size < 1) return 0; 24 | uint32_t total_size = 0; 25 | uint8_t *buf = (uint8_t*)data; 26 | for (uint32_t i = 0; i < size; i += 3){ 27 | uint16_t len = *(uint16_t*)&buf[i]; 28 | for (uint16_t j = 0; j < len; j += 1){ 29 | *dest++ = buf[i+2]; 30 | total_size++; 31 | } 32 | } 33 | return total_size; 34 | } 35 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.0) 2 | cmake_policy(SET CMP0057 NEW) 3 | project(eco2d) 4 | include(cmake/utils.cmake) 5 | 6 | set(CMAKE_C_STANDARD 11) 7 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/) 8 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/) 9 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}) 10 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}) 11 | SET(CMAKE_USE_RELATIVE_PATHS OFF) 12 | 13 | if(MSVC) 14 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 15 | endif() 16 | 17 | if (EMSCRIPTEN) 18 | 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") 19 | set(CMAKE_EXECUTABLE_SUFFIX ".html") 20 | endif () 21 | 22 | include_directories(code/common code/vendors code/vendors/flecs) 23 | 24 | include(cmake/FindRaylib.cmake) 25 | 26 | add_subdirectory(code/vendors) 27 | 28 | add_subdirectory(code/foundation) 29 | add_subdirectory(code/games) 30 | -------------------------------------------------------------------------------- /art/queries/eco2d/resources.sql: -------------------------------------------------------------------------------- 1 | INSERT INTO resources (asset, kind) VALUES 2 | (asset('EMPTY'), 0), 3 | (asset('BLANK'), 0), 4 | (asset('BLOCK_FRAME'), 0), 5 | (asset('BUILDMODE_HIGHLIGHT'), 0), 6 | (asset('COAL'), 0), 7 | (asset('IRON_ORE'), 0), 8 | (asset('IRON_INGOT'), 0), 9 | (asset('IRON_PLATES'), 0), 10 | (asset('SCREWS'), 0), 11 | (asset('LOG'), 0), 12 | (asset('PLANK'), 0), 13 | (asset('CHEST'), 0), 14 | (asset('CREATURE'), 0), 15 | (asset('CREATURE_FOOD'), 0), 16 | (asset('FURNACE'), 0), 17 | (asset('SPLITTER'), 0), 18 | (asset('ASSEMBLER'), 0), 19 | (asset('CRAFTBENCH'), 0), 20 | (asset('BLUEPRINT'), 0), 21 | (asset('BLUEPRINT_DEMO_HOUSE'), 0), 22 | (asset('MOB'), 0), 23 | (asset('PLAYER'), 0), 24 | (asset('FENCE'), 0), 25 | (asset('DEV'), 0), 26 | (asset('GROUND'), 0), 27 | (asset('DIRT'), 0), 28 | (asset('WATER'), 2), 29 | (asset('LAVA'), 0), 30 | (asset('WALL'), 0), 31 | (asset('HILL'), 0), 32 | (asset('HILL_SNOW'), 0), 33 | (asset('HOLE'), 0), 34 | (asset('WOOD'), 0), 35 | (asset('TEST_TALL'), 0), 36 | (asset('TREE'), 0), 37 | (asset('BELT'), 0), 38 | (asset('BELT_LEFT'), 0), 39 | (asset('BELT_RIGHT'), 0), 40 | (asset('BELT_UP'), 0), 41 | (asset('BELT_DOWN'), 0); 42 | 43 | -------------------------------------------------------------------------------- /code/foundation/src/pkt/packet.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | #define PKT_BUFSIZ 4000000 5 | 6 | typedef enum { 7 | MSG_ID_00_INIT, 8 | MSG_ID_01_WELCOME, 9 | MSG_ID_LIBRG_UPDATE, 10 | MSG_ID_SEND_KEYSTATE, 11 | MSG_ID_SEND_BLOCKPOS, 12 | MSG_ID_SWITCH_VIEWER, 13 | MSG_ID_SEND_NOTIFICATION, 14 | MSG_ID_SEND_CODE, 15 | MSG_NEXT_FREE_ID, 16 | MAX_PACKETS = 256, 17 | } pkt_messages; 18 | 19 | typedef struct pkt_header { 20 | uint16_t id; 21 | uint16_t sender; 22 | uint16_t view_id; 23 | uint16_t channel_id; 24 | uint8_t *data; 25 | uint32_t datalen; 26 | int8_t is_reliable; 27 | int8_t ok; 28 | void* udata; 29 | } pkt_header; 30 | 31 | #define PKT_HANDLER_PROC(name) int32_t name(pkt_header *header) 32 | typedef PKT_HANDLER_PROC(pkt_handler_proc); 33 | 34 | typedef struct { 35 | uint16_t id; 36 | pkt_handler_proc *handler; 37 | } pkt_handler; 38 | 39 | int32_t pkt_header_encode(pkt_messages id, uint16_t view_id, void *data, size_t datalen); 40 | int32_t pkt_header_decode(pkt_header *table, void *data, size_t datalen); 41 | 42 | extern pkt_handler pkt_handlers[]; 43 | extern uint8_t pkt_buffer[]; 44 | -------------------------------------------------------------------------------- /code/foundation/src/world/blocks.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "models/assets.h" 4 | 5 | typedef enum { 6 | BLOCK_FLAG_COLLISION = (1 << 1), 7 | BLOCK_FLAG_HAZARD = (1 << 2), 8 | BLOCK_FLAG_ESSENTIAL = (1 << 3), 9 | BLOCK_FLAG_DESTROY_ON_COLLISION = (1 << 4), 10 | BLOCK_FLAG_ENTITY = (1 << 5), 11 | } block_flags; 12 | 13 | typedef uint16_t block_id; 14 | 15 | void blocks_db(void); 16 | int32_t blocks_setup(void); 17 | void blocks_destroy(void); 18 | 19 | block_id blocks_find(asset_id kind); 20 | block_id blocks_find_by_symbol(char symbol); 21 | 22 | asset_id blocks_get_asset(block_id id); 23 | char blocks_get_symbol(block_id id); 24 | uint32_t blocks_get_flags(block_id id); 25 | float blocks_get_drag(block_id id); 26 | float blocks_get_friction(block_id id); 27 | float blocks_get_bounce(block_id id); 28 | float blocks_get_velx(block_id id); 29 | float blocks_get_vely(block_id id); 30 | 31 | // NOTE(zaklaus): viewer-related functions 32 | void *blocks_get_img(block_id id); 33 | 34 | void blocks_build_chunk_tex(uint64_t id, block_id *blocks, void *view); 35 | void *blocks_get_chunk_tex(uint64_t id); 36 | void blocks_remove_chunk_tex(uint64_t id); 37 | -------------------------------------------------------------------------------- /tools/License.txt: -------------------------------------------------------------------------------- 1 | 7-Zip Extra 2 | ~~~~~~~~~~~ 3 | License for use and distribution 4 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 | 6 | Copyright (C) 1999-2019 Igor Pavlov. 7 | 8 | 7-Zip Extra files are under the GNU LGPL license. 9 | 10 | 11 | Notes: 12 | You can use 7-Zip Extra on any computer, including a computer in a commercial 13 | organization. You don't need to register or pay for 7-Zip. 14 | 15 | 16 | GNU LGPL information 17 | -------------------- 18 | 19 | This library is free software; you can redistribute it and/or 20 | modify it under the terms of the GNU Lesser General Public 21 | License as published by the Free Software Foundation; either 22 | version 2.1 of the License, or (at your option) any later version. 23 | 24 | This library is distributed in the hope that it will be useful, 25 | but WITHOUT ANY WARRANTY; without even the implied warranty of 26 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 27 | Lesser General Public License for more details. 28 | 29 | You can receive a copy of the GNU Lesser General Public License from 30 | http://www.gnu.org/ 31 | 32 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_notif.c: -------------------------------------------------------------------------------- 1 | #include "packets/pkt_send_notif.h" 2 | #include "pkt/packet.h" 3 | #include "world/world.h" 4 | #include "core/game.h" 5 | #include "world/entity_view.h" 6 | 7 | #include "models/components.h" 8 | #include "systems/systems.h" 9 | 10 | // client 11 | #include "gui/notifications.h" 12 | 13 | pkt_desc pkt_send_notification_desc[] = { 14 | { PKT_ARRAY(pkt_send_notification, title) }, 15 | { PKT_ARRAY(pkt_send_notification, text) }, 16 | { PKT_END }, 17 | }; 18 | 19 | size_t pkt_notification_send(uint64_t peer_id, uint16_t view_id, const char *title, const char *text) { 20 | pkt_send_notification table = { 0 }; 21 | zpl_strncpy(table.title, title, sizeof(table.title)); 22 | zpl_strncpy(table.text, text, sizeof(table.text)); 23 | return pkt_world_write(MSG_ID_SEND_NOTIFICATION, pkt_table_encode(pkt_send_notification_desc, PKT_STRUCT_PTR(&table)), 1, view_id, (void*)peer_id, 0); 24 | } 25 | 26 | int32_t pkt_send_notification_handler(pkt_header *header) { 27 | pkt_send_notification table; 28 | PKT_IF(pkt_msg_decode(header, pkt_send_notification_desc, pkt_pack_desc_args(pkt_send_notification_desc), PKT_STRUCT_PTR(&table))); 29 | 30 | notification_push(table.title, table.text); 31 | 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /code/foundation/src/dev/debug_draw.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | // NOTE(zaklaus): Debug drawing queue 5 | 6 | typedef enum { 7 | DDRAW_LINE, 8 | DDRAW_CIRCLE, 9 | DDRAW_RECT, 10 | } debug_draw_kind; 11 | 12 | typedef struct { 13 | float x,y; 14 | } debug_v2; 15 | 16 | typedef struct { 17 | debug_draw_kind kind; 18 | int32_t color; 19 | 20 | union { 21 | struct { 22 | debug_v2 a, b; 23 | }; 24 | 25 | struct { 26 | debug_v2 bmin, bmax; 27 | }; 28 | 29 | struct { 30 | debug_v2 pos; 31 | float radius; 32 | }; 33 | }; 34 | } debug_draw_entry; 35 | 36 | #ifndef DEBUG_DRAW_MAX_ENTRIES 37 | #define DEBUG_DRAW_MAX_ENTRIES 65535 38 | #endif 39 | 40 | typedef struct { 41 | size_t num_entries; 42 | debug_draw_entry entries[DEBUG_DRAW_MAX_ENTRIES]; 43 | } debug_draw_queue; 44 | 45 | debug_draw_queue *debug_draw_samples(void); 46 | void debug_draw_flush(void); 47 | void debug_draw_enable(bool state); 48 | bool debug_draw_state(void); 49 | 50 | void debug_push_line(debug_v2 a, debug_v2 b, int32_t color); 51 | void debug_push_circle(debug_v2 pos, float radius, int32_t color); 52 | void debug_push_rect(debug_v2 bmin, debug_v2 bmax, int32_t color); 53 | 54 | -------------------------------------------------------------------------------- /code/foundation/src/systems/modules/system_blueprint.c: -------------------------------------------------------------------------------- 1 | void BuildBlueprints(ecs_iter_t *it) { 2 | Blueprint *blueprint = ecs_field(it, Blueprint, 1); 3 | Device *d = ecs_field(it, Device, 2); 4 | Position *p = ecs_field(it, Position, 3); 5 | 6 | for (int i = 0; i < it->count; i++) { 7 | // TODO check storage and only build if we have enough resources 8 | // build blocks over time and show progress bar while building a block 9 | 10 | int w = (int)blueprint[i].w; 11 | int h = (int)blueprint[i].h; 12 | 13 | for (int y = 0; y < blueprint[i].h; y++) { 14 | for (int x = 0; x < blueprint[i].w; x++) { 15 | asset_id c = blueprint[i].plan[y*w + x]; 16 | if (c == ASSET_EMPTY) continue; 17 | world_block_lookup l = world_block_from_realpos(p[i].x + x * WORLD_BLOCK_SIZE - (w * WORLD_BLOCK_SIZE)/2, p[i].y + y * WORLD_BLOCK_SIZE - (h * WORLD_BLOCK_SIZE)/2); 18 | world_chunk_place_block(l.chunk_id, l.id, blocks_find(c)); 19 | } 20 | } 21 | 22 | entity_despawn(it->entities[i]); 23 | 24 | // d[i].progress_active = (producer[i].processed_item > 0); 25 | // d[i].progress_value = 1.0f-((producer[i].process_time - game_time()) / game_rules.furnace_cook_time); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /code/foundation/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB PKT_SRCS src/packets/*.h src/packets/*.c) 2 | 3 | add_library(eco2d-foundation STATIC 4 | src/core/game.c 5 | src/core/camera.c 6 | src/core/rules_default.c 7 | 8 | src/platform/signal_handling.c 9 | src/platform/profiler.c 10 | src/platform/input.c 11 | 12 | src/models/database.c 13 | src/models/assets.c 14 | src/models/components.c 15 | src/models/items.c 16 | src/models/entity.c 17 | src/models/device.c 18 | src/models/crafting.c 19 | 20 | src/models/prefabs/player.c 21 | src/models/prefabs/vehicle.c 22 | 23 | src/pkt/packet.c 24 | 25 | src/gen/texgen_fallback.c 26 | 27 | src/dev/debug_ui.c 28 | src/dev/debug_draw.c 29 | 30 | src/utils/options.c 31 | src/utils/compress.c 32 | 33 | src/net/network_enet.c 34 | 35 | src/world/blocks.c 36 | src/world/perlin.c 37 | src/world/world.c 38 | src/world/world_view.c 39 | src/world/entity_view.c 40 | src/world/prediction.c 41 | 42 | src/systems/systems.c 43 | 44 | ${PKT_SRCS} 45 | ) 46 | 47 | target_compile_definitions(eco2d-foundation PRIVATE CLIENT) 48 | include_directories(src ../modules ../../art/gen) 49 | target_link_libraries(eco2d-foundation raylib raylib_nuklear cwpack flecs-bundle vendors-bundle) 50 | 51 | link_system_libs(eco2d-foundation) 52 | -------------------------------------------------------------------------------- /code/foundation/src/assets_ids.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define ASSET_INVALID 0xFF 4 | 5 | #define _ASSETS\ 6 | X(ASSET_EMPTY)\ 7 | X(ASSET_BLANK)\ 8 | X(ASSET_BLOCK_FRAME)\ 9 | X(ASSET_BUILDMODE_HIGHLIGHT)\ 10 | X(ASSET_PLAYER)\ 11 | X(ASSET_THING)\ 12 | X(ASSET_CREATURE)\ 13 | X(ASSET_CREATURE_FOOD)\ 14 | X(ASSET_CHEST)\ 15 | X(ASSET_SPLITTER)\ 16 | X(ASSET_ASSEMBLER)\ 17 | X(ASSET_FURNACE)\ 18 | X(ASSET_CRAFTBENCH)\ 19 | X(ASSET_BLUEPRINT_BEGIN)\ 20 | X(ASSET_BLUEPRINT)\ 21 | X(ASSET_BLUEPRINT_DEMO_HOUSE)\ 22 | X(ASSET_BLUEPRINT_END)\ 23 | X(ASSET_FENCE)\ 24 | X(ASSET_DEV)\ 25 | X(ASSET_GROUND)\ 26 | X(ASSET_DIRT)\ 27 | X(ASSET_WATER)\ 28 | X(ASSET_LAVA)\ 29 | X(ASSET_WALL)\ 30 | X(ASSET_HILL)\ 31 | X(ASSET_HILL_SNOW)\ 32 | X(ASSET_HOLE)\ 33 | X(ASSET_WOOD)\ 34 | X(ASSET_TREE)\ 35 | X(ASSET_COAL)\ 36 | X(ASSET_IRON_ORE)\ 37 | X(ASSET_IRON_INGOT)\ 38 | X(ASSET_IRON_PLATES)\ 39 | X(ASSET_SCREWS)\ 40 | X(ASSET_LOG)\ 41 | X(ASSET_PLANK)\ 42 | X(ASSET_TEST_TALL)\ 43 | X(ASSET_BELT)\ 44 | X(ASSET_BELT_LEFT)\ 45 | X(ASSET_BELT_RIGHT)\ 46 | X(ASSET_BELT_UP)\ 47 | X(ASSET_BELT_DOWN) 48 | 49 | typedef enum { 50 | #define X(idx) idx, 51 | _ASSETS 52 | #undef X 53 | MAX_INTERNAL_ASSETS, 54 | NEXT_FREE_ASSET = MAX_INTERNAL_ASSETS, 55 | MAX_ASSETS = 255 56 | } asset_id; 57 | 58 | extern const char *asset_names[]; 59 | -------------------------------------------------------------------------------- /docs/entity_streamer.gvz: -------------------------------------------------------------------------------- 1 | digraph G { 2 | label = "eco2d entity streaming model\n\nThe path from an entity living in a simulation to the rendered image on our screens..."; 3 | subgraph cluster_0 { 4 | color=green; 5 | node [style=filled,shape=box]; 6 | flecs, librg_world_write, cwpack_pack; 7 | label = "host"; 8 | 9 | librg_world_write->cwpack_pack; 10 | } 11 | 12 | subgraph cluster_2 { 13 | color=blue; 14 | node [style=filled,shape=box,label="Packet translation layer"]; 15 | pkt; 16 | 17 | label = "communication"; 18 | labelloc = "b"; 19 | 20 | subgraph cluster_3 { 21 | color = lightgray; 22 | node [style=filled,shape=box,label="in-memory"]; 23 | mem; 24 | node [style=filled,shape=box,label="enet"]; 25 | enet; 26 | 27 | label = "Packet transmission"; 28 | labelloc = "b"; 29 | } 30 | 31 | pkt->mem [style=dotted,dir=none]; 32 | pkt->enet [style=dotted,dir=none]; 33 | } 34 | 35 | subgraph cluster_1 { 36 | node [style=filled,shape=box]; 37 | librg_world_read, cwpack_unpack, raylib; 38 | 39 | label = "viewers"; 40 | color=red; 41 | 42 | cwpack_unpack->librg_world_read; 43 | librg_world_read->raylib; 44 | } 45 | 46 | flecs->librg_world_write; 47 | cwpack_pack->pkt; 48 | pkt->cwpack_unpack; 49 | } 50 | -------------------------------------------------------------------------------- /code/foundation/src/world/world_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "world/entity_view.h" 4 | #include "world/world.h" 5 | 6 | typedef struct { 7 | uint16_t view_id; 8 | uint64_t owner_id; 9 | entity_view_tbl entities; 10 | librg_world *tracker; 11 | 12 | uint32_t seed; 13 | uint32_t size; 14 | uint32_t dim, chk_dim; 15 | uint16_t chunk_size; 16 | uint16_t chunk_amount; 17 | 18 | block_id **block_mapping; 19 | block_id **outer_block_mapping; 20 | entity_view **chunk_mapping; 21 | 22 | // NOTE(zaklaus): metrics 23 | float last_update[WORLD_TRACKER_LAYERS]; 24 | float delta_time[WORLD_TRACKER_LAYERS]; 25 | uint8_t active_layer_id; 26 | } world_view; 27 | 28 | world_view world_view_create(uint16_t view_id); 29 | void world_view_init(world_view *view, uint32_t seed, uint64_t ent_id, uint16_t chunk_size, uint16_t chunk_amount); 30 | void world_view_destroy(world_view *view); 31 | 32 | void world_view_setup_chunk(world_view *view, entity_view *chk); 33 | void world_view_clear_chunk(world_view *view, entity_view *chk); 34 | 35 | typedef struct { 36 | uint16_t id; 37 | block_id bid; 38 | entity_view* chunk_e; 39 | int64_t chunk_id; 40 | float ox, oy; 41 | float aox, aoy; 42 | bool is_outer; 43 | } world_view_block_lookup; 44 | 45 | world_view_block_lookup world_view_block_from_realpos(world_view *view, float x, float y); 46 | -------------------------------------------------------------------------------- /art/queries/eco2d/blocks.sql: -------------------------------------------------------------------------------- 1 | -- typedef enum { 2 | -- BLOCK_FLAG_COLLISION = (1 << 1), 3 | -- BLOCK_FLAG_HAZARD = (1 << 2), 4 | -- BLOCK_FLAG_ESSENTIAL = (1 << 3), 5 | -- BLOCK_FLAG_DESTROY_ON_COLLISION = (1 << 4), 6 | -- BLOCK_FLAG_ENTITY = (1 << 5), 7 | -- } block_flags; 8 | 9 | INSERT INTO blocks (kind, flags, drag, friction, bounce, velx, vely) VALUES 10 | (asset('EMPTY'), NULL, NULL, NULL, NULL, NULL, NULL), 11 | (asset('GROUND'), NULL, 1.0, 1.0, NULL, NULL, NULL), 12 | (asset('DIRT'), NULL, 2.1, 1.0, NULL, NULL, NULL), 13 | (asset('WALL'), (1<<1), 1.0, 1.0, 1.0, NULL, NULL), 14 | (asset('HILL'), (1<<1), 1.0, 1.0, NULL, NULL, NULL), 15 | (asset('HILL_SNOW'), (1<<1), 1.0, 1.0, NULL, NULL, NULL), 16 | (asset('WATER'), 0, 0.11, 1.0, NULL, NULL, NULL), 17 | (asset('LAVA'), (1<<2), 6.2, 4.0, NULL, NULL, NULL), 18 | (asset('FENCE'), (1<<1), 1.0, 1.0, 1.0, NULL, NULL), 19 | (asset('WOOD'), (1<<1), 1.0, 1.0, 0.0, NULL, NULL), 20 | (asset('TREE'), (1<<1)|(1<<4), 1.0, 1.0, 0.0, NULL, NULL), 21 | (asset('CHEST'), (1<<5), NULL, NULL, NULL, NULL, NULL), 22 | (asset('FURNACE'), (1<<5), NULL, NULL, NULL, NULL, NULL), 23 | (asset('TEST_TALL'), (1<<1), NULL, NULL, NULL, NULL, NULL), 24 | (asset('BELT_LEFT'), NULL, 1.0, 1.0, NULL, -150.0, NULL), 25 | (asset('BELT_RIGHT'), NULL, 1.0, 1.0, NULL, 150.0, NULL), 26 | (asset('BELT_UP'), NULL, 1.0, 1.0, NULL, NULL, -150.0), 27 | (asset('BELT_DOWN'), NULL, 1.0, 1.0, NULL, NULL, 150.0); 28 | 29 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_keystate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "pkt/packet_utils.h" 4 | #include "models/item_placement.h" 5 | 6 | typedef struct { 7 | float x; 8 | float y; 9 | float mx; 10 | float my; 11 | uint8_t use; 12 | uint8_t sprint; 13 | uint8_t ctrl; 14 | uint8_t pick; 15 | 16 | // NOTE(zaklaus): inventory 17 | uint8_t storage_action; 18 | uint8_t selected_item; 19 | uint8_t storage_selected_item; 20 | uint8_t drop; 21 | uint8_t swap; 22 | uint8_t swap_storage; 23 | uint8_t swap_from; 24 | uint8_t swap_to; 25 | uint16_t craft_item; 26 | 27 | // TODO(zaklaus): build mode 28 | uint8_t placement_num; 29 | uint8_t deletion_mode; 30 | item_placement placements[BUILD_MAX_PLACEMENTS]; 31 | } pkt_send_keystate; 32 | 33 | typedef struct { 34 | float mx; 35 | float my; 36 | } pkt_send_blockpos; 37 | 38 | typedef pkt_send_keystate game_keystate_data; 39 | 40 | size_t pkt_send_keystate_send(uint16_t view_id, 41 | game_keystate_data *data); 42 | 43 | size_t pkt_send_blockpos_send(uint16_t view_id, 44 | pkt_send_blockpos *data); 45 | 46 | extern pkt_desc pkt_send_keystate_desc[]; 47 | extern pkt_desc pkt_send_blockpos_desc[]; 48 | 49 | PKT_HANDLER_PROC(pkt_send_keystate_handler); 50 | PKT_HANDLER_PROC(pkt_send_blockpos_handler); 51 | 52 | -------------------------------------------------------------------------------- /code/foundation/src/platform/signal_handling.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "zpl.h" 3 | #include "core/game.h" 4 | #ifdef ZPL_SYSTEM_WINDOWS 5 | #include 6 | 7 | static BOOL WINAPI _sighandler_win32_control_handler(DWORD control_type) 8 | { 9 | switch (control_type) 10 | { 11 | case CTRL_C_EVENT: 12 | case DBG_CONTROL_C: 13 | game_request_close(); 14 | return 0; 15 | case CTRL_CLOSE_EVENT: 16 | case CTRL_LOGOFF_EVENT: 17 | case CTRL_BREAK_EVENT: 18 | case CTRL_SHUTDOWN_EVENT: 19 | game_request_close(); 20 | return 1; 21 | } 22 | 23 | return 0; 24 | } 25 | #else //POSIX complaint 26 | #include 27 | static void _sighandler_posix_signal_handler(int sig) { 28 | (void)sig; 29 | game_request_close(); 30 | } 31 | #endif 32 | 33 | void sighandler_register() { 34 | #ifdef ZPL_SYSTEM_WINDOWS 35 | { 36 | if (!SetConsoleCtrlHandler(_sighandler_win32_control_handler, 1)) { 37 | zpl_printf("Could not set up signal handler!\n"); 38 | } 39 | } 40 | #else // POSIX compliant 41 | signal(SIGINT, &_sighandler_posix_signal_handler); 42 | signal(SIGTERM, &_sighandler_posix_signal_handler); 43 | #endif 44 | } 45 | 46 | void sighandler_unregister() { 47 | #ifdef ZPL_SYSTEM_WINDOWS 48 | { 49 | if (!SetConsoleCtrlHandler(_sighandler_win32_control_handler, 0)) { 50 | zpl_printf("Could not uninstall signal handler!"); 51 | } 52 | } 53 | #else // POSIX compliant 54 | #endif 55 | } 56 | -------------------------------------------------------------------------------- /code/games/minimal/src/worldgen.c: -------------------------------------------------------------------------------- 1 | #include "zpl.h" 2 | 3 | #include 4 | #include 5 | 6 | #include "world/world.h" 7 | #include "world/blocks.h" 8 | #include "world/perlin.h" 9 | 10 | #include "models/components.h" 11 | #include "models/entity.h" 12 | #include "models/prefabs/vehicle.h" 13 | #include "models/items.h" 14 | #include "world/blocks_info.h" 15 | 16 | #include "world/worldgen_utils.h" 17 | 18 | int32_t worldgen_build(world_data *wld) { 19 | // TODO(zaklaus): pass world as an arg instead 20 | world = wld; 21 | 22 | // TODO: perform world gen 23 | // atm, we will fill the world with ground and surround it by walls 24 | block_id wall_id = blocks_find(ASSET_WALL); 25 | block_id grnd_id = blocks_find(ASSET_GROUND); 26 | block_id dirt_id = blocks_find(ASSET_DIRT); 27 | block_id watr_id = blocks_find(ASSET_WATER); 28 | block_id lava_id = blocks_find(ASSET_LAVA); 29 | block_id tree_id = blocks_find(ASSET_TREE); 30 | 31 | srand(world->seed); 32 | 33 | // walls 34 | world_fill_rect(world->data, wall_id, 0, 0, world->dim, world->dim, NULL); 35 | 36 | // ground 37 | world_fill_rect(world->data, watr_id, 1, 1, world->dim-2, world->dim-2, NULL); 38 | 39 | int radius = 25; 40 | 41 | // wide boy circle 42 | world_fill_circle(world->data, dirt_id, world->dim / 2, world->dim / 2, radius, NULL); 43 | 44 | // narrow boy cirlce 45 | world_fill_circle(world->data, grnd_id, world->dim / 2, world->dim / 2, (uint32_t)(radius * 0.7f), NULL); 46 | 47 | return WORLD_ERROR_NONE; 48 | } 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause 2 | Copyright (c) 2021 Dominik Madarász, Vladyslav Hrytsenko. All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 3. Neither the name of the copyright holder nor the names of its contributors 13 | may be used to endorse or promote products derived from this software without 14 | specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /code/foundation/src/net/network.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | 4 | int32_t network_init(void); 5 | int32_t network_destroy(void); 6 | 7 | // NOTE(zaklaus): client 8 | int32_t network_client_connect(const char *host, uint16_t port); 9 | int32_t network_client_disconnect(void); 10 | int32_t network_client_tick(void); 11 | void network_client_update(void *data); 12 | bool network_client_is_connected(); 13 | 14 | typedef struct { 15 | // NOTE(zaklaus): persistent stats bytes 16 | uint32_t incoming_total; 17 | uint64_t total_received; 18 | uint32_t outgoing_total; 19 | uint64_t total_sent; 20 | 21 | // NOTE(zaklaus): bandwidth (bytes/sec) 22 | float incoming_bandwidth; 23 | float outgoing_bandwidth; 24 | 25 | // NOTE(zaklaus): packet integrity 26 | uint64_t packets_sent; 27 | uint32_t packets_lost; 28 | float packet_loss; 29 | 30 | // NOTE(zaklaus): ping 31 | uint32_t ping; 32 | uint32_t low_ping; 33 | } network_client_stats; 34 | 35 | network_client_stats 36 | network_client_fetch_stats(void); 37 | 38 | // NOTE(zaklaus): server 39 | int32_t network_server_start(const char *host, uint16_t port); 40 | int32_t network_server_stop(void); 41 | int32_t network_server_tick(void); 42 | void network_server_despawn_viewers(void *peer_id); 43 | uint64_t network_server_get_entity(void *peer_id, uint16_t view_id); 44 | 45 | // NOTE(zaklaus): messaging 46 | int32_t network_msg_send(void *peer_id, void *data, size_t datalen, uint16_t channel_id); 47 | int32_t network_msg_send_unreliable(void *peer_id, void *data, size_t datalen, uint16_t channel_id); 48 | -------------------------------------------------------------------------------- /project.4coder: -------------------------------------------------------------------------------- 1 | version(1); 2 | 3 | project_name = "eco2d"; 4 | 5 | patterns = 6 | { 7 | "*.c", 8 | "*.cpp", 9 | "*.jai", 10 | "*.odin", 11 | "*.zig", 12 | "*.h", 13 | "*.inc", 14 | "*.bat", 15 | "*.sh", 16 | "*.4coder", 17 | "*.txt", 18 | "*.cmake", 19 | "*.md", 20 | "*.lst", 21 | }; 22 | 23 | blacklist_patterns = 24 | { 25 | ".*", 26 | }; 27 | 28 | load_paths = 29 | { 30 | {{ 31 | { ".", .recursive = false, .relative = true }, 32 | { "code/games", .recursive = true, .relative = true }, 33 | { "code/foundation", .recursive = true, .relative = true }, 34 | { "code/vendors", .recursive = true, .relative = true }, 35 | { "cmake", .recursive = true, .relative = true }, 36 | { "build/_deps/raylib-src/src", .recursive = true, .relative = true } 37 | }, .os = "win"} 38 | }; 39 | 40 | command_list = 41 | { 42 | 43 | { 44 | .name = "build", 45 | .out = "*compilation*", 46 | .footer_panel = true, 47 | .save_dirty_files = true, 48 | .cursor_at_end = false, 49 | .cmd = 50 | { 51 | { "cmake --build build", .os = "win" }, 52 | }, 53 | }, 54 | 55 | { 56 | .name = "run", 57 | .out = "*console*", 58 | .footer_panel = false, 59 | .save_dirty_files = true, 60 | .cursor_at_end = true, 61 | .cmd = 62 | { 63 | { "run.bat", .os = "win" }, 64 | }, 65 | }, 66 | 67 | }; 68 | 69 | fkey_command[1] = "build"; 70 | fkey_command[2] = "run"; 71 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/examples/raylib-nuklear-texture.c: -------------------------------------------------------------------------------- 1 | /* =============================================================== 2 | * 3 | * EXAMPLE 4 | * 5 | * ===============================================================*/ 6 | /* 7 | This example shows how to use the image API from raylib nuklear. 8 | And then display it. 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define RAYLIB_NUKLEAR_IMPLEMENTATION 16 | #include "raylib-nuklear.h" 17 | 18 | int main() 19 | { 20 | InitWindow(1280, 720, "[raylib-nuklear] - Texture/Image"); 21 | 22 | // Initialize the context 23 | struct nk_context* ctx = InitNuklear(20); 24 | 25 | // Scale up the Nuklear GUI 26 | SetNuklearScaling(ctx, 1.2f); 27 | 28 | // Load the nk_image 29 | struct nk_image img = LoadNuklearImage("resources/test-image.png"); 30 | 31 | while (!WindowShouldClose()) 32 | { 33 | // Input 34 | UpdateNuklear(ctx); 35 | 36 | // The window called "Image example" is opend 37 | if(nk_begin(ctx, "Image example", nk_rect(300, 100, img.w, img.h + 50), NK_WINDOW_MINIMIZABLE|NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) 38 | { 39 | // Setup the layout 40 | nk_layout_row_static(ctx, img.h, img.w, 1); 41 | 42 | // Draw the image 43 | nk_image(ctx, img); 44 | } 45 | nk_end(ctx); 46 | 47 | // Draw the GUI 48 | BeginDrawing(); 49 | ClearBackground(RAYWHITE); 50 | DrawNuklear(ctx); 51 | EndDrawing(); 52 | } 53 | 54 | // Unload the Nuklear image 55 | UnloadNuklearImage(img); 56 | 57 | CloseWindow(); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_00_init.c: -------------------------------------------------------------------------------- 1 | #include "packets/pkt_00_init.h" 2 | #include "packets/pkt_01_welcome.h" 3 | #include "pkt/packet.h" 4 | #include "world/world.h" 5 | #include "core/game.h" 6 | #include "net/network.h" 7 | #include "world/entity_view.h" 8 | #include "core/camera.h" 9 | #include "models/prefabs/player.h" 10 | #include "models/entity.h" 11 | 12 | #include "models/components.h" 13 | #include "systems/systems.h" 14 | 15 | pkt_desc pkt_00_init_desc[] = { 16 | { PKT_FIELD(CWP_ITEM_POSITIVE_INTEGER, pkt_00_init, view_id) }, 17 | { PKT_END }, 18 | }; 19 | 20 | size_t pkt_00_init_send(uint16_t view_id) { 21 | pkt_00_init table = {.view_id = view_id }; 22 | return pkt_world_write(MSG_ID_00_INIT, pkt_table_encode(pkt_00_init_desc, PKT_STRUCT_PTR(&table)), 1, view_id, NULL, 1); 23 | } 24 | 25 | int32_t pkt_00_init_handler(pkt_header *header) { 26 | pkt_00_init table; 27 | PKT_IF(pkt_msg_decode(header, pkt_00_init_desc, pkt_pack_desc_args(pkt_00_init_desc), PKT_STRUCT_PTR(&table))); 28 | 29 | uint64_t peer_id = (uint64_t)header->udata; 30 | uint64_t ent_id = player_spawn(NULL); 31 | 32 | entity_set_position(ent_id, world_dim()/2.0f + rand()%15*15.0f, world_dim()/2.0f + rand()%15*15.0f); 33 | 34 | game_player_joined(ent_id); 35 | 36 | zpl_printf("[INFO] initializing player entity id: %d with view id: %d for peer id: %d...\n", ent_id, table.view_id, peer_id); 37 | ecs_set(world_ecs(), ent_id, ClientInfo, {.peer = peer_id, .view_id = header->view_id, .active = false }); 38 | pkt_01_welcome_send(world_seed(), peer_id, header->view_id, ent_id, world_chunk_size(), world_chunk_amount()); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /code/foundation/src/core/camera.c: -------------------------------------------------------------------------------- 1 | #include "zpl.h" 2 | #include "core/camera.h" 3 | #include "platform/platform.h" 4 | #include "world/entity_view.h" 5 | #include "core/game.h" 6 | 7 | #define CAMERA_LERP_FACTOR 11.2f 8 | 9 | static camera main_camera; 10 | 11 | void camera_reset(void) { 12 | zpl_zero_item(&main_camera); 13 | main_camera.mode = CAMERA_MODE_STATIONARY; 14 | main_camera.first_time = true; 15 | } 16 | 17 | void camera_update(void) { 18 | switch (main_camera.mode) { 19 | case CAMERA_MODE_FOLLOW: { 20 | world_view *world = game_world_view_get_active(); 21 | if (!world) break; 22 | entity_view *view = entity_view_get(&world->entities, main_camera.ent_id); 23 | if (!view) break; 24 | float smooth_ms = zpl_clamp((float)platform_frametime(), 0.0f, 1.0f); 25 | 26 | main_camera.x = zpl_lerp((float)main_camera.x, view->x, CAMERA_LERP_FACTOR*smooth_ms); 27 | main_camera.y = zpl_lerp((float)main_camera.y, view->y, CAMERA_LERP_FACTOR*smooth_ms); 28 | 29 | if (main_camera.first_time) { 30 | main_camera.first_time = false; 31 | main_camera.x = view->x; 32 | main_camera.y = view->y; 33 | } 34 | }break; 35 | 36 | default: { 37 | 38 | }break; 39 | } 40 | } 41 | void camera_set_follow(uint64_t ent_id) { 42 | main_camera.mode = CAMERA_MODE_FOLLOW; 43 | main_camera.ent_id = ent_id; 44 | } 45 | void camera_set_pos(double x, double y) { 46 | main_camera.mode = CAMERA_MODE_STATIONARY; 47 | main_camera.x = x; 48 | main_camera.y = y; 49 | } 50 | camera camera_get(void) { 51 | return main_camera; 52 | } 53 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_switch_viewer.c: -------------------------------------------------------------------------------- 1 | #include "packets/pkt_switch_viewer.h" 2 | #include "pkt/packet.h" 3 | #include "world/world.h" 4 | #include "core/game.h" 5 | #include "net/network.h" 6 | #include "world/entity_view.h" 7 | #include "core/camera.h" 8 | #include "models/prefabs/player.h" 9 | 10 | #include "models/components.h" 11 | #include "systems/systems.h" 12 | 13 | pkt_desc pkt_switch_viewer_desc[] = { 14 | { PKT_FIELD(CWP_ITEM_POSITIVE_INTEGER, pkt_switch_viewer, view_id) }, 15 | { PKT_END }, 16 | }; 17 | 18 | size_t pkt_switch_viewer_send(uint16_t view_id) { 19 | pkt_switch_viewer table = {.view_id = view_id }; 20 | return pkt_world_write(MSG_ID_SWITCH_VIEWER, pkt_table_encode(pkt_switch_viewer_desc, PKT_STRUCT_PTR(&table)), 1, view_id, NULL, 1); 21 | } 22 | 23 | int32_t pkt_switch_viewer_handler(pkt_header *header) { 24 | pkt_switch_viewer table; 25 | PKT_IF(pkt_msg_decode(header, pkt_switch_viewer_desc, pkt_pack_desc_args(pkt_switch_viewer_desc), PKT_STRUCT_PTR(&table))); 26 | 27 | ecs_entity_t e = network_server_get_entity(header->udata, header->view_id); 28 | uint64_t peer_id = (uint64_t)header->udata; 29 | 30 | if (!world_entity_valid(e)) 31 | return 1; 32 | 33 | ecs_iter_t it = ecs_query_iter(world_ecs(), world_ecs_clientinfo()); 34 | 35 | while (ecs_query_next(&it)) { 36 | ClientInfo *p = ecs_field(&it, ClientInfo, 1); 37 | 38 | for (int i = 0; i < it.count; i++) { 39 | if (p[i].peer == (uintptr_t)peer_id && p[i].view_id == table.view_id) { 40 | p[i].active = true; 41 | } else if (p[i].peer == (uintptr_t)peer_id) { 42 | p[i].active = false; 43 | } 44 | } 45 | } 46 | 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_01_welcome.c: -------------------------------------------------------------------------------- 1 | #include "packets/pkt_01_welcome.h" 2 | #include "pkt/packet.h" 3 | #include "world/world.h" 4 | #include "core/game.h" 5 | #include "world/entity_view.h" 6 | #include "core/camera.h" 7 | 8 | pkt_desc pkt_01_welcome_desc[] = { 9 | { PKT_FIELD(CWP_ITEM_POSITIVE_INTEGER, pkt_01_welcome, seed) }, 10 | { PKT_FIELD(CWP_ITEM_POSITIVE_INTEGER, pkt_01_welcome, ent_id) }, 11 | { PKT_FIELD(CWP_ITEM_POSITIVE_INTEGER, pkt_01_welcome, chunk_size) }, 12 | { PKT_FIELD(CWP_ITEM_POSITIVE_INTEGER, pkt_01_welcome, world_size) }, 13 | { PKT_END }, 14 | }; 15 | 16 | size_t pkt_01_welcome_send(uint32_t seed, 17 | uint64_t peer_id, 18 | uint16_t view_id, 19 | uint64_t ent_id, 20 | uint16_t chunk_size, 21 | uint16_t world_size) { 22 | pkt_01_welcome table = {.seed = seed, .ent_id = ent_id, .chunk_size = chunk_size, .world_size = world_size}; 23 | return pkt_world_write(MSG_ID_01_WELCOME, pkt_table_encode(pkt_01_welcome_desc, PKT_STRUCT_PTR(&table)), 1, view_id, (void*)peer_id, 0); 24 | } 25 | 26 | int32_t pkt_01_welcome_handler(pkt_header *header) { 27 | pkt_01_welcome table; 28 | PKT_IF(pkt_msg_decode(header, pkt_01_welcome_desc, pkt_pack_desc_args(pkt_01_welcome_desc), PKT_STRUCT_PTR(&table))); 29 | 30 | world_view *view = game_world_view_get(header->view_id); 31 | 32 | 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); 33 | world_view_init(view, table.seed, table.ent_id, table.chunk_size, table.world_size); 34 | game_world_view_set_active(view); 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /code/foundation/src/models/crafting.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "models/assets.h" 4 | 5 | #include "models/components.h" 6 | 7 | typedef struct { 8 | asset_id id; 9 | uint32_t qty; 10 | } reagent; 11 | 12 | typedef struct { 13 | asset_id product; 14 | uint32_t product_qty; 15 | int32_t process_ticks; 16 | asset_id producer; 17 | reagent *reagents; 18 | } recipe; 19 | 20 | void craft_db(void); 21 | 22 | // NOTE(zaklaus): resolves recipe dependencies and consumes reagents 23 | // to enqueue a production of a new item. 24 | // TODO(zaklaus): "items" is assumed to come from ItemContainer component. 25 | asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id target, uint32_t *quantity, int32_t *process_ticks); 26 | 27 | // NOTE(zaklaus): mostly used by item router so we don't push reagents out 28 | bool craft_is_reagent_used_in_producer(asset_id reagent, asset_id producer); 29 | 30 | // used to filter out craftables 31 | bool craft_is_item_produced_by_producer(asset_id item, asset_id producer); 32 | 33 | // used to filter out reagents 34 | bool craft_is_item_produced_by_reagent(asset_id item, asset_id reagent); 35 | 36 | // NOTE(zaklaus): utilities 37 | uint16_t craft_get_num_recipes(void); 38 | asset_id craft_get_recipe_asset(uint16_t id); 39 | uint16_t craft_get_recipe_id_from_product(asset_id id); 40 | recipe craft_get_recipe_data(uint16_t i); 41 | 42 | //~TODO(zaklaus): not implemented and might get removed 43 | 44 | // NOTE(zaklaus): informs us on whether this product has any byproducts desired. 45 | asset_id craft_has_byproducts(asset_id product); 46 | 47 | // NOTE(zaklaus): resolves the production chain and analyses the amount of items required 48 | // and a number of hops (production layers) needed to produce the item. 49 | // optionally, it allows to calculate "direct_cost" of the product. 50 | uint32_t craft_resolve_graph(asset_id product, uint16_t *hops, uint8_t direct_cost); 51 | -------------------------------------------------------------------------------- /win/setup_cl_generic.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | where /q cl 4 | IF %ERRORLEVEL% == 0 (EXIT /b) 5 | 6 | SET "LIB=" 7 | 8 | 9 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 14.0 10 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" %1)) 11 | 12 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 13.0 13 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" %1)) 14 | 15 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 12.0 16 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" %1)) 17 | 18 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 11.0 19 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" %1)) 20 | 21 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0 22 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\vcvarsall.bat" %1)) 23 | 24 | SET VC_PATH=C:\Program Files\Microsoft Visual Studio\2022\Community 25 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) 26 | 27 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Community 28 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) 29 | 30 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise 31 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\Common7\Tools\VsDevCmd.bat")) 32 | 33 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise 34 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) 35 | 36 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\Community 37 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) 38 | 39 | SET VC_PATH=C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools 40 | IF NOT DEFINED LIB (IF EXIST "%VC_PATH%" (call "%VC_PATH%\VC\Auxiliary\Build\vcvarsall.bat" %1)) 41 | -------------------------------------------------------------------------------- /art/queries/eco2d/tables.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE assets ( 2 | id INTEGER PRIMARY KEY AUTOINCREMENT, 3 | name VARCHAR(255) NOT NULL 4 | ); 5 | 6 | CREATE TABLE resources ( 7 | id INTEGER PRIMARY KEY AUTOINCREMENT, 8 | asset INTEGER NOT NULL, 9 | kind INTEGER NOT NULL 10 | ); 11 | 12 | CREATE TABLE blocks ( 13 | id INTEGER PRIMARY KEY AUTOINCREMENT, 14 | kind INTEGER NOT NULL, 15 | flags INTEGER DEFAULT 0, 16 | drag REAL, 17 | friction REAL, 18 | bounce REAL, 19 | velx REAL, 20 | vely REAL, 21 | FOREIGN KEY (kind) REFERENCES assets(id) 22 | ); 23 | 24 | CREATE TABLE items ( 25 | id INTEGER PRIMARY KEY AUTOINCREMENT, 26 | kind INTEGER NOT NULL, 27 | usage INTEGER, 28 | attachment INTEGER, 29 | max_quantity INTEGER, 30 | has_storage BOOLEAN, 31 | 32 | place_kind INTEGER, 33 | directional BOOLEAN, 34 | 35 | proxy_id INTEGER, 36 | 37 | place_item_id INTEGER, 38 | 39 | producer INTEGER, 40 | energy_level REAL, 41 | 42 | blueprint_w INTEGER, 43 | blueprint_h INTEGER, 44 | blueprint_plan TEXT, 45 | 46 | FOREIGN KEY (kind) REFERENCES assets(id) 47 | ); 48 | 49 | CREATE TABLE reagents ( 50 | id INTEGER PRIMARY KEY AUTOINCREMENT, 51 | asset_id INTEGER NOT NULL, 52 | qty INTEGER NOT NULL, 53 | FOREIGN KEY (asset_id) REFERENCES assets(id) 54 | ); 55 | 56 | CREATE TABLE recipes ( 57 | id INTEGER PRIMARY KEY AUTOINCREMENT, 58 | product INTEGER NOT NULL, 59 | product_qty INTEGER NOT NULL, 60 | process_ticks INTEGER NOT NULL, 61 | producer INTEGER NOT NULL, 62 | FOREIGN KEY (product) REFERENCES assets(id), 63 | FOREIGN KEY (producer) REFERENCES assets(id) 64 | ); 65 | 66 | CREATE TABLE recipe_reagents ( 67 | id INTEGER PRIMARY KEY AUTOINCREMENT, 68 | recipe_id INTEGER NOT NULL, 69 | reagent_id INTEGER NOT NULL, 70 | FOREIGN KEY (recipe_id) REFERENCES recipes(id), 71 | FOREIGN KEY (reagent_id) REFERENCES reagents(id) 72 | ); 73 | -------------------------------------------------------------------------------- /code/foundation/src/dev/debug_draw.c: -------------------------------------------------------------------------------- 1 | #include "dev/debug_draw.h" 2 | #include "core/game.h" 3 | 4 | static debug_draw_queue draw_queue = {0}; 5 | 6 | #if !defined(_DEBUG) || 0 7 | static bool draw_is_enabled = false; 8 | #else 9 | static bool draw_is_enabled = true; 10 | #endif 11 | 12 | debug_draw_queue *debug_draw_samples(void) { 13 | return &draw_queue; 14 | } 15 | 16 | void debug_draw_flush(void) { 17 | draw_queue.num_entries = 0; 18 | } 19 | 20 | void debug_draw_enable(bool state) { 21 | draw_is_enabled = state; 22 | } 23 | 24 | bool debug_draw_state(void) { 25 | return draw_is_enabled; 26 | } 27 | 28 | static inline void debug_push_entry(debug_draw_entry entry) { 29 | if (!draw_is_enabled) return; 30 | if (game_get_kind() == GAMEKIND_HEADLESS) return; 31 | ZPL_ASSERT(draw_queue.num_entries < DEBUG_DRAW_MAX_ENTRIES); 32 | draw_queue.entries[draw_queue.num_entries++] = entry; 33 | } 34 | 35 | void debug_push_line(debug_v2 a, debug_v2 b, int32_t color) { 36 | debug_push_entry((debug_draw_entry){ 37 | .kind = DDRAW_LINE, 38 | .color = color, 39 | 40 | .a = a, 41 | .b = b, 42 | }); 43 | } 44 | 45 | void debug_push_circle(debug_v2 pos, float radius, int32_t color) { 46 | debug_push_entry((debug_draw_entry){ 47 | .kind = DDRAW_CIRCLE, 48 | .color = color, 49 | 50 | .pos = pos, 51 | .radius = radius, 52 | }); 53 | } 54 | 55 | void debug_push_rect(debug_v2 bmin, debug_v2 bmax, int32_t color) { 56 | debug_push_entry((debug_draw_entry){ 57 | .kind = DDRAW_RECT, 58 | .color = color, 59 | 60 | .bmin = bmin, 61 | .bmax = bmax, 62 | }); 63 | } 64 | -------------------------------------------------------------------------------- /code/foundation/src/core/game.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "world/world_view.h" 4 | #include "packets/pkt_send_keystate.h" 5 | #include "packets/pkt_send_code.h" 6 | 7 | typedef enum { 8 | GAMEKIND_SINGLE, 9 | GAMEKIND_CLIENT, 10 | GAMEKIND_HEADLESS, 11 | FORCE_GAMEKIND_UINT8 = UINT8_MAX 12 | } game_kind; 13 | 14 | void game_setup(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); 15 | void game_shutdown(); 16 | void game_request_close(); 17 | uint8_t game_is_running(); 18 | int8_t game_is_networked(); 19 | float game_time(); 20 | game_kind game_get_kind(void); 21 | 22 | //~ NOTE(zaklaus): game events 23 | // Implemented by games 24 | void game_init(bool new_db); 25 | void game_init_ecs(); // called once the world is initialised 26 | void game_input(); 27 | void game_update(); 28 | void game_render(); 29 | void game_player_joined(uint64_t ent); 30 | void game_player_departed(uint64_t ent); 31 | void game_player_died(uint64_t ent); 32 | void game_client_receive_code(pkt_send_code data); 33 | 34 | // base methods called from games 35 | void game_core_input(); 36 | void game_core_update(); 37 | void game_core_render(); 38 | 39 | //~ Called from platform.c 40 | void game_draw_ui(); 41 | 42 | //~ NOTE(zaklaus): world view management 43 | world_view *game_world_view_get_active(void); 44 | world_view *game_world_view_get(uint16_t idx); 45 | size_t game_world_view_count(void); 46 | void game_world_view_set_active_by_idx(uint16_t idx); 47 | void game_world_view_set_active(world_view *view); 48 | void game_world_view_cycle_active(int8_t dir); 49 | void game_world_view_active_entity_map(void (*map_proc)(uint64_t key, entity_view * value)); 50 | entity_view *game_world_view_active_get_entity(uint64_t ent_id); 51 | void game_world_view_render_world(void); 52 | 53 | //~ NOTE(zaklaus): viewer -> host actions 54 | void game_action_send_keystate(game_keystate_data *data); 55 | void game_action_send_blockpos(float mx, float my); 56 | -------------------------------------------------------------------------------- /code/foundation/src/models/prefabs/vehicle.c: -------------------------------------------------------------------------------- 1 | #include "vehicle.h" 2 | 3 | #include "world/entity_view.h" 4 | #include "world/world.h" 5 | 6 | #include "models/entity.h" 7 | #include "models/components.h" 8 | 9 | 10 | uint64_t vehicle_spawn(uint8_t veh_kind) { 11 | ecs_entity_t e = entity_spawn(EKIND_VEHICLE); 12 | 13 | Vehicle *veh = ecs_get_mut(world_ecs(), e, Vehicle); 14 | *veh = (Vehicle){ 15 | .wheel_base = 50.0f, 16 | .speed = 50.0f, 17 | .reverse_speed = -20.0f, 18 | .force = 0.0f, 19 | .veh_kind = veh_kind, 20 | }; 21 | 22 | switch (veh_kind) { 23 | case EVEH_CAR: { 24 | veh->wheel_base = 50.0f; 25 | veh->speed = 50.0f; 26 | veh->reverse_speed = -20.0f; 27 | veh->force = 0.0f; 28 | } break; 29 | case EVEH_TRUCK: { 30 | veh->wheel_base = 100.0f; 31 | veh->speed = 30.0f; 32 | veh->reverse_speed = -10.0f; 33 | veh->force = 0.0f; 34 | 35 | ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer); 36 | *storage = (ItemContainer){0}; 37 | 38 | Device *dev = ecs_get_mut(world_ecs(), e, Device); 39 | dev->asset = ASSET_FURNACE; 40 | } break; 41 | case EVEH_FURNACEMOBILE: { 42 | veh->wheel_base = 100.0f; 43 | veh->speed = 30.0f; 44 | veh->reverse_speed = -10.0f; 45 | veh->force = 0.0f; 46 | 47 | ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer); 48 | *storage = (ItemContainer){0}; 49 | 50 | Device *dev = ecs_get_mut(world_ecs(), e, Device); 51 | dev->asset = ASSET_FURNACE; 52 | 53 | Producer *producer = ecs_get_mut(world_ecs(), e, Producer); 54 | *producer = (Producer){0}; 55 | producer->energy_level = 69.0f; 56 | } break; 57 | } 58 | 59 | ecs_add(world_ecs(), e, BlockHarvest); 60 | return (uint64_t)e; 61 | } 62 | 63 | void vehicle_despawn(uint64_t ent_id) { 64 | entity_despawn(ent_id); 65 | } 66 | -------------------------------------------------------------------------------- /code/foundation/src/systems/modules/system_health.c: -------------------------------------------------------------------------------- 1 | #define HAZARD_BLOCK_DMG 5.0f 2 | 3 | void HurtOnHazardBlock(ecs_iter_t *it) { 4 | Position *p = ecs_field(it, Position, 1); 5 | Health *h = ecs_field(it, Health, 2); 6 | 7 | for (int i = 0; i < it->count; i++) { 8 | world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y); 9 | if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) { 10 | h[i].dmg += HAZARD_BLOCK_DMG; 11 | } 12 | } 13 | } 14 | 15 | //#define HP_REGEN_PAIN_COOLDOWN 5.0f 16 | 17 | void RegenerateHP(ecs_iter_t *it) { 18 | Health *h = ecs_field(it, Health, 1); 19 | HealthRegen *r = ecs_field(it, HealthRegen, 2); 20 | 21 | for (int i = 0; i < it->count; i++) { 22 | // TODO delay regen on hurt 23 | if (h[i].hp < h[i].max_hp) { 24 | h[i].hp += r->amt; 25 | h[i].hp = zpl_min(h[i].max_hp, h[i].hp); 26 | entity_wake(it->entities[i]); 27 | } 28 | } 29 | } 30 | 31 | void ProcessHealthDamage(ecs_iter_t *it) { 32 | for (int i = 0; i < it->count; i++) { 33 | Health *hp = ecs_get_mut(it->world, it->entities[i], Health); 34 | if (hp->dmg > 0.0f) { 35 | hp->hp = zpl_max(hp->hp-hp->dmg, 0.0f); 36 | hp->dmg = 0.0f; 37 | ecs_set(it->world, it->entities[i], HealDelay, { .delay = 10 }); 38 | 39 | if (hp->hp <= 0.0f) { 40 | ecs_add(it->world, it->entities[i], Dead); 41 | } 42 | } 43 | } 44 | } 45 | 46 | void OnDead(ecs_iter_t *it) { 47 | for (int i = 0; i < it->count; i++) { 48 | const ClientInfo *ci = ecs_get(it->world, it->entities[i], ClientInfo); 49 | Input *pi = ecs_get_mut_if(it->world, it->entities[i], Input); 50 | 51 | if (ci) { 52 | pkt_notification_send(0, 0, "Someone died!", zpl_bprintf("Player %d has died!", it->entities[i])); 53 | game_player_died(it->entities[i]); 54 | } 55 | 56 | if (pi) { 57 | *pi = (Input) { 0 }; 58 | pi->is_blocked = 1; 59 | } 60 | } 61 | } 62 | 63 | void TickDownHealDelay(ecs_iter_t *it) { 64 | HealDelay *h = ecs_field(it, HealDelay, 1); 65 | 66 | for (int i = 0; i < it->count; i++) { 67 | TICK_VAR(h[i].delay); 68 | 69 | if (h[i].delay == 0) { 70 | ecs_remove(it->world, it->entities[i], HealDelay); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /code/foundation/src/models/items.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "models/assets.h" 4 | #include "world/blocks.h" 5 | 6 | #include "models/components.h" 7 | 8 | typedef enum { 9 | // NOTE(zaklaus): hardcoded fields for placement ops 10 | UKIND_DELETE, 11 | UKIND_PLACE, 12 | UKIND_PLACE_ITEM, 13 | UKIND_PLACE_ITEM_DATA, 14 | UKIND_END_PLACE, 15 | 16 | // NOTE(zaklaus): the rest of possible actions 17 | UKIND_HOLD, 18 | UKIND_PROXY, 19 | } item_usage; 20 | 21 | typedef enum { 22 | UDATA_NONE, 23 | UDATA_ENERGY_SOURCE, 24 | } item_attachment; 25 | 26 | typedef struct { 27 | asset_id kind; 28 | item_usage usage; 29 | item_attachment attachment; 30 | uint32_t max_quantity; 31 | uint8_t has_storage; 32 | 33 | // NOTE(zaklaus): usage data 34 | union { 35 | struct { 36 | asset_id kind; 37 | bool directional; // NOTE(zaklaus): expects next 4 asset entries to be direction assets 38 | } place; 39 | 40 | struct { 41 | asset_id id; 42 | } proxy; 43 | 44 | struct { 45 | asset_id id; 46 | } place_item; 47 | }; 48 | 49 | union { 50 | struct { 51 | asset_id producer; 52 | float energy_level; 53 | } energy_source; 54 | }; 55 | 56 | // NOTE: item data 57 | union { 58 | struct { 59 | uint8_t w; 60 | uint8_t h; 61 | const asset_id *plan; 62 | } blueprint; 63 | }; 64 | } item_desc; 65 | 66 | typedef uint16_t item_id; 67 | 68 | void item_db(void); 69 | 70 | // NOTE(zaklaus): item drops 71 | void item_show(uint64_t ent, bool show); 72 | 73 | uint64_t item_spawn(asset_id kind, uint32_t qty); 74 | void item_despawn(uint64_t id); 75 | 76 | // NOTE(zaklaus): items 77 | item_id item_find(asset_id kind); 78 | item_id item_find_no_proxy(asset_id kind); 79 | void item_use(ecs_world_t *ecs, ecs_entity_t e, Item *it, Position p, uint64_t udata); 80 | Item *item_get_data(uint64_t ent); 81 | const Item *item_get_data_const(uint64_t ent); 82 | 83 | uint32_t item_max_quantity(item_id id); 84 | item_usage item_get_usage(item_id id); 85 | bool item_get_place_directional(item_id id); 86 | item_desc item_get_desc(item_id id); 87 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_librg_update.c: -------------------------------------------------------------------------------- 1 | #include "zpl.h" 2 | #include "pkt/packet_utils.h" 3 | #include "packets/pkt_send_librg_update.h" 4 | #include "world/world.h" 5 | #include "core/game.h" 6 | 7 | size_t pkt_send_librg_update(uint64_t peer_id, 8 | uint16_t view_id, 9 | uint8_t ticker, 10 | void *data, 11 | size_t datalen) { 12 | return pkt_world_write(MSG_ID_LIBRG_UPDATE, pkt_send_librg_update_encode(data, (int32_t)datalen, ticker), 1, view_id, (void*)peer_id, 0); 13 | } 14 | 15 | size_t pkt_send_librg_update_encode(void *data, int32_t data_length, uint8_t layer_id) { 16 | cw_pack_context pc = {0}; 17 | pkt_pack_msg(&pc, 2); 18 | cw_pack_unsigned(&pc, layer_id); 19 | cw_pack_bin(&pc, data, data_length); 20 | return pkt_pack_msg_size(&pc); 21 | } 22 | 23 | #define NUM_SAMPLES 128 24 | 25 | static float smooth_time(float time) { 26 | static float time_samples[NUM_SAMPLES] = {0}; 27 | static int32_t curr_index = 0; 28 | 29 | time_samples[curr_index] = time; 30 | if (++curr_index == NUM_SAMPLES) 31 | curr_index = 0; 32 | 33 | float average = 0; 34 | for (int32_t i = NUM_SAMPLES; i--; ) 35 | average += time_samples[i]; 36 | average /= NUM_SAMPLES; 37 | 38 | time = zpl_min(time, average * 2); 39 | return time; 40 | } 41 | 42 | #undef NUM_SAMPLES 43 | 44 | int32_t pkt_send_librg_update_handler(pkt_header *header) { 45 | cw_unpack_context uc = {0}; 46 | pkt_unpack_msg(&uc, header, 2); 47 | cw_unpack_next(&uc); 48 | 49 | if (uc.item.type != CWP_ITEM_POSITIVE_INTEGER) 50 | return -1; 51 | 52 | uint8_t layer_id = (uint8_t)uc.item.as.u64; 53 | 54 | cw_unpack_next(&uc); 55 | 56 | if (uc.item.type != CWP_ITEM_BIN) 57 | return -1; 58 | 59 | world_view *view = game_world_view_get(header->view_id); 60 | view->active_layer_id = layer_id; 61 | 62 | int32_t state = librg_world_read(view->tracker, header->view_id, uc.item.as.bin.start, uc.item.as.bin.length, NULL); 63 | if (state < 0) zpl_printf("[ERROR] world read error: %d\n", state); 64 | 65 | float now = (float)get_cached_time(); 66 | view->delta_time[layer_id] = smooth_time(now - view->last_update[layer_id]); 67 | view->last_update[layer_id] = now; 68 | 69 | return state; 70 | } 71 | -------------------------------------------------------------------------------- /code/foundation/src/platform/profiler.c: -------------------------------------------------------------------------------- 1 | #include "platform/profiler.h" 2 | #include "raylib.h" 3 | #include 4 | 5 | #define PROF_COLLATE_WINDOW 0.5 6 | 7 | static float profiler_warmup = 3.0f; 8 | 9 | // NOTE(zaklaus): KEEP ORDER IN SYNC WITH profiler_kind ENUM !!! 10 | static profiler profilers[] = { 11 | { .id = PROF_TOTAL_TIME, .name = "measured time" }, 12 | { .id = PROF_MAIN_LOOP, .name = "main loop" }, 13 | { .id = PROF_WORLD_WRITE, .name = "world write" }, 14 | { .id = PROF_RENDER, .name = "render" }, 15 | { .id = PROF_UPDATE_SYSTEMS, .name = "update systems" }, 16 | { .id = PROF_ENTITY_LERP, .name = "entity lerp" }, 17 | { .id = PROF_INTEGRATE_POS, .name = "entity movement" }, 18 | { .id = PROF_PHYS_BLOCK_COLS, .name = "block collisions" }, 19 | { .id = PROF_PHYS_BODY_COLS, .name = "body collisions" }, 20 | { .id = PROF_RENDER_PUSH_AND_SORT_ENTRIES, .name = "push&sort entries" }, 21 | }; 22 | 23 | static_assert((sizeof(profilers)/sizeof(profilers[0])) == MAX_PROF, "mismatched profilers"); 24 | 25 | void profiler_reset(profiler_kind id) { 26 | profilers[id].num_invocations = 0; 27 | profilers[id].total_time = 0.0; 28 | } 29 | 30 | void profiler_start(profiler_kind id) { 31 | profilers[id].start_time = GetTime(); 32 | } 33 | 34 | void profiler_stop(profiler_kind id) { 35 | profilers[id].num_invocations += 1; 36 | profilers[id].total_time += GetTime() - profilers[id].start_time; 37 | profilers[id].start_time = 0.0; 38 | } 39 | 40 | void profiler_collate() { 41 | if (profiler_warmup > 0) { 42 | profiler_warmup -= GetFrameTime(); 43 | for (uint32_t i = PROF_MAIN_LOOP; i < MAX_PROF; i += 1) { 44 | profiler_reset(i); 45 | } 46 | return; 47 | } 48 | static double frame_counter = 0.0; 49 | static uint64_t frames = 0; 50 | 51 | frame_counter += GetFrameTime(); 52 | frames++; 53 | 54 | if (frame_counter >= PROF_COLLATE_WINDOW) { 55 | profilers[PROF_TOTAL_TIME].delta_time = frame_counter / (double)frames; 56 | 57 | for (uint32_t i = PROF_MAIN_LOOP; i < MAX_PROF; i += 1) { 58 | profiler *p = &profilers[i]; 59 | p->delta_time = p->num_invocations == 0 ? 0.0 : p->total_time / (double)p->num_invocations; 60 | } 61 | 62 | frame_counter = 0.0; 63 | frames = 0; 64 | } 65 | } 66 | 67 | double profiler_delta(profiler_kind id) { 68 | return profilers[id].delta_time; 69 | } 70 | 71 | char const *profiler_name(profiler_kind id) { 72 | return profilers[id].name; 73 | } 74 | -------------------------------------------------------------------------------- /code/vendors/raylib-nuklear/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # raylib 2 | find_package(raylib QUIET) 3 | if (NOT raylib_FOUND) 4 | include(FetchContent) 5 | FetchContent_Declare( 6 | raylib 7 | GIT_REPOSITORY https://github.com/raysan5/raylib.git 8 | GIT_TAG 4.2.0 9 | ) 10 | FetchContent_GetProperties(raylib) 11 | if (NOT raylib_POPULATED) # Have we downloaded raylib yet? 12 | set(FETCHCONTENT_QUIET NO) 13 | FetchContent_Populate(raylib) 14 | set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) 15 | set(BUILD_GAMES OFF CACHE BOOL "" FORCE) 16 | add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR}) 17 | endif() 18 | endif() 19 | 20 | # raylib-nuklear-example 21 | add_executable(raylib-nuklear-example 22 | raylib-nuklear-example.c 23 | ) 24 | target_link_libraries(raylib-nuklear-example PUBLIC 25 | raylib 26 | raylib_nuklear 27 | ) 28 | 29 | # raylib-nuklear-demo 30 | add_executable(raylib-nuklear-demo 31 | raylib-nuklear-demo.c 32 | ) 33 | target_link_libraries(raylib-nuklear-demo PUBLIC 34 | raylib 35 | raylib_nuklear 36 | ) 37 | 38 | # raylib-nuklear-font 39 | add_executable(raylib-nuklear-font 40 | raylib-nuklear-font.c 41 | ) 42 | target_link_libraries(raylib-nuklear-font PUBLIC 43 | raylib 44 | raylib_nuklear 45 | ) 46 | 47 | # raylib-nuklear-texture 48 | add_executable(raylib-nuklear-texture 49 | raylib-nuklear-texture.c 50 | ) 51 | target_link_libraries(raylib-nuklear-texture PUBLIC 52 | raylib 53 | raylib_nuklear 54 | ) 55 | 56 | # Target C99 57 | set_property(TARGET raylib-nuklear-example PROPERTY C_STANDARD 99) 58 | set_property(TARGET raylib-nuklear-demo PROPERTY C_STANDARD 99) 59 | set_property(TARGET raylib-nuklear-font PROPERTY C_STANDARD 99) 60 | set_property(TARGET raylib-nuklear-texture PROPERTY C_STANDARD 99) 61 | 62 | # Enable warnings 63 | if(MSVC) 64 | target_compile_options(raylib-nuklear-example PRIVATE /W4 /WX) 65 | target_compile_options(raylib-nuklear-demo PRIVATE /W4 /WX) 66 | target_compile_options(raylib-nuklear-font PRIVATE /W4 /WX) 67 | target_compile_options(raylib-nuklear-texture PRIVATE /W4 /WX) 68 | else() 69 | target_compile_options(raylib-nuklear-example PRIVATE -Wall -Wextra -Wpedantic -Werror) 70 | target_compile_options(raylib-nuklear-demo PRIVATE -Wall -Wextra -Wpedantic -Werror) 71 | target_compile_options(raylib-nuklear-font PRIVATE -Wall -Wextra -Wpedantic -Werror) 72 | target_compile_options(raylib-nuklear-texture PRIVATE -Wall -Wextra -Wpedantic -Werror) 73 | endif() 74 | 75 | # Resources 76 | configure_file(resources/anonymous_pro_bold.ttf resources/anonymous_pro_bold.ttf COPYONLY) 77 | configure_file(resources/test-image.png resources/test-image.png COPYONLY) 78 | -------------------------------------------------------------------------------- /code/foundation/src/systems/modules/system_phys.c: -------------------------------------------------------------------------------- 1 | 2 | void PhysOnCreateBody(ecs_iter_t *it) { 3 | PhysicsBody *pb = ecs_field(it, PhysicsBody, 1); 4 | Position *p = ecs_field(it, Position, 2); 5 | 6 | for (int i = 0; i < it->count; i++) { 7 | if (pb[i].body_ptr > 0) continue; 8 | const frMaterial mat = { 9 | .density = pb[i].density, 10 | .staticFriction = pb[i].static_friction, 11 | .dynamicFriction = pb[i].dynamic_friction, 12 | }; 13 | 14 | frShape *shape = 0; 15 | if (pb[i].kind == PHYS_CIRCLE) { 16 | shape = frCreateCircle(mat, pb[i].circle.r); 17 | } else { 18 | shape = frCreateRectangle(mat, pb[i].rect.w, pb[i].rect.h); 19 | } 20 | 21 | frBodyFlags flags = 0x0; 22 | if (pb[i].inf_inertia) flags |= FR_FLAG_INFINITE_INERTIA; 23 | if (pb[i].inf_mass) flags |= FR_FLAG_INFINITE_MASS; 24 | frBody *body = frCreateBodyFromShape(FR_BODY_DYNAMIC, flags, frVec2PixelsToMeters((Vector2){p[i].x, p[i].y}), shape); 25 | frAddToWorld(phys_world, body); 26 | pb[i].body_ptr = (uintptr_t)body; 27 | } 28 | } 29 | 30 | void PhysOnRemoveBody(ecs_iter_t *it) { 31 | PhysicsBody *pb = ecs_field(it, PhysicsBody, 1); 32 | 33 | for (int i = 0; i < it->count; i++) { 34 | frBody *body = (frBody*)pb[i].body_ptr; 35 | frRemoveFromWorld(phys_world, body); 36 | frShape *shape = frGetBodyShape(body); 37 | frReleaseBody(body); 38 | frReleaseShape(shape); 39 | } 40 | } 41 | 42 | void PhysSetVelocity(ecs_iter_t *it) { 43 | PhysicsBody *pb = ecs_field(it, PhysicsBody, 1); 44 | Velocity *v = ecs_field(it, Velocity, 2); 45 | 46 | for (int i = 0; i < it->count; i++) { 47 | frBody *body = (frBody*)pb[i].body_ptr; 48 | frSetBodyVelocity(body, frVec2PixelsToMeters((Vector2) { v[i].x , v[i].y })); 49 | } 50 | } 51 | 52 | void PhysUpdatePosition(ecs_iter_t *it) { 53 | PhysicsBody *pb = ecs_field(it, PhysicsBody, 1); 54 | Position *p = ecs_field(it, Position, 2); 55 | Velocity *v = ecs_field(it, Velocity, 3); 56 | 57 | for (int i = 0; i < it->count; i++) { 58 | frBody *body = (frBody*)pb[i].body_ptr; 59 | Vector2 pos = frVec2MetersToPixels(frGetBodyPosition(body)); 60 | entity_set_position(it->entities[i], pos.x, pos.y); 61 | Vector2 vel = frVec2MetersToPixels(frGetBodyVelocity(body)); 62 | v[i].x = vel.x; 63 | v[i].y = vel.y; 64 | } 65 | } 66 | 67 | void PhysResetPosition(ecs_iter_t *it) { 68 | Position *p = ecs_field(it, Position, 1); 69 | 70 | for (int i = 0; i < it->count; i++) { 71 | const PhysicsBody *pb = ecs_get(it->world, it->entities[i], PhysicsBody); 72 | if (!pb) continue; 73 | frBody *body = (frBody*)pb->body_ptr; 74 | frSetBodyPosition(body, frVec2PixelsToMeters((Vector2){p[i].x, p[i].y})); 75 | } 76 | } 77 | 78 | void PhysSimulateWorld(ecs_iter_t *it) { 79 | frSimulateWorld(phys_world, 1.0f/60.0f); 80 | } 81 | -------------------------------------------------------------------------------- /eco2d.10x: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | *.*, 5 | *.obj,*.lib,*.pch,*.dll,*.pdb,.vs,Debug,Release,x64,obj,*.user,Intermediate, 6 | true 7 | true 8 | true 9 | false 10 | false 11 | build.bat 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | build\eco2d.sln 20 | false 21 | 22 | Debug 23 | Release 24 | 25 | 26 | x64 27 | 28 | 29 | C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include 30 | C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include 31 | C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt 32 | C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um 33 | C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared 34 | C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt 35 | C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt 36 | C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um 37 | 38 | 39 | ZPL_IMPL 40 | _WIN32 41 | _WIN64 42 | RAYLIB_NUKLEAR_IMPLEMENTATION 43 | NK_IMPLEMENTATION 44 | TINYC2_IMPL 45 | CUTE_C2_IMPLEMENTATION 46 | 47 | 48 | 49 | Debug:x64 50 | 51 | 52 | 53 | 54 | Debug 55 | 56 | 57 | 58 | x64 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /code/foundation/src/gen/texgen_fallback.c: -------------------------------------------------------------------------------- 1 | #include "gen/texgen.h" 2 | #include "world/world.h" 3 | #include "zpl.h" 4 | #include "utils/raylib_helpers.h" 5 | 6 | Texture2D texgen_build_anim_fallback(asset_id id, int64_t counter) { 7 | (void)counter; 8 | switch (id) { 9 | case ASSET_WATER: { 10 | return LoadTexEco(zpl_bprintf("%s%d", "water", counter%3)); 11 | }break; 12 | 13 | default: return GenColorEco(PINK); break; 14 | } 15 | } 16 | 17 | Texture2D texgen_build_sprite_fallback(asset_id id) { 18 | switch (id) { 19 | case ASSET_BLANK: return GenColorEco(WHITE); break; 20 | case ASSET_BUILDMODE_HIGHLIGHT: return GenColorEco(WHITE); break; 21 | case ASSET_BLOCK_FRAME: return GenFrameRect(); break; 22 | 23 | // NOTE(zaklaus): items 24 | case ASSET_COAL: return LoadTexEco("coal"); 25 | case ASSET_IRON_ORE: return LoadTexEco("iron_ore"); 26 | case ASSET_IRON_INGOT: return LoadTexEco("iron_ingot"); 27 | case ASSET_IRON_PLATES: return LoadTexEco("iron_plate"); 28 | case ASSET_SCREWS: return LoadTexEco("screws"); 29 | case ASSET_LOG: return LoadTexEco("log"); 30 | case ASSET_PLANK: return LoadTexEco("plank"); 31 | case ASSET_CREATURE: return GenColorEco(YELLOW); 32 | case ASSET_CREATURE_FOOD: return GenColorEco(GREEN); 33 | 34 | // NOTE(zaklaus): blocks 35 | case ASSET_FENCE: return LoadTexEco("fence"); 36 | case ASSET_GROUND: return LoadTexEco("grass"); 37 | case ASSET_DIRT: return LoadTexEco("dirt"); 38 | case ASSET_WALL: return LoadTexEco("asphalt"); 39 | case ASSET_HILL_SNOW: 40 | case ASSET_HILL: return LoadTexEco("rock"); 41 | case ASSET_LAVA: return LoadTexEco("lava"); 42 | case ASSET_WOOD: return LoadTexEco("wood"); 43 | case ASSET_TREE: return LoadTexEco("bigtree"); 44 | case ASSET_TEST_TALL: return LoadTexEco("test-tall"); 45 | // case ASSET_WATER: return LoadTexEco("water"); 46 | 47 | case ASSET_BELT: 48 | case ASSET_BELT_RIGHT: return LoadTexEco("belt_right"); 49 | case ASSET_BELT_LEFT: return LoadTexEco("belt_left"); 50 | case ASSET_BELT_UP: return LoadTexEco("belt_up"); 51 | case ASSET_BELT_DOWN: return LoadTexEco("belt_down"); 52 | 53 | // NOTE(zaklaus): devices 54 | case ASSET_CHEST: return LoadTexEco("chest"); 55 | case ASSET_FURNACE: return LoadTexEco("furnace"); 56 | case ASSET_CRAFTBENCH: return LoadTexEco("craftbench"); 57 | case ASSET_SPLITTER: return LoadTexEco("item_splitter"); 58 | case ASSET_ASSEMBLER: return LoadTexEco("assembler"); 59 | 60 | default: break; 61 | } 62 | 63 | if (id > ASSET_BLUEPRINT_BEGIN && id < ASSET_BLUEPRINT_END) { 64 | return LoadTexEco("blueprint"); 65 | } 66 | 67 | return GenColorEco(PINK); 68 | } 69 | -------------------------------------------------------------------------------- /code/foundation/src/systems/modules/system_producer.c: -------------------------------------------------------------------------------- 1 | #include "models/crafting.h" 2 | 3 | void ProduceItems(ecs_iter_t *it) { 4 | ItemContainer *storage = ecs_field(it, ItemContainer, 1); 5 | Producer *producer = ecs_field(it, Producer, 2); 6 | Position *p = ecs_field(it, Position, 3); 7 | Device *d = ecs_field(it, Device, 4); 8 | 9 | for (int i = 0; i < it->count; i++) { 10 | for (int j = 0; j < ITEMS_CONTAINER_SIZE; j++) { 11 | ecs_entity_t item_slot_ent = storage[i].items[j]; 12 | if (item_slot_ent == 0) continue; 13 | Item *item = item_get_data(item_slot_ent); 14 | 15 | const EnergySource *energy_source = 0; 16 | if ((energy_source = ecs_get_if(it->world, item_slot_ent, EnergySource))) { 17 | if (energy_source->kind == d->asset) { 18 | producer[i].energy_level += energy_source->kind; 19 | item_despawn(item_slot_ent); 20 | storage[i].items[j] = 0; 21 | } 22 | continue; 23 | } 24 | 25 | // TODO(zaklaus): handle fuel 26 | // if (producer[i].energy_level <= 0.0f) continue; 27 | 28 | if (producer[i].process_ticks_left == 0) { 29 | if (producer[i].processed_item > 0) { 30 | uint64_t e = item_spawn(producer[i].processed_item, producer[i].processed_item_qty); 31 | entity_set_position(e, p[i].x, p[i].y); 32 | producer[i].processed_item = 0; 33 | 34 | if (producer[i].pending_task == PRODUCER_CRAFT_BUSY) 35 | producer[i].pending_task = PRODUCER_CRAFT_WAITING; 36 | } else { 37 | if (producer[i].pending_task != PRODUCER_CRAFT_WAITING) { 38 | producer[i].processed_item = craft_perform_recipe(storage[i].items, d[i].asset, producer[i].target_item, &producer[i].processed_item_qty, &producer[i].process_ticks); 39 | producer[i].process_ticks_left = producer[i].process_ticks; 40 | 41 | if (producer[i].pending_task == PRODUCER_CRAFT_ENQUEUED) { 42 | if (producer[i].processed_item > 0) 43 | producer[i].pending_task = PRODUCER_CRAFT_BUSY; 44 | else 45 | producer[i].pending_task = PRODUCER_CRAFT_WAITING; 46 | } 47 | } 48 | } 49 | } 50 | } 51 | 52 | d[i].progress_active = (producer[i].processed_item > 0); 53 | d[i].progress_value = 1.0f-(producer[i].process_ticks_left / (float)producer[i].process_ticks); 54 | 55 | if (d[i].progress_active) { 56 | entity_wake(it->entities[i]); 57 | } 58 | 59 | TICK_VAR(producer[i].process_ticks_left); 60 | } 61 | } 62 | 63 | -------------------------------------------------------------------------------- /code/foundation/src/world/perlin.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "world/perlin.h" 3 | 4 | // adapted from: https://gist.github.com/nowl/828013#gistcomment-2807232 5 | 6 | static const uint8_t PERLIN_PERM_TABLE[] = { 7 | 208,34,231,213,32,248,233,56,161,78,24,140,71,48,140,254,245,255,247,247,40, 8 | 185,248,251,245,28,124,204,204,76,36,1,107,28,234,163,202,224,245,128,167,204, 9 | 9,92,217,54,239,174,173,102,193,189,190,121,100,108,167,44,43,77,180,204,8,81, 10 | 70,223,11,38,24,254,210,210,177,32,81,195,243,125,8,169,112,32,97,53,195,13, 11 | 203,9,47,104,125,117,114,124,165,203,181,235,193,206,70,180,174,0,167,181,41, 12 | 164,30,116,127,198,245,146,87,224,149,206,57,4,192,210,65,210,129,240,178,105, 13 | 228,108,245,148,140,40,35,195,38,58,65,207,215,253,65,85,208,76,62,3,237,55,89, 14 | 232,50,217,64,244,157,199,121,252,90,17,212,203,149,152,140,187,234,177,73,174, 15 | 193,100,192,143,97,53,145,135,19,103,13,90,135,151,199,91,239,247,33,39,145, 16 | 101,120,99,3,186,86,99,41,237,203,111,79,220,135,158,42,30,154,120,67,87,167, 17 | 135,176,183,191,253,115,184,21,233,58,129,233,142,39,128,211,118,137,139,255, 18 | 114,20,218,113,154,27,127,246,250,1,8,198,250,209,92,222,173,21,88,102,219 19 | }; 20 | 21 | static int32_t perlin_noise2_sample(int32_t seed, int32_t x, int32_t y) { 22 | int32_t yindex = (y + seed) % 256; 23 | if (yindex < 0) 24 | yindex += 256; 25 | int32_t xindex = (PERLIN_PERM_TABLE[yindex] + x) % 256; 26 | if (xindex < 0) 27 | xindex += 256; 28 | return PERLIN_PERM_TABLE[xindex]; 29 | } 30 | 31 | static double perlin_lerp(double x, double y, double t) { 32 | return x + t*(y - x); 33 | } 34 | 35 | static double perlin_smooth_lerp(double x, double y, double t) { 36 | return perlin_lerp(x, y, t * t * (3-2*t)); 37 | } 38 | 39 | double perlin_noise2d(int32_t seed, double x, double y) { 40 | int32_t x_int = (int32_t)floor(x); 41 | int32_t y_int = (int32_t)floor(y); 42 | double x_frac = x - x_int; 43 | double y_frac = y - y_int; 44 | int32_t s = perlin_noise2_sample(seed, x_int, y_int); 45 | int32_t t = perlin_noise2_sample(seed, x_int+1, y_int); 46 | int32_t u = perlin_noise2_sample(seed, x_int, y_int+1); 47 | int32_t v = perlin_noise2_sample(seed, x_int+1, y_int+1); 48 | double low = perlin_smooth_lerp(s, t, x_frac); 49 | double high = perlin_smooth_lerp(u, v, x_frac); 50 | double result = perlin_smooth_lerp(low, high, y_frac); 51 | return result; 52 | } 53 | 54 | double perlin_fbm(int32_t seed, double x, double y, double freq, uint32_t octaves) { 55 | double xa = x*freq; 56 | double ya = y*freq; 57 | double amp = 1.0; 58 | double res = 0.0; 59 | double div = 0.0; 60 | 61 | for (uint32_t i=0; i 0); 20 | const char* dir = GetDirectoryPath(argv[0]); 21 | Assert(ChangeDirectory(dir)); 22 | 23 | // InitNuklear() 24 | struct nk_context *ctx = InitNuklear(10); 25 | Assert(ctx); 26 | 27 | // Image 28 | struct nk_image image = LoadNuklearImage("resources/test-image.png"); 29 | Assert(image.handle.ptr); 30 | Texture texture = TextureFromNuklear(image); 31 | Assert(texture.width > 0); 32 | 33 | // UpdateNuklear() 34 | UpdateNuklear(ctx); 35 | 36 | // Nuklear GUI Code 37 | // https://github.com/Immediate-Mode-UI/Nuklear/wiki/Window 38 | if (nk_begin(ctx, "Nuklear", nk_rect(50, 50, 400, 400), 39 | NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) { 40 | nk_button_label(ctx, "Button"); 41 | nk_layout_row_static(ctx, 256, 256, 1); 42 | nk_image(ctx, image); 43 | } 44 | nk_end(ctx); 45 | 46 | // Render 47 | BeginDrawing(); 48 | ClearBackground(RAYWHITE); 49 | 50 | // DrawNuklear() 51 | DrawNuklear(ctx); 52 | EndDrawing(); 53 | 54 | // UnloadNuklearImage() 55 | UnloadNuklearImage(image); 56 | 57 | // UnloadNuklear() 58 | UnloadNuklear(ctx); 59 | 60 | // InitNuklearEx() 61 | Font font = LoadFont("resources/anonymous_pro_bold.ttf"); 62 | ctx = InitNuklearEx(font, 25.0f); 63 | Assert(ctx); 64 | UnloadNuklear(ctx); 65 | UnloadFont(font); 66 | 67 | // RectangleFromNuklear() 68 | { 69 | ctx = NULL; 70 | struct nk_rect rect = nk_rect(10, 20, 30, 40); 71 | Rectangle rectangle = RectangleFromNuklear(ctx, rect); 72 | AssertEqual(rect.x, rectangle.x); 73 | AssertEqual(rect.y, rectangle.y); 74 | AssertEqual(rect.w, rectangle.width); 75 | AssertEqual(rect.h, rectangle.height); 76 | } 77 | 78 | // RectangleFromNuklear(), RectangleToNuklear(), with scaling 79 | { 80 | struct nk_rect rect = nk_rect(10, 20, 30, 40); 81 | ctx = InitNuklear(10); 82 | SetNuklearScaling(ctx, 2.0f); 83 | float scaling = GetNuklearScaling(ctx); 84 | AssertEqual(scaling, 2.0f, "Scaling was incorrectly set."); 85 | Rectangle rectangle = RectangleFromNuklear(ctx, rect); 86 | AssertEqual(rect.x, rectangle.x / 2); 87 | AssertEqual(rect.y, rectangle.y / 2); 88 | AssertEqual(rect.w, rectangle.width / 2); 89 | AssertEqual(rect.h, rectangle.height / 2); 90 | 91 | rectangle = (Rectangle){20, 40, 60, 80}; 92 | rect = RectangleToNuklear(ctx, rectangle); 93 | AssertEqual(rect.x, rectangle.x / 2); 94 | AssertEqual(rect.y, rectangle.y / 2); 95 | AssertEqual(rect.w, rectangle.width / 2); 96 | AssertEqual(rect.h, rectangle.height / 2); 97 | 98 | UnloadNuklear(ctx); 99 | } 100 | 101 | CloseWindow(); 102 | TraceLog(LOG_INFO, "================================"); 103 | TraceLog(LOG_INFO, "raylib-nuklear tests succesful"); 104 | TraceLog(LOG_INFO, "================================"); 105 | 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /code/foundation/src/world/prediction.c: -------------------------------------------------------------------------------- 1 | #include "zpl.h" 2 | #include "world/prediction.h" 3 | #include "platform/platform.h" 4 | #include "world/world.h" 5 | #include "core/game.h" 6 | 7 | #define PREDICT_SMOOTH_FACTOR_LO 7.5f 8 | #define PREDICT_SMOOTH_FACTOR_HI 12.5f 9 | 10 | static inline float map_factor(float x) { 11 | x = 1.0f - zpl_clamp01(x); 12 | return 1.0f - x*x*x*x*x*x*x*x; 13 | } 14 | 15 | static inline float base_angle(float x) { 16 | while (x > ZPL_TAU) x -= ZPL_TAU; 17 | while (x < 0.0f) x += ZPL_TAU; 18 | return x; 19 | } 20 | 21 | static inline float spherical_lerp(float a, float b, float t) { 22 | a = base_angle(a); 23 | b = base_angle(b); 24 | float d = b - a; 25 | 26 | if (d < -ZPL_PI) { 27 | b += ZPL_TAU; 28 | } else if (d > ZPL_PI) { 29 | b -= ZPL_TAU; 30 | } 31 | 32 | return base_angle(zpl_lerp(a, b, t)); 33 | } 34 | 35 | float smooth_val(float cur, float tgt, float dt) { 36 | float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS))); 37 | 38 | return zpl_lerp(cur, tgt, zpl_clamp01(zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor)*platform_frametime())); 39 | } 40 | 41 | float smooth_val_spherical(float cur, float tgt, float dt) { 42 | float factor = zpl_clamp01(map_factor(zpl_unlerp(dt, WORLD_TRACKER_UPDATE_MP_FAST_MS, WORLD_TRACKER_UPDATE_MP_SLOW_MS))); 43 | 44 | return spherical_lerp(cur, tgt, zpl_clamp01(zpl_lerp(PREDICT_SMOOTH_FACTOR_LO, PREDICT_SMOOTH_FACTOR_HI, factor)*platform_frametime())); 45 | } 46 | 47 | void predict_receive_update(entity_view *d, entity_view *data) { 48 | if (d && data->flag & EFLAG_INTERP) { 49 | // NOTE(zaklaus): store target pos but keep x,y unchanged 50 | float tx = data->x; 51 | float ty = data->y; 52 | float theading = data->heading; 53 | data->x = d->x; 54 | data->y = d->y; 55 | data->heading = d->heading; 56 | data->tx = tx; 57 | data->ty = ty; 58 | data->theading = theading; 59 | } 60 | 61 | data->tran_effect = d->tran_effect; 62 | data->tran_time = d->tran_time; 63 | } 64 | 65 | #define ENTITY_DO_LERP_SP 0 66 | 67 | void lerp_entity_positions(uint64_t key, entity_view *data) { 68 | (void)key; 69 | world_view *view = game_world_view_get_active(); 70 | 71 | if (data->flag == EFLAG_INTERP) { 72 | #if ENTITY_DO_LERP_SP==0 73 | if (game_get_kind() == GAMEKIND_CLIENT) 74 | #else 75 | if (1) 76 | #endif 77 | { 78 | data->x = smooth_val(data->x, data->tx, view->delta_time[data->layer_id]); 79 | data->y = smooth_val(data->y, data->ty, view->delta_time[data->layer_id]); 80 | data->heading = smooth_val_spherical(data->heading, data->theading, view->delta_time[data->layer_id]); 81 | } else { 82 | (void)view; 83 | data->x = data->tx; 84 | data->y = data->ty; 85 | data->heading = data->theading; 86 | } 87 | } 88 | } 89 | 90 | void do_entity_fadeinout(uint64_t key, entity_view * data) { 91 | (void)key; 92 | switch (data->tran_effect) { 93 | case ETRAN_FADEIN: { 94 | data->tran_time += platform_frametime(); 95 | 96 | if (data->tran_time > 1.0f) { 97 | data->tran_effect = ETRAN_NONE; 98 | data->tran_time = 1.0f; 99 | } 100 | }break; 101 | 102 | case ETRAN_FADEOUT: { 103 | data->tran_time -= platform_frametime(); 104 | 105 | if (data->tran_time < 0.0f) { 106 | data->tran_effect = ETRAN_REMOVE; 107 | data->tran_time = 0.0f; 108 | } 109 | }break; 110 | 111 | default: break; 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /code/foundation/src/gui/notifications.c: -------------------------------------------------------------------------------- 1 | #define MAX_NOTIFICATIONS_ON_SCREEN 5 2 | 3 | typedef struct { 4 | zpl_string title; 5 | zpl_string text; 6 | } notification; 7 | 8 | static notification *notifications = 0; 9 | 10 | static bool show_notification_list = 0; 11 | 12 | void notification_push(const char* title1, const char* text1) { 13 | if (!notifications) { 14 | zpl_array_init(notifications, zpl_heap()); 15 | } 16 | 17 | zpl_string title = zpl_string_make(zpl_heap(), title1); 18 | zpl_string text = zpl_string_make(zpl_heap(), text1); 19 | 20 | zpl_array_append(notifications, ((notification) { title, text })); 21 | } 22 | 23 | void notification_clear(void) { 24 | for (zpl_isize i = 0; i < zpl_array_count(notifications); i++) { 25 | zpl_string_free(notifications[i].title); 26 | zpl_string_free(notifications[i].text); 27 | } 28 | zpl_array_clear(notifications); 29 | } 30 | 31 | void notification_draw(void) { 32 | float width = (float)GetScreenWidth(); 33 | float height = (float)GetScreenHeight(); 34 | // draw ctrl panel 35 | if (nk_begin(game_ui, "Notifications", nk_rect(width - 220, 20, 200, 80), 36 | NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_TITLE | NK_WINDOW_DYNAMIC)) { 37 | { 38 | nk_layout_row_dynamic(game_ui, 0, 2); 39 | 40 | if (nk_button_label(game_ui, "Clear All")) { 41 | notification_clear(); 42 | } 43 | 44 | if (nk_button_label(game_ui, show_notification_list ? "Hide Manager" : "Show All")) { 45 | show_notification_list ^= 1; 46 | } 47 | } 48 | nk_end(game_ui); 49 | } 50 | 51 | float ypos = 100; 52 | zpl_isize cnt = zpl_min(zpl_array_count(notifications), MAX_NOTIFICATIONS_ON_SCREEN)-1; 53 | 54 | for (zpl_isize i = cnt; i >= 0; --i) { 55 | notification *notif = (notifications + i); 56 | if (nk_begin_titled(game_ui, zpl_bprintf("%d%fnotif%s", i, ypos, notif->title), notif->title, nk_rect(width - 320, ypos, 300, 1200), 57 | NK_WINDOW_DYNAMIC|NK_WINDOW_NO_SCROLLBAR)) { 58 | { 59 | if (nk_tree_push_id(game_ui, NK_TREE_TAB, notif->title, NK_MAXIMIZED, (int)i)) { 60 | nk_label_wrap(game_ui, notif->text); 61 | 62 | if (nk_button_label(game_ui, "OK")) { 63 | zpl_string_free(notifications[i].title); 64 | zpl_string_free(notifications[i].text); 65 | zpl_array_remove_at(notifications, i); 66 | } 67 | nk_tree_pop(game_ui); 68 | } 69 | } 70 | ypos += nk_window_get_panel(game_ui)->row.height + 80; 71 | 72 | nk_end(game_ui); 73 | } 74 | } 75 | 76 | if (show_notification_list) { 77 | if (nk_begin(game_ui, "Notifications Manager", nk_rect(width/2.0f - 320, height/2.0f - 240, 640, 480), 78 | NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_TITLE | NK_WINDOW_MOVABLE | NK_WINDOW_DYNAMIC )) { 79 | { 80 | nk_layout_row_dynamic(game_ui, 5 , 1); 81 | { 82 | for (zpl_isize i = 0; i < zpl_array_count(notifications); ++i) { 83 | notification *notif = (notifications + i); 84 | if (nk_tree_push_id(game_ui, NK_TREE_TAB, notif->title, NK_MINIMIZED, (int)i)) { 85 | { 86 | nk_label_wrap(game_ui, notif->text); 87 | 88 | if (nk_button_label(game_ui, "OK")) { 89 | zpl_string_free(notifications[i].title); 90 | zpl_string_free(notifications[i].text); 91 | zpl_array_remove_at(notifications, i); --i; 92 | } 93 | } 94 | nk_tree_pop(game_ui); 95 | } 96 | } 97 | } 98 | 99 | nk_layout_row_dynamic(game_ui, 0, 2); 100 | 101 | if (nk_button_label(game_ui, "Clear All")) { 102 | notification_clear(); 103 | } 104 | 105 | if (nk_button_label(game_ui, "Hide Manager")) { 106 | show_notification_list = 0 ; 107 | } 108 | } 109 | nk_end(game_ui); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /code/foundation/src/world/entity_view.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "models/assets.h" 4 | #include "models/items.h" 5 | 6 | #define ZPL_PICO 7 | #include "zpl.h" 8 | 9 | #define MAX_CRAFTABLES 32 10 | 11 | #define _CLASSES\ 12 | X(EKIND_SERVER)\ 13 | X(EKIND_PLAYER)\ 14 | X(EKIND_ITEM)\ 15 | X(EKIND_DEVICE)\ 16 | X(EKIND_SPRITE)\ 17 | X(EKIND_WEAPON)\ 18 | X(EKIND_VEHICLE)\ 19 | X(EKIND_DEMO_NPC)\ 20 | X(EKIND_MONSTER)\ 21 | X(EKIND_MACRO_BOT)\ 22 | X(EKIND_CHUNK) 23 | 24 | typedef enum { 25 | #define X(id) id, 26 | _CLASSES 27 | #undef X 28 | FORCE_EKIND_UINT16 = UINT16_MAX 29 | } entity_kind; 30 | 31 | typedef enum { 32 | EFLAG_INTERP = (1 << 0), 33 | FORCE_EFLAG_UINT16 = UINT16_MAX 34 | } entity_flag; 35 | 36 | typedef enum { 37 | ETRAN_NONE, 38 | ETRAN_FADEOUT, 39 | ETRAN_FADEIN, 40 | ETRAN_REMOVE, 41 | FORCE_ETRAN_UINT8 = UINT8_MAX 42 | } entity_transition_effect; 43 | 44 | extern const char *class_names[]; 45 | 46 | typedef struct entity_view { 47 | int64_t ent_id; 48 | entity_kind kind; 49 | entity_flag flag; 50 | float x; 51 | float y; 52 | float vx; 53 | float vy; 54 | float tx; 55 | float ty; 56 | float hx; 57 | float hy; 58 | float angle; 59 | 60 | float hp; 61 | float max_hp; 62 | 63 | // TODO(zaklaus): Find a way to stream dynamic arrays 64 | uint32_t chk_id; 65 | uint8_t blocks_used; 66 | block_id blocks[256]; 67 | block_id outer_blocks[256]; 68 | uint32_t color; 69 | uint8_t is_dirty; 70 | int64_t tex; 71 | 72 | // NOTE(zaklaus): vehicle 73 | float heading, theading; 74 | bool inside_vehicle; 75 | uint32_t veh_kind; 76 | 77 | // NOTE(zaklaus): items, ... 78 | asset_id asset; 79 | uint32_t quantity; 80 | float durability; 81 | 82 | // NOTE(zaklaus): device progress bar 83 | bool is_producer; 84 | uint32_t progress_active; 85 | float progress_value; 86 | 87 | // sprite index 88 | union { 89 | struct { 90 | uint32_t spritesheet; 91 | uint32_t frame; 92 | }; 93 | struct { 94 | uint32_t sprite_id; 95 | uint32_t sprite_data; 96 | }; 97 | }; 98 | 99 | // NOTE(zaklaus): inventory 100 | uint8_t has_items; 101 | Item items[ITEMS_INVENTORY_SIZE]; 102 | uint8_t selected_item; 103 | 104 | // NOTE(zaklaus): storage interface 105 | uint8_t has_storage_items; 106 | Item storage_items[ITEMS_CONTAINER_SIZE]; 107 | uint8_t storage_selected_item; 108 | 109 | // NOTE(zaklaus): craftable recipes 110 | uint16_t craftables[MAX_CRAFTABLES]; 111 | 112 | // NOTE(zaklaus): entity picking 113 | uint64_t pick_ent; 114 | uint64_t sel_ent; 115 | 116 | // NOTE(zaklaus): internals 117 | uint8_t layer_id; 118 | uint64_t last_update; 119 | 120 | // NOTE(zaklaus): fade in-out effect 121 | entity_transition_effect tran_effect; 122 | float tran_time; 123 | } entity_view; 124 | 125 | ZPL_TABLE_DECLARE(, entity_view_tbl, entity_view_tbl_, entity_view); 126 | 127 | void entity_view_init(entity_view_tbl *map); 128 | void entity_view_free(entity_view_tbl *map); 129 | 130 | void entity_view_update_or_create(entity_view_tbl *map, uint64_t ent_id, entity_view data); 131 | void entity_view_destroy(entity_view_tbl *map, uint64_t ent_id); 132 | 133 | entity_view *entity_view_get(entity_view_tbl *map, uint64_t ent_id); 134 | void entity_view_map(entity_view_tbl *map, void (*map_proc)(uint64_t key, entity_view *value)); 135 | 136 | size_t entity_view_pack_struct(void *data, size_t len, entity_view *view); 137 | entity_view entity_view_unpack_struct(void *data, size_t len); 138 | 139 | void entity_view_mark_for_removal(entity_view_tbl *map, uint64_t ent_id); 140 | void entity_view_mark_for_fadein(entity_view_tbl *map, uint64_t ent_id); 141 | void entity_view_update_chunk_texture(entity_view_tbl *map, uint64_t ent_id, void *view); 142 | void entity_view_remove_chunk_texture(entity_view_tbl *map, uint64_t ent_id); 143 | -------------------------------------------------------------------------------- /code/vendors/flecs/flecs-os_api-stdcpp.cpp: -------------------------------------------------------------------------------- 1 | #include "flecs_os_api_stdcpp.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #include "flecs/flecs.h" 7 | 8 | #ifdef _WIN32 9 | #include 10 | #endif 11 | 12 | static 13 | ecs_os_thread_t stdcpp_thread_new( 14 | ecs_os_thread_callback_t callback, 15 | void *arg) 16 | { 17 | std::thread *thread = new std::thread{callback,arg}; 18 | return reinterpret_cast(thread); 19 | } 20 | 21 | static 22 | void* stdcpp_thread_join( 23 | ecs_os_thread_t thread) 24 | { 25 | void *arg = nullptr; 26 | std::thread *thr = reinterpret_cast(thread); 27 | thr->join(); 28 | delete thr; 29 | return arg; 30 | } 31 | 32 | static 33 | int32_t stdcpp_ainc(int32_t *count) { 34 | int value; 35 | #ifdef __GNUC__ 36 | value = __sync_add_and_fetch (count, 1); 37 | return value; 38 | #else 39 | (void)value; 40 | return InterlockedIncrement(reinterpret_cast(count)); 41 | #endif 42 | } 43 | 44 | static 45 | int32_t stdcpp_adec(int32_t *count) { 46 | int value; 47 | #ifdef __GNUC__ 48 | value = __sync_sub_and_fetch (count, 1); 49 | return value; 50 | #else 51 | (void)value; 52 | return InterlockedDecrement(reinterpret_cast(count)); 53 | #endif 54 | } 55 | 56 | static 57 | ecs_os_mutex_t stdcpp_mutex_new(void) { 58 | std::mutex *mutex = new std::mutex; 59 | return reinterpret_cast(mutex); 60 | } 61 | 62 | static 63 | void stdcpp_mutex_free(ecs_os_mutex_t m) { 64 | std::mutex*mutex = reinterpret_cast(m); 65 | delete mutex; 66 | } 67 | 68 | static 69 | void stdcpp_mutex_lock(ecs_os_mutex_t m) { 70 | std::mutex*mutex = reinterpret_cast(m); 71 | mutex->lock(); 72 | } 73 | 74 | static 75 | void stdcpp_mutex_unlock(ecs_os_mutex_t m) { 76 | std::mutex *mutex = reinterpret_cast(m); 77 | mutex->unlock(); 78 | } 79 | 80 | static 81 | ecs_os_cond_t stdcpp_cond_new(void) { 82 | std::condition_variable_any* cond = new std::condition_variable_any{}; 83 | return (ecs_os_cond_t)cond; 84 | } 85 | 86 | static 87 | void stdcpp_cond_free(ecs_os_cond_t c) { 88 | std::condition_variable_any *cond = reinterpret_cast(c); 89 | delete cond; 90 | } 91 | 92 | static 93 | void stdcpp_cond_signal(ecs_os_cond_t c) { 94 | std::condition_variable_any *cond = reinterpret_cast(c); 95 | cond->notify_one(); 96 | } 97 | 98 | static 99 | void stdcpp_cond_broadcast(ecs_os_cond_t c) { 100 | std::condition_variable_any*cond = reinterpret_cast(c); 101 | cond->notify_all(); 102 | } 103 | 104 | static 105 | void stdcpp_cond_wait(ecs_os_cond_t c, ecs_os_mutex_t m) { 106 | std::condition_variable_any* cond = reinterpret_cast(c); 107 | std::mutex* mutex = reinterpret_cast(m); 108 | cond->wait(*mutex); 109 | } 110 | 111 | #ifdef __cplusplus 112 | extern "C" { 113 | #endif 114 | void stdcpp_set_os_api(void) { 115 | ecs_os_set_api_defaults(); 116 | 117 | ecs_os_api_t api = ecs_os_api; 118 | 119 | api.thread_new_ = stdcpp_thread_new; 120 | api.thread_join_ = stdcpp_thread_join; 121 | api.ainc_ = stdcpp_ainc; 122 | api.adec_ = stdcpp_adec; 123 | api.mutex_new_ = stdcpp_mutex_new; 124 | api.mutex_free_ = stdcpp_mutex_free; 125 | api.mutex_lock_ = stdcpp_mutex_lock; 126 | api.mutex_unlock_ = stdcpp_mutex_unlock; 127 | api.cond_new_ = stdcpp_cond_new; 128 | api.cond_free_ = stdcpp_cond_free; 129 | api.cond_signal_ = stdcpp_cond_signal; 130 | api.cond_broadcast_ = stdcpp_cond_broadcast; 131 | api.cond_wait_ = stdcpp_cond_wait; 132 | 133 | ecs_os_set_api(&api); 134 | } 135 | #ifdef __cplusplus 136 | } 137 | #endif 138 | -------------------------------------------------------------------------------- /code/vendors/flecs/flecs_os_api_posix.c: -------------------------------------------------------------------------------- 1 | #include "flecs_os_api_posix.h" 2 | 3 | #include 4 | 5 | #include "flecs/flecs.h" 6 | 7 | static 8 | ecs_os_thread_t posix_thread_new( 9 | ecs_os_thread_callback_t callback, 10 | void *arg) 11 | { 12 | pthread_t *thread = ecs_os_malloc(sizeof(pthread_t)); 13 | int r; 14 | 15 | if ((r = pthread_create (thread, NULL, callback, arg))) { 16 | abort(); 17 | } 18 | 19 | return (ecs_os_thread_t)(uintptr_t)thread; 20 | } 21 | 22 | static 23 | void* posix_thread_join( 24 | ecs_os_thread_t thread) 25 | { 26 | void *arg; 27 | pthread_t *thr = (pthread_t*)(uintptr_t)thread; 28 | pthread_join(*thr, &arg); 29 | ecs_os_free(thr); 30 | return arg; 31 | } 32 | 33 | static 34 | int32_t posix_ainc(int32_t *count) { 35 | int value; 36 | #ifdef __GNUC__ 37 | value = __sync_add_and_fetch (count, 1); 38 | return value; 39 | #else 40 | /* Unsupported */ 41 | abort(); 42 | #endif 43 | } 44 | 45 | static 46 | int32_t posix_adec(int32_t *count) { 47 | int value; 48 | #ifdef __GNUC__ 49 | value = __sync_sub_and_fetch (count, 1); 50 | return value; 51 | #else 52 | /* Unsupported */ 53 | abort(); 54 | #endif 55 | } 56 | 57 | static 58 | ecs_os_mutex_t posix_mutex_new(void) { 59 | pthread_mutex_t *mutex = ecs_os_malloc(sizeof(pthread_mutex_t)); 60 | if (pthread_mutex_init(mutex, NULL)) { 61 | abort(); 62 | } 63 | return (ecs_os_mutex_t)(uintptr_t)mutex; 64 | } 65 | 66 | static 67 | void posix_mutex_free(ecs_os_mutex_t m) { 68 | pthread_mutex_t *mutex = (pthread_mutex_t*)(intptr_t)m; 69 | pthread_mutex_destroy(mutex); 70 | ecs_os_free(mutex); 71 | } 72 | 73 | static 74 | void posix_mutex_lock(ecs_os_mutex_t m) { 75 | pthread_mutex_t *mutex = (pthread_mutex_t*)(intptr_t)m; 76 | if (pthread_mutex_lock(mutex)) { 77 | abort(); 78 | } 79 | } 80 | 81 | static 82 | void posix_mutex_unlock(ecs_os_mutex_t m) { 83 | pthread_mutex_t *mutex = (pthread_mutex_t*)(intptr_t)m; 84 | if (pthread_mutex_unlock(mutex)) { 85 | abort(); 86 | } 87 | } 88 | 89 | static 90 | ecs_os_cond_t posix_cond_new(void) { 91 | pthread_cond_t *cond = ecs_os_malloc(sizeof(pthread_cond_t)); 92 | if (pthread_cond_init(cond, NULL)) { 93 | abort(); 94 | } 95 | return (ecs_os_cond_t)(uintptr_t)cond; 96 | } 97 | 98 | static 99 | void posix_cond_free(ecs_os_cond_t c) { 100 | pthread_cond_t *cond = (pthread_cond_t*)(intptr_t)c; 101 | if (pthread_cond_destroy(cond)) { 102 | abort(); 103 | } 104 | ecs_os_free(cond); 105 | } 106 | 107 | static 108 | void posix_cond_signal(ecs_os_cond_t c) { 109 | pthread_cond_t *cond = (pthread_cond_t*)(intptr_t)c; 110 | if (pthread_cond_signal(cond)) { 111 | abort(); 112 | } 113 | } 114 | 115 | static 116 | void posix_cond_broadcast(ecs_os_cond_t c) { 117 | pthread_cond_t *cond = (pthread_cond_t*)(intptr_t)c; 118 | if (pthread_cond_broadcast(cond)) { 119 | abort(); 120 | } 121 | } 122 | 123 | static 124 | void posix_cond_wait(ecs_os_cond_t c, ecs_os_mutex_t m) { 125 | pthread_cond_t *cond = (pthread_cond_t*)(intptr_t)c; 126 | pthread_mutex_t *mutex = (pthread_mutex_t*)(intptr_t)m; 127 | if (pthread_cond_wait(cond, mutex)) { 128 | abort(); 129 | } 130 | } 131 | 132 | void posix_set_os_api(void) { 133 | ecs_os_set_api_defaults(); 134 | 135 | ecs_os_api_t api = ecs_os_api; 136 | 137 | api.thread_new_ = posix_thread_new; 138 | api.thread_join_ = posix_thread_join; 139 | api.ainc_ = posix_ainc; 140 | api.adec_ = posix_adec; 141 | api.mutex_new_ = posix_mutex_new; 142 | api.mutex_free_ = posix_mutex_free; 143 | api.mutex_lock_ = posix_mutex_lock; 144 | api.mutex_unlock_ = posix_mutex_unlock; 145 | api.cond_new_ = posix_cond_new; 146 | api.cond_free_ = posix_cond_free; 147 | api.cond_signal_ = posix_cond_signal; 148 | api.cond_broadcast_ = posix_cond_broadcast; 149 | api.cond_wait_ = posix_cond_wait; 150 | 151 | ecs_os_set_api(&api); 152 | } 153 | -------------------------------------------------------------------------------- /code/games/survival/src/main.c: -------------------------------------------------------------------------------- 1 | #define ZPL_IMPL 2 | #include "zpl.h" 3 | #include "platform/system.h" 4 | #include "core/game.h" 5 | #include "game.h" 6 | #include "models/entity.h" 7 | #include "world/entity_view.h" 8 | #include "utils/options.h" 9 | #include "platform/signal_handling.h" 10 | #include "platform/profiler.h" 11 | 12 | #include "flecs.h" 13 | #include "flecs/flecs_os_api_stdcpp.h" 14 | 15 | #include "models/components.h" 16 | #include "systems/systems.h" 17 | 18 | #include "platform/arch.h" 19 | 20 | ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(0) 21 | #include "tinyc2.h" 22 | ZPL_DIAGNOSTIC_POP 23 | 24 | #define DEFAULT_WORLD_SEED 302097 25 | #define DEFAULT_CHUNK_SIZE 16 /* amount of blocks within a chunk (single axis) */ 26 | #define DEFAULT_WORLD_SIZE 20 /* amount of chunks within a world (single axis) */ 27 | 28 | /* 29 | TODO 30 | + monster spawner 31 | + the longer we survive, the more and stronger enemies we spawn 32 | - player grows HP by leveling up 33 | - XP increases by killing mobs 34 | - player can pick an "ability" upon reaching level milestones 35 | - abilities: armor/shield, TODO ... 36 | + enemies damage player when close to him in ticks (damage effects, ...) 37 | + basic projectile pooling (flecs) 38 | - somewhat believable world gen, small hamlets with cols, etc 39 | */ 40 | 41 | 42 | int main(int argc, char** argv) { 43 | zpl_opts opts={0}; 44 | zpl_opts_init(&opts, zpl_heap(), argv[0]); 45 | 46 | zpl_opts_add(&opts, "?", "help", "the HELP section", ZPL_OPTS_FLAG); 47 | zpl_opts_add(&opts, "v", "viewer-only", "run viewer-only client", ZPL_OPTS_FLAG); 48 | zpl_opts_add(&opts, "d", "server-only", "run dedicated server", ZPL_OPTS_FLAG); 49 | zpl_opts_add(&opts, "p", "preview-map", "draw world preview", ZPL_OPTS_FLAG); 50 | zpl_opts_add(&opts, "s", "seed", "world seed", ZPL_OPTS_INT); 51 | zpl_opts_add(&opts, "r", "random-seed", "generate random world seed", ZPL_OPTS_FLAG); 52 | zpl_opts_add(&opts, "ed", "enable-dash", "enables flecs dash", ZPL_OPTS_FLAG); 53 | //zpl_opts_add(&opts, "cs", "chunk-size", "amount of blocks within a chunk (single axis)", ZPL_OPTS_INT); 54 | zpl_opts_add(&opts, "ws", "world-size", "amount of chunks within a world (single axis)", ZPL_OPTS_INT); 55 | zpl_opts_add(&opts, "ip", "host", "host IP address", ZPL_OPTS_STRING); 56 | zpl_opts_add(&opts, "port", "port", "port number", ZPL_OPTS_INT); 57 | 58 | uint32_t ok = zpl_opts_compile(&opts, argc, argv); 59 | 60 | if (!ok) { 61 | zpl_opts_print_errors(&opts); 62 | zpl_opts_print_help(&opts); 63 | return -1; 64 | } 65 | 66 | int8_t is_viewer_only = zpl_opts_has_arg(&opts, "viewer-only"); 67 | int8_t is_server_only = zpl_opts_has_arg(&opts, "server-only"); 68 | int8_t is_dash_enabled = zpl_opts_has_arg(&opts, "enable-dash"); 69 | int32_t seed = (int32_t)zpl_opts_integer(&opts, "seed", DEFAULT_WORLD_SEED); 70 | uint16_t world_size = (uint16_t)zpl_opts_integer(&opts, "world-size", DEFAULT_WORLD_SIZE); 71 | uint16_t chunk_size = DEFAULT_CHUNK_SIZE; //zpl_opts_integer(&opts, "chunk-size", DEFAULT_CHUNK_SIZE); 72 | zpl_string host = zpl_opts_string(&opts, "host", NULL); 73 | uint16_t port = (uint16_t)zpl_opts_integer(&opts, "port", 0); 74 | 75 | game_kind play_mode = GAMEKIND_SINGLE; 76 | 77 | if (is_viewer_only) play_mode = GAMEKIND_CLIENT; 78 | if (is_server_only) play_mode = GAMEKIND_HEADLESS; 79 | 80 | if (zpl_opts_has_arg(&opts, "random-seed")) { 81 | zpl_random rnd={0}; 82 | zpl_random_init(&rnd); 83 | seed = zpl_random_gen_u32(&rnd); 84 | zpl_printf("Seed: %u\n", seed); 85 | } 86 | 87 | if (zpl_opts_has_arg(&opts, "preview-map")) { 88 | generate_minimap(seed, WORLD_BLOCK_SIZE, chunk_size, world_size); 89 | return 0; 90 | } 91 | 92 | sighandler_register(); 93 | game_setup(host, port, play_mode, 1, seed, chunk_size, world_size, is_dash_enabled); 94 | game_run(); 95 | 96 | game_shutdown(); 97 | sighandler_unregister(); 98 | 99 | zpl_string_free(host); 100 | zpl_opts_free(&opts); 101 | return 0; 102 | } 103 | -------------------------------------------------------------------------------- /code/foundation/src/models/assets.c: -------------------------------------------------------------------------------- 1 | #include "models/assets.h" 2 | #include "raylib.h" 3 | #include "gen/texgen.h" 4 | #include "models/database.h" 5 | #include 6 | 7 | //#define ASSETS_COUNT (sizeof(assets)/sizeof(asset)) 8 | 9 | typedef struct { 10 | asset_id id; 11 | asset_kind kind; 12 | 13 | union { 14 | Texture2D tex; 15 | Sound snd; 16 | }; 17 | 18 | // NOTE(zaklaus): metadata 19 | } asset; 20 | 21 | //#include "lists/assets_list.c" 22 | static asset *assets; 23 | 24 | #define ASSETS_COUNT (zpl_array_count(assets)) 25 | 26 | #define ASSET_FRAME_RENDER_MS (1.0/1.0) 27 | #define ASSET_FRAME_SKIP 4 28 | static int64_t assets_frame_counter = 1; 29 | static double assets_frame_next_draw = 0.0; 30 | 31 | #include 32 | 33 | static uint16_t asset_counter; 34 | 35 | void assets_new(const char *name) { 36 | assert(asset_counter < MAX_ASSETS); 37 | db_exec(zpl_bprintf("INSERT INTO assets (id, name) VALUES (%d, '%s');", asset_counter++, name)); 38 | } 39 | 40 | void assets_db_init(void) { 41 | for (uint16_t i=0; ikind) { 65 | case AKIND_TEXTURE: { 66 | b->tex = texgen_build_sprite(b->id); 67 | }break; 68 | 69 | case AKIND_ANIM: { 70 | b->tex = texgen_build_anim(b->id, 0); 71 | }break; 72 | 73 | case AKIND_SOUND: { 74 | // TODO(zaklaus): soundgen 75 | }break; 76 | 77 | default: break; 78 | } 79 | } 80 | assets_frame_next_draw = get_cached_time() + ASSET_FRAME_RENDER_MS; 81 | return 0; 82 | } 83 | 84 | int32_t assets_frame(void) { 85 | if (assets_frame_next_draw < get_cached_time()) { 86 | for (uint32_t i=0; ikind) { 90 | case AKIND_ANIM: { 91 | UnloadTexture(b->tex); 92 | b->tex = texgen_build_anim(b->id, assets_frame_counter); 93 | }break; 94 | 95 | default: break; 96 | } 97 | } 98 | 99 | assets_frame_next_draw = get_cached_time() + ASSET_FRAME_RENDER_MS; 100 | assets_frame_counter += ASSET_FRAME_SKIP; 101 | } 102 | 103 | return 0; 104 | } 105 | 106 | void assets_destroy(void) { 107 | for (uint32_t i=0; ienergy_level = 69.0f; 23 | producer->pending_task = PRODUCER_CRAFT_AUTO; 24 | producer->push_filter = PRODUCER_PUSH_PRODUCT; 25 | producer->target_item = ASSET_INVALID; 26 | 27 | ecs_set(world_ecs(), e, ItemRouter, {.push_qty = 1, .counter = 0}); 28 | return (uint64_t)e; 29 | } 30 | 31 | //------------------------------------------------------------------------ 32 | 33 | uint64_t blueprint_spawn(uint8_t w, uint8_t h, const asset_id *plan) { 34 | ZPL_ASSERT((w*h) < 256); 35 | ecs_entity_t e = device_spawn(ASSET_BLUEPRINT); 36 | 37 | Blueprint *blueprint = ecs_get_mut(world_ecs(), e, Blueprint); 38 | blueprint->w = w; 39 | blueprint->h = h; 40 | zpl_memcopy(blueprint->plan, plan, w*h*sizeof(asset_id)); 41 | 42 | return (uint64_t)e; 43 | } 44 | 45 | uint64_t blueprint_spawn_udata(void* udata) { 46 | item_desc *it = (item_desc*)udata; 47 | return blueprint_spawn(it->blueprint.w, it->blueprint.h, it->blueprint.plan); 48 | } 49 | 50 | //------------------------------------------------------------------------ 51 | 52 | uint64_t craftbench_spawn(void) { 53 | ecs_entity_t e = device_spawn(ASSET_CRAFTBENCH); 54 | 55 | ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer); 56 | *storage = (ItemContainer){0}; 57 | 58 | Producer *producer = ecs_get_mut(world_ecs(), e, Producer); 59 | *producer = (Producer){0}; 60 | producer->energy_level = 69.0f; 61 | producer->pending_task = PRODUCER_CRAFT_WAITING; 62 | producer->push_filter = PRODUCER_PUSH_NONE; 63 | return (uint64_t)e; 64 | } 65 | 66 | //------------------------------------------------------------------------ 67 | 68 | uint64_t creature_spawn(void) { 69 | ecs_entity_t e = entity_spawn(EKIND_DEMO_NPC); 70 | 71 | Creature *c = ecs_get_mut(world_ecs(), e, Creature); 72 | c->hunger_satisfied = 0; 73 | c->mating_satisfied = rand() % 1800; 74 | c->life_remaining = 500 + rand() % 5200; 75 | 76 | return (uint64_t)e; 77 | } 78 | 79 | //------------------------------------------------------------------------ 80 | 81 | uint64_t furnace_spawn(void) { 82 | ecs_entity_t e = device_spawn(ASSET_FURNACE); 83 | 84 | ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer); 85 | *storage = (ItemContainer){0}; 86 | 87 | Producer *producer = ecs_get_mut(world_ecs(), e, Producer); 88 | *producer = (Producer){0}; 89 | producer->energy_level = 69.0f; 90 | producer->pending_task = PRODUCER_CRAFT_AUTO; 91 | producer->push_filter = PRODUCER_PUSH_ANY; 92 | 93 | ecs_set(world_ecs(), e, ItemRouter, {.push_qty = 1, .counter = 0}); 94 | return (uint64_t)e; 95 | } 96 | 97 | //------------------------------------------------------------------------ 98 | 99 | uint64_t splitter_spawn(void) { 100 | ecs_entity_t e = device_spawn(ASSET_SPLITTER); 101 | 102 | ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer); 103 | *storage = (ItemContainer){0}; 104 | 105 | ecs_set(world_ecs(), e, ItemRouter, {.push_qty = 1, .counter = 0}); 106 | return (uint64_t)e; 107 | } 108 | 109 | //------------------------------------------------------------------------ 110 | 111 | uint64_t storage_spawn(void) { 112 | ecs_entity_t e = device_spawn(ASSET_CHEST); 113 | 114 | ItemContainer *storage = ecs_get_mut(world_ecs(), e, ItemContainer); 115 | *storage = (ItemContainer){0}; 116 | return (uint64_t)e; 117 | } 118 | 119 | //------------------------------------------------------------------------ 120 | 121 | -------------------------------------------------------------------------------- /code/foundation/src/platform/input.c: -------------------------------------------------------------------------------- 1 | #include "input.h" 2 | #include "raylib.h" 3 | 4 | static const input_map maps[] = { 5 | { 6 | "left", 7 | IN_LEFT, 8 | (input_bind[]){ 9 | {DEV_KEYBOARD, KEY_LEFT}, 10 | {DEV_KEYBOARD, KEY_A}, 11 | {0} 12 | } 13 | }, 14 | { 15 | "right", 16 | IN_RIGHT, 17 | (input_bind[]){ 18 | {DEV_KEYBOARD, KEY_RIGHT}, 19 | {DEV_KEYBOARD, KEY_D}, 20 | {0} 21 | } 22 | }, 23 | { 24 | "up", 25 | IN_UP, 26 | (input_bind[]){ 27 | {DEV_KEYBOARD, KEY_UP}, 28 | {DEV_KEYBOARD, KEY_W}, 29 | {0} 30 | } 31 | }, 32 | { 33 | "down", 34 | IN_DOWN, 35 | (input_bind[]){ 36 | {DEV_KEYBOARD, KEY_DOWN}, 37 | {DEV_KEYBOARD, KEY_S}, 38 | {0} 39 | } 40 | }, 41 | { 42 | "use", 43 | IN_USE, 44 | (input_bind[]){ 45 | {DEV_KEYBOARD, KEY_SPACE}, 46 | {0} 47 | } 48 | }, 49 | { 50 | "sprint", 51 | IN_SPRINT, 52 | (input_bind[]){ 53 | {DEV_KEYBOARD, KEY_LEFT_SHIFT}, 54 | {DEV_KEYBOARD, KEY_RIGHT_SHIFT}, 55 | {0} 56 | } 57 | }, 58 | { 59 | "drop", 60 | IN_DROP, 61 | (input_bind[]){ 62 | {DEV_KEYBOARD, KEY_G}, 63 | {0} 64 | } 65 | }, 66 | { 67 | "ctrl", 68 | IN_CTRL, 69 | (input_bind[]){ 70 | {DEV_KEYBOARD, KEY_LEFT_CONTROL}, 71 | {DEV_KEYBOARD, KEY_RIGHT_CONTROL}, 72 | {0} 73 | } 74 | }, 75 | { 76 | "toggle inventory", 77 | IN_TOGGLE_INV, 78 | (input_bind[]){ 79 | {DEV_KEYBOARD, KEY_TAB}, 80 | {0} 81 | } 82 | }, 83 | { 84 | "toggle build", 85 | IN_TOGGLE_DEMOLITION, 86 | (input_bind[]){ 87 | {DEV_KEYBOARD, KEY_B}, 88 | {0} 89 | } 90 | }, 91 | {0} 92 | }; 93 | 94 | input_map input__get_map(uint8_t action) { 95 | for (const input_map *map = maps; map->action > 0; ++map) { 96 | if (map->action == action) { 97 | return *map; 98 | } 99 | } 100 | 101 | ZPL_PANIC("key not bound!"); 102 | return maps[0]; 103 | } 104 | 105 | uint8_t input_is_down(uint8_t action) { 106 | input_map map = input__get_map(action); 107 | for (input_bind *bind = map.binds; bind->device > 0; ++bind) { 108 | switch (bind->device) { 109 | case DEV_KEYBOARD: { 110 | if (IsKeyDown(bind->id)) return 1; 111 | }break; 112 | case DEV_MOUSE: { 113 | if (IsMouseButtonDown(bind->id)) return 1; 114 | }break; 115 | case DEV_JOYSTICK: { 116 | // TODO(zaklaus): 117 | }break; 118 | } 119 | } 120 | 121 | return 0; 122 | } 123 | 124 | uint8_t input_is_pressed(uint8_t action) { 125 | input_map map = input__get_map(action); 126 | for (input_bind *bind = map.binds; bind->device > 0; ++bind) { 127 | switch (bind->device) { 128 | case DEV_KEYBOARD: { 129 | if (IsKeyPressed(bind->id)) return 1; 130 | }break; 131 | case DEV_MOUSE: { 132 | if (IsMouseButtonPressed(bind->id)) return 1; 133 | }break; 134 | case DEV_JOYSTICK: { 135 | // TODO(zaklaus): 136 | }break; 137 | } 138 | } 139 | 140 | return 0; 141 | } 142 | 143 | uint8_t input_is_released(uint8_t action) { 144 | input_map map = input__get_map(action); 145 | for (input_bind *bind = map.binds; bind->device > 0; ++bind) { 146 | switch (bind->device) { 147 | case DEV_KEYBOARD: { 148 | if (IsKeyReleased(bind->id)) return 1; 149 | }break; 150 | case DEV_MOUSE: { 151 | if (IsMouseButtonReleased(bind->id)) return 1; 152 | }break; 153 | case DEV_JOYSTICK: { 154 | // TODO(zaklaus): 155 | }break; 156 | } 157 | } 158 | 159 | return 0; 160 | } 161 | -------------------------------------------------------------------------------- /code/foundation/src/packets/pkt_send_keystate.c: -------------------------------------------------------------------------------- 1 | #include "pkt/packet_utils.h" 2 | #include "net/network.h" 3 | #include "packets/pkt_send_keystate.h" 4 | #include "models/components.h" 5 | #include "systems/systems.h" 6 | #include "world/world.h" 7 | #include "models/entity.h" 8 | 9 | #include "dev/debug_replay.h" 10 | 11 | pkt_desc pkt_send_keystate_desc[] = { 12 | { PKT_REAL(pkt_send_keystate, x) }, 13 | { PKT_REAL(pkt_send_keystate, y) }, 14 | { PKT_REAL(pkt_send_keystate, mx) }, 15 | { PKT_REAL(pkt_send_keystate, my) }, 16 | { PKT_UINT(pkt_send_keystate, use) }, 17 | { PKT_UINT(pkt_send_keystate, sprint) }, 18 | { PKT_UINT(pkt_send_keystate, ctrl) }, 19 | { PKT_UINT(pkt_send_keystate, pick) }, 20 | { PKT_UINT(pkt_send_keystate, storage_action) }, 21 | { PKT_UINT(pkt_send_keystate, selected_item) }, 22 | { PKT_UINT(pkt_send_keystate, storage_selected_item) }, 23 | { PKT_UINT(pkt_send_keystate, drop) }, 24 | { PKT_UINT(pkt_send_keystate, swap) }, 25 | { PKT_UINT(pkt_send_keystate, swap_storage) }, 26 | { PKT_UINT(pkt_send_keystate, swap_from) }, 27 | { PKT_UINT(pkt_send_keystate, swap_to) }, 28 | { PKT_UINT(pkt_send_keystate, craft_item) }, 29 | { PKT_UINT(pkt_send_keystate, placement_num) }, 30 | { PKT_UINT(pkt_send_keystate, deletion_mode) }, 31 | { PKT_ARRAY(pkt_send_keystate, placements) }, 32 | { PKT_END }, 33 | }; 34 | 35 | pkt_desc pkt_send_blockpos_desc[] = { 36 | { PKT_REAL(pkt_send_blockpos, mx) }, 37 | { PKT_REAL(pkt_send_blockpos, my) }, 38 | { PKT_END }, 39 | }; 40 | 41 | size_t pkt_send_keystate_send(uint16_t view_id, 42 | game_keystate_data *data) { 43 | return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_table_encode(pkt_send_keystate_desc, PKT_STRUCT_PTR(data)), 1, view_id, NULL, 1); 44 | } 45 | 46 | size_t pkt_send_blockpos_send(uint16_t view_id, 47 | pkt_send_blockpos *data){ 48 | return pkt_world_write(MSG_ID_SEND_BLOCKPOS, pkt_table_encode(pkt_send_blockpos_desc, PKT_STRUCT_PTR(data)), 1, view_id, NULL, 1); 49 | 50 | } 51 | 52 | int32_t pkt_send_keystate_handler(pkt_header *header) { 53 | pkt_send_keystate table; 54 | PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table))); 55 | ecs_entity_t e = network_server_get_entity(header->udata, header->view_id); 56 | 57 | if (!world_entity_valid(e)) 58 | return 1; 59 | 60 | Input *i = ecs_get_mut(world_ecs(), e, Input); 61 | if (i && !i->is_blocked) { 62 | i->x = zpl_clamp(table.x, -1.0f, 1.0f); 63 | i->y = zpl_clamp(table.y, -1.0f, 1.0f); 64 | i->mx = table.mx; 65 | i->my = table.my; 66 | if (i->x != 0.0f || i->y != 0.0f) { 67 | i->hx = i->x; 68 | i->hy = i->y; 69 | } 70 | i->use |= table.use; 71 | i->sprint = table.sprint; 72 | i->ctrl = table.ctrl; 73 | i->pick |= table.pick; 74 | i->selected_item = zpl_clamp(table.selected_item, 0, ITEMS_CONTAINER_SIZE-1); 75 | i->storage_selected_item = zpl_clamp(table.storage_selected_item, 0, ITEMS_CONTAINER_SIZE-1); 76 | i->drop |= table.drop; 77 | i->swap |= table.swap; 78 | i->swap_storage |= table.swap_storage; 79 | i->swap_from = zpl_clamp(table.swap_from, 0, ITEMS_CONTAINER_SIZE-1); 80 | i->swap_to = zpl_clamp(table.swap_to, 0, ITEMS_CONTAINER_SIZE-1); 81 | i->craft_item = table.craft_item; 82 | i->storage_action = table.storage_action; 83 | i->deletion_mode = table.deletion_mode; 84 | if (table.placement_num > 0) { 85 | i->num_placements = zpl_clamp(table.placement_num, 0, BUILD_MAX_PLACEMENTS); 86 | for (uint8_t j = 0; j < i->num_placements; j++) { 87 | i->placements_x[j] = table.placements[j].x; 88 | i->placements_y[j] = table.placements[j].y; 89 | } 90 | } 91 | debug_replay_record_keystate(table); 92 | entity_wake(e); 93 | } 94 | 95 | return 0; 96 | } 97 | 98 | int32_t pkt_send_blockpos_handler(pkt_header *header) { 99 | pkt_send_blockpos table; 100 | PKT_IF(pkt_msg_decode(header, pkt_send_blockpos_desc, pkt_pack_desc_args(pkt_send_blockpos_desc), PKT_STRUCT_PTR(&table))); 101 | ecs_entity_t e = network_server_get_entity(header->udata, header->view_id); 102 | 103 | if (!world_entity_valid(e)) 104 | return 1; 105 | 106 | Input *i = ecs_get_mut(world_ecs(), e, Input); 107 | if (i && !i->is_blocked) { 108 | i->bx = table.mx; 109 | i->by = table.my; 110 | } 111 | 112 | return 0; 113 | } 114 | -------------------------------------------------------------------------------- /code/games/survival/src/platform.c: -------------------------------------------------------------------------------- 1 | #include "platform/platform.h" 2 | #include "raylib.h" 3 | #include "raymath.h" 4 | #include "net/network.h" 5 | #include "core/game.h" 6 | #include "world/entity_view.h" 7 | #include "world/prediction.h" 8 | #include "core/camera.h" 9 | #include "math.h" 10 | #include "world/blocks.h" 11 | #include "models/assets.h" 12 | #include "platform/profiler.h" 13 | #include "dev/debug_draw.h" 14 | #include "dev/debug_ui.h" 15 | #include "utils/raylib_helpers.h" 16 | #include "platform/renderer.h" 17 | 18 | ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(0) 19 | #include "raylib-nuklear.h" 20 | ZPL_DIAGNOSTIC_POP 21 | 22 | #define ARCH_IMPL 23 | #include "platform/arch.h" 24 | 25 | 26 | // NOTE(zaklaus): add-ins 27 | #include "gui/ui_skin.c" 28 | #include "gui/tooltip.c" 29 | #include "gui/notifications.c" 30 | #include "gui/spritesheet_viewer.c" 31 | 32 | #include "renderer.c" 33 | 34 | void platform_init() { 35 | platform_create_window("horde survival game"); 36 | renderer_init(); 37 | } 38 | 39 | void platform_shutdown() { 40 | renderer_shutdown(); 41 | CloseWindow(); 42 | } 43 | 44 | void platform_input() { 45 | float mouse_z = (GetMouseWheelMove()*0.5f); 46 | float mouse_modified = target_zoom < 4 ? mouse_z / (zpl_exp(4 - (target_zoom))) : mouse_z; 47 | 48 | if (mouse_z != 0.0f) { 49 | target_zoom = zpl_clamp(target_zoom + mouse_modified, 0.1f, 11.0f); 50 | } 51 | 52 | 53 | // NOTE(zaklaus): keystate handling 54 | { 55 | float x=0.0f, y=0.0f; 56 | uint8_t use, sprint, ctrl; 57 | if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) x += 1.0f; 58 | if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f; 59 | if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f; 60 | if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) y -= 1.0f; 61 | 62 | use = IsKeyPressed(KEY_SPACE); 63 | sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT); 64 | ctrl = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL); 65 | 66 | // NOTE(zaklaus): NEW! mouse movement 67 | Vector2 mouse_pos = GetMousePosition(); 68 | mouse_pos.x /= screenWidth; 69 | mouse_pos.y /= screenHeight; 70 | mouse_pos.x -= 0.5f; 71 | mouse_pos.y -= 0.5f; 72 | mouse_pos = Vector2Normalize(mouse_pos); 73 | 74 | if (game_get_kind() == GAMEKIND_SINGLE && IsMouseButtonDown(MOUSE_MIDDLE_BUTTON)) { 75 | x = mouse_pos.x; 76 | y = -mouse_pos.y; 77 | } 78 | 79 | game_keystate_data in_data = { 80 | .x = x, 81 | .y = y, 82 | .mx = mouse_pos.x, 83 | .my = mouse_pos.y, 84 | .use = use, 85 | .sprint = sprint, 86 | .ctrl = ctrl, 87 | }; 88 | 89 | platform_input_update_input_frame(in_data); 90 | } 91 | } 92 | 93 | void recalc_max_mobs(); 94 | extern uint64_t mob_kills; 95 | 96 | void platform_render() { 97 | platform_resize_window(); 98 | 99 | profile(PROF_ENTITY_LERP) { 100 | game_world_view_active_entity_map(lerp_entity_positions); 101 | game_world_view_active_entity_map(do_entity_fadeinout); 102 | } 103 | 104 | assets_frame(); 105 | 106 | BeginDrawing(); 107 | { 108 | profile (PROF_RENDER) { 109 | renderer_draw(); 110 | } 111 | renderer_debug_draw(); 112 | 113 | debug_draw(); 114 | 115 | #if defined(_DEBUG) 116 | if (nk_begin(game_ui, "Spritesheet Viewer", nk_rect(460, 100, 800, 600), 117 | NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|NK_WINDOW_TITLE)) 118 | { 119 | spritesheet_viewer(game_ui, main_sprite_sheet_nk, main_sprite_sheet.frameSize, main_sprite_sheet.framesPerRow); 120 | nk_end(game_ui); 121 | } 122 | 123 | 124 | notification_draw(); 125 | 126 | if (nk_begin(game_ui, "Debug stuff", nk_rect(400, 10, 220, 140), 127 | NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|NK_WINDOW_TITLE)) 128 | { 129 | nk_layout_row_dynamic(game_ui, 0, 1); 130 | if (nk_button_label(game_ui, "max_mobs hack")) { 131 | mob_kills = 2000; 132 | recalc_max_mobs(); 133 | } 134 | if (nk_button_label(game_ui, "big hp")) { 135 | ecs_entity_t plr = camera_get().ent_id; 136 | Health *hp = ecs_get_mut(world_ecs(), plr, Health); 137 | hp->hp = hp->max_hp = 999999; 138 | } 139 | nk_end(game_ui); 140 | } 141 | #endif 142 | 143 | game_draw_ui(); 144 | } 145 | EndDrawing(); 146 | 147 | if (request_shutdown) { 148 | CloseWindow(); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | eco2d 3 |

4 | 5 |
6 | 7 |
8 | discord 9 | play 10 |
11 | 12 |
13 |
14 | Small C99 2D game engine with a focus on prototyping. 15 |
16 | 17 |
18 | 19 | Brought to you by @zpl-zak, 20 | @inlife 21 | and contributors 22 | 23 |
24 | 25 | # Introduction 26 | eco2d is a experimental set of games made out of curiosity. It attempts to bridge several libraries to create a playable sandbox with ease of extensibility and with performance in mind. The goal is not to make a generic 2D game engine but to build a game prototype that anyone can use to build various experiments. 27 | 28 | The game runs on top of [raylib](https://raylib.com/) technologies and makes use of the [zpl](https://zpl.pw/) ecosystem alongside the **cwpack** library for data serialization. The game logic and lifecycle are maintained using [flecs](https://github.com/SanderMertens/flecs/) library and its suite of tools that help us improve the development efficiency. 29 | 30 | It was built with networked game sessions in mind from the ground up and therefore provided two significant ways to play the game: 31 | * Networked game (UDP) - networked sessions benefit from the use of [enet](https://github.com/zpl-c/enet/) library. 32 | * Local Only sessions - Data is streamed via local buffers. 33 | 34 | In both cases, the game engine does not differentiate between these two options and makes the concept of Server<>client infrastructure entirely abstract. As a result, gameplay logic is only tied to living entities, where the entity might represent a networked client / local controller. 35 | 36 | All data is transferred via packets fully automated by our serialization rule system, which uses the **cwpack** library in the background. 37 | 38 | Data is streamed in or out using the [librg](https://github.com/zpl-c/librg/) library, thanks to which all clients only receive data relevant to their location. 39 | 40 | On top of that, the game client can also spin up multiple client heads and cycle between them, which allows us to easily debug new features locally without having to start the Server physically. 41 | 42 | In the abstract sense, we call the Server the game master hosting all gameplay rules and features, while the Client represents a terminal sending key inputs and receiving data to render. 43 | 44 | ## Major things to do 45 | * More believable world generation. 46 | * Improved rendering - the current world structure does not allow for layered blocks, but it's something worth looking into. 47 | * UI and visual effects 48 | 49 | # Media 50 | ![image](https://user-images.githubusercontent.com/9026786/127201607-936241ee-762e-4630-b52f-e75ae72c3ed3.png) 51 | ![image](https://user-images.githubusercontent.com/9026786/127201653-f0ca5626-24a9-4294-98ac-1a62aff0e1e5.png) 52 | 53 | # Build the project 54 | We use CMake to generate project files and manage builds. 55 | 56 | ## Web 57 | We have a set of scripts ready for web development, these steps will get you up and running with a web build: 58 | ```sh 59 | # Setup emsdk locally and configure a web project 60 | web/setup.sh 61 | 62 | # Build the web project 63 | web/build.sh 64 | 65 | # Host the files on a web server (Python3) 66 | web/host.sh 67 | ``` 68 | 69 | ## Desktop 70 | ### Pre-requisites 71 | #### Linux 72 | Follow [raylib-linux](https://github.com/raysan5/raylib/wiki/Working-on-GNU-Linux) guide to install dependencies on your system. 73 | 74 | #### macOS 75 | Follow [raylib-macos](https://github.com/raysan5/raylib/wiki/Working-on-macOS) guide to install dependencies on your system. 76 | #### Windows 77 | You need to have Visual Studio 2019+ installed on your system. Make sure to run the commands below in a VS Developer Command Prompt. 78 | ### Build 79 | You can do the following on the command line to create and build this project: 80 | ```sh 81 | git clone https://github.com/zpl-c/eco2d.git 82 | cd eco2d 83 | cmake -S . -B build 84 | cmake --build build 85 | ``` 86 | 87 | Run the following command to see all the options: 88 | ```sh 89 | build\eco2d.exe -? 90 | ``` 91 | 92 | # License 93 | eco2d code is licensed under the BSD 3-Clause license, as seen [here](LICENSE). 94 | 95 | Assets under the **art** folder are released into [Public Domain](https://creativecommons.org/share-your-work/public-domain/cc0/) unless otherwise stated. 96 | 97 | Third-party vendors are licensed according to their respective authors. 98 | -------------------------------------------------------------------------------- /code/foundation/src/world/worldgen_utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "platform/system.h" 3 | #include "world/blocks.h" 4 | #include "world/world.h" 5 | #include "world/perlin.h" 6 | 7 | static world_data *world; 8 | 9 | #define WORLD_BLOCK_OBSERVER(name) block_id name(block_id *data, block_id id, uint32_t block_idx) 10 | typedef WORLD_BLOCK_OBSERVER(world_block_observer_proc); 11 | 12 | #ifndef WORLD_CUSTOM_PERLIN 13 | #define WORLD_PERLIN_FREQ 100 14 | #define WORLD_PERLIN_OCTAVES 1 15 | #endif 16 | 17 | #define BLOCK_INVALID 0xF 18 | 19 | // ensure it is set in worldgen_build 20 | 21 | int worldgen_in_circle(int x, int y, int radius) { 22 | return (zpl_pow((float)x, 2.0f) + zpl_pow((float)y, 2.0f)) < zpl_pow((float)radius, 2.0f); 23 | } 24 | 25 | static void world_fill_rect(block_id *data, block_id id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, world_block_observer_proc *proc) { 26 | for (uint32_t cy=y; cy= world->dim) continue; 29 | if (cy >= world->dim) continue; 30 | uint32_t i = (cy*world->dim) + cx; 31 | 32 | if (proc) { 33 | block_id new_id = (*proc)(data, id, i); 34 | if (new_id != BLOCK_INVALID) { 35 | id = new_id; 36 | } 37 | else continue; 38 | } 39 | 40 | data[i] = id; 41 | } 42 | } 43 | } 44 | 45 | static void world_fill_circle(block_id *data, block_id id, uint32_t cx, uint32_t cy, uint32_t radius, world_block_observer_proc *proc) { 46 | for (int x = -(int32_t)(radius); x < (int32_t)radius; ++x) { 47 | for (int y = -(int32_t)(radius); y < (int32_t)radius; ++y) { 48 | if (worldgen_in_circle(x, y, radius)) { 49 | int fx = x + cx; 50 | int fy = y + cy; 51 | 52 | uint32_t i = (fy*world->dim) + fx; 53 | 54 | if (proc) { 55 | block_id new_id = (*proc)(data, id, i); 56 | if (new_id != BLOCK_INVALID) { 57 | id = new_id; 58 | } 59 | else continue; 60 | } 61 | 62 | data[i] = id; 63 | } 64 | } 65 | } 66 | } 67 | 68 | static void world_fill_rect_anchor(block_id *data, block_id id, uint32_t x, uint32_t y, uint32_t w, uint32_t h, float ax, float ay, world_block_observer_proc *proc) { 69 | uint32_t w2 = (uint32_t)floorf(w*ax); 70 | uint32_t h2 = (uint32_t)floorf(h*ay); 71 | world_fill_rect(data, id, x-w2, y-h2, w, h, proc); 72 | } 73 | 74 | 75 | static block_id world_perlin_cond_offset(uint32_t block_idx, double chance, uint32_t ofx, uint32_t ofy) { 76 | uint32_t x = block_idx % world->dim + ofx; 77 | uint32_t y = block_idx / world->dim + ofy; 78 | 79 | return perlin_fbm(world->seed, x, y, WORLD_PERLIN_FREQ, WORLD_PERLIN_OCTAVES) < chance; 80 | } 81 | 82 | #ifndef WORLD_CUSTOM_SHAPER 83 | static WORLD_BLOCK_OBSERVER(shaper) { 84 | uint32_t kind = id; 85 | 86 | return id; 87 | } 88 | #endif 89 | 90 | static block_id world_perlin_cond(uint32_t block_idx, double chance) { 91 | return world_perlin_cond_offset(block_idx, chance, 0, 0); 92 | } 93 | 94 | #if 1 95 | static WORLD_BLOCK_OBSERVER(shaper_noise80) { 96 | return world_perlin_cond(block_idx, 0.80) ? shaper(data, id, block_idx) : BLOCK_INVALID; 97 | } 98 | 99 | static WORLD_BLOCK_OBSERVER(shaper_noise50) { 100 | return world_perlin_cond(block_idx, 0.50) ? shaper(data, id, block_idx) : BLOCK_INVALID; 101 | } 102 | 103 | static WORLD_BLOCK_OBSERVER(shaper_noise33) { 104 | return world_perlin_cond(block_idx, 0.33) ? shaper(data, id, block_idx) : BLOCK_INVALID; 105 | } 106 | 107 | static WORLD_BLOCK_OBSERVER(shaper_noise05) { 108 | return world_perlin_cond(block_idx, 0.05) ? shaper(data, id, block_idx) : BLOCK_INVALID; 109 | } 110 | 111 | static WORLD_BLOCK_OBSERVER(shaper_noise05b) { 112 | return world_perlin_cond_offset(block_idx, 0.05, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID; 113 | } 114 | 115 | static WORLD_BLOCK_OBSERVER(shaper_noise01b) { 116 | return world_perlin_cond_offset(block_idx, 0.01, 32, 0) ? shaper(data, id, block_idx) : BLOCK_INVALID; 117 | } 118 | #else 119 | static WORLD_BLOCK_OBSERVER(shaper_noise80) { 120 | return rand()%10 < 8 ? shaper(id, block_idx) : BLOCK_INVALID; 121 | } 122 | 123 | static WORLD_BLOCK_OBSERVER(shaper_noise50) { 124 | return rand()%10 < 5 ? shaper(id, block_idx) : BLOCK_INVALID; 125 | } 126 | 127 | static WORLD_BLOCK_OBSERVER(shaper_noise33) { 128 | return rand()%10 < 3 ? shaper(id, block_idx) : BLOCK_INVALID; 129 | } 130 | #endif 131 | 132 | 133 | #define RAND_RANGE(x,y) (x + (int)rand()%(y-(x))) 134 | #define RAND_RANGEF(x,y) ((float)RAND_RANGE(x,y)) 135 | --------------------------------------------------------------------------------