ItemRouter system

efd/v1
Dominik Madarász 2022-10-17 19:44:28 +02:00
parent 6385ea4461
commit 4cb85f069f
6 changed files with 168 additions and 108 deletions

View File

@ -18,6 +18,7 @@ ECS_COMPONENT_DECLARE(ItemContainer);
ECS_COMPONENT_DECLARE(Producer);
ECS_COMPONENT_DECLARE(EnergySource);
ECS_COMPONENT_DECLARE(Ingredient);
ECS_COMPONENT_DECLARE(ItemRouter);
ECS_COMPONENT_DECLARE(Device);
ECS_COMPONENT_DECLARE(Blueprint);
ECS_COMPONENT_DECLARE(DemoNPC);
@ -44,6 +45,7 @@ void ComponentsImport(ecs_world_t *ecs) {
ECS_COMPONENT_DEFINE(ecs, Producer);
ECS_COMPONENT_DEFINE(ecs, EnergySource);
ECS_COMPONENT_DEFINE(ecs, Ingredient);
ECS_COMPONENT_DEFINE(ecs, ItemRouter);
ECS_COMPONENT_DEFINE(ecs, Device);
ECS_COMPONENT_DEFINE(ecs, Blueprint);
ECS_COMPONENT_DEFINE(ecs, DemoNPC);

View File

@ -135,6 +135,10 @@ typedef struct {
float energy_level;
} Producer;
typedef struct {
char _unused;
} ItemRouter;
typedef struct {
asset_id kind;
float energy_level;
@ -185,6 +189,7 @@ extern ECS_COMPONENT_DECLARE(ItemContainer);
extern ECS_COMPONENT_DECLARE(Producer);
extern ECS_COMPONENT_DECLARE(EnergySource);
extern ECS_COMPONENT_DECLARE(Ingredient);
extern ECS_COMPONENT_DECLARE(ItemRouter);
extern ECS_COMPONENT_DECLARE(Device);
extern ECS_COMPONENT_DECLARE(Blueprint);
extern ECS_COMPONENT_DECLARE(DemoNPC);

View File

@ -14,6 +14,8 @@ uint64_t furnace_spawn(void) {
Producer *producer = ecs_get_mut(world_ecs(), e, Producer);
*producer = (Producer){0};
producer->energy_level = 69.0f;
ecs_add(world_ecs(), e, ItemRouter);
return (uint64_t)e;
}

View File

@ -0,0 +1,110 @@
static inline
asset_id FetchAssetAtPos(float x, float y) {
world_block_lookup lookup = world_block_from_realpos(x, y);
if (lookup.is_outer) {
return blocks_get_asset(lookup.bid);
}
return ASSET_INVALID;
}
// NOTE(zaklaus): Expects float[4] dx, dy
static inline
uint8_t CheckForNearbyBelts(Position *p, float *dx, float *dy) {
asset_id bid = ASSET_INVALID;
float o = WORLD_BLOCK_SIZE;
uint8_t nodes = 0x0;
// up
bid = FetchAssetAtPos(p->x + 0, p->y - o);
if (bid == ASSET_BELT_UP) {
dx[0] = 0;
dy[0] = -o;
nodes |= ZPL_BIT(0);
}
// down
bid = FetchAssetAtPos(p->x + 0, p->y + o);
if (bid == ASSET_BELT_DOWN) {
dx[1] = 0;
dy[1] = o;
nodes |= ZPL_BIT(1);
}
// left
bid = FetchAssetAtPos(p->x - o, p->y + 0);
if (bid == ASSET_BELT_LEFT) {
dx[2] = -o;
dy[2] = 0;
nodes |= ZPL_BIT(2);
}
// right
bid = FetchAssetAtPos(p->x + o, p->y + 0);
if (bid == ASSET_BELT_RIGHT) {
dx[3] = o;
dy[3] = 0;
nodes |= ZPL_BIT(3);
}
return nodes;
}
void PushItemsOnNodes(ecs_iter_t *it) {
ItemContainer *storage = ecs_field(it, ItemContainer, 1);
Position *p = ecs_field(it, Position, 2);
Device *d = ecs_field(it, Device, 3);
ItemRouter *r = ecs_field(it, ItemRouter, 4);
for (int i = 0; i < it->count; i++) {
// TODO(zaklaus): Cache output nodes so we avoid
// calling world_block_from_realpos each time.
// We need a way to refer to specific blocks in the world so we can do easy block ID checks
// and re-build the cache when a change is detected.
float push_dx[4], push_dy[4];
uint8_t nodes = CheckForNearbyBelts(&p[i], push_dx, push_dy);
uint8_t num_nodes = (uint8_t)zpl_count_set_bits(nodes);
uint8_t counter = 0;
if (num_nodes == 0) {
// NOTE(zaklaus): We don't have any output nodes yet.
continue;
}
for (int j = 0; j < ITEMS_CONTAINER_SIZE; j++) {
ecs_entity_t item_slot_ent = storage[i].items[j];
if (item_slot_ent == 0) continue;
Item *item = item_get_data(item_slot_ent);
const Ingredient *ing = 0;
// NOTE(zaklaus): Make sure we don't push out items from input node
if ((ing = ecs_get_if(it->world, item_slot_ent, Ingredient))) {
if (ing->producer == d->asset) {
continue;
}
}
while (item->quantity > 0 && num_nodes > 0) {
// NOTE(zaklaus): Use a rolling counter to select an output node.
while (!(nodes & (1 << counter)) && counter < 4) ++counter;
if (counter > 3) {
counter = 0;
continue;
}
uint64_t e = item_spawn(item->kind, 1);
entity_set_position(e, p[i].x + push_dx[counter], p[i].y + push_dy[counter]);
Velocity *e_vel = ecs_get_mut_ex(it->world, e, Velocity);
e_vel->x = push_dx[counter];
e_vel->y = push_dy[counter];
--item->quantity;
--num_nodes;
++counter;
}
}
}
}

View File

@ -1,58 +1,3 @@
static inline
asset_id FetchAssetAtPos(float x, float y) {
world_block_lookup lookup = world_block_from_realpos(x, y);
if (lookup.is_outer) {
return blocks_get_asset(lookup.bid);
}
return ASSET_INVALID;
}
static inline
bool CheckForNearbyBelt(Position *p, float *dx, float *dy) {
asset_id bid = ASSET_INVALID;
float o = WORLD_BLOCK_SIZE;
// up
bid = FetchAssetAtPos(p->x + 0, p->y - o);
{
debug_v2 a = {p->x, p->y};
debug_v2 b = {p->x, p->y-WORLD_BLOCK_SIZE};
debug_push_line(a, b, 0xFFFFFFFF);
}
if (bid == ASSET_BELT_UP) {
*dx = 0;
*dy = -o;
return true;
}
// down
bid = FetchAssetAtPos(p->x + 0, p->y + o);
if (bid == ASSET_BELT_DOWN) {
*dx = 0;
*dy = o;
return true;
}
// left
bid = FetchAssetAtPos(p->x - o, p->y + 0);
if (bid == ASSET_BELT_LEFT) {
*dx = -o;
*dy = 0;
return true;
}
// right
bid = FetchAssetAtPos(p->x + o, p->y + 0);
if (bid == ASSET_BELT_RIGHT) {
*dx = o;
*dy = 0;
return true;
}
return false;
}
void ProduceItems(ecs_iter_t *it) {
ItemContainer *storage = ecs_field(it, ItemContainer, 1);
Producer *producer = ecs_field(it, Producer, 2);
@ -60,9 +5,6 @@ void ProduceItems(ecs_iter_t *it) {
Device *d = ecs_field(it, Device, 4);
for (int i = 0; i < it->count; i++) {
float push_dx=0.0f, push_dy=0.0f;
bool has_output_node = CheckForNearbyBelt(&p[i], &push_dx, &push_dy);
for (int j = 0; j < ITEMS_CONTAINER_SIZE; j++) {
ecs_entity_t item_slot_ent = storage[i].items[j];
Item *item = item_get_data(item_slot_ent);
@ -81,16 +23,8 @@ void ProduceItems(ecs_iter_t *it) {
if (producer[i].process_time < game_time()) {
if (producer[i].processed_item > 0) {
uint64_t e = item_spawn(producer[i].processed_item, 1);
producer[i].processed_item = 0;
if (has_output_node) {
entity_set_position(e, p[i].x+push_dx, p[i].y+push_dy);
Velocity *e_vel = ecs_get_mut_ex(it->world, e, Velocity);
e_vel->x = push_dx;
e_vel->y = push_dy;
} else {
entity_set_position(e, p[i].x, p[i].y);
}
producer[i].processed_item = 0;
} else {
const Ingredient *ing = 0;
if ((ing = ecs_get_if(it->world, item_slot_ent, Ingredient))) {

View File

@ -16,6 +16,7 @@
#include "modules/system_demo.c"
#include "modules/system_vehicle.c"
#include "modules/system_items.c"
#include "modules/system_logistics.c"
#include "modules/system_producer.c"
#include "modules/system_blueprint.c"
@ -46,20 +47,20 @@ void IntegratePositions(ecs_iter_t *it) {
p[i].y = zpl_clamp(p[i].y, 0, w-1);
}
#if PHY_BLOCK_COLLISION==1
#if PHY_BLOCK_COLLISION==1
// NOTE(zaklaus): X axis
{
world_block_lookup lookup = world_block_from_realpos(p[i].x+PHY_LOOKAHEAD(v[i].x), p[i].y);
uint32_t flags = blocks_get_flags(lookup.bid);
float bounce = blocks_get_bounce(lookup.bid);
if (flags & BLOCK_FLAG_COLLISION && physics_check_aabb(p[i].x-WORLD_BLOCK_SIZE/4, p[i].x+WORLD_BLOCK_SIZE/4, p[i].y-0.5f, p[i].y+0.5f, lookup.aox-WORLD_BLOCK_SIZE/2, lookup.aox+WORLD_BLOCK_SIZE/2, lookup.aoy-WORLD_BLOCK_SIZE/2, lookup.aoy+WORLD_BLOCK_SIZE/2)) {
#if 1
#if 1
{
debug_v2 a = {p[i].x-WORLD_BLOCK_SIZE/4 + PHY_LOOKAHEAD(v[i].x), p[i].y-0.5f};
debug_v2 b = {p[i].x+WORLD_BLOCK_SIZE/4 + PHY_LOOKAHEAD(v[i].x), p[i].y+0.5f};
debug_push_rect(a, b, 0xFF0000FF);
}
#endif
#endif
v[i].x = physics_correction(lookup.ox, v[i].x, bounce, WORLD_BLOCK_SIZE/2);
}
}
@ -69,25 +70,25 @@ void IntegratePositions(ecs_iter_t *it) {
world_block_lookup lookup = world_block_from_realpos(p[i].x, p[i].y+PHY_LOOKAHEAD(v[i].y));
uint32_t flags = blocks_get_flags(lookup.bid);
float bounce = blocks_get_bounce(lookup.bid);
#if 0
#if 0
{
debug_v2 a = {lookup.aox-WORLD_BLOCK_SIZE/2, lookup.aoy-WORLD_BLOCK_SIZE/2};
debug_v2 b = {lookup.aox+WORLD_BLOCK_SIZE/2, lookup.aoy+WORLD_BLOCK_SIZE/2};
debug_push_rect(a, b, 0xFFFFFFFF);
}
#endif
#endif
if (flags & BLOCK_FLAG_COLLISION && physics_check_aabb(p[i].x-WORLD_BLOCK_SIZE/4, p[i].x+WORLD_BLOCK_SIZE/4, p[i].y-0.5f, p[i].y+0.5f, lookup.aox-WORLD_BLOCK_SIZE/2, lookup.aox+WORLD_BLOCK_SIZE/2, lookup.aoy-WORLD_BLOCK_SIZE/2, lookup.aoy+WORLD_BLOCK_SIZE/2)) {
#if 1
#if 1
{
debug_v2 a = {p[i].x-WORLD_BLOCK_SIZE/4, p[i].y-0.5f + PHY_LOOKAHEAD(v[i].y)};
debug_v2 b = {p[i].x+WORLD_BLOCK_SIZE/4, p[i].y+0.5f + PHY_LOOKAHEAD(v[i].y)};
debug_push_rect(a, b, 0xFF0000FF);
}
#endif
#endif
v[i].y = physics_correction(lookup.oy, v[i].y, bounce, WORLD_BLOCK_SIZE/4);
}
}
#endif
#endif
entity_set_position(it->entities[i], p[i].x+v[i].x*safe_dt(it), p[i].y+v[i].y*safe_dt(it));
}
@ -229,8 +230,13 @@ void DisableWorldEdit(ecs_iter_t *it) {
#define ECO2D_TICK_RATE (1.0f/20.f)
#define ECS_SYSTEM_TICKED(world, id, stage, ...)\
ECS_SYSTEM(world, id, stage, __VA_ARGS__);\
ecs_set_tick_source(world, id, timer);
ECS_SYSTEM(world, id, stage, __VA_ARGS__);\
ecs_set_tick_source(world, id, timer);
#define ECS_SYSTEM_TICKED_EX(world, id, stage, time, ...)\
ECS_SYSTEM(world, id, stage, __VA_ARGS__);\
ecs_entity_t timer_##id = ecs_set_interval(ecs, 0, ECO2D_TICK_RATE*time);\
ecs_set_tick_source(world, id, timer_##id);
void SystemsImport(ecs_world_t *ecs) {
ECS_MODULE(ecs, Systems);
@ -261,6 +267,7 @@ void SystemsImport(ecs_world_t *ecs) {
ECS_SYSTEM_TICKED(ecs, HarvestIntoContainers, EcsPostUpdate, components.ItemContainer, components.Position, !components.BlockHarvest);
ECS_SYSTEM_TICKED(ecs, ProduceItems, EcsPostUpdate, components.ItemContainer, components.Producer, components.Position, components.Device);
ECS_SYSTEM_TICKED_EX(ecs, PushItemsOnNodes, EcsPostUpdate, 20, components.ItemContainer, components.Position, components.Device, components.ItemRouter);
ECS_SYSTEM_TICKED(ecs, BuildBlueprints, EcsPostUpdate, components.Blueprint, components.Device, components.Position);
ECS_SYSTEM(ecs, ResetActivators, EcsPostUpdate, components.Input);