diff --git a/src/client.cpp b/src/client.cpp index 658b10393..6fd007181 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "network/connection.h" #include "network/networkpacket.h" #include "threading/mutex_auto_lock.h" +#include "client/clientevent.h" #include "client/renderingengine.h" #include "util/auth.h" #include "util/directiontables.h" @@ -425,9 +426,9 @@ void Client::step(float dtime) sendDamage(damage); // Add to ClientEvent queue - ClientEvent event; - event.type = CE_PLAYER_DAMAGE; - event.player_damage.amount = damage; + ClientEvent *event = new ClientEvent(); + event->type = CE_PLAYER_DAMAGE; + event->player_damage.amount = damage; m_client_event_queue.push(event); } } @@ -1661,12 +1662,12 @@ void Client::addUpdateMeshTaskForNode(v3s16 nodepos, bool ack_to_server, bool ur } } -ClientEvent Client::getClientEvent() +ClientEvent *Client::getClientEvent() { FATAL_ERROR_IF(m_client_event_queue.empty(), "Cannot getClientEvent, queue is empty."); - ClientEvent event = m_client_event_queue.front(); + ClientEvent *event = m_client_event_queue.front(); m_client_event_queue.pop(); return event; } @@ -1865,6 +1866,11 @@ bool Client::shouldShowMinimap() const return !m_minimap_disabled_by_server; } +void Client::pushToEventQueue(ClientEvent *event) +{ + m_client_event_queue.push(event); +} + void Client::showGameChat(const bool show) { m_game_ui_flags->show_chat = show; diff --git a/src/client.h b/src/client.h index 2ee81ea09..6f2d3371d 100644 --- a/src/client.h +++ b/src/client.h @@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define CLIENT_CHAT_MESSAGE_LIMIT_PER_10S 10.0f +struct ClientEvent; struct MeshMakeData; struct ChatMessage; class MapBlockMesh; @@ -68,137 +69,6 @@ enum LocalClientState { LC_Ready }; -enum ClientEventType -{ - CE_NONE, - CE_PLAYER_DAMAGE, - CE_PLAYER_FORCE_MOVE, - CE_DEATHSCREEN, - CE_SHOW_FORMSPEC, - CE_SHOW_LOCAL_FORMSPEC, - CE_SPAWN_PARTICLE, - CE_ADD_PARTICLESPAWNER, - CE_DELETE_PARTICLESPAWNER, - CE_HUDADD, - CE_HUDRM, - CE_HUDCHANGE, - CE_SET_SKY, - CE_OVERRIDE_DAY_NIGHT_RATIO, - CE_CLOUD_PARAMS, -}; - -struct ClientEvent -{ - ClientEventType type; - union{ - //struct{ - //} none; - struct{ - u8 amount; - } player_damage; - struct{ - f32 pitch; - f32 yaw; - } player_force_move; - struct{ - bool set_camera_point_target; - f32 camera_point_target_x; - f32 camera_point_target_y; - f32 camera_point_target_z; - } deathscreen; - struct{ - std::string *formspec; - std::string *formname; - } show_formspec; - //struct{ - //} textures_updated; - struct{ - v3f *pos; - v3f *vel; - v3f *acc; - f32 expirationtime; - f32 size; - bool collisiondetection; - bool collision_removal; - bool vertical; - std::string *texture; - struct TileAnimationParams animation; - u8 glow; - } spawn_particle; - struct{ - u16 amount; - f32 spawntime; - v3f *minpos; - v3f *maxpos; - v3f *minvel; - v3f *maxvel; - v3f *minacc; - v3f *maxacc; - f32 minexptime; - f32 maxexptime; - f32 minsize; - f32 maxsize; - bool collisiondetection; - bool collision_removal; - u16 attached_id; - bool vertical; - std::string *texture; - u32 id; - struct TileAnimationParams animation; - u8 glow; - } add_particlespawner; - struct{ - u32 id; - } delete_particlespawner; - struct{ - u32 id; - u8 type; - v2f *pos; - std::string *name; - v2f *scale; - std::string *text; - u32 number; - u32 item; - u32 dir; - v2f *align; - v2f *offset; - v3f *world_pos; - v2s32 * size; - } hudadd; - struct{ - u32 id; - } hudrm; - struct{ - u32 id; - HudElementStat stat; - v2f *v2fdata; - std::string *sdata; - u32 data; - v3f *v3fdata; - v2s32 * v2s32data; - } hudchange; - struct{ - video::SColor *bgcolor; - std::string *type; - std::vector *params; - bool clouds; - } set_sky; - struct{ - bool do_override; - float ratio_f; - } override_day_night_ratio; - struct { - f32 density; - u32 color_bright; - u32 color_ambient; - f32 height; - f32 thickness; - f32 speed_x; - f32 speed_y; - } cloud_params; - }; -}; - /* Packet counter */ @@ -450,7 +320,7 @@ public: bool hasClientEvents() const { return !m_client_event_queue.empty(); } // Get event from queue. If queue is empty, it triggers an assertion failure. - ClientEvent getClientEvent(); + ClientEvent * getClientEvent(); bool accessDenied() const { return m_access_denied; } @@ -530,10 +400,7 @@ public: ClientScripting *getScript() { return m_script; } const bool moddingEnabled() const { return m_modding_enabled; } - inline void pushToEventQueue(const ClientEvent &event) - { - m_client_event_queue.push(event); - } + void pushToEventQueue(ClientEvent *event); void showGameChat(bool show = true); void showGameHud(bool show = true); @@ -662,7 +529,7 @@ private: bool m_access_denied = false; bool m_access_denied_reconnect = false; std::string m_access_denied_reason = ""; - std::queue m_client_event_queue; + std::queue m_client_event_queue; bool m_itemdef_received = false; bool m_nodedef_received = false; ClientMediaDownloader *m_media_downloader; diff --git a/src/client/clientevent.h b/src/client/clientevent.h new file mode 100644 index 000000000..67125cce6 --- /dev/null +++ b/src/client/clientevent.h @@ -0,0 +1,170 @@ +/* +Minetest +Copyright (C) 2017 nerzhul, Loic Blot + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#pragma once + +#include +#include "irrlichttypes_bloated.h" +#include "hud.h" + +enum ClientEventType : u8 +{ + CE_NONE, + CE_PLAYER_DAMAGE, + CE_PLAYER_FORCE_MOVE, + CE_DEATHSCREEN, + CE_SHOW_FORMSPEC, + CE_SHOW_LOCAL_FORMSPEC, + CE_SPAWN_PARTICLE, + CE_ADD_PARTICLESPAWNER, + CE_DELETE_PARTICLESPAWNER, + CE_HUDADD, + CE_HUDRM, + CE_HUDCHANGE, + CE_SET_SKY, + CE_OVERRIDE_DAY_NIGHT_RATIO, + CE_CLOUD_PARAMS, + CLIENTEVENT_MAX, +}; + +struct ClientEvent +{ + ClientEventType type; + union + { + // struct{ + //} none; + struct + { + u8 amount; + } player_damage; + struct + { + f32 pitch; + f32 yaw; + } player_force_move; + struct + { + bool set_camera_point_target; + f32 camera_point_target_x; + f32 camera_point_target_y; + f32 camera_point_target_z; + } deathscreen; + struct + { + std::string *formspec; + std::string *formname; + } show_formspec; + // struct{ + //} textures_updated; + struct + { + v3f *pos; + v3f *vel; + v3f *acc; + f32 expirationtime; + f32 size; + bool collisiondetection; + bool collision_removal; + bool vertical; + std::string *texture; + struct TileAnimationParams animation; + u8 glow; + } spawn_particle; + struct + { + u16 amount; + f32 spawntime; + v3f *minpos; + v3f *maxpos; + v3f *minvel; + v3f *maxvel; + v3f *minacc; + v3f *maxacc; + f32 minexptime; + f32 maxexptime; + f32 minsize; + f32 maxsize; + bool collisiondetection; + bool collision_removal; + u16 attached_id; + bool vertical; + std::string *texture; + u32 id; + struct TileAnimationParams animation; + u8 glow; + } add_particlespawner; + struct + { + u32 id; + } delete_particlespawner; + struct + { + u32 id; + u8 type; + v2f *pos; + std::string *name; + v2f *scale; + std::string *text; + u32 number; + u32 item; + u32 dir; + v2f *align; + v2f *offset; + v3f *world_pos; + v2s32 *size; + } hudadd; + struct + { + u32 id; + } hudrm; + struct + { + u32 id; + HudElementStat stat; + v2f *v2fdata; + std::string *sdata; + u32 data; + v3f *v3fdata; + v2s32 *v2s32data; + } hudchange; + struct + { + video::SColor *bgcolor; + std::string *type; + std::vector *params; + bool clouds; + } set_sky; + struct + { + bool do_override; + float ratio_f; + } override_day_night_ratio; + struct + { + f32 density; + u32 color_bright; + u32 color_ambient; + f32 height; + f32 thickness; + f32 speed_x; + f32 speed_y; + } cloud_params; + }; +}; diff --git a/src/game.cpp b/src/game.cpp index 43495e8a6..17ab68e7c 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/renderingengine.h" #include "camera.h" #include "client.h" +#include "client/clientevent.h" #include "client/inputhandler.h" #include "client/tile.h" // For TextureSource #include "client/keys.h" @@ -1181,6 +1182,13 @@ struct RunStats { Jitter dtime_jitter, busy_time_jitter; }; +class Game; + +struct ClientEventHandler +{ + void (Game::*handler)(ClientEvent *, CameraOrientation *); +}; + /**************************************************************************** THE GAME ****************************************************************************/ @@ -1361,6 +1369,25 @@ protected: private: void showPauseMenu(); + // ClientEvent handlers + void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_HandleParticleEvent(ClientEvent *event, + CameraOrientation *cam); + void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event, + CameraOrientation *cam); + void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam); + + static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX]; + InputHandler *input; Client *client; @@ -3125,272 +3152,301 @@ inline void Game::step(f32 *dtime) } } +const ClientEventHandler Game::clientEventHandler[CLIENTEVENT_MAX] = { + {&Game::handleClientEvent_None}, + {&Game::handleClientEvent_PlayerDamage}, + {&Game::handleClientEvent_PlayerForceMove}, + {&Game::handleClientEvent_Deathscreen}, + {&Game::handleClientEvent_ShowFormSpec}, + {&Game::handleClientEvent_ShowLocalFormSpec}, + {&Game::handleClientEvent_HandleParticleEvent}, + {&Game::handleClientEvent_HandleParticleEvent}, + {&Game::handleClientEvent_HandleParticleEvent}, + {&Game::handleClientEvent_HudAdd}, + {&Game::handleClientEvent_HudRemove}, + {&Game::handleClientEvent_HudChange}, + {&Game::handleClientEvent_SetSky}, + {&Game::handleClientEvent_OverrideDayNigthRatio}, + {&Game::handleClientEvent_CloudParams}, +}; -void Game::processClientEvents(CameraOrientation *cam) +void Game::handleClientEvent_None(ClientEvent *event, CameraOrientation *cam) +{ + FATAL_ERROR("ClientEvent type None received"); +} + +void Game::handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam) +{ + if (client->getHP() == 0) + return; + + if (client->moddingEnabled()) { + client->getScript()->on_damage_taken(event->player_damage.amount); + } + + runData.damage_flash += 95.0 + 3.2 * event->player_damage.amount; + runData.damage_flash = MYMIN(runData.damage_flash, 127.0); + + LocalPlayer *player = client->getEnv().getLocalPlayer(); + + player->hurt_tilt_timer = 1.5; + player->hurt_tilt_strength = + rangelim(event->player_damage.amount / 4, 1.0, 4.0); + + client->event()->put(new SimpleTriggerEvent("PlayerDamage")); +} + +void Game::handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam) +{ + cam->camera_yaw = event->player_force_move.yaw; + cam->camera_pitch = event->player_force_move.pitch; +} + +void Game::handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam) +{ + // This should be enabled for death formspec in builtin + client->getScript()->on_death(); + + LocalPlayer *player = client->getEnv().getLocalPlayer(); + + /* Handle visualization */ + runData.damage_flash = 0; + player->hurt_tilt_timer = 0; + player->hurt_tilt_strength = 0; +} + +void Game::handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam) +{ + if (event->show_formspec.formspec->empty()) { + if (current_formspec && (event->show_formspec.formname->empty() + || *(event->show_formspec.formname) == cur_formname)) { + current_formspec->quitMenu(); + } + } else { + FormspecFormSource *fs_src = + new FormspecFormSource(*(event->show_formspec.formspec)); + TextDestPlayerInventory *txt_dst = + new TextDestPlayerInventory(client, *(event->show_formspec.formname)); + + create_formspec_menu(¤t_formspec, client, &input->joystick, + fs_src, txt_dst); + cur_formname = *(event->show_formspec.formname); + } + + delete event->show_formspec.formspec; + delete event->show_formspec.formname; +} + +void Game::handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam) +{ + FormspecFormSource *fs_src = new FormspecFormSource(*event->show_formspec.formspec); + LocalFormspecHandler *txt_dst = + new LocalFormspecHandler(*event->show_formspec.formname, client); + create_formspec_menu(¤t_formspec, client, &input->joystick, fs_src, txt_dst); + + delete event->show_formspec.formspec; + delete event->show_formspec.formname; +} + +void Game::handleClientEvent_HandleParticleEvent(ClientEvent *event, + CameraOrientation *cam) +{ + LocalPlayer *player = client->getEnv().getLocalPlayer(); + client->getParticleManager()->handleParticleEvent(event, client, player); +} + +void Game::handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam) { LocalPlayer *player = client->getEnv().getLocalPlayer(); - while (client->hasClientEvents()) { - ClientEvent event = client->getClientEvent(); + u32 id = event->hudadd.id; - switch (event.type) { - case CE_PLAYER_DAMAGE: - if (client->getHP() == 0) - break; - if (client->moddingEnabled()) { - client->getScript()->on_damage_taken(event.player_damage.amount); - } + HudElement *e = player->getHud(id); - runData.damage_flash += 95.0 + 3.2 * event.player_damage.amount; - runData.damage_flash = MYMIN(runData.damage_flash, 127.0); - - player->hurt_tilt_timer = 1.5; - player->hurt_tilt_strength = - rangelim(event.player_damage.amount / 4, 1.0, 4.0); - - client->event()->put(new SimpleTriggerEvent("PlayerDamage")); - break; - - case CE_PLAYER_FORCE_MOVE: - cam->camera_yaw = event.player_force_move.yaw; - cam->camera_pitch = event.player_force_move.pitch; - break; - - case CE_DEATHSCREEN: - // This should be enabled for death formspec in builtin - client->getScript()->on_death(); - - /* Handle visualization */ - runData.damage_flash = 0; - player->hurt_tilt_timer = 0; - player->hurt_tilt_strength = 0; - break; - - case CE_SHOW_FORMSPEC: - if (event.show_formspec.formspec->empty()) { - if (current_formspec && (event.show_formspec.formname->empty() - || *(event.show_formspec.formname) == cur_formname)) { - current_formspec->quitMenu(); - } - } else { - FormspecFormSource *fs_src = - new FormspecFormSource(*(event.show_formspec.formspec)); - TextDestPlayerInventory *txt_dst = - new TextDestPlayerInventory(client, *(event.show_formspec.formname)); - - create_formspec_menu(¤t_formspec, client, &input->joystick, - fs_src, txt_dst); - cur_formname = *(event.show_formspec.formname); - } - - delete event.show_formspec.formspec; - delete event.show_formspec.formname; - break; - - case CE_SHOW_LOCAL_FORMSPEC: - { - FormspecFormSource *fs_src = new FormspecFormSource(*event.show_formspec.formspec); - LocalFormspecHandler *txt_dst = new LocalFormspecHandler(*event.show_formspec.formname, client); - create_formspec_menu(¤t_formspec, client, &input->joystick, - fs_src, txt_dst); - } - delete event.show_formspec.formspec; - delete event.show_formspec.formname; - break; - - case CE_SPAWN_PARTICLE: - case CE_ADD_PARTICLESPAWNER: - case CE_DELETE_PARTICLESPAWNER: - client->getParticleManager()->handleParticleEvent(&event, client, player); - break; - - case CE_HUDADD: - { - u32 id = event.hudadd.id; - - HudElement *e = player->getHud(id); - - if (e != NULL) { - delete event.hudadd.pos; - delete event.hudadd.name; - delete event.hudadd.scale; - delete event.hudadd.text; - delete event.hudadd.align; - delete event.hudadd.offset; - delete event.hudadd.world_pos; - delete event.hudadd.size; - continue; - } - - e = new HudElement; - e->type = (HudElementType)event.hudadd.type; - e->pos = *event.hudadd.pos; - e->name = *event.hudadd.name; - e->scale = *event.hudadd.scale; - e->text = *event.hudadd.text; - e->number = event.hudadd.number; - e->item = event.hudadd.item; - e->dir = event.hudadd.dir; - e->align = *event.hudadd.align; - e->offset = *event.hudadd.offset; - e->world_pos = *event.hudadd.world_pos; - e->size = *event.hudadd.size; - - u32 new_id = player->addHud(e); - //if this isn't true our huds aren't consistent - sanity_check(new_id == id); - } - - delete event.hudadd.pos; - delete event.hudadd.name; - delete event.hudadd.scale; - delete event.hudadd.text; - delete event.hudadd.align; - delete event.hudadd.offset; - delete event.hudadd.world_pos; - delete event.hudadd.size; - break; - - case CE_HUDRM: - { - HudElement *e = player->removeHud(event.hudrm.id); - - delete e; - } - break; - - case CE_HUDCHANGE: - { - u32 id = event.hudchange.id; - HudElement *e = player->getHud(id); - - if (e == NULL) { - delete event.hudchange.v3fdata; - delete event.hudchange.v2fdata; - delete event.hudchange.sdata; - delete event.hudchange.v2s32data; - continue; - } - - switch (event.hudchange.stat) { - case HUD_STAT_POS: - e->pos = *event.hudchange.v2fdata; - break; - - case HUD_STAT_NAME: - e->name = *event.hudchange.sdata; - break; - - case HUD_STAT_SCALE: - e->scale = *event.hudchange.v2fdata; - break; - - case HUD_STAT_TEXT: - e->text = *event.hudchange.sdata; - break; - - case HUD_STAT_NUMBER: - e->number = event.hudchange.data; - break; - - case HUD_STAT_ITEM: - e->item = event.hudchange.data; - break; - - case HUD_STAT_DIR: - e->dir = event.hudchange.data; - break; - - case HUD_STAT_ALIGN: - e->align = *event.hudchange.v2fdata; - break; - - case HUD_STAT_OFFSET: - e->offset = *event.hudchange.v2fdata; - break; - - case HUD_STAT_WORLD_POS: - e->world_pos = *event.hudchange.v3fdata; - break; - - case HUD_STAT_SIZE: - e->size = *event.hudchange.v2s32data; - break; - } - } - - delete event.hudchange.v3fdata; - delete event.hudchange.v2fdata; - delete event.hudchange.sdata; - delete event.hudchange.v2s32data; - break; - - case CE_SET_SKY: - sky->setVisible(false); - // Whether clouds are visible in front of a custom skybox - sky->setCloudsEnabled(event.set_sky.clouds); - - if (skybox) { - skybox->remove(); - skybox = NULL; - } - - // Handle according to type - if (*event.set_sky.type == "regular") { - sky->setVisible(true); - sky->setCloudsEnabled(true); - } else if (*event.set_sky.type == "skybox" && - event.set_sky.params->size() == 6) { - sky->setFallbackBgColor(*event.set_sky.bgcolor); - skybox = RenderingEngine::get_scene_manager()->addSkyBoxSceneNode( - texture_src->getTextureForMesh((*event.set_sky.params)[0]), - texture_src->getTextureForMesh((*event.set_sky.params)[1]), - texture_src->getTextureForMesh((*event.set_sky.params)[2]), - texture_src->getTextureForMesh((*event.set_sky.params)[3]), - texture_src->getTextureForMesh((*event.set_sky.params)[4]), - texture_src->getTextureForMesh((*event.set_sky.params)[5])); - } - // Handle everything else as plain color - else { - if (*event.set_sky.type != "plain") - infostream << "Unknown sky type: " - << (*event.set_sky.type) << std::endl; - - sky->setFallbackBgColor(*event.set_sky.bgcolor); - } - - delete event.set_sky.bgcolor; - delete event.set_sky.type; - delete event.set_sky.params; - break; - - case CE_OVERRIDE_DAY_NIGHT_RATIO: - client->getEnv().setDayNightRatioOverride( - event.override_day_night_ratio.do_override, - event.override_day_night_ratio.ratio_f * 1000); - break; - - case CE_CLOUD_PARAMS: - if (clouds) { - clouds->setDensity(event.cloud_params.density); - clouds->setColorBright(video::SColor(event.cloud_params.color_bright)); - clouds->setColorAmbient(video::SColor(event.cloud_params.color_ambient)); - clouds->setHeight(event.cloud_params.height); - clouds->setThickness(event.cloud_params.thickness); - clouds->setSpeed(v2f( - event.cloud_params.speed_x, - event.cloud_params.speed_y)); - } - break; - - default: - // unknown or unhandled type - break; - - } + if (e != NULL) { + delete event->hudadd.pos; + delete event->hudadd.name; + delete event->hudadd.scale; + delete event->hudadd.text; + delete event->hudadd.align; + delete event->hudadd.offset; + delete event->hudadd.world_pos; + delete event->hudadd.size; + return; } + + e = new HudElement; + e->type = (HudElementType)event->hudadd.type; + e->pos = *event->hudadd.pos; + e->name = *event->hudadd.name; + e->scale = *event->hudadd.scale; + e->text = *event->hudadd.text; + e->number = event->hudadd.number; + e->item = event->hudadd.item; + e->dir = event->hudadd.dir; + e->align = *event->hudadd.align; + e->offset = *event->hudadd.offset; + e->world_pos = *event->hudadd.world_pos; + e->size = *event->hudadd.size; + + u32 new_id = player->addHud(e); + //if this isn't true our huds aren't consistent + sanity_check(new_id == id); + + delete event->hudadd.pos; + delete event->hudadd.name; + delete event->hudadd.scale; + delete event->hudadd.text; + delete event->hudadd.align; + delete event->hudadd.offset; + delete event->hudadd.world_pos; + delete event->hudadd.size; } +void Game::handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam) +{ + LocalPlayer *player = client->getEnv().getLocalPlayer(); + HudElement *e = player->removeHud(event->hudrm.id); + delete e; +} + +void Game::handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam) +{ + LocalPlayer *player = client->getEnv().getLocalPlayer(); + + u32 id = event->hudchange.id; + HudElement *e = player->getHud(id); + + if (e == NULL) { + delete event->hudchange.v3fdata; + delete event->hudchange.v2fdata; + delete event->hudchange.sdata; + delete event->hudchange.v2s32data; + return; + } + + switch (event->hudchange.stat) { + case HUD_STAT_POS: + e->pos = *event->hudchange.v2fdata; + break; + + case HUD_STAT_NAME: + e->name = *event->hudchange.sdata; + break; + + case HUD_STAT_SCALE: + e->scale = *event->hudchange.v2fdata; + break; + + case HUD_STAT_TEXT: + e->text = *event->hudchange.sdata; + break; + + case HUD_STAT_NUMBER: + e->number = event->hudchange.data; + break; + + case HUD_STAT_ITEM: + e->item = event->hudchange.data; + break; + + case HUD_STAT_DIR: + e->dir = event->hudchange.data; + break; + + case HUD_STAT_ALIGN: + e->align = *event->hudchange.v2fdata; + break; + + case HUD_STAT_OFFSET: + e->offset = *event->hudchange.v2fdata; + break; + + case HUD_STAT_WORLD_POS: + e->world_pos = *event->hudchange.v3fdata; + break; + + case HUD_STAT_SIZE: + e->size = *event->hudchange.v2s32data; + break; + } + + delete event->hudchange.v3fdata; + delete event->hudchange.v2fdata; + delete event->hudchange.sdata; + delete event->hudchange.v2s32data; +} + +void Game::handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam) +{ + sky->setVisible(false); + // Whether clouds are visible in front of a custom skybox + sky->setCloudsEnabled(event->set_sky.clouds); + + if (skybox) { + skybox->remove(); + skybox = NULL; + } + + // Handle according to type + if (*event->set_sky.type == "regular") { + sky->setVisible(true); + sky->setCloudsEnabled(true); + } else if (*event->set_sky.type == "skybox" && + event->set_sky.params->size() == 6) { + sky->setFallbackBgColor(*event->set_sky.bgcolor); + skybox = RenderingEngine::get_scene_manager()->addSkyBoxSceneNode( + texture_src->getTextureForMesh((*event->set_sky.params)[0]), + texture_src->getTextureForMesh((*event->set_sky.params)[1]), + texture_src->getTextureForMesh((*event->set_sky.params)[2]), + texture_src->getTextureForMesh((*event->set_sky.params)[3]), + texture_src->getTextureForMesh((*event->set_sky.params)[4]), + texture_src->getTextureForMesh((*event->set_sky.params)[5])); + } + // Handle everything else as plain color + else { + if (*event->set_sky.type != "plain") + infostream << "Unknown sky type: " + << (*event->set_sky.type) << std::endl; + + sky->setFallbackBgColor(*event->set_sky.bgcolor); + } + + delete event->set_sky.bgcolor; + delete event->set_sky.type; + delete event->set_sky.params; +} + +void Game::handleClientEvent_OverrideDayNigthRatio(ClientEvent *event, + CameraOrientation *cam) +{ + client->getEnv().setDayNightRatioOverride( + event->override_day_night_ratio.do_override, + event->override_day_night_ratio.ratio_f * 1000.0f); +} + +void Game::handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam) +{ + if (!clouds) + return; + + clouds->setDensity(event->cloud_params.density); + clouds->setColorBright(video::SColor(event->cloud_params.color_bright)); + clouds->setColorAmbient(video::SColor(event->cloud_params.color_ambient)); + clouds->setHeight(event->cloud_params.height); + clouds->setThickness(event->cloud_params.thickness); + clouds->setSpeed(v2f(event->cloud_params.speed_x, event->cloud_params.speed_y)); +} + +void Game::processClientEvents(CameraOrientation *cam) +{ + while (client->hasClientEvents()) { + std::unique_ptr event(client->getClientEvent()); + FATAL_ERROR_IF(event->type >= CLIENTEVENT_MAX, "Invalid clientevent type"); + const ClientEventHandler& evHandler = clientEventHandler[event->type]; + (this->*evHandler.handler)(event.get(), cam); + } +} void Game::updateCamera(u32 busy_time, f32 dtime) { diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index f42f9219b..49dba7a91 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serialization.h" #include "server.h" #include "util/strfnd.h" +#include "client/clientevent.h" #include "network/clientopcodes.h" #include "network/connection.h" #include "script/scripting_client.h" @@ -577,9 +578,9 @@ void Client::handleCommand_HP(NetworkPacket* pkt) if (hp < oldhp) { // Add to ClientEvent queue - ClientEvent event; - event.type = CE_PLAYER_DAMAGE; - event.player_damage.amount = oldhp - hp; + ClientEvent *event = new ClientEvent(); + event->type = CE_PLAYER_DAMAGE; + event->player_damage.amount = oldhp - hp; m_client_event_queue.push(event); } } @@ -620,10 +621,10 @@ void Client::handleCommand_MovePlayer(NetworkPacket* pkt) it would just force the pitch and yaw values to whatever the camera points to. */ - ClientEvent event; - event.type = CE_PLAYER_FORCE_MOVE; - event.player_force_move.pitch = pitch; - event.player_force_move.yaw = yaw; + ClientEvent *event = new ClientEvent(); + event->type = CE_PLAYER_FORCE_MOVE; + event->player_force_move.pitch = pitch; + event->player_force_move.yaw = yaw; m_client_event_queue.push(event); // Ignore damage for a few seconds, so that the player doesn't @@ -639,12 +640,12 @@ void Client::handleCommand_DeathScreen(NetworkPacket* pkt) *pkt >> set_camera_point_target; *pkt >> camera_point_target; - ClientEvent event; - event.type = CE_DEATHSCREEN; - event.deathscreen.set_camera_point_target = set_camera_point_target; - event.deathscreen.camera_point_target_x = camera_point_target.X; - event.deathscreen.camera_point_target_y = camera_point_target.Y; - event.deathscreen.camera_point_target_z = camera_point_target.Z; + ClientEvent *event = new ClientEvent(); + event->type = CE_DEATHSCREEN; + event->deathscreen.set_camera_point_target = set_camera_point_target; + event->deathscreen.camera_point_target_x = camera_point_target.X; + event->deathscreen.camera_point_target_y = camera_point_target.Y; + event->deathscreen.camera_point_target_z = camera_point_target.Z; m_client_event_queue.push(event); } @@ -942,12 +943,12 @@ void Client::handleCommand_ShowFormSpec(NetworkPacket* pkt) *pkt >> formname; - ClientEvent event; - event.type = CE_SHOW_FORMSPEC; + ClientEvent *event = new ClientEvent(); + event->type = CE_SHOW_FORMSPEC; // pointer is required as event is a struct only! // adding a std:string to a struct isn't possible - event.show_formspec.formspec = new std::string(formspec); - event.show_formspec.formname = new std::string(formname); + event->show_formspec.formspec = new std::string(formspec); + event->show_formspec.formname = new std::string(formname); m_client_event_queue.push(event); } @@ -975,19 +976,19 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt) glow = readU8(is); } catch (...) {} - ClientEvent event; - event.type = CE_SPAWN_PARTICLE; - event.spawn_particle.pos = new v3f (pos); - event.spawn_particle.vel = new v3f (vel); - event.spawn_particle.acc = new v3f (acc); - event.spawn_particle.expirationtime = expirationtime; - event.spawn_particle.size = size; - event.spawn_particle.collisiondetection = collisiondetection; - event.spawn_particle.collision_removal = collision_removal; - event.spawn_particle.vertical = vertical; - event.spawn_particle.texture = new std::string(texture); - event.spawn_particle.animation = animation; - event.spawn_particle.glow = glow; + ClientEvent *event = new ClientEvent(); + event->type = CE_SPAWN_PARTICLE; + event->spawn_particle.pos = new v3f (pos); + event->spawn_particle.vel = new v3f (vel); + event->spawn_particle.acc = new v3f (acc); + event->spawn_particle.expirationtime = expirationtime; + event->spawn_particle.size = size; + event->spawn_particle.collisiondetection = collisiondetection; + event->spawn_particle.collision_removal = collision_removal; + event->spawn_particle.vertical = vertical; + event->spawn_particle.texture = new std::string(texture); + event->spawn_particle.animation = animation; + event->spawn_particle.glow = glow; m_client_event_queue.push(event); } @@ -1035,28 +1036,28 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) glow = readU8(is); } catch (...) {} - ClientEvent event; - event.type = CE_ADD_PARTICLESPAWNER; - event.add_particlespawner.amount = amount; - event.add_particlespawner.spawntime = spawntime; - event.add_particlespawner.minpos = new v3f (minpos); - event.add_particlespawner.maxpos = new v3f (maxpos); - event.add_particlespawner.minvel = new v3f (minvel); - event.add_particlespawner.maxvel = new v3f (maxvel); - event.add_particlespawner.minacc = new v3f (minacc); - event.add_particlespawner.maxacc = new v3f (maxacc); - event.add_particlespawner.minexptime = minexptime; - event.add_particlespawner.maxexptime = maxexptime; - event.add_particlespawner.minsize = minsize; - event.add_particlespawner.maxsize = maxsize; - event.add_particlespawner.collisiondetection = collisiondetection; - event.add_particlespawner.collision_removal = collision_removal; - event.add_particlespawner.attached_id = attached_id; - event.add_particlespawner.vertical = vertical; - event.add_particlespawner.texture = new std::string(texture); - event.add_particlespawner.id = id; - event.add_particlespawner.animation = animation; - event.add_particlespawner.glow = glow; + ClientEvent *event = new ClientEvent(); + event->type = CE_ADD_PARTICLESPAWNER; + event->add_particlespawner.amount = amount; + event->add_particlespawner.spawntime = spawntime; + event->add_particlespawner.minpos = new v3f (minpos); + event->add_particlespawner.maxpos = new v3f (maxpos); + event->add_particlespawner.minvel = new v3f (minvel); + event->add_particlespawner.maxvel = new v3f (maxvel); + event->add_particlespawner.minacc = new v3f (minacc); + event->add_particlespawner.maxacc = new v3f (maxacc); + event->add_particlespawner.minexptime = minexptime; + event->add_particlespawner.maxexptime = maxexptime; + event->add_particlespawner.minsize = minsize; + event->add_particlespawner.maxsize = maxsize; + event->add_particlespawner.collisiondetection = collisiondetection; + event->add_particlespawner.collision_removal = collision_removal; + event->add_particlespawner.attached_id = attached_id; + event->add_particlespawner.vertical = vertical; + event->add_particlespawner.texture = new std::string(texture); + event->add_particlespawner.id = id; + event->add_particlespawner.animation = animation; + event->add_particlespawner.glow = glow; m_client_event_queue.push(event); } @@ -1076,10 +1077,11 @@ void Client::handleCommand_DeleteParticleSpawner(NetworkPacket* pkt) } - ClientEvent event; - event.type = CE_DELETE_PARTICLESPAWNER; - event.delete_particlespawner.id = - (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? (u32) legacy_id : id); + ClientEvent *event = new ClientEvent(); + event->type = CE_DELETE_PARTICLESPAWNER; + event->delete_particlespawner.id = + (pkt->getCommand() == TOCLIENT_DELETE_PARTICLESPAWNER_LEGACY ? + (u32) legacy_id : id); m_client_event_queue.push(event); } @@ -1114,21 +1116,21 @@ void Client::handleCommand_HudAdd(NetworkPacket* pkt) *pkt >> size; } catch(SerializationError &e) {}; - ClientEvent event; - event.type = CE_HUDADD; - event.hudadd.id = id; - event.hudadd.type = type; - event.hudadd.pos = new v2f(pos); - event.hudadd.name = new std::string(name); - event.hudadd.scale = new v2f(scale); - event.hudadd.text = new std::string(text); - event.hudadd.number = number; - event.hudadd.item = item; - event.hudadd.dir = dir; - event.hudadd.align = new v2f(align); - event.hudadd.offset = new v2f(offset); - event.hudadd.world_pos = new v3f(world_pos); - event.hudadd.size = new v2s32(size); + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDADD; + event->hudadd.id = id; + event->hudadd.type = type; + event->hudadd.pos = new v2f(pos); + event->hudadd.name = new std::string(name); + event->hudadd.scale = new v2f(scale); + event->hudadd.text = new std::string(text); + event->hudadd.number = number; + event->hudadd.item = item; + event->hudadd.dir = dir; + event->hudadd.align = new v2f(align); + event->hudadd.offset = new v2f(offset); + event->hudadd.world_pos = new v3f(world_pos); + event->hudadd.size = new v2s32(size); m_client_event_queue.push(event); } @@ -1138,9 +1140,9 @@ void Client::handleCommand_HudRemove(NetworkPacket* pkt) *pkt >> id; - ClientEvent event; - event.type = CE_HUDRM; - event.hudrm.id = id; + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDRM; + event->hudrm.id = id; m_client_event_queue.push(event); } @@ -1168,15 +1170,15 @@ void Client::handleCommand_HudChange(NetworkPacket* pkt) else *pkt >> intdata; - ClientEvent event; - event.type = CE_HUDCHANGE; - event.hudchange.id = id; - event.hudchange.stat = (HudElementStat)stat; - event.hudchange.v2fdata = new v2f(v2fdata); - event.hudchange.v3fdata = new v3f(v3fdata); - event.hudchange.sdata = new std::string(sdata); - event.hudchange.data = intdata; - event.hudchange.v2s32data = new v2s32(v2s32data); + ClientEvent *event = new ClientEvent(); + event->type = CE_HUDCHANGE; + event->hudchange.id = id; + event->hudchange.stat = (HudElementStat)stat; + event->hudchange.v2fdata = new v2f(v2fdata); + event->hudchange.v3fdata = new v3f(v3fdata); + event->hudchange.sdata = new std::string(sdata); + event->hudchange.data = intdata; + event->hudchange.v2s32data = new v2s32(v2s32data); m_client_event_queue.push(event); } @@ -1261,12 +1263,12 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) clouds = readU8(is); } catch (...) {} - ClientEvent event; - event.type = CE_SET_SKY; - event.set_sky.bgcolor = bgcolor; - event.set_sky.type = type; - event.set_sky.params = params; - event.set_sky.clouds = clouds; + ClientEvent *event = new ClientEvent(); + event->type = CE_SET_SKY; + event->set_sky.bgcolor = bgcolor; + event->set_sky.type = type; + event->set_sky.params = params; + event->set_sky.clouds = clouds; m_client_event_queue.push(event); } @@ -1282,19 +1284,19 @@ void Client::handleCommand_CloudParams(NetworkPacket* pkt) *pkt >> density >> color_bright >> color_ambient >> height >> thickness >> speed; - ClientEvent event; - event.type = CE_CLOUD_PARAMS; - event.cloud_params.density = density; + ClientEvent *event = new ClientEvent(); + event->type = CE_CLOUD_PARAMS; + event->cloud_params.density = density; // use the underlying u32 representation, because we can't // use struct members with constructors here, and this way // we avoid using new() and delete() for no good reason - event.cloud_params.color_bright = color_bright.color; - event.cloud_params.color_ambient = color_ambient.color; - event.cloud_params.height = height; - event.cloud_params.thickness = thickness; + event->cloud_params.color_bright = color_bright.color; + event->cloud_params.color_ambient = color_ambient.color; + event->cloud_params.height = height; + event->cloud_params.thickness = thickness; // same here: deconstruct to skip constructor - event.cloud_params.speed_x = speed.X; - event.cloud_params.speed_y = speed.Y; + event->cloud_params.speed_x = speed.X; + event->cloud_params.speed_y = speed.Y; m_client_event_queue.push(event); } @@ -1307,10 +1309,10 @@ void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt) float day_night_ratio_f = (float)day_night_ratio_u / 65536; - ClientEvent event; - event.type = CE_OVERRIDE_DAY_NIGHT_RATIO; - event.override_day_night_ratio.do_override = do_override; - event.override_day_night_ratio.ratio_f = day_night_ratio_f; + ClientEvent *event = new ClientEvent(); + event->type = CE_OVERRIDE_DAY_NIGHT_RATIO; + event->override_day_night_ratio.do_override = do_override; + event->override_day_night_ratio.ratio_f = day_night_ratio_f; m_client_event_queue.push(event); } diff --git a/src/particles.cpp b/src/particles.cpp index 815ae98c5..4839e45c4 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "particles.h" #include "client.h" #include "collision.h" +#include "client/clientevent.h" #include "client/renderingengine.h" #include "util/numeric.h" #include "light.h" diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp index 81bf49329..ba22a0424 100644 --- a/src/script/lua_api/l_client.cpp +++ b/src/script/lua_api/l_client.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "l_client.h" #include "chatmessage.h" #include "client.h" +#include "client/clientevent.h" #include "clientenvironment.h" #include "common/c_content.h" #include "common/c_converter.h" @@ -129,10 +130,10 @@ int ModApiClient::l_show_formspec(lua_State *L) if (!lua_isstring(L, 1) || !lua_isstring(L, 2)) return 0; - ClientEvent event; - event.type = CE_SHOW_LOCAL_FORMSPEC; - event.show_formspec.formname = new std::string(luaL_checkstring(L, 1)); - event.show_formspec.formspec = new std::string(luaL_checkstring(L, 2)); + ClientEvent *event = new ClientEvent(); + event->type = CE_SHOW_LOCAL_FORMSPEC; + event->show_formspec.formname = new std::string(luaL_checkstring(L, 1)); + event->show_formspec.formspec = new std::string(luaL_checkstring(L, 2)); getClient(L)->pushToEventQueue(event); lua_pushboolean(L, true); return 1;