ecs: rework crafting to tick-based process

efd/v1
Dominik Madarász 2023-01-14 10:24:57 +01:00
parent e15cdab4ff
commit f0ccac8e0c
19 changed files with 6252 additions and 6167 deletions

11
CMakePresets.json 100644
View File

@ -0,0 +1,11 @@
{
"version": 2,
"buildPresets": [
{
"name": "vs2022-debug",
"displayName": "Visual Studio Community 2022 Release - x86_amd64 - Debug",
"configurePreset": "vs2022",
"configuration": "Debug"
}
]
}

View File

@ -1,20 +1,20 @@
find_package(raylib 3.5 QUIET)
if (NOT raylib_FOUND)
include(FetchContent)
FetchContent_Declare(
raylib
URL https://github.com/zpl-c/raylib/archive/master.tar.gz
)
FetchContent_GetProperties(raylib)
if (NOT raylib_POPULATED)
set(FETCHCONTENT_QUIET NO)
FetchContent_Populate(raylib)
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR})
endif()
endif()
find_package(raylib 3.5 QUIET)
if (NOT raylib_FOUND)
include(FetchContent)
FetchContent_Declare(
raylib
URL https://github.com/zpl-c/raylib/archive/master.tar.gz
)
FetchContent_GetProperties(raylib)
if (NOT raylib_POPULATED)
set(FETCHCONTENT_QUIET NO)
FetchContent_Populate(raylib)
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(${raylib_SOURCE_DIR} ${raylib_BINARY_DIR})
endif()
endif()

View File

@ -7,6 +7,7 @@ add_library(eco2d-foundation STATIC
src/platform/signal_handling.c
src/platform/profiler.c
src/platform/input.c
src/models/assets.c
src/models/components.c

View File

@ -5,7 +5,6 @@ typedef struct {
float phy_walk_drag;
uint64_t demo_npc_move_speed;
uint64_t demo_npc_steer_speed;
float furnace_cook_time;
float item_pick_radius;
float item_merger_radius;
float item_attract_radius;

View File

@ -4,7 +4,6 @@ game_rulesdef game_rules = {
.phy_walk_drag = 4.23f,
.demo_npc_move_speed = 500,
.demo_npc_steer_speed = 300,
.furnace_cook_time = 1.f,
.item_pick_radius = 25.0f,
.item_merger_radius = 75.0f,
.item_attract_radius = 75.0f,

View File

@ -27,26 +27,26 @@ void buildmode_draw(void) {
platform_get_block_realpos(&mx, &my);
cam.x = (double)mx;
cam.y = (double)my;
renderer_draw_single((float)cam.x, (float)cam.y, ASSET_BLOCK_FRAME, WHITE);
// NOTE(zaklaus): Check distance
double dx = old_cam.x - cam.x;
double dy = old_cam.y - cam.y;
double dsq = (dx*dx + dy*dy);
bool is_outside_range = (dsq > zpl_square(WORLD_BLOCK_SIZE*14));
if (build_submit_placements) {
build_submit_placements = false;
buildmode_clear_buffers();
}
if (IsKeyPressed(KEY_B)){
if (input_is_pressed(IN_TOGGLE_DEMOLITION)){
build_is_deletion_mode = !build_is_deletion_mode;
}
Item *item = &e->items[e->selected_item];
if (e->has_items && !e->inside_vehicle && (build_is_deletion_mode || (item->quantity > 0 && !is_outside_range))) {
item_usage usage = 0;
uint16_t item_id = 0;
@ -60,21 +60,21 @@ void buildmode_draw(void) {
build_num_placements = 0;
buildmode_clear_buffers();
}
uint32_t qty = BUILD_MAX_PLACEMENTS;
bool directional = false;
if (!build_is_deletion_mode){
directional = item_get_place_directional(item_id);
qty = item->quantity;
}
world_view_block_lookup l = world_view_block_from_realpos(game_world_view_get_active(), (float)cam.x, (float)cam.y);
if (build_is_deletion_mode && !l.is_outer){
renderer_draw_single((float)cam.x, (float)cam.y, ASSET_BUILDMODE_HIGHLIGHT, ColorAlpha(RED, 0.4f));
goto build_skip_placements;
}
if (build_is_in_draw_mode) {
for (size_t i = 0; i < BUILD_MAX_PLACEMENTS; i++) {
item_placement *it = &build_placements[i];
@ -90,7 +90,7 @@ void buildmode_draw(void) {
float sy = zpl_sign0(p2y-p1y);
float sxx = zpl_sign0(p3x-p1x);
float syy = zpl_sign0(p3y-p1y);
if (sx != sxx || sy != syy) break;
}
it->x = (float)cam.x;
@ -103,35 +103,35 @@ void buildmode_draw(void) {
}
}
}
if (!is_outside_range) {
if (build_is_deletion_mode)
renderer_draw_single((float)cam.x, (float)cam.y, ASSET_BUILDMODE_HIGHLIGHT, ColorAlpha(RED, 0.2f));
else
renderer_draw_single((float)cam.x, (float)cam.y, item->kind, ColorAlpha(WHITE, 0.2f));
}
build_skip_placements:
build_num_placements = zpl_min(build_num_placements, qty);
}
}
for (size_t i = 0; i < build_num_placements; i++) {
item_placement *it = &build_placements[i];
renderer_draw_single(it->x, it->y, !build_is_deletion_mode ? item->kind : ASSET_BUILDMODE_HIGHLIGHT, ColorAlpha(build_is_deletion_mode ? RED : RAYWHITE, 0.6f));
}
if (build_is_in_draw_mode) {
if (IsKeyPressed(KEY_SPACE)) {
build_is_in_draw_mode = false;
buildmode_clear_buffers();
}
if (IsMouseButtonReleased(MOUSE_RIGHT_BUTTON)) {
build_submit_placements = true;
build_is_in_draw_mode = false;
}
}
}

View File

@ -251,7 +251,7 @@ void inventory_draw() {
entity_view *e = game_world_view_active_get_entity(cam.ent_id);
if (!e || !e->has_items) return;
if (IsKeyPressed(KEY_TAB)) {
if (input_is_pressed(IN_TOGGLE_INV)) {
inv_is_open = !inv_is_open;
}
@ -264,9 +264,4 @@ void inventory_draw() {
inventory_render_held_item(true);
inventory_render_held_item(false);
// TODO(zaklaus): draw craft list
if (IsKeyPressed(KEY_O)) {
player_inv.craft_item = ASSET_SCREWS;
}
}

View File

@ -6,10 +6,11 @@
.qty = qty1\
}
#define RECIPE(id,prod,qty,...)\
#define RECIPE(id,prod,qty,ticks,...)\
{\
.product = id,\
.product_qty = qty,\
.process_ticks = ticks,\
.producer = prod,\
.reagents = (reagent[]){\
__VA_ARGS__\
@ -18,12 +19,12 @@ __VA_ARGS__\
static recipe recipes[] = {
// NOTE(zaklaus): Belt
RECIPE(ASSET_IRON_PLATES, ASSET_FURNACE, 4, R(ASSET_IRON_ORE, 1), {0}),
RECIPE(ASSET_SCREWS, ASSET_CRAFTBENCH, 8, R(ASSET_IRON_PLATES, 1), {0}),
RECIPE(ASSET_BELT, ASSET_ASSEMBLER, 1, R(ASSET_FENCE, 1), R(ASSET_SCREWS, 4), R(ASSET_IRON_PLATES, 2), {0}),
RECIPE(ASSET_IRON_PLATES, ASSET_FURNACE, 4, 20, R(ASSET_IRON_ORE, 1), {0}),
RECIPE(ASSET_SCREWS, ASSET_CRAFTBENCH, 8, 40, R(ASSET_IRON_PLATES, 1), {0}),
RECIPE(ASSET_BELT, ASSET_ASSEMBLER, 1,120, R(ASSET_FENCE, 1), R(ASSET_SCREWS, 4), R(ASSET_IRON_PLATES, 2), {0}),
};
#define MAX_RECIPES (sizeof(recipes)/sizeof(recipes[0]))
#undef R
#undef RECIPE
#undef RECIPE

View File

@ -11,10 +11,11 @@ static item_desc items[] = {
ITEM_SELF(ASSET_TEST_TALL, 64),
// ITEM_BLUEPRINT(ASSET_BLUEPRINT, 1, 4, 4, "]]]]]CF] ]]]]]"),
ITEM_BLUEPRINT_PROXY(ASSET_BLUEPRINT_DEMO_HOUSE, ASSET_BLUEPRINT, 1, 4, 4, PROT({ ASSET_WOOD,ASSET_WOOD,ASSET_WOOD,ASSET_WOOD,
ASSET_WOOD,ASSET_FURNACE,ASSET_CHEST,ASSET_WOOD,
ASSET_WOOD,ASSET_EMPTY,ASSET_EMPTY,ASSET_WOOD,
ASSET_WOOD,ASSET_WOOD,ASSET_EMPTY,ASSET_WOOD})),
ITEM_BLUEPRINT_PROXY(ASSET_BLUEPRINT_DEMO_HOUSE, ASSET_BLUEPRINT, 1, 4, 4,
PROT({ ASSET_WOOD,ASSET_WOOD,ASSET_WOOD,ASSET_WOOD,
ASSET_WOOD,ASSET_FURNACE,ASSET_CHEST,ASSET_WOOD,
ASSET_WOOD,ASSET_EMPTY,ASSET_EMPTY,ASSET_WOOD,
ASSET_WOOD,ASSET_WOOD,ASSET_EMPTY,ASSET_WOOD})),
ITEM_SELF_DIR(ASSET_BELT, 999),
ITEM_PROXY(ASSET_BELT_LEFT, ASSET_BELT),

View File

@ -147,7 +147,8 @@ typedef struct {
asset_id target_item;
asset_id processed_item;
uint32_t processed_item_qty;
float process_time;
int32_t process_ticks;
int32_t process_ticks_left;
float energy_level;
uint8_t pending_task;
uint8_t push_filter;

View File

@ -9,6 +9,7 @@ typedef struct {
typedef struct {
asset_id product;
uint32_t product_qty;
int32_t process_ticks;
asset_id producer;
reagent *reagents;
} recipe;
@ -60,7 +61,7 @@ asset_id craft_get_recipe_asset(uint16_t id) {
return recipes[id].product;
}
asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id target, uint32_t *quantity) {
asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id target, uint32_t *quantity, int32_t *process_ticks) {
ZPL_ASSERT_NOT_NULL(items);
for (int i = 0; i < ITEMS_CONTAINER_SIZE; i++) {
@ -146,6 +147,7 @@ asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id t
// NOTE(zaklaus): all done, return the product and its qty
*quantity = rec->product_qty;
*process_ticks = rec->process_ticks;
return rec->product;
}
}

View File

@ -7,7 +7,7 @@
// NOTE(zaklaus): resolves recipe dependencies and consumes reagents
// to enqueue a production of a new item.
// TODO(zaklaus): "items" is assumed to come from ItemContainer component.
asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id target, uint32_t *quantity);
asset_id craft_perform_recipe(ecs_entity_t *items, asset_id producer, asset_id target, uint32_t *quantity, int32_t *process_ticks);
// NOTE(zaklaus): mostly used by item router so we don't push reagents out
bool craft_is_reagent_used_in_producer(asset_id reagent, asset_id producer);

View File

@ -25,8 +25,7 @@ void ProduceItems(ecs_iter_t *it) {
// TODO(zaklaus): handle fuel
// if (producer[i].energy_level <= 0.0f) continue;
// TODO(zaklaus): use ticks
if (producer[i].process_time < game_time()) {
if (producer[i].process_ticks_left == 0) {
if (producer[i].processed_item > 0) {
uint64_t e = item_spawn(producer[i].processed_item, producer[i].processed_item_qty);
entity_set_position(e, p[i].x, p[i].y);
@ -36,8 +35,8 @@ void ProduceItems(ecs_iter_t *it) {
producer[i].pending_task = PRODUCER_CRAFT_WAITING;
} else {
if (producer[i].pending_task != PRODUCER_CRAFT_WAITING) {
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_time = game_time() + game_rules.furnace_cook_time;
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);
producer[i].process_ticks_left = producer[i].process_ticks;
if (producer[i].pending_task == PRODUCER_CRAFT_ENQUEUED) {
if (producer[i].processed_item > 0)
@ -47,15 +46,17 @@ void ProduceItems(ecs_iter_t *it) {
}
}
}
}
}
}
d[i].progress_active = (producer[i].processed_item > 0);
d[i].progress_value = 1.0f-((producer[i].process_time - game_time()) / game_rules.furnace_cook_time);
d[i].progress_value = 1.0f-(producer[i].process_ticks_left / (float)producer[i].process_ticks);
if (d[i].progress_active) {
entity_wake(it->entities[i]);
}
producer[i].process_ticks_left = zpl_max(producer[i].process_ticks_left-1, 0) ;
}
}

View File

@ -5,53 +5,55 @@
ZPL_TABLE_DEFINE(entity_view_tbl, entity_view_tbl_, entity_view);
pkt_desc pkt_entity_view_desc[] = {
{ PKT_UINT(entity_view, kind) },
{ PKT_UINT(entity_view, flag) },
{ PKT_HALF(entity_view, x) },
{ PKT_HALF(entity_view, y) },
{ PKT_KEEP_IF(entity_view, blocks_used, 0, 2) }, // NOTE(zaklaus): skip velocity for chunks
{ PKT_HALF(entity_view, vx) },
{ PKT_HALF(entity_view, vy) },
{ PKT_SKIP_IF(entity_view, blocks_used, 0, 3) }, // NOTE(zaklaus): skip blocks for anything else
{ PKT_UINT(entity_view, chk_id) },
{ PKT_ARRAY(entity_view, blocks) },
{ PKT_ARRAY(entity_view, outer_blocks) },
{ PKT_KEEP_IF(entity_view, blocks_used, 0, 2) }, // NOTE(zaklaus): skip hp for chunks
{ PKT_HALF(entity_view, hp) },
{ PKT_HALF(entity_view, max_hp) },
{ PKT_KEEP_IF(entity_view, kind, EKIND_VEHICLE, 1) }, // NOTE(zaklaus): keep for vehicles
{ PKT_HALF(entity_view, heading) },
{ PKT_UINT(entity_view, inside_vehicle) },
{ PKT_UINT(entity_view, veh_kind) },
{ PKT_KEEP_IF(entity_view, kind, EKIND_ITEM, 2) },
{ PKT_UINT(entity_view, asset) },
{ PKT_UINT(entity_view, quantity) },
{ PKT_HALF(entity_view, durability) },
{ PKT_KEEP_IF(entity_view, kind, EKIND_DEVICE, 3) },
{ PKT_UINT(entity_view, asset) },
{ PKT_UINT(entity_view, progress_active) },
{ PKT_UINT(entity_view, is_producer) },
{ PKT_HALF(entity_view, progress_value) },
{ PKT_KEEP_IF(entity_view, has_items, true, 3) },
{ PKT_UINT(entity_view, has_items) },
{ PKT_UINT(entity_view, selected_item) },
{ PKT_ARRAY(entity_view, items) },
{ PKT_UINT(entity_view, pick_ent) },
{ PKT_UINT(entity_view, sel_ent) },
{ PKT_KEEP_IF(entity_view, has_storage_items, true, 3) },
{ PKT_KEEP_IF(entity_view, has_storage_items, true, 4) },
{ PKT_UINT(entity_view, has_storage_items) },
{ PKT_UINT(entity_view, storage_selected_item) },
{ PKT_ARRAY(entity_view, storage_items) },
{ PKT_ARRAY(entity_view, craftables) },
{ PKT_END },
};
@ -65,10 +67,10 @@ size_t entity_view_pack_struct(void *data, size_t len, entity_view *view) {
entity_view entity_view_unpack_struct(void *data, size_t len) {
cw_unpack_context uc = {0};
cw_unpack_context_init(&uc, data, (unsigned long)len, 0);
entity_view view = {0};
pkt_unpack_struct(&uc, pkt_entity_view_desc, PKT_STRUCT_PTR(&view));
return view;
}

View File

@ -6,6 +6,8 @@
#define ZPL_PICO
#include "zpl.h"
#define MAX_CRAFTABLES 32
typedef enum {
EKIND_SERVER = 0,
EKIND_PLAYER,
@ -42,10 +44,10 @@ typedef struct entity_view {
float vy;
float tx;
float ty;
float hp;
float max_hp;
// TODO(zaklaus): Find a way to stream dynamic arrays
uint32_t chk_id;
uint8_t blocks_used;
@ -54,39 +56,43 @@ typedef struct entity_view {
uint32_t color;
uint8_t is_dirty;
int64_t tex;
// NOTE(zaklaus): vehicle
float heading, theading;
bool inside_vehicle;
uint32_t veh_kind;
// NOTE(zaklaus): items, ...
asset_id asset;
uint32_t quantity;
float durability;
// NOTE(zaklaus): device progress bar
bool is_producer;
uint32_t progress_active;
float progress_value;
// NOTE(zaklaus): inventory
uint8_t has_items;
Item items[ITEMS_INVENTORY_SIZE];
uint8_t selected_item;
// NOTE(zaklaus): storage interface
uint8_t has_storage_items;
Item storage_items[ITEMS_CONTAINER_SIZE];
uint8_t storage_selected_item;
// NOTE(zaklaus): craftable recipes
uint8_t craftables[MAX_CRAFTABLES];
// NOTE(zaklaus): entity picking
uint64_t pick_ent;
uint64_t sel_ent;
// NOTE(zaklaus): internals
uint8_t layer_id;
uint64_t last_update;
// NOTE(zaklaus): fade in-out effect
entity_transition_effect tran_effect;
float tran_time;

View File

@ -71,6 +71,7 @@ entity_view *world_build_entity_view(int64_t e) {
view.asset = dev->asset;
view.progress_active = dev->progress_active;
view.progress_value = dev->progress_value;
view.is_producer = ecs_get(world_ecs(), e, Producer) != 0;
}
view.inside_vehicle = ecs_get(world_ecs(), e, IsInVehicle) != 0 ? true : false;
@ -101,6 +102,11 @@ entity_view *world_build_entity_view(int64_t e) {
}
view.storage_selected_item = in->storage_selected_item;
if (ecs_get(world_ecs(), e, Producer)) {
Device const* dev = ecs_get(world_ecs(), e, Device);
}
}
}
}

View File

@ -7,6 +7,7 @@
#include "world/prediction.h"
#include "core/camera.h"
#include "math.h"
#include "platform/input.h"
#include "world/blocks.h"
#include "models/assets.h"
#include "platform/profiler.h"
@ -61,15 +62,15 @@ void platform_input() {
{
float x=0.0f, y=0.0f;
uint8_t use, sprint, drop, ctrl, pick;
if (IsKeyDown(KEY_RIGHT) || IsKeyDown(KEY_D)) x += 1.0f;
if (IsKeyDown(KEY_LEFT) || IsKeyDown(KEY_A)) x -= 1.0f;
if (IsKeyDown(KEY_UP) || IsKeyDown(KEY_W)) y += 1.0f;
if (IsKeyDown(KEY_DOWN) || IsKeyDown(KEY_S)) y -= 1.0f;
if (input_is_down(IN_RIGHT)) x += 1.0f;
if (input_is_down(IN_LEFT)) x -= 1.0f;
if (input_is_down(IN_UP)) y += 1.0f;
if (input_is_down(IN_DOWN)) y -= 1.0f;
use = IsKeyPressed(KEY_SPACE);
sprint = IsKeyDown(KEY_LEFT_SHIFT) || IsKeyDown(KEY_RIGHT_SHIFT);
ctrl = IsKeyDown(KEY_LEFT_CONTROL) || IsKeyDown(KEY_RIGHT_CONTROL);
drop = IsKeyPressed(KEY_G) || player_inv.drop_item || storage_inv.drop_item;
use = input_is_pressed(IN_USE);
sprint = input_is_down(IN_SPRINT);
ctrl = input_is_down(IN_CTRL);
drop = input_is_pressed(IN_DROP) || player_inv.drop_item || storage_inv.drop_item;
// NOTE(zaklaus): NEW! mouse movement
Vector2 mouse_pos = GetMousePosition();

12140
code/vendors/enet.h vendored

File diff suppressed because it is too large Load Diff

59
eco2d.10x 100644
View File

@ -0,0 +1,59 @@
<?xml version="1.0"?>
<N10X>
<Workspace>
<IncludeFilter>*.*,</IncludeFilter>
<ExcludeFilter>*.obj,*.lib,*.pch,*.dll,*.pdb,.vs,Debug,Release,x64,obj,*.user,Intermediate,</ExcludeFilter>
<SyncFiles>true</SyncFiles>
<Recursive>true</Recursive>
<IsVirtual>false</IsVirtual>
<IsFolder>false</IsFolder>
<BuildCommand>build.bat</BuildCommand>
<RebuildCommand></RebuildCommand>
<BuildFileCommand></BuildFileCommand>
<CleanCommand></CleanCommand>
<BuildWorkingDirectory></BuildWorkingDirectory>
<RunCommand></RunCommand>
<DebugCommand></DebugCommand>
<ExePathCommand></ExePathCommand>
<DebugSln></DebugSln>
<UseVisualStudioEnvBat>false</UseVisualStudioEnvBat>
<Configurations>
<Configuration>Debug</Configuration>
<Configuration>Release</Configuration>
</Configurations>
<Platforms>
<Platform>x64</Platform>
</Platforms>
<AdditionalIncludePaths>
<AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.33.31629\include</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\um</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\shared</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\winrt</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\10\\include\10.0.22621.0\\cppwinrt</AdditionalIncludePath>
<AdditionalIncludePath>C:\Program Files (x86)\Windows Kits\NETFXSDK\4.8\include\um</AdditionalIncludePath>
</AdditionalIncludePaths>
<Defines>
<Define>ZPL_IMPL</Define>
<Define>_WIN32</Define>
<Define>_WIN64</Define>
</Defines>
<ConfigProperties>
<ConfigAndPlatform>
<Name>Debug:x64</Name>
<Defines></Defines>
<ForceIncludes></ForceIncludes>
</ConfigAndPlatform>
<Config>
<Name>Debug</Name>
<Defines></Defines>
</Config>
<Platform>
<Name>x64</Name>
<Defines></Defines>
</Platform>
</ConfigProperties>
<Children></Children>
</Workspace>
</N10X>