diff --git a/code/foundation/CMakeLists.txt b/code/foundation/CMakeLists.txt index 8bda5a4..3c10096 100644 --- a/code/foundation/CMakeLists.txt +++ b/code/foundation/CMakeLists.txt @@ -17,6 +17,7 @@ add_library(eco2d-foundation STATIC src/models/prefabs/vehicle.c src/models/prefabs/storage.c src/models/prefabs/furnace.c + src/models/prefabs/blueprint.c src/pkt/packet.c diff --git a/code/foundation/src/debug/debug_ui.c b/code/foundation/src/debug/debug_ui.c index 55855ef..96ad7f6 100644 --- a/code/foundation/src/debug/debug_ui.c +++ b/code/foundation/src/debug/debug_ui.c @@ -141,6 +141,7 @@ static debug_item items[] = { { .kind = DITEM_BUTTON, .name = "spawn chest", .on_click = ActSpawnChest }, { .kind = DITEM_BUTTON, .name = "spawn belt", .on_click = ActSpawnBelt }, { .kind = DITEM_BUTTON, .name = "spawn furnace", .on_click = ActSpawnFurnace }, + { .kind = DITEM_BUTTON, .name = "spawn demo blueprint", .on_click = ActSpawnDemoHouseItem }, { .kind = DITEM_LIST, .name = "demo npcs", diff --git a/code/foundation/src/debug/debug_ui_actions.c b/code/foundation/src/debug/debug_ui_actions.c index 3db1789..aad8e9e 100644 --- a/code/foundation/src/debug/debug_ui_actions.c +++ b/code/foundation/src/debug/debug_ui_actions.c @@ -71,6 +71,17 @@ ActSpawnFurnace(void) { entity_set_position(e, dest->x, dest->y); } +void +ActSpawnDemoHouseItem(void) { + ecs_entity_t e = item_spawn(ASSET_BLUEPRINT, 1); + ecs_entity_t plr = camera_get().ent_id; + + Position const* origin = ecs_get(world_ecs(), plr, Position); + Position * dest = ecs_get_mut(world_ecs(), e, Position); + *dest = *origin; + entity_set_position(e, dest->x, dest->y); +} + void ActSpawnCirclingDriver(void) { ecs_entity_t plr = camera_get().ent_id; diff --git a/code/foundation/src/gen/assets.h b/code/foundation/src/gen/assets.h index 0550309..a7715f1 100644 --- a/code/foundation/src/gen/assets.h +++ b/code/foundation/src/gen/assets.h @@ -15,6 +15,7 @@ typedef enum { ASSET_THING, ASSET_CHEST, ASSET_FURNACE, + ASSET_BLUEPRINT, // NOTE(zaklaus): items ASSET_DEMO_ICEMAKER, diff --git a/code/foundation/src/gen/assets_list.c b/code/foundation/src/gen/assets_list.c index e3cc374..92a9477 100644 --- a/code/foundation/src/gen/assets_list.c +++ b/code/foundation/src/gen/assets_list.c @@ -18,6 +18,7 @@ static asset assets[] = { ASSET_TEX(ASSET_DEMO_ICEMAKER), ASSET_TEX(ASSET_CHEST), ASSET_TEX(ASSET_FURNACE), + ASSET_TEX(ASSET_BLUEPRINT), // NOTE(zaklaus): blocks ASSET_TEX(ASSET_FENCE), diff --git a/code/foundation/src/models/components.c b/code/foundation/src/models/components.c index 811ca9d..fbb158b 100644 --- a/code/foundation/src/models/components.c +++ b/code/foundation/src/models/components.c @@ -19,6 +19,7 @@ ECS_COMPONENT_DECLARE(Producer); ECS_COMPONENT_DECLARE(EnergySource); ECS_COMPONENT_DECLARE(Ingredient); ECS_COMPONENT_DECLARE(Device); +ECS_COMPONENT_DECLARE(Blueprint); ECS_COMPONENT_DECLARE(DemoNPC); ECS_COMPONENT_DECLARE(StreamInfo); @@ -44,6 +45,7 @@ void ComponentsImport(ecs_world_t *ecs) { ECS_COMPONENT_DEFINE(ecs, EnergySource); ECS_COMPONENT_DEFINE(ecs, Ingredient); ECS_COMPONENT_DEFINE(ecs, Device); + ECS_COMPONENT_DEFINE(ecs, Blueprint); ECS_COMPONENT_DEFINE(ecs, DemoNPC); ECS_COMPONENT_DEFINE(ecs, StreamInfo); } diff --git a/code/foundation/src/models/components.h b/code/foundation/src/models/components.h index 14b59a9..619e8ee 100644 --- a/code/foundation/src/models/components.h +++ b/code/foundation/src/models/components.h @@ -154,6 +154,12 @@ typedef struct { float progress_value; } Device; +typedef struct { + uint8_t w; + uint8_t h; + char plan[256]; +} Blueprint; + typedef struct { double last_update; double tick_delay; @@ -180,6 +186,7 @@ extern ECS_COMPONENT_DECLARE(Producer); extern ECS_COMPONENT_DECLARE(EnergySource); extern ECS_COMPONENT_DECLARE(Ingredient); extern ECS_COMPONENT_DECLARE(Device); +extern ECS_COMPONENT_DECLARE(Blueprint); extern ECS_COMPONENT_DECLARE(DemoNPC); extern ECS_COMPONENT_DECLARE(StreamInfo); diff --git a/code/foundation/src/models/entity.c b/code/foundation/src/models/entity.c index fbb4146..7ea3dfe 100644 --- a/code/foundation/src/models/entity.c +++ b/code/foundation/src/models/entity.c @@ -47,6 +47,15 @@ uint64_t entity_spawn_id(uint16_t id){ return 0; } +uint64_t entity_spawn_id_with_data(uint16_t id, void *udata){ + for (size_t i = 0; i < MAX_ENTITY_SPAWNDEFS; ++i){ + if (entity_spawnlist[i].id == id){ + ZPL_ASSERT(entity_spawnlist[i].proc_udata); + return entity_spawnlist[i].proc_udata(udata); + } + } + return 0; +} void entity_batch_despawn(uint64_t *ids, size_t num_ids) { for (size_t i = 0; i < num_ids; i++ ) { librg_entity_untrack(world_tracker(), ids[i]); diff --git a/code/foundation/src/models/entity.h b/code/foundation/src/models/entity.h index eaea315..fd52603 100644 --- a/code/foundation/src/models/entity.h +++ b/code/foundation/src/models/entity.h @@ -5,6 +5,7 @@ uint64_t entity_spawn(uint16_t class_id /* 0 = no streaming */); uint64_t entity_spawn_id(uint16_t id); +uint64_t entity_spawn_id_with_data(uint16_t id, void* udata); void entity_batch_despawn(uint64_t *ids, size_t num_ids); void entity_despawn(uint64_t ent_id); void entity_set_position(uint64_t ent_id, float x, float y); diff --git a/code/foundation/src/models/entity_spawnlist.c b/code/foundation/src/models/entity_spawnlist.c index fcf2147..e1d6e67 100644 --- a/code/foundation/src/models/entity_spawnlist.c +++ b/code/foundation/src/models/entity_spawnlist.c @@ -1,13 +1,16 @@ // NOTE(zaklaus): access to spawners #include "models/prefabs/storage.h" #include "models/prefabs/furnace.h" +#include "models/prefabs/blueprint.h" static struct { asset_id id; uint64_t (*proc)(); + uint64_t (*proc_udata)(void*); } entity_spawnlist[] = { { .id = ASSET_CHEST, .proc = storage_spawn }, - { .id = ASSET_FURNACE, .proc = furnace_spawn } + { .id = ASSET_FURNACE, .proc = furnace_spawn }, + { .id = ASSET_BLUEPRINT, .proc_udata = blueprint_spawn_udata }, }; #define MAX_ENTITY_SPAWNDEFS ((sizeof(entity_spawnlist))/(sizeof(entity_spawnlist[0]))) diff --git a/code/foundation/src/models/items.c b/code/foundation/src/models/items.c index 9b132b9..0b17681 100644 --- a/code/foundation/src/models/items.c +++ b/code/foundation/src/models/items.c @@ -129,6 +129,22 @@ void item_use(ecs_world_t *ecs, ecs_entity_t e, Item *it, Position p, uint64_t u it->quantity--; }break; + case UKIND_PLACE_ITEM_DATA:{ + world_block_lookup l = world_block_from_realpos(p.x, p.y); + if (l.is_outer && l.bid > 0) { + return; + } + // NOTE(zaklaus): This is an inner layer block, we can't build over it if it has a collision! + else if (l.bid > 0 && blocks_get_flags(l.bid) & (BLOCK_FLAG_COLLISION|BLOCK_FLAG_ESSENTIAL)) { + return; + } + + ecs_entity_t e = entity_spawn_id_with_data(desc->place_item.id, desc); + ZPL_ASSERT(world_entity_valid(e)); + entity_set_position(e, p.x, p.y); + + it->quantity--; + }break; case UKIND_DELETE: case UKIND_END_PLACE: diff --git a/code/foundation/src/models/items.h b/code/foundation/src/models/items.h index 6ced2b0..4185d1d 100644 --- a/code/foundation/src/models/items.h +++ b/code/foundation/src/models/items.h @@ -10,6 +10,7 @@ typedef enum { UKIND_DELETE, UKIND_PLACE, UKIND_PLACE_ITEM, + UKIND_PLACE_ITEM_DATA, UKIND_END_PLACE, // NOTE(zaklaus): the rest of possible actions @@ -57,6 +58,15 @@ typedef struct { asset_id additional_ingredient; } ingredient; }; + + // NOTE: item data + union { + struct { + uint8_t w; + uint8_t h; + const char plan[256]; + } blueprint; + }; } item_desc; typedef uint16_t item_id; diff --git a/code/foundation/src/models/items_list.c b/code/foundation/src/models/items_list.c index af6f7cb..8bb4349 100644 --- a/code/foundation/src/models/items_list.c +++ b/code/foundation/src/models/items_list.c @@ -9,6 +9,8 @@ static item_desc items[] = { ITEM_ENERGY(ASSET_WOOD, ASSET_FURNACE, 64, 15.0f), ITEM_HOLD(ASSET_TREE, 64), + ITEM_BLUEPRINT(ASSET_BLUEPRINT, 1, 4, 4, "]]]]]CF] ]]]]]"), + ITEM_SELF_DIR(ASSET_BELT, 999), ITEM_PROXY(ASSET_BELT_LEFT, ASSET_BELT), ITEM_PROXY(ASSET_BELT_RIGHT, ASSET_BELT), diff --git a/code/foundation/src/models/items_list_helpers.h b/code/foundation/src/models/items_list_helpers.h index 4c70d75..6a85a19 100644 --- a/code/foundation/src/models/items_list_helpers.h +++ b/code/foundation/src/models/items_list_helpers.h @@ -20,6 +20,22 @@ }\ } +#define ITEM_BLUEPRINT(asset, qty, w_, h_, plan_)\ +{\ +.kind = asset,\ +.usage = UKIND_PLACE_ITEM_DATA,\ +.attachment = UDATA_NONE,\ +.max_quantity = qty,\ +.blueprint = {\ +.w = w_,\ +.h = h_,\ +.plan = plan_\ +},\ +.place_item = {\ +.id = asset\ +}\ +} + #define ITEM_INGREDIENT(asset, qty, _producer, _product, _additional)\ {\ .kind = asset,\ diff --git a/code/foundation/src/models/prefabs/blueprint.c b/code/foundation/src/models/prefabs/blueprint.c new file mode 100644 index 0000000..ce83658 --- /dev/null +++ b/code/foundation/src/models/prefabs/blueprint.c @@ -0,0 +1,31 @@ +#include "vehicle.h" + +#include "world/entity_view.h" +#include "world/world.h" + +#include "models/device.h" +#include "models/entity.h" +#include "models/items.h" +#include "models/components.h" + +uint64_t blueprint_spawn(uint8_t w, uint8_t h, const char *plan) { + ZPL_ASSERT((w*h) == zpl_strlen(plan)); + ZPL_ASSERT((w*h) < 256); + ecs_entity_t e = device_spawn(ASSET_BLUEPRINT); + + Blueprint *blueprint = ecs_get_mut(world_ecs(), e, Blueprint); + blueprint->w = w; + blueprint->h = h; + zpl_memcopy(blueprint->plan, plan, w*h); + + return (uint64_t)e; +} + +uint64_t blueprint_spawn_udata(void* udata) { + item_desc *it = (item_desc*)udata; + return blueprint_spawn(it->blueprint.w, it->blueprint.h, it->blueprint.plan); +} + +void blueprint_despawn(uint64_t id) { + entity_despawn(id); +} diff --git a/code/foundation/src/models/prefabs/blueprint.h b/code/foundation/src/models/prefabs/blueprint.h new file mode 100644 index 0000000..514d7ce --- /dev/null +++ b/code/foundation/src/models/prefabs/blueprint.h @@ -0,0 +1,8 @@ +#pragma once +#include "platform/system.h" + +uint64_t blueprint_spawn(uint8_t w, uint8_t h, const char *plan); +uint64_t blueprint_spawn_udata(void* udata); +void blueprint_despawn(uint64_t id); + + diff --git a/code/foundation/src/systems/modules/system_blueprint.c b/code/foundation/src/systems/modules/system_blueprint.c new file mode 100644 index 0000000..54c1353 --- /dev/null +++ b/code/foundation/src/systems/modules/system_blueprint.c @@ -0,0 +1,27 @@ +void BuildBlueprints(ecs_iter_t *it) { + Blueprint *blueprint = ecs_field(it, Blueprint, 1); + Device *d = ecs_field(it, Device, 2); + Position *p = ecs_field(it, Position, 3); + + for (int i = 0; i < it->count; i++) { + // TODO check storage and only build if we have enough resources + // build blocks over time and show progress bar while building a block + + int w = (int)blueprint[i].w; + int h = (int)blueprint[i].h; + + for (int y = 0; y < blueprint[i].h; y++) { + for (int x = 0; x < blueprint[i].w; x++) { + char c = blueprint[i].plan[y*w + x]; + if (c == ' ') continue; + 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); + world_chunk_place_block(l.chunk_id, l.id, blocks_find_by_symbol(c)); + } + } + + entity_despawn(it->entities[i]); + + // 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); + } +} diff --git a/code/foundation/src/systems/systems.c b/code/foundation/src/systems/systems.c index 1402384..c2905e6 100644 --- a/code/foundation/src/systems/systems.c +++ b/code/foundation/src/systems/systems.c @@ -17,6 +17,7 @@ #include "modules/system_vehicle.c" #include "modules/system_items.c" #include "modules/system_producer.c" +#include "modules/system_blueprint.c" static inline float physics_correction(float x, float vx, float bounce) { float r = (((zpl_max(0.0f, (WORLD_BLOCK_SIZE/2.0f) - zpl_abs(x))*zpl_sign(x)))*(WORLD_BLOCK_SIZE/2.0f)); @@ -219,6 +220,7 @@ void SystemsImport(ecs_world_t *ecs) { ECS_SYSTEM(ecs, InspectContainers, EcsPostUpdate, components.Input, !components.IsInVehicle); ECS_SYSTEM(ecs, HarvestIntoContainers, EcsPostUpdate, components.ItemContainer, components.Position, [none] !components.BlockHarvest); ECS_SYSTEM(ecs, ProduceItems, EcsPostUpdate, components.ItemContainer, components.Producer, components.Position, components.Device); + ECS_SYSTEM(ecs, BuildBlueprints, EcsPostUpdate, components.Blueprint, components.Device, components.Position); ECS_SYSTEM(ecs, ResetActivators, EcsPostUpdate, components.Input); diff --git a/code/foundation/src/world/blocks.c b/code/foundation/src/world/blocks.c index c60ef50..a157d2d 100644 --- a/code/foundation/src/world/blocks.c +++ b/code/foundation/src/world/blocks.c @@ -57,6 +57,14 @@ block_id blocks_find(asset_id kind) { return 0xF; } +block_id blocks_find_by_symbol(char symbol) { + for (block_id i=0; i= 0 && block_idx < zpl_square(world.chunk_size)); + ZPL_ASSERT(!(blocks_get_flags(bid) & BLOCK_FLAG_DEVICE)); world.block_mapping[id][block_idx] = bid; world_chunk_mark_dirty(world.chunk_mapping[id]); } void world_chunk_replace_block(int64_t id, uint16_t block_idx, block_id bid) { ZPL_ASSERT(block_idx >= 0 && block_idx < zpl_square(world.chunk_size)); - world.outer_block_mapping[id][block_idx] = bid; - world_chunk_mark_dirty(world.chunk_mapping[id]); + if (blocks_get_flags(bid) & BLOCK_FLAG_DEVICE) { + ecs_entity_t e = entity_spawn_id(blocks_get_asset(bid)); + world_block_lookup l = world_block_from_index(id, block_idx); + entity_set_position(e, l.ox, l.oy); + } else { + world.outer_block_mapping[id][block_idx] = bid; + world_chunk_mark_dirty(world.chunk_mapping[id]); + } } bool world_chunk_place_block(int64_t id, uint16_t block_idx, block_id bid) { ZPL_ASSERT(block_idx >= 0 && block_idx < zpl_square(world.chunk_size)); if (world.outer_block_mapping[id][block_idx] != 0 && bid != 0) return false; - world.outer_block_mapping[id][block_idx] = bid; - world_chunk_mark_dirty(world.chunk_mapping[id]); + if (blocks_get_flags(bid) & BLOCK_FLAG_DEVICE) { + ecs_entity_t e = entity_spawn_id(blocks_get_asset(bid)); + world_block_lookup l = world_block_from_index(id, block_idx); + entity_set_position(e, l.ox, l.oy); + } else { + world.outer_block_mapping[id][block_idx] = bid; + world_chunk_mark_dirty(world.chunk_mapping[id]); + } return true; }