send notification from server
parent
65766d8748
commit
11549eb324
|
@ -1,23 +1,30 @@
|
|||
#define MAX_NOTIFICATIONS_ON_SCREEN 5
|
||||
|
||||
typedef struct {
|
||||
const char *title;
|
||||
const char *text;
|
||||
zpl_string title;
|
||||
zpl_string text;
|
||||
} notification;
|
||||
|
||||
static notification *notifications = 0;
|
||||
|
||||
static bool show_notification_list = 0;
|
||||
|
||||
void notification_push(const char* title, const char* text) {
|
||||
void notification_push(const char* title1, const char* text1) {
|
||||
if (!notifications) {
|
||||
zpl_array_init(notifications, zpl_heap());
|
||||
}
|
||||
|
||||
zpl_string title = zpl_string_make(zpl_heap(), title1);
|
||||
zpl_string text = zpl_string_make(zpl_heap(), text1);
|
||||
|
||||
zpl_array_append(notifications, ((notification) { title, text }));
|
||||
}
|
||||
|
||||
void notification_clear(void) {
|
||||
for (zpl_isize i = 0; i < zpl_array_count(notifications); i++) {
|
||||
zpl_string_free(notifications[i].title);
|
||||
zpl_string_free(notifications[i].text);
|
||||
}
|
||||
zpl_array_clear(notifications);
|
||||
}
|
||||
|
||||
|
@ -53,6 +60,8 @@ void notification_draw(void) {
|
|||
nk_label_wrap(game_ui, notif->text);
|
||||
|
||||
if (nk_button_label(game_ui, "OK")) {
|
||||
zpl_string_free(notifications[i].title);
|
||||
zpl_string_free(notifications[i].text);
|
||||
zpl_array_remove_at(notifications, i);
|
||||
}
|
||||
nk_tree_pop(game_ui);
|
||||
|
@ -77,6 +86,8 @@ void notification_draw(void) {
|
|||
nk_label_wrap(game_ui, notif->text);
|
||||
|
||||
if (nk_button_label(game_ui, "OK")) {
|
||||
zpl_string_free(notifications[i].title);
|
||||
zpl_string_free(notifications[i].text);
|
||||
zpl_array_remove_at(notifications, i); --i;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -100,6 +100,8 @@ typedef struct {
|
|||
float max_hp;
|
||||
} Health;
|
||||
|
||||
typedef struct { char _unused; } Dead;
|
||||
|
||||
typedef struct {
|
||||
float amt;
|
||||
} HealthRegen;
|
||||
|
@ -241,6 +243,7 @@ typedef struct {
|
|||
X(Input)\
|
||||
X(ClientInfo)\
|
||||
X(Health)\
|
||||
X(Dead)\
|
||||
X(HealthRegen)\
|
||||
X(HealDelay)\
|
||||
X(HealthDecreased)\
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
#include "packets/pkt_send_notif.h"
|
||||
#include "pkt/packet.h"
|
||||
#include "world/world.h"
|
||||
#include "core/game.h"
|
||||
#include "world/entity_view.h"
|
||||
#include "core/camera.h"
|
||||
#include "models/prefabs/player.h"
|
||||
|
||||
#include "models/components.h"
|
||||
#include "systems/systems.h"
|
||||
|
||||
// client
|
||||
#include "gui/notifications.h"
|
||||
|
||||
pkt_desc pkt_send_notification_desc[] = {
|
||||
{ PKT_ARRAY(pkt_send_notification, title) },
|
||||
{ PKT_ARRAY(pkt_send_notification, text) },
|
||||
{ PKT_END },
|
||||
};
|
||||
|
||||
size_t pkt_notification_send(uint64_t peer_id, uint16_t view_id, const char *title, const char *text) {
|
||||
pkt_send_notification table = { 0 };
|
||||
zpl_strncpy(table.title, title, sizeof(table.title));
|
||||
zpl_strncpy(table.text, text, sizeof(table.text));
|
||||
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);
|
||||
}
|
||||
|
||||
int32_t pkt_send_notification_handler(pkt_header *header) {
|
||||
pkt_send_notification table;
|
||||
PKT_IF(pkt_msg_decode(header, pkt_send_notification_desc, pkt_pack_desc_args(pkt_send_notification_desc), PKT_STRUCT_PTR(&table)));
|
||||
|
||||
notification_push(table.title, table.text);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include "platform/system.h"
|
||||
#include "pkt/packet_utils.h"
|
||||
|
||||
typedef struct {
|
||||
char title[64];
|
||||
char text[1024];
|
||||
} pkt_send_notification;
|
||||
|
||||
size_t pkt_notification_send(uint64_t peer_id, uint16_t view_id, const char *title, const char *text);
|
||||
extern pkt_desc pkt_send_notification_desc[];
|
||||
|
||||
PKT_HANDLER_PROC(pkt_send_notification_handler);
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
#include "packets/pkt_01_welcome.h"
|
||||
#include "packets/pkt_send_keystate.h"
|
||||
#include "packets/pkt_send_librg_update.h"
|
||||
#include "packets/pkt_send_notif.h"
|
||||
#include "packets/pkt_switch_viewer.h"
|
||||
|
||||
#define PKT_HEADER_ELEMENTS 3
|
||||
|
@ -18,7 +19,8 @@ pkt_handler pkt_handlers[] = {
|
|||
{.id = MSG_ID_LIBRG_UPDATE, .handler = pkt_send_librg_update_handler},
|
||||
{.id = MSG_ID_SEND_KEYSTATE, .handler = pkt_send_keystate_handler},
|
||||
{.id = MSG_ID_SEND_BLOCKPOS, .handler = pkt_send_blockpos_handler},
|
||||
{.id = MSG_ID_SWITCH_VIEWER, .handler = pkt_switch_viewer_handler},
|
||||
{.id = MSG_ID_SWITCH_VIEWER, .handler = pkt_switch_viewer_handler},
|
||||
{.id = MSG_ID_SEND_NOTIFICATION, .handler = pkt_send_notification_handler},
|
||||
};
|
||||
|
||||
uint8_t pkt_buffer[PKT_BUFSIZ];
|
||||
|
|
|
@ -9,7 +9,8 @@ typedef enum {
|
|||
MSG_ID_LIBRG_UPDATE,
|
||||
MSG_ID_SEND_KEYSTATE,
|
||||
MSG_ID_SEND_BLOCKPOS,
|
||||
MSG_ID_SWITCH_VIEWER,
|
||||
MSG_ID_SWITCH_VIEWER,
|
||||
MSG_ID_SEND_NOTIFICATION,
|
||||
MSG_NEXT_FREE_ID,
|
||||
MAX_PACKETS = 256,
|
||||
} pkt_messages;
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
#define HAZARD_BLOCK_DMG 5.0f
|
||||
|
||||
void HurtOnHazardBlock(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Health *h = ecs_field(it, Health, 2);
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y);
|
||||
if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) {
|
||||
h->hp -= HAZARD_BLOCK_DMG;
|
||||
h->hp = zpl_max(0.0f, h->hp);
|
||||
ecs_add(it->world, it->entities[i], HealthDecreased);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#define HP_REGEN_PAIN_COOLDOWN 5.0f
|
||||
|
||||
void RegenerateHP(ecs_iter_t *it) {
|
||||
Health *h = ecs_field(it, Health, 1);
|
||||
HealthRegen *r = ecs_field(it, HealthRegen, 2);
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
// TODO delay regen on hurt
|
||||
if (h[i].hp < h[i].max_hp) {
|
||||
h[i].hp += r->amt;
|
||||
h[i].hp = zpl_min(h[i].max_hp, h[i].hp);
|
||||
entity_wake(it->entities[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnHealthChangePutDelay(ecs_iter_t *it) {
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
ecs_set(it->world, it->entities[i], HealDelay, { .delay = 10 });
|
||||
ecs_remove(it->world, it->entities[i], HealthDecreased);
|
||||
}
|
||||
}
|
||||
|
||||
void OnHealthChangeCheckDead(ecs_iter_t *it) {
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
const Health *hp = ecs_get(it->world, it->entities[i], Health);
|
||||
|
||||
if (hp && hp->hp <= 0.0f) {
|
||||
ecs_add(it->world, it->entities[i], Dead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnDead(ecs_iter_t *it) {
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
const ClientInfo *ci = ecs_get(it->world, it->entities[i], ClientInfo);
|
||||
Input *pi = ecs_get_mut_if_ex(it->world, it->entities[i], Input);
|
||||
|
||||
if (ci) {
|
||||
pkt_notification_send(0, 0, "Someone died!", zpl_bprintf("Player %d has died!", it->entities[i]));
|
||||
}
|
||||
|
||||
if (pi) {
|
||||
pi->is_blocked = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TickDownHealDelay(ecs_iter_t *it) {
|
||||
HealDelay *h = ecs_field(it, HealDelay, 1);
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
--h[i].delay;
|
||||
|
||||
if (h[i].delay == 0) {
|
||||
ecs_remove(it->world, it->entities[i], HealDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,8 @@
|
|||
#include "core/game.h"
|
||||
#include "core/rules.h"
|
||||
|
||||
#include "packets/pkt_send_notif.h"
|
||||
|
||||
ZPL_DIAGNOSTIC_PUSH_WARNLEVEL(0)
|
||||
#define CUTE_C2_IMPLEMENTATION
|
||||
#include "tinyc2.h"
|
||||
|
@ -22,6 +24,7 @@ ecs_query_t *ecs_rigidbodies = 0;
|
|||
ecs_entity_t ecs_timer = 0;
|
||||
|
||||
#include "modules/system_onfoot.c"
|
||||
#include "modules/system_health.c"
|
||||
#include "modules/system_demo.c"
|
||||
#include "modules/system_vehicle.c"
|
||||
#include "modules/system_items.c"
|
||||
|
@ -263,57 +266,6 @@ void IntegratePositions(ecs_iter_t *it) {
|
|||
}
|
||||
}
|
||||
|
||||
#define HAZARD_BLOCK_DMG 5.0f
|
||||
|
||||
void HurtOnHazardBlock(ecs_iter_t *it) {
|
||||
Position *p = ecs_field(it, Position, 1);
|
||||
Health *h = ecs_field(it, Health, 2);
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
world_block_lookup l = world_block_from_realpos(p[i].x, p[i].y);
|
||||
if (blocks_get_flags(l.bid) & BLOCK_FLAG_HAZARD) {
|
||||
h->hp -= HAZARD_BLOCK_DMG;
|
||||
h->hp = zpl_max(0.0f, h->hp);
|
||||
ecs_add(it->world, it->entities[i], HealthDecreased);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//#define HP_REGEN_PAIN_COOLDOWN 5.0f
|
||||
|
||||
void RegenerateHP(ecs_iter_t *it) {
|
||||
Health *h = ecs_field(it, Health, 1);
|
||||
HealthRegen *r = ecs_field(it, HealthRegen, 2);
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
// TODO delay regen on hurt
|
||||
if (h[i].hp < h[i].max_hp) {
|
||||
h[i].hp += r->amt;
|
||||
h[i].hp = zpl_min(h[i].max_hp, h[i].hp);
|
||||
entity_wake(it->entities[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnHealthChangePutDelay(ecs_iter_t *it) {
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
ecs_set(it->world, it->entities[i], HealDelay, { .delay = 10 });
|
||||
ecs_remove(it->world, it->entities[i], HealthDecreased);
|
||||
}
|
||||
}
|
||||
|
||||
void TickDownHealDelay(ecs_iter_t *it) {
|
||||
HealDelay *h = ecs_field(it, HealDelay, 1);
|
||||
|
||||
for (int i = 0; i < it->count; i++) {
|
||||
--h[i].delay;
|
||||
|
||||
if (h[i].delay == 0) {
|
||||
ecs_remove(it->world, it->entities[i], HealDelay);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResetActivators(ecs_iter_t *it) {
|
||||
Input *in = ecs_field(it, Input, 1);
|
||||
|
||||
|
@ -399,25 +351,29 @@ void SystemsImport(ecs_world_t *ecs) {
|
|||
ecs_rigidbodies = ecs_query_new(ecs, "components.Position, components.Velocity, components.PhysicsBody");
|
||||
|
||||
ECS_SYSTEM(ecs, EnableWorldEdit, EcsOnLoad);
|
||||
ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, components.Input, components.Velocity, components.Position, !components.IsInVehicle);
|
||||
ECS_SYSTEM(ecs, DemoNPCMoveAround, EcsOnLoad, components.Velocity, components.DemoNPC);
|
||||
|
||||
ECS_SYSTEM(ecs, ApplyWorldDragOnVelocity, EcsOnUpdate, components.Position, components.Velocity);
|
||||
// health
|
||||
ECS_SYSTEM_TICKED_EX(ecs, HurtOnHazardBlock, EcsOnUpdate, 20.0f, components.Position, components.Health);
|
||||
ECS_SYSTEM_TICKED_EX(ecs, RegenerateHP, EcsOnUpdate, 40.0f, components.Health, components.HealthRegen, !components.HealDelay);
|
||||
ECS_SYSTEM_TICKED_EX(ecs, TickDownHealDelay, EcsOnUpdate, 20.0f, components.HealDelay);
|
||||
ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity);
|
||||
|
||||
ECS_OBSERVER(ecs, OnHealthChangePutDelay, EcsOnAdd, components.HealthDecreased);
|
||||
ECS_OBSERVER(ecs, OnHealthChangeCheckDead, EcsOnAdd, components.HealthDecreased);
|
||||
ECS_OBSERVER(ecs, OnDead, EcsOnAdd, components.Dead);
|
||||
|
||||
// collisions and movement physics
|
||||
ECS_SYSTEM(ecs, ApplyWorldDragOnVelocity, EcsOnUpdate, components.Position, components.Velocity);
|
||||
ECS_SYSTEM(ecs, VehicleHandling, EcsOnUpdate, components.Vehicle, components.Position, components.Velocity);
|
||||
ECS_SYSTEM(ecs, BodyCollisions, EcsOnUpdate, components.Position, components.Velocity, components.PhysicsBody);
|
||||
ECS_SYSTEM(ecs, BlockCollisions, EcsOnValidate, components.Position, components.Velocity);
|
||||
ECS_SYSTEM(ecs, IntegratePositions, EcsOnValidate, components.Position, components.Velocity);
|
||||
|
||||
// vehicles
|
||||
ECS_SYSTEM(ecs, EnterVehicle, EcsPostUpdate, components.Input, components.Position, !components.IsInVehicle);
|
||||
ECS_SYSTEM(ecs, LeaveVehicle, EcsPostUpdate, components.Input, components.IsInVehicle, components.Velocity);
|
||||
|
||||
ECS_SYSTEM(ecs, PlayerClosestInteractable, EcsPostUpdate, components.Input);
|
||||
// player interaction
|
||||
ECS_SYSTEM(ecs, MovementImpulse, EcsOnLoad, components.Input, components.Velocity, components.Position, !components.IsInVehicle);
|
||||
ECS_SYSTEM(ecs, PlayerClosestInteractable, EcsPostUpdate, components.Input);
|
||||
ECS_SYSTEM(ecs, PickItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
|
||||
ECS_SYSTEM(ecs, DropItem, EcsPostUpdate, components.Input, components.Position, components.Inventory, !components.IsInVehicle);
|
||||
ECS_SYSTEM(ecs, SwapItems, EcsPostUpdate, components.Input, components.Inventory);
|
||||
|
@ -426,18 +382,22 @@ void SystemsImport(ecs_world_t *ecs) {
|
|||
ECS_SYSTEM(ecs, CraftItem, EcsPostUpdate, components.Input, !components.IsInVehicle);
|
||||
ECS_SYSTEM(ecs, InspectContainers, EcsPostUpdate, components.Input, !components.IsInVehicle);
|
||||
|
||||
// logistics and production
|
||||
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);
|
||||
|
||||
// demo creature sim
|
||||
ECS_SYSTEM_TICKED(ecs, CreatureCheckNeeds, EcsPostUpdate, components.Creature);
|
||||
ECS_SYSTEM_TICKED(ecs, CreatureSeekFood, EcsPostUpdate, components.Creature, components.Position, components.Velocity, components.SeeksFood, !components.SeeksCompanion);
|
||||
ECS_SYSTEM_TICKED(ecs, CreatureSeekCompanion, EcsPostUpdate, components.Creature, components.Position, components.Velocity, components.SeeksCompanion, !components.SeeksFood);
|
||||
ECS_SYSTEM(ecs, CreatureRoamAround, EcsPostUpdate, components.Velocity, components.Creature, !components.SeeksFood, !components.SeeksCompanion);
|
||||
|
||||
// player input reset
|
||||
ECS_SYSTEM(ecs, ResetActivators, EcsPostUpdate, components.Input);
|
||||
|
||||
// cleanup systems
|
||||
ECS_SYSTEM(ecs, ClearVehicle, EcsUnSet, components.Vehicle);
|
||||
ECS_SYSTEM(ecs, ThrowItemsOut, EcsUnSet, components.ItemContainer, components.Position);
|
||||
|
||||
|
|
|
@ -102,6 +102,7 @@ void platform_render() {
|
|||
}
|
||||
|
||||
debug_draw();
|
||||
notification_draw();
|
||||
game_draw_ui();
|
||||
}
|
||||
EndDrawing();
|
||||
|
|
|
@ -98,17 +98,6 @@ void platform_render() {
|
|||
game_world_view_active_entity_map(do_entity_fadeinout);
|
||||
}
|
||||
|
||||
// HACK run once when player is dead
|
||||
{
|
||||
static char done = 0;
|
||||
camera cam = camera_get();
|
||||
entity_view *e = game_world_view_active_get_entity(cam.ent_id);
|
||||
if (e && e->hp <= 0.0f && !done) {
|
||||
done = 1;
|
||||
notification_push("DEAD", "YOU ARE DEAD!");
|
||||
}
|
||||
}
|
||||
|
||||
assets_frame();
|
||||
|
||||
BeginDrawing();
|
||||
|
|
Loading…
Reference in New Issue