player movement impl wip

isolation_bkp/dynres
Dominik Madarász 2021-05-07 16:43:54 +02:00
parent 1b06c13f5e
commit 1ad39ad67e
15 changed files with 102 additions and 24 deletions

View File

@ -4,6 +4,7 @@
#include "world/world.h" #include "world/world.h"
typedef struct { typedef struct {
uint16_t view_id;
uint64_t owner_id; uint64_t owner_id;
entity_view_tbl entities; entity_view_tbl entities;
librg_world *tracker; librg_world *tracker;
@ -16,6 +17,6 @@ typedef struct {
uint16_t world_size; uint16_t world_size;
} world_view; } world_view;
world_view world_view_create(void); world_view world_view_create(uint16_t view_id);
void world_view_init(world_view *view, uint64_t ent_id, uint16_t block_size, uint16_t chunk_size, uint16_t world_size); void world_view_init(world_view *view, uint64_t ent_id, uint16_t block_size, uint16_t chunk_size, uint16_t world_size);
void world_view_destroy(world_view *view); void world_view_destroy(world_view *view);

View File

@ -16,6 +16,7 @@
#include "packets/pkt_00_init.h" #include "packets/pkt_00_init.h"
#include "packets/pkt_01_welcome.h" #include "packets/pkt_01_welcome.h"
#include "packets/pkt_send_keystate.h"
static int8_t is_viewer_only; static int8_t is_viewer_only;
@ -36,7 +37,7 @@ static WORLD_PKT_READER(pkt_reader) {
} }
static WORLD_PKT_WRITER(sp_pkt_writer) { static WORLD_PKT_WRITER(sp_pkt_writer) {
return world_read(pkt->data, pkt->datalen, 0); return world_read(pkt->data, pkt->datalen, (void*)game_world_view_get_active()->owner_id);
} }
static WORLD_PKT_WRITER(mp_pkt_writer) { static WORLD_PKT_WRITER(mp_pkt_writer) {
@ -52,7 +53,7 @@ void world_viewers_init(uint32_t num_viewers) {
zpl_buffer_init(world_viewers, zpl_heap(), num_viewers); zpl_buffer_init(world_viewers, zpl_heap(), num_viewers);
for (uint32_t i = 0; i < num_viewers; i++) { for (uint32_t i = 0; i < num_viewers; i++) {
world_viewers[i] = world_view_create(); world_viewers[i] = world_view_create(i);
} }
} }
@ -145,3 +146,6 @@ void game_render() {
platform_render(); platform_render();
} }
void game_action_send_keystate(double x, double y, uint8_t use) {
pkt_send_keystate_send(active_viewer->view_id, x, y, use);
}

View File

@ -34,6 +34,20 @@ void platform_input() {
if (mouse_z != 0.0f) { if (mouse_z != 0.0f) {
render_camera.zoom = zpl_clamp(render_camera.zoom+mouse_z*0.04f, 0.01f, 1.0f); render_camera.zoom = zpl_clamp(render_camera.zoom+mouse_z*0.04f, 0.01f, 1.0f);
} }
// NOTE(zaklaus): keystate handling
{
double x=0.0, y=0.0;
uint8_t use;
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;
use = IsKeyPressed(KEY_SPACE);
pkt_send_keystate_send(game_world_view_get_active()->view_id, x, y, use);
}
} }
void display_conn_status(); void display_conn_status();

View File

@ -35,8 +35,9 @@ int32_t tracker_read_create(librg_world *w, librg_event *e) {
return 0; return 0;
} }
world_view world_view_create(void) { world_view world_view_create(uint16_t view_id) {
world_view view = {0}; world_view view = {0};
view.view_id = view_id;
view.tracker = librg_world_create(); view.tracker = librg_world_create();
entity_view_init(&view.entities); entity_view_init(&view.entities);
return view; return view;

View File

@ -7,11 +7,16 @@ void game_shutdown();
uint8_t game_is_running(); uint8_t game_is_running();
int8_t game_is_networked(); int8_t game_is_networked();
//~ NOTE(zaklaus): game events
void game_input(); void game_input();
void game_update(); void game_update();
void game_render(); void game_render();
//~ NOTE(zaklaus): world view management
world_view *game_world_view_get_active(void); world_view *game_world_view_get_active(void);
world_view *game_world_view_get(uint16_t idx); world_view *game_world_view_get(uint16_t idx);
void game_world_view_set_active_by_idx(uint16_t idx); void game_world_view_set_active_by_idx(uint16_t idx);
void game_world_view_set_active(world_view *view); void game_world_view_set_active(world_view *view);
//~ NOTE(zaklaus): viewer -> host actions
void game_action_send_keystate(double x, double y, uint8_t use);

View File

@ -15,6 +15,7 @@ pkt_handler pkt_handlers[] = {
{.id = MSG_ID_00_INIT, .handler = pkt_00_init_handler}, {.id = MSG_ID_00_INIT, .handler = pkt_00_init_handler},
{.id = MSG_ID_01_WELCOME, .handler = pkt_01_welcome_handler}, {.id = MSG_ID_01_WELCOME, .handler = pkt_01_welcome_handler},
{.id = MSG_ID_LIBRG_UPDATE, .handler = pkt_send_librg_update_handler}, {.id = MSG_ID_LIBRG_UPDATE, .handler = pkt_send_librg_update_handler},
{.id = MSG_ID_SEND_KEYSTATE, .handler = pkt_send_keystate_handler},
}; };
uint8_t pkt_buffer[PKT_BUFSIZ]; uint8_t pkt_buffer[PKT_BUFSIZ];

View File

@ -7,12 +7,12 @@
#define PKT_IF(c) if (c < 0) return -1; #define PKT_IF(c) if (c < 0) return -1;
#endif #endif
inline void pkt_pack_msg(cw_pack_context *pc, uint32_t args) { static inline void pkt_pack_msg(cw_pack_context *pc, uint32_t args) {
cw_pack_context_init(pc, pkt_buffer, PKT_BUFSIZ, 0); cw_pack_context_init(pc, pkt_buffer, PKT_BUFSIZ, 0);
cw_pack_array_size(pc, args); cw_pack_array_size(pc, args);
} }
inline int32_t pkt_unpack_msg(cw_unpack_context *uc, pkt_header *header, uint32_t args) { static inline int32_t pkt_unpack_msg(cw_unpack_context *uc, pkt_header *header, uint32_t args) {
cw_unpack_context_init(uc, header->data, header->datalen, 0); cw_unpack_context_init(uc, header->data, header->datalen, 0);
cw_unpack_next(uc); cw_unpack_next(uc);
@ -23,23 +23,23 @@ inline int32_t pkt_unpack_msg(cw_unpack_context *uc, pkt_header *header, uint32_
return 0; return 0;
} }
inline int32_t pkt_unpack_msg_raw(cw_unpack_context *uc, uint8_t *data, uint32_t datalen, uint32_t args) { static inline int32_t pkt_unpack_msg_raw(cw_unpack_context *uc, uint8_t *data, uint32_t datalen, uint32_t args) {
pkt_header header = {.data = data, .datalen = datalen}; pkt_header header = {.data = data, .datalen = datalen};
return pkt_unpack_msg(uc, &header, args); return pkt_unpack_msg(uc, &header, args);
} }
inline int32_t pkt_validate_eof_msg(cw_unpack_context *uc) { static inline int32_t pkt_validate_eof_msg(cw_unpack_context *uc) {
if (uc->return_code != CWP_RC_OK) return -1; // unpacking failed somwwhere if (uc->return_code != CWP_RC_OK) return -1; // unpacking failed somwwhere
cw_unpack_next(uc); cw_unpack_next(uc);
if (uc->return_code != CWP_RC_END_OF_INPUT) return -1; // not finished yet but should be? if (uc->return_code != CWP_RC_END_OF_INPUT) return -1; // not finished yet but should be?
return 0; return 0;
} }
inline size_t pkt_pack_msg_size(cw_pack_context *pc) { static inline size_t pkt_pack_msg_size(cw_pack_context *pc) {
return pc->current - pc->start; // NOTE(zaklaus): length return pc->current - pc->start; // NOTE(zaklaus): length
} }
inline int32_t pkt_prep_msg(pkt_header *pkt, pkt_messages id, uint16_t view_id, size_t pkt_size, int8_t is_reliable) { static inline int32_t pkt_prep_msg(pkt_header *pkt, pkt_messages id, uint16_t view_id, size_t pkt_size, int8_t is_reliable) {
zpl_zero_item(pkt); zpl_zero_item(pkt);
static uint8_t pkt_data[PKT_BUFSIZ] = {0}; static uint8_t pkt_data[PKT_BUFSIZ] = {0};
zpl_memcopy(pkt_data, pkt_buffer, pkt_size); zpl_memcopy(pkt_data, pkt_buffer, pkt_size);
@ -54,7 +54,7 @@ inline int32_t pkt_prep_msg(pkt_header *pkt, pkt_messages id, uint16_t view_id,
extern int32_t world_write(pkt_header *pkt, void *udata); extern int32_t world_write(pkt_header *pkt, void *udata);
inline int32_t pkt_world_write(pkt_messages id, size_t pkt_size, int8_t is_reliable, uint16_t view_id, void *udata) { static inline int32_t pkt_world_write(pkt_messages id, size_t pkt_size, int8_t is_reliable, uint16_t view_id, void *udata) {
pkt_header pkt; pkt_header pkt;
PKT_IF(pkt_prep_msg(&pkt, id, view_id, pkt_size, is_reliable)); PKT_IF(pkt_prep_msg(&pkt, id, view_id, pkt_size, is_reliable));
return world_write(&pkt, udata); return world_write(&pkt, udata);
@ -101,6 +101,10 @@ inline int32_t pkt_world_write(pkt_messages id, size_t pkt_size, int8_t is_relia
#define PKT_END .type = CWP_NOT_AN_ITEM #define PKT_END .type = CWP_NOT_AN_ITEM
#endif #endif
#ifndef PKT_GET_ENT
#define PKT_GET_ENT(h) (ecs_entity_t)(h->udata)
#endif
typedef struct pkt_desc { typedef struct pkt_desc {
cwpack_item_types type; cwpack_item_types type;
size_t offset; size_t offset;
@ -110,7 +114,7 @@ typedef struct pkt_desc {
int32_t pkt_unpack_struct(cw_unpack_context *uc, pkt_desc *desc, void *raw_blob, uint32_t blob_size); int32_t pkt_unpack_struct(cw_unpack_context *uc, pkt_desc *desc, void *raw_blob, uint32_t blob_size);
inline int32_t pkt_msg_decode(pkt_header *header, pkt_desc* desc, uint32_t args, void *raw_blob, uint32_t blob_size) { static inline int32_t pkt_msg_decode(pkt_header *header, pkt_desc* desc, uint32_t args, void *raw_blob, uint32_t blob_size) {
cw_unpack_context uc = {0}; cw_unpack_context uc = {0};
PKT_IF(pkt_unpack_msg(&uc, header, args)); PKT_IF(pkt_unpack_msg(&uc, header, args));
PKT_IF(pkt_unpack_struct(&uc, desc, raw_blob, blob_size)); PKT_IF(pkt_unpack_struct(&uc, desc, raw_blob, blob_size));
@ -118,7 +122,7 @@ inline int32_t pkt_msg_decode(pkt_header *header, pkt_desc* desc, uint32_t args,
return pkt_validate_eof_msg(&uc); return pkt_validate_eof_msg(&uc);
} }
inline size_t pkt_pack_desc_args(pkt_desc *desc) { static inline size_t pkt_pack_desc_args(pkt_desc *desc) {
size_t cnt = 0; size_t cnt = 0;
for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field, ++cnt) {} for (pkt_desc *field = desc; field->type != CWP_NOT_AN_ITEM; ++field, ++cnt) {}
return cnt; return cnt;

View File

@ -1,13 +1,23 @@
#include "packet_utils.h" #include "packet_utils.h"
#include "packets/pkt_send_keystate.h" #include "packets/pkt_send_keystate.h"
#include "modules/controllers.h"
#include "world/world.h"
pkt_desc pkt_send_keystate_desc[] = { pkt_desc pkt_send_keystate_desc[] = {
{ PKT_FIELD(CWP_ITEM_DOUBLE, pkt_send_keystate, x) }, { PKT_REAL(pkt_send_keystate, x) },
{ PKT_FIELD(CWP_ITEM_DOUBLE, pkt_send_keystate, y) }, { PKT_REAL(pkt_send_keystate, y) },
{ PKT_FIELD(CWP_ITEM_POSITIVE_INTEGER, pkt_send_keystate, use) }, { PKT_UINT(pkt_send_keystate, use) },
{ PKT_END }, { PKT_END },
}; };
size_t pkt_send_keystate_send(uint16_t view_id,
double x,
double y,
uint8_t use) {
pkt_send_keystate table = { .x = x, .y = y, .use = use };
return pkt_world_write(MSG_ID_SEND_KEYSTATE, pkt_send_keystate_encode(&table), 1, view_id, NULL);
}
size_t pkt_send_keystate_encode(pkt_send_keystate *table) { size_t pkt_send_keystate_encode(pkt_send_keystate *table) {
cw_pack_context pc = {0}; cw_pack_context pc = {0};
pkt_pack_msg(&pc, pkt_pack_desc_args(pkt_send_keystate_desc)); pkt_pack_msg(&pc, pkt_pack_desc_args(pkt_send_keystate_desc));
@ -18,6 +28,16 @@ size_t pkt_send_keystate_encode(pkt_send_keystate *table) {
int32_t pkt_send_keystate_handler(pkt_header *header) { int32_t pkt_send_keystate_handler(pkt_header *header) {
pkt_send_keystate table; pkt_send_keystate table;
PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table))); PKT_IF(pkt_msg_decode(header, pkt_send_keystate_desc, pkt_pack_desc_args(pkt_send_keystate_desc), PKT_STRUCT_PTR(&table)));
ecs_entity_t e = PKT_GET_ENT(header);
ecs_world_t *ecs = world_ecs();
ECS_IMPORT(ecs, Controllers);
Input *i = ecs_get_mut(world_ecs(), e, Input, NULL);
if (i) {
i->x = table.x;
i->y = table.y;
i->use = table.use;
}
return 0; return 0;
} }

View File

@ -7,7 +7,10 @@ typedef struct {
double y; double y;
uint8_t use; uint8_t use;
} pkt_send_keystate; } pkt_send_keystate;
size_t pkt_send_keystate_send(uint16_t view_id,
double x,
double y,
uint8_t use);
size_t pkt_send_keystate_encode(pkt_send_keystate *table); size_t pkt_send_keystate_encode(pkt_send_keystate *table);
pkt_desc pkt_send_keystate_desc[]; pkt_desc pkt_send_keystate_desc[];

View File

@ -7,11 +7,13 @@
#include "modules/general.h" #include "modules/general.h"
#include "modules/controllers.h" #include "modules/controllers.h"
#include "modules/net.h" #include "modules/net.h"
#include "modules/physics.h"
#include "zpl.h" #include "zpl.h"
uint64_t player_spawn(char *name) { uint64_t player_spawn(char *name) {
ECS_IMPORT(world_ecs(), General); ECS_IMPORT(world_ecs(), General);
ECS_IMPORT(world_ecs(), Controllers); ECS_IMPORT(world_ecs(), Controllers);
ECS_IMPORT(world_ecs(), Physics);
ECS_IMPORT(world_ecs(), Net); ECS_IMPORT(world_ecs(), Net);
ecs_entity_t e = ecs_new(world_ecs(), 0); ecs_entity_t e = ecs_new(world_ecs(), 0);
@ -24,6 +26,8 @@ uint64_t player_spawn(char *name) {
ecs_set(world_ecs(), e, ClientInfo, {0}); ecs_set(world_ecs(), e, ClientInfo, {0});
ecs_set(world_ecs(), e, EcsName, {.alloc_value = name }); ecs_set(world_ecs(), e, EcsName, {.alloc_value = name });
ecs_set(world_ecs(), e, Input, {0}); ecs_set(world_ecs(), e, Input, {0});
ecs_set(world_ecs(), e, Velocity, {0});
ecs_add(world_ecs(), e, Walking);
Position *pos = ecs_get_mut(world_ecs(), e, Position, NULL); Position *pos = ecs_get_mut(world_ecs(), e, Position, NULL);
uint16_t world_dim = world_block_size() * world_chunk_size() * world_world_size(); uint16_t world_dim = world_block_size() * world_chunk_size() * world_world_size();
uint16_t half_world_dim = world_dim / 2; uint16_t half_world_dim = world_dim / 2;

View File

@ -15,6 +15,7 @@ typedef struct {
ECS_DECLARE_ENTITY(EcsBuilder); ECS_DECLARE_ENTITY(EcsBuilder);
ECS_DECLARE_TYPE(Player); ECS_DECLARE_TYPE(Player);
ECS_DECLARE_TYPE(Builder); ECS_DECLARE_TYPE(Builder);
ECS_DECLARE_ENTITY(MovementImpulse);
} Controllers; } Controllers;
#define ControllersImportHandles(handles)\ #define ControllersImportHandles(handles)\
@ -24,5 +25,6 @@ typedef struct {
ECS_IMPORT_ENTITY(handles, EcsActor);\ ECS_IMPORT_ENTITY(handles, EcsActor);\
ECS_IMPORT_ENTITY(handles, EcsPlayer);\ ECS_IMPORT_ENTITY(handles, EcsPlayer);\
ECS_IMPORT_ENTITY(handles, EcsBuilder);\ ECS_IMPORT_ENTITY(handles, EcsBuilder);\
ECS_IMPORT_ENTITY(handles, MovementImpulse);\
void ControllersImport(ecs_world_t *ecs); void ControllersImport(ecs_world_t *ecs);

View File

@ -1,9 +1,10 @@
#pragma once #pragma once
#include "flecs/flecs.h" #include "flecs/flecs.h"
#include "flecs/flecs_meta.h"
#include "modules/general.h" #include "modules/general.h"
typedef Vector2D Velocity; ECS_ALIAS(Vector2D, Velocity);
typedef struct { typedef struct {
ECS_DECLARE_TYPE(Movement); ECS_DECLARE_TYPE(Movement);

View File

@ -2,6 +2,20 @@
#include "modules/general.h" #include "modules/general.h"
#include "modules/physics.h" #include "modules/physics.h"
#include "zpl.h"
// TODO(zaklaus): move to physics
#define CTRL_DRAG_FACTOR 0.20
void MovementImpulse(ecs_iter_t *it) {
Input *in = ecs_column(it, Input, 1);
Velocity *v = ecs_column(it, Velocity, 2);
for (int i = 0; i < it->count; i++) {
v[i].x = zpl_lerp(v[i].x, in[i].x*1000, CTRL_DRAG_FACTOR);
v[i].y = zpl_lerp(v[i].y, in[i].y*1000, CTRL_DRAG_FACTOR);
}
}
void ControllersImport(ecs_world_t *ecs) { void ControllersImport(ecs_world_t *ecs) {
ECS_MODULE(ecs, Controllers); ECS_MODULE(ecs, Controllers);
@ -9,14 +23,16 @@ void ControllersImport(ecs_world_t *ecs) {
ECS_IMPORT(ecs, General); ECS_IMPORT(ecs, General);
ECS_IMPORT(ecs, Physics); ECS_IMPORT(ecs, Physics);
ECS_IMPORT(ecs, FlecsMeta); ECS_IMPORT(ecs, FlecsMeta);
ECS_META(ecs, Input); ECS_META(ecs, Input);
ECS_TAG(ecs, EcsActor); ECS_TAG(ecs, EcsActor);
ECS_TAG(ecs, EcsPlayer); ECS_TAG(ecs, EcsPlayer);
ECS_TAG(ecs, EcsBuilder); ECS_TAG(ecs, EcsBuilder);
ECS_SYSTEM(ecs, MovementImpulse, EcsOnUpdate, Input, physics.Velocity);
ECS_PREFAB(ecs, Base, general.Position, physics.Velocity, Input, EcsActor); ECS_PREFAB(ecs, Base, general.Position, physics.Velocity, Input, EcsActor);
ECS_TYPE(ecs, Player, INSTANCEOF | Base, SWITCH | physics.Movement, CASE | physics.Walking, EcsActor, EcsPlayer); ECS_TYPE(ecs, Player, INSTANCEOF | Base, SWITCH | physics.Movement, CASE | physics.Walking, EcsActor, EcsPlayer);
ECS_TYPE(ecs, Builder, INSTANCEOF | Base, SWITCH | physics.Movement, CASE | physics.Flying, EcsActor, EcsBuilder); ECS_TYPE(ecs, Builder, INSTANCEOF | Base, SWITCH | physics.Movement, CASE | physics.Flying, EcsActor, EcsBuilder);
@ -27,4 +43,5 @@ void ControllersImport(ecs_world_t *ecs) {
ECS_SET_ENTITY(EcsBuilder); ECS_SET_ENTITY(EcsBuilder);
ECS_SET_TYPE(Builder); ECS_SET_TYPE(Builder);
ECS_SET_TYPE(Player); ECS_SET_TYPE(Player);
ECS_SET_ENTITY(MovementImpulse);
} }

View File

@ -1,4 +1,6 @@
#include "modules/physics.h" #include "modules/physics.h"
#include "world/world.h"
#include "zpl.h"
void MoveWalk(ecs_iter_t *it) { void MoveWalk(ecs_iter_t *it) {
Position *p = ecs_column(it, Position, 1); Position *p = ecs_column(it, Position, 1);
@ -8,6 +10,7 @@ void MoveWalk(ecs_iter_t *it) {
// TODO: handle collisions // TODO: handle collisions
p[i].x += v[i].x * it->delta_time; p[i].x += v[i].x * it->delta_time;
p[i].y += v[i].y * it->delta_time; p[i].y += v[i].y * it->delta_time;
librg_entity_chunk_set(world_tracker(), it->entities[i], librg_chunk_from_realpos(world_tracker(), p[i].x, p[i].y, 0));
} }
} }
@ -19,9 +22,9 @@ void PhysicsImport(ecs_world_t *ecs) {
ECS_TAG(ecs, Flying); ECS_TAG(ecs, Flying);
ECS_TYPE(ecs, Movement, Walking, Flying); ECS_TYPE(ecs, Movement, Walking, Flying);
ECS_COMPONENT(ecs, Velocity); ECS_META(ecs, Velocity);
ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, general.Position, Velocity, SWITCH | Movement, CASE | Walking); ECS_SYSTEM(ecs, MoveWalk, EcsOnUpdate, general.Position, Velocity);
ECS_SET_TYPE(Movement); ECS_SET_TYPE(Movement);
ECS_SET_ENTITY(Walking); ECS_SET_ENTITY(Walking);

View File

@ -19979,7 +19979,6 @@ librg_chunk librg_chunk_from_chunkpos(librg_world *world, int16_t chunk_x, int16
int16_t chz = librg_util_chunkoffset_line(chunk_z, wld->chunkoffset.z, wld->worldsize.z); int16_t chz = librg_util_chunkoffset_line(chunk_z, wld->chunkoffset.z, wld->worldsize.z);
#define kk(aax,aay) (aax > -aay && aax < aay) #define kk(aax,aay) (aax > -aay && aax < aay)
#define ll(aax,aay) (aax <= -aay || aax >= aay) #define ll(aax,aay) (aax <= -aay || aax >= aay)
zpl_printf("%d %d\n", chz, wld->worldsize.z);
if (ll(chx, wld->worldsize.x) || ll(chy, wld->worldsize.y) /*|| ll(chz, wld->worldsize.z)*/) if (ll(chx, wld->worldsize.x) || ll(chy, wld->worldsize.y) /*|| ll(chz, wld->worldsize.z)*/)
return LIBRG_CHUNK_INVALID; return LIBRG_CHUNK_INVALID;
@ -20472,7 +20471,6 @@ int32_t librg_world_fetch_ownerarray(librg_world *world, const int64_t *owner_id
static LIBRG_ALWAYS_INLINE void librg_util_chunkrange(librg_world_t *w, librg_table_i64 *ch, int cx, int cy, int cz, int8_t radius) { static LIBRG_ALWAYS_INLINE void librg_util_chunkrange(librg_world_t *w, librg_table_i64 *ch, int cx, int cy, int cz, int8_t radius) {
int radius2 = radius * radius; int radius2 = radius * radius;
zpl_printf("========================\n");
for (int z=-radius; z<=radius; z++) { for (int z=-radius; z<=radius; z++) {
for (int y=-radius; y<=radius; y++) { for (int y=-radius; y<=radius; y++) {
for (int x=-radius; x<=radius; x++) { for (int x=-radius; x<=radius; x++) {