From b16252dcae8c6b0e79c20fa4c3cbddc37ad377cb Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 22 Dec 2016 19:29:15 +0100 Subject: Various anticheat improvements * Calculate maximum interact distance from wielded tool * New "interacted_while_dead" cheat_type for the Lua API * Disallow dropping items while dead * Move player to spawn before resurrecting them --- src/server.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index c9d5c7129..fa7a838d4 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2557,15 +2557,15 @@ void Server::RespawnPlayer(u16 peer_id) playersao->setHP(PLAYER_MAX_HP); playersao->setBreath(PLAYER_MAX_BREATH); - SendPlayerHP(peer_id); - SendPlayerBreath(peer_id); - bool repositioned = m_script->on_respawnplayer(playersao); - if(!repositioned){ + if (!repositioned) { v3f pos = findSpawnPos(); // setPos will send the new position to client playersao->setPos(pos); } + + SendPlayerHP(peer_id); + SendPlayerBreath(peer_id); } -- cgit v1.2.3 From 52ba1f867e5edb579a59a44fbb8286d4f1e54931 Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Sun, 1 Jan 2017 16:13:01 +0100 Subject: Breath cheat fix: server side Breath is now handled server side. Changing this behaviour required some modifications to core: * Ignore TOSERVER_BREATH package, marking it as obsolete * Clients doesn't send the breath to server anymore * Use PlayerSAO pointer instead of peer_id in Server::SendPlayerBreath to prevent a useless lookup (little perf gain) * drop a useless static_cast in emergePlayer --- src/client.cpp | 11 +++-- src/content_sao.cpp | 39 +++++++++++++++-- src/content_sao.h | 7 +++- src/environment.cpp | 84 ++++++++++++++++++------------------- src/network/clientopcodes.cpp | 2 +- src/network/networkprotocol.h | 6 ++- src/network/serveropcodes.cpp | 2 +- src/network/serverpackethandler.cpp | 40 ------------------ src/remoteplayer.cpp | 2 +- src/script/lua_api/l_object.cpp | 5 --- src/server.cpp | 15 +++---- src/server.h | 3 +- src/unittest/test_player.cpp | 4 +- 13 files changed, 107 insertions(+), 113 deletions(-) (limited to 'src/server.cpp') diff --git a/src/client.cpp b/src/client.cpp index 5476aad0e..1446ebad8 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -499,9 +499,10 @@ void Client::step(float dtime) m_client_event_queue.push(event); } } - else if(event.type == CEE_PLAYER_BREATH) { - u16 breath = event.player_breath.amount; - sendBreath(breath); + // Protocol v29 or greater obsoleted this event + else if (event.type == CEE_PLAYER_BREATH && m_proto_ver < 29) { + u16 breath = event.player_breath.amount; + sendBreath(breath); } } @@ -1270,6 +1271,10 @@ void Client::sendBreath(u16 breath) { DSTACK(FUNCTION_NAME); + // Protocol v29 make this obsolete + if (m_proto_ver >= 29) + return; + NetworkPacket pkt(TOSERVER_BREATH, sizeof(u16)); pkt << breath; Send(&pkt); diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 77ab51a02..f866d4372 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serialization.h" // For compressZlib #include "tool.h" // For ToolCapabilities #include "gamedef.h" +#include "nodedef.h" #include "remoteplayer.h" #include "server.h" #include "scripting_game.h" @@ -940,8 +941,35 @@ bool PlayerSAO::isAttached() void PlayerSAO::step(float dtime, bool send_recommended) { - if(!m_properties_sent) - { + if (m_drowning_interval.step(dtime, 2.0)) { + // get head position + v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_env->getMap().getNodeNoEx(p); + const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n); + // If node generates drown + if (c.drowning > 0) { + if (m_hp > 0 && m_breath > 0) + setBreath(m_breath - 1); + + // No more breath, damage player + if (m_breath == 0) { + setHP(m_hp - c.drowning); + ((Server*) m_env->getGameDef())->SendPlayerHPOrDie(this); + } + } + } + + if (m_breathing_interval.step(dtime, 0.5)) { + // get head position + v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_env->getMap().getNodeNoEx(p); + const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n); + // If player is alive & no drowning, breath + if (m_hp > 0 && c.drowning == 0) + setBreath(m_breath + 1); + } + + if (!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list @@ -1237,12 +1265,15 @@ void PlayerSAO::setHP(s16 hp) m_properties_sent = false; } -void PlayerSAO::setBreath(const u16 breath) +void PlayerSAO::setBreath(const u16 breath, bool send) { if (m_player && breath != m_breath) m_player->setDirty(true); - m_breath = breath; + m_breath = MYMIN(breath, PLAYER_MAX_BREATH); + + if (send) + ((Server *) m_env->getGameDef())->SendPlayerBreath(this); } void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups) diff --git a/src/content_sao.h b/src/content_sao.h index 86255183d..9c66068b3 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef CONTENT_SAO_HEADER #define CONTENT_SAO_HEADER +#include #include "serverobject.h" #include "itemgroup.h" #include "object_properties.h" @@ -232,7 +233,7 @@ public: void setHPRaw(s16 hp) { m_hp = hp; } s16 readDamage(); u16 getBreath() const { return m_breath; } - void setBreath(const u16 breath); + void setBreath(const u16 breath, bool send = true); void setArmorGroups(const ItemGroupList &armor_groups); ItemGroupList getArmorGroups(); void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop); @@ -339,6 +340,10 @@ private: v3s16 m_nocheat_dig_pos; float m_nocheat_dig_time; + // Timers + IntervalLimiter m_breathing_interval; + IntervalLimiter m_drowning_interval; + int m_wield_index; bool m_position_not_sent; ItemGroupList m_armor_groups; diff --git a/src/environment.cpp b/src/environment.cpp index 707d89659..ac9b5b079 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -2511,51 +2511,51 @@ void ClientEnvironment::step(float dtime) } } - /* - Drowning - */ - if(m_drowning_interval.step(dtime, 2.0)) - { - v3f pf = lplayer->getPosition(); - - // head - v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); - MapNode n = m_map->getNodeNoEx(p); - ContentFeatures c = m_gamedef->ndef()->get(n); - u8 drowning_damage = c.drowning; - if(drowning_damage > 0 && lplayer->hp > 0){ - u16 breath = lplayer->getBreath(); - if(breath > 10){ - breath = 11; - } - if(breath > 0){ - breath -= 1; + // Protocol v29 make this behaviour obsolete + if (((Client*) getGameDef())->getProtoVersion() < 29) { + /* + Drowning + */ + if (m_drowning_interval.step(dtime, 2.0)) { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + u8 drowning_damage = c.drowning; + if (drowning_damage > 0 && lplayer->hp > 0) { + u16 breath = lplayer->getBreath(); + if (breath > 10) { + breath = 11; + } + if (breath > 0) { + breath -= 1; + } + lplayer->setBreath(breath); + updateLocalPlayerBreath(breath); } - lplayer->setBreath(breath); - updateLocalPlayerBreath(breath); - } - if(lplayer->getBreath() == 0 && drowning_damage > 0){ - damageLocalPlayer(drowning_damage, true); + if (lplayer->getBreath() == 0 && drowning_damage > 0) { + damageLocalPlayer(drowning_damage, true); + } } - } - if(m_breathing_interval.step(dtime, 0.5)) - { - v3f pf = lplayer->getPosition(); - - // head - v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); - MapNode n = m_map->getNodeNoEx(p); - ContentFeatures c = m_gamedef->ndef()->get(n); - if (!lplayer->hp){ - lplayer->setBreath(11); - } - else if(c.drowning == 0){ - u16 breath = lplayer->getBreath(); - if(breath <= 10){ - breath += 1; - lplayer->setBreath(breath); - updateLocalPlayerBreath(breath); + if (m_breathing_interval.step(dtime, 0.5)) { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + if (!lplayer->hp) { + lplayer->setBreath(11); + } else if (c.drowning == 0) { + u16 breath = lplayer->getBreath(); + if (breath <= 10) { + breath += 1; + lplayer->setBreath(breath); + updateLocalPlayerBreath(breath); + } } } } diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index 3364de8c5..6defdcf1b 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -193,7 +193,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] = null_command_factory, // 0x3f { "TOSERVER_REQUEST_MEDIA", 1, true }, // 0x40 { "TOSERVER_RECEIVED_MEDIA", 1, true }, // 0x41 - { "TOSERVER_BREATH", 0, true }, // 0x42 + null_command_factory, // 0x42 old TOSERVER_BREATH. Ignored by servers { "TOSERVER_CLIENT_READY", 0, true }, // 0x43 null_command_factory, // 0x44 null_command_factory, // 0x45 diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 018b392b6..f65167380 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -138,9 +138,11 @@ with this program; if not, write to the Free Software Foundation, Inc., Add nodedef v3 - connected nodeboxes PROTOCOL_VERSION 28: CPT2_MESHOPTIONS + PROTOCOL_VERSION 29: + Server doesn't accept TOSERVER_BREATH anymore */ -#define LATEST_PROTOCOL_VERSION 28 +#define LATEST_PROTOCOL_VERSION 29 // Server's supported network protocol range #define SERVER_PROTOCOL_VERSION_MIN 13 @@ -833,7 +835,7 @@ enum ToServerCommand */ - TOSERVER_BREATH = 0x42, + TOSERVER_BREATH = 0x42, // Obsolete /* u16 breath */ diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index 9b14a1be3..642dd376a 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -90,7 +90,7 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] = null_command_handler, // 0x3f { "TOSERVER_REQUEST_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40 { "TOSERVER_RECEIVED_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_ReceivedMedia }, // 0x41 - { "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Breath }, // 0x42 + { "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Deprecated }, // 0x42 Old breath model which is now deprecated for anticheating { "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43 null_command_handler, // 0x44 null_command_handler, // 0x45 diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index d0f4d948d..eeabcca71 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1136,46 +1136,6 @@ void Server::handleCommand_Damage(NetworkPacket* pkt) } } -void Server::handleCommand_Breath(NetworkPacket* pkt) -{ - u16 breath; - - *pkt >> breath; - - RemotePlayer *player = m_env->getPlayer(pkt->getPeerId()); - - if (player == NULL) { - errorstream << "Server::ProcessData(): Canceling: " - "No player for peer_id=" << pkt->getPeerId() - << " disconnecting peer!" << std::endl; - m_con.DisconnectPeer(pkt->getPeerId()); - return; - } - - - PlayerSAO *playersao = player->getPlayerSAO(); - if (playersao == NULL) { - errorstream << "Server::ProcessData(): Canceling: " - "No player object for peer_id=" << pkt->getPeerId() - << " disconnecting peer!" << std::endl; - m_con.DisconnectPeer(pkt->getPeerId()); - return; - } - - /* - * If player is dead, we don't need to update the breath - * He is dead ! - */ - if (playersao->isDead()) { - verbosestream << "TOSERVER_BREATH: " << player->getName() - << " is dead. Ignoring packet"; - return; - } - - playersao->setBreath(breath); - SendPlayerBreath(pkt->getPeerId()); -} - void Server::handleCommand_Password(NetworkPacket* pkt) { if (pkt->getSize() != PASSWORD_SIZE * 2) diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp index 67ab89113..18bfa1030 100644 --- a/src/remoteplayer.cpp +++ b/src/remoteplayer.cpp @@ -148,7 +148,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername, } catch (SettingNotFoundException &e) {} try { - sao->setBreath(args.getS32("breath")); + sao->setBreath(args.getS32("breath"), false); } catch (SettingNotFoundException &e) {} } diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 2a8b8a64e..cfdceb28e 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1152,13 +1152,8 @@ int ObjectRef::l_set_breath(lua_State *L) PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; u16 breath = luaL_checknumber(L, 2); - // Do it co->setBreath(breath); - // If the object is a player sent the breath to client - if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) - getServer(L)->SendPlayerBreath(((PlayerSAO*)co)->getPeerID()); - return 0; } diff --git a/src/server.cpp b/src/server.cpp index fa7a838d4..60dbef0d2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1076,8 +1076,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id) } m_clients.unlock(); - RemotePlayer *player = - static_cast(m_env->getPlayer(playername.c_str())); + RemotePlayer *player = m_env->getPlayer(playername.c_str()); // If failed, cancel if ((playersao == NULL) || (player == NULL)) { @@ -1113,7 +1112,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id) SendPlayerHPOrDie(playersao); // Send Breath - SendPlayerBreath(peer_id); + SendPlayerBreath(playersao); // Show death screen if necessary if (playersao->isDead()) @@ -1857,14 +1856,13 @@ void Server::SendPlayerHP(u16 peer_id) playersao->m_messages_out.push(aom); } -void Server::SendPlayerBreath(u16 peer_id) +void Server::SendPlayerBreath(PlayerSAO *sao) { DSTACK(FUNCTION_NAME); - PlayerSAO *playersao = getPlayerSAO(peer_id); - assert(playersao); + assert(sao); - m_script->player_event(playersao, "breath_changed"); - SendBreath(peer_id, playersao->getBreath()); + m_script->player_event(sao, "breath_changed"); + SendBreath(sao->getPeerID(), sao->getBreath()); } void Server::SendMovePlayer(u16 peer_id) @@ -2565,7 +2563,6 @@ void Server::RespawnPlayer(u16 peer_id) } SendPlayerHP(peer_id); - SendPlayerBreath(peer_id); } diff --git a/src/server.h b/src/server.h index cab7e2445..f0df0f9ec 100644 --- a/src/server.h +++ b/src/server.h @@ -180,7 +180,6 @@ public: void handleCommand_InventoryAction(NetworkPacket* pkt); void handleCommand_ChatMessage(NetworkPacket* pkt); void handleCommand_Damage(NetworkPacket* pkt); - void handleCommand_Breath(NetworkPacket* pkt); void handleCommand_Password(NetworkPacket* pkt); void handleCommand_PlayerItem(NetworkPacket* pkt); void handleCommand_Respawn(NetworkPacket* pkt); @@ -358,7 +357,7 @@ public: void printToConsoleOnly(const std::string &text); void SendPlayerHPOrDie(PlayerSAO *player); - void SendPlayerBreath(u16 peer_id); + void SendPlayerBreath(PlayerSAO *sao); void SendInventory(PlayerSAO* playerSAO); void SendMovePlayer(u16 peer_id); diff --git a/src/unittest/test_player.cpp b/src/unittest/test_player.cpp index 85fbc8b2d..655ee08fd 100644 --- a/src/unittest/test_player.cpp +++ b/src/unittest/test_player.cpp @@ -49,7 +49,7 @@ void TestPlayer::testSave(IGameDef *gamedef) PlayerSAO sao(NULL, 1, false); sao.initialize(&rplayer, std::set()); rplayer.setPlayerSAO(&sao); - sao.setBreath(10); + sao.setBreath(10, false); sao.setHPRaw(8); sao.setYaw(0.1f); sao.setPitch(0.6f); @@ -64,7 +64,7 @@ void TestPlayer::testLoad(IGameDef *gamedef) PlayerSAO sao(NULL, 1, false); sao.initialize(&rplayer, std::set()); rplayer.setPlayerSAO(&sao); - sao.setBreath(10); + sao.setBreath(10, false); sao.setHPRaw(8); sao.setYaw(0.1f); sao.setPitch(0.6f); -- cgit v1.2.3 From 8e7449e09253e138716d8dbad6a2ab5c6e089e28 Mon Sep 17 00:00:00 2001 From: Ner'zhul Date: Mon, 9 Jan 2017 20:39:22 +0100 Subject: Environment & IGameDef code refactoring (#4985) * Environment code refactoring * Cleanup includes & class declarations in client & server environment to improve build speed * ServerEnvironment::m_gamedef is now a pointer to Server instead of IGameDef, permitting to cleanup many casts. * Cleanup IGameDef * Move ITextureSource* IGameDef::getTextureSource() to Client only. * Also move ITextureSource *IGameDef::tsrc() helper * drop getShaderSource, getSceneManager, getSoundManager & getCamera abstract call * drop unused emerge() call * cleanup server unused functions (mentionned before) * Drop one unused parameter from ContentFeatures::updateTextures * move checkLocalPrivilege to Client * Remove some unnecessary casts * create_formspec_menu: remove IWritableTextureSource pointer, as client already knows it * Fix some comments * Change required IGameDef to Server/Client pointers * Previous change that game.cpp sometimes calls functions with Client + InventoryManager + IGameDef in same functions but it's the same objects * Remove duplicate Client pointer in GUIFormSpecMenu::GUIFormSpecMenu * drop ClientMap::sectorWasDrawn which is unused --- build/android/jni/Android.mk | 2 ++ src/camera.cpp | 21 ++++++------ src/camera.h | 6 ++-- src/client.cpp | 2 +- src/client.h | 17 +++++----- src/clientenvironment.cpp | 30 +++++++++--------- src/clientenvironment.h | 8 ++--- src/clientmap.cpp | 7 ++-- src/clientmap.h | 21 ++++-------- src/clientobject.cpp | 9 +++--- src/clientobject.h | 21 +++--------- src/collision.cpp | 3 ++ src/content_cao.cpp | 67 +++++++++++++++++++-------------------- src/content_cao.h | 9 +++--- src/content_cso.cpp | 13 +------- src/content_mapblock.cpp | 6 ++-- src/content_sao.cpp | 20 ++++++------ src/emerge.cpp | 14 ++++---- src/emerge.h | 3 +- src/environment.h | 7 ---- src/game.cpp | 59 +++++++++++++++------------------- src/gamedef.h | 29 ++--------------- src/guiEngine.cpp | 2 -- src/guiFormSpecMenu.cpp | 39 +++++++++++------------ src/guiFormSpecMenu.h | 6 +--- src/hud.cpp | 20 ++++++------ src/hud.h | 8 ++--- src/itemdef.cpp | 22 ++++++------- src/itemdef.h | 9 +++--- src/localplayer.cpp | 23 +++++++------- src/localplayer.h | 4 +-- src/mapblock_mesh.cpp | 25 +++++++-------- src/mapblock_mesh.h | 8 ++--- src/mg_biome.cpp | 11 +++---- src/mg_biome.h | 5 +-- src/mg_schematic.cpp | 10 +++--- src/mg_schematic.h | 6 ++-- src/nodedef.cpp | 16 ++++++---- src/nodedef.h | 4 +-- src/particles.cpp | 16 ++++------ src/particles.h | 2 +- src/pathfinder.cpp | 6 +--- src/script/lua_api/l_nodemeta.cpp | 6 +--- src/server.cpp | 18 ----------- src/server.h | 6 +--- src/serverenvironment.cpp | 20 ++++++------ src/serverenvironment.h | 12 ++++--- src/wieldmesh.cpp | 26 +++++++-------- src/wieldmesh.h | 6 ++-- 49 files changed, 301 insertions(+), 409 deletions(-) (limited to 'src/server.cpp') diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index 2567457b9..3be856770 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -117,6 +117,7 @@ LOCAL_SRC_FILES := \ jni/src/cavegen.cpp \ jni/src/chat.cpp \ jni/src/client.cpp \ + jni/src/clientenvironment.cpp \ jni/src/clientiface.cpp \ jni/src/clientmap.cpp \ jni/src/clientmedia.cpp \ @@ -210,6 +211,7 @@ LOCAL_SRC_FILES := \ jni/src/rollback_interface.cpp \ jni/src/serialization.cpp \ jni/src/server.cpp \ + jni/src/serverenvironment.cpp \ jni/src/serverlist.cpp \ jni/src/serverobject.cpp \ jni/src/shader.cpp \ diff --git a/src/camera.cpp b/src/camera.cpp index 43980db1c..4768e8778 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -27,7 +27,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "wieldmesh.h" #include "noise.h" // easeCurve -#include "gamedef.h" #include "sound.h" #include "event.h" #include "profiler.h" @@ -41,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, - IGameDef *gamedef): + Client *client): m_playernode(NULL), m_headnode(NULL), m_cameranode(NULL), @@ -50,7 +49,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, m_wieldnode(NULL), m_draw_control(draw_control), - m_gamedef(gamedef), + m_client(client), m_camera_position(0,0,0), m_camera_direction(0,0,0), @@ -88,7 +87,7 @@ Camera::Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, m_wieldmgr = smgr->createNewSceneManager(); m_wieldmgr->addCameraSceneNode(); m_wieldnode = new WieldMeshSceneNode(m_wieldmgr->getRootSceneNode(), m_wieldmgr, -1, false); - m_wieldnode->setItem(ItemStack(), m_gamedef); + m_wieldnode->setItem(ItemStack(), m_client); m_wieldnode->drop(); // m_wieldmgr grabbed it /* TODO: Add a callback function so these can be updated when a setting @@ -151,7 +150,7 @@ void Camera::step(f32 dtime) m_wield_change_timer = MYMIN(m_wield_change_timer + dtime, 0.125); if (m_wield_change_timer >= 0 && was_under_zero) - m_wieldnode->setItem(m_wield_item_next, m_gamedef); + m_wieldnode->setItem(m_wield_item_next, m_client); if (m_view_bobbing_state != 0) { @@ -189,7 +188,7 @@ void Camera::step(f32 dtime) (was > 0.5f && m_view_bobbing_anim <= 0.5f)); if(step) { MtEvent *e = new SimpleTriggerEvent("ViewBobbingStep"); - m_gamedef->event()->put(e); + m_client->event()->put(e); } } } @@ -210,10 +209,10 @@ void Camera::step(f32 dtime) if(m_digging_button == 0) { MtEvent *e = new SimpleTriggerEvent("CameraPunchLeft"); - m_gamedef->event()->put(e); + m_client->event()->put(e); } else if(m_digging_button == 1) { MtEvent *e = new SimpleTriggerEvent("CameraPunchRight"); - m_gamedef->event()->put(e); + m_client->event()->put(e); } } } @@ -352,7 +351,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, my_cp.Y = m_camera_position.Y + (m_camera_direction.Y*-i); // Prevent camera positioned inside nodes - INodeDefManager *nodemgr = m_gamedef->ndef(); + INodeDefManager *nodemgr = m_client->ndef(); MapNode n = c_env.getClientMap().getNodeNoEx(floatToInt(my_cp, BS)); const ContentFeatures& features = nodemgr->get(n); if(features.walkable) @@ -390,7 +389,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, // Get FOV f32 fov_degrees; - if (player->getPlayerControl().zoom && m_gamedef->checkLocalPrivilege("zoom")) { + if (player->getPlayerControl().zoom && m_client->checkLocalPrivilege("zoom")) { fov_degrees = m_cache_zoom_fov; } else { fov_degrees = m_cache_fov; @@ -468,7 +467,7 @@ void Camera::update(LocalPlayer* player, f32 frametime, f32 busytime, const bool climbing = movement_Y && player->is_climbing; if ((walking || swimming || climbing) && m_cache_view_bobbing && - (!g_settings->getBool("free_move") || !m_gamedef->checkLocalPrivilege("fly"))) + (!g_settings->getBool("free_move") || !m_client->checkLocalPrivilege("fly"))) { // Start animation m_view_bobbing_state = 1; diff --git a/src/camera.h b/src/camera.h index cb0e9686d..b5be26718 100644 --- a/src/camera.h +++ b/src/camera.h @@ -33,7 +33,7 @@ with this program; if not, write to the Free Software Foundation, Inc., class LocalPlayer; struct MapDrawControl; -class IGameDef; +class Client; class WieldMeshSceneNode; struct Nametag { @@ -61,7 +61,7 @@ class Camera { public: Camera(scene::ISceneManager* smgr, MapDrawControl& draw_control, - IGameDef *gamedef); + Client *client); ~Camera(); // Get player scene node. @@ -189,7 +189,7 @@ private: // draw control MapDrawControl& m_draw_control; - IGameDef *m_gamedef; + Client *m_client; video::IVideoDriver *m_driver; // Absolute camera position diff --git a/src/client.cpp b/src/client.cpp index 693a90604..c2471dbd7 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -221,7 +221,7 @@ Client::Client( m_event(event), m_mesh_update_thread(), m_env( - new ClientMap(this, this, control, + new ClientMap(this, control, device->getSceneManager()->getRootSceneNode(), device->getSceneManager(), 666), device->getSceneManager(), diff --git a/src/client.h b/src/client.h index 9a09704a6..df3e7e605 100644 --- a/src/client.h +++ b/src/client.h @@ -34,7 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "localplayer.h" #include "hud.h" #include "particles.h" -#include "network/networkpacket.h" struct MeshMakeData; class MapBlockMesh; @@ -51,6 +50,7 @@ class Database; class Mapper; struct MinimapMapblock; class Camera; +class NetworkPacket; struct QueuedMeshUpdate { @@ -402,9 +402,6 @@ public: void ProcessData(NetworkPacket *pkt); - // Returns true if something was received - bool AsyncProcessPacket(); - bool AsyncProcessData(); void Send(NetworkPacket* pkt); void interact(u8 action, const PointedThing& pointed); @@ -422,8 +419,9 @@ public: void sendRespawn(); void sendReady(); - ClientEnvironment& getEnv() - { return m_env; } + ClientEnvironment& getEnv() { return m_env; } + ITextureSource *tsrc() { return getTextureSource(); } + ISoundManager *sound() { return getSoundManager(); } // Causes urgent mesh updates (unlike Map::add/removeNodeWithEvent) void removeNode(v3s16 p); @@ -521,14 +519,15 @@ public: virtual IItemDefManager* getItemDefManager(); virtual INodeDefManager* getNodeDefManager(); virtual ICraftDefManager* getCraftDefManager(); - virtual ITextureSource* getTextureSource(); + ITextureSource* getTextureSource(); virtual IShaderSource* getShaderSource(); - virtual scene::ISceneManager* getSceneManager(); + IShaderSource *shsrc() { return getShaderSource(); } + scene::ISceneManager* getSceneManager(); virtual u16 allocateUnknownNodeId(const std::string &name); virtual ISoundManager* getSoundManager(); virtual MtEventManager* getEventManager(); virtual ParticleManager* getParticleManager(); - virtual bool checkLocalPrivilege(const std::string &priv) + bool checkLocalPrivilege(const std::string &priv) { return checkPrivilege(priv); } virtual scene::IAnimatedMesh* getMesh(const std::string &filename); diff --git a/src/clientenvironment.cpp b/src/clientenvironment.cpp index e831de109..65646c6b4 100644 --- a/src/clientenvironment.cpp +++ b/src/clientenvironment.cpp @@ -34,13 +34,13 @@ with this program; if not, write to the Free Software Foundation, Inc., */ ClientEnvironment::ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr, - ITextureSource *texturesource, IGameDef *gamedef, + ITextureSource *texturesource, Client *client, IrrlichtDevice *irr): m_map(map), m_local_player(NULL), m_smgr(smgr), m_texturesource(texturesource), - m_gamedef(gamedef), + m_client(client), m_irr(irr) { char zero = 0; @@ -94,7 +94,7 @@ void ClientEnvironment::step(float dtime) stepTimeOfDay(dtime); // Get some settings - bool fly_allowed = m_gamedef->checkLocalPrivilege("fly"); + bool fly_allowed = m_client->checkLocalPrivilege("fly"); bool free_move = fly_allowed && g_settings->getBool("free_move"); // Get local player @@ -223,7 +223,7 @@ void ClientEnvironment::step(float dtime) f32 post_factor = 1; // 1 hp per node/s if(info.type == COLLISION_NODE) { - const ContentFeatures &f = m_gamedef->ndef()-> + const ContentFeatures &f = m_client->ndef()-> get(m_map->getNodeNoEx(info.node_p)); // Determine fall damage multiplier int addp = itemgroup_get(f.groups, "fall_damage_add_percent"); @@ -237,7 +237,7 @@ void ClientEnvironment::step(float dtime) if(damage != 0){ damageLocalPlayer(damage, true); MtEvent *e = new SimpleTriggerEvent("PlayerFallingDamage"); - m_gamedef->event()->put(e); + m_client->event()->put(e); } } } @@ -259,11 +259,11 @@ void ClientEnvironment::step(float dtime) u32 damage_per_second = 0; damage_per_second = MYMAX(damage_per_second, - m_gamedef->ndef()->get(n1).damage_per_second); + m_client->ndef()->get(n1).damage_per_second); damage_per_second = MYMAX(damage_per_second, - m_gamedef->ndef()->get(n2).damage_per_second); + m_client->ndef()->get(n2).damage_per_second); damage_per_second = MYMAX(damage_per_second, - m_gamedef->ndef()->get(n3).damage_per_second); + m_client->ndef()->get(n3).damage_per_second); if(damage_per_second != 0) { @@ -272,7 +272,7 @@ void ClientEnvironment::step(float dtime) } // Protocol v29 make this behaviour obsolete - if (((Client*) getGameDef())->getProtoVersion() < 29) { + if (getGameDef()->getProtoVersion() < 29) { /* Drowning */ @@ -282,7 +282,7 @@ void ClientEnvironment::step(float dtime) // head v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); MapNode n = m_map->getNodeNoEx(p); - ContentFeatures c = m_gamedef->ndef()->get(n); + ContentFeatures c = m_client->ndef()->get(n); u8 drowning_damage = c.drowning; if (drowning_damage > 0 && lplayer->hp > 0) { u16 breath = lplayer->getBreath(); @@ -306,7 +306,7 @@ void ClientEnvironment::step(float dtime) // head v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); MapNode n = m_map->getNodeNoEx(p); - ContentFeatures c = m_gamedef->ndef()->get(n); + ContentFeatures c = m_client->ndef()->get(n); if (!lplayer->hp) { lplayer->setBreath(11); } else if (c.drowning == 0) { @@ -332,7 +332,7 @@ void ClientEnvironment::step(float dtime) v3s16 p = lplayer->getLightPosition(); node_at_lplayer = m_map->getNodeNoEx(p); - u16 light = getInteriorLight(node_at_lplayer, 0, m_gamedef->ndef()); + u16 light = getInteriorLight(node_at_lplayer, 0, m_client->ndef()); u8 day = light & 0xff; u8 night = (light >> 8) & 0xff; finalColorBlend(lplayer->light_color, day, night, day_night_ratio); @@ -360,7 +360,7 @@ void ClientEnvironment::step(float dtime) v3s16 p = obj->getLightPosition(); MapNode n = m_map->getNodeNoEx(p, &pos_ok); if (pos_ok) - light = n.getLightBlend(day_night_ratio, m_gamedef->ndef()); + light = n.getLightBlend(day_night_ratio, m_client->ndef()); else light = blend_light(day_night_ratio, LIGHT_SUN, 0); @@ -467,7 +467,7 @@ u16 ClientEnvironment::addActiveObject(ClientActiveObject *object) v3s16 p = object->getLightPosition(); MapNode n = m_map->getNodeNoEx(p, &pos_ok); if (pos_ok) - light = n.getLightBlend(getDayNightRatio(), m_gamedef->ndef()); + light = n.getLightBlend(getDayNightRatio(), m_client->ndef()); else light = blend_light(getDayNightRatio(), LIGHT_SUN, 0); @@ -480,7 +480,7 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type, const std::string &init_data) { ClientActiveObject* obj = - ClientActiveObject::create((ActiveObjectType) type, m_gamedef, this); + ClientActiveObject::create((ActiveObjectType) type, m_client, this); if(obj == NULL) { infostream<<"ClientEnvironment::addActiveObject(): " diff --git a/src/clientenvironment.h b/src/clientenvironment.h index e6292b5b7..b30a7a6d7 100644 --- a/src/clientenvironment.h +++ b/src/clientenvironment.h @@ -30,6 +30,7 @@ class ClientMap; class ClientActiveObject; class GenericCAO; class LocalPlayer; +struct PointedThing; /* The client-side environment. @@ -66,15 +67,14 @@ class ClientEnvironment : public Environment { public: ClientEnvironment(ClientMap *map, scene::ISceneManager *smgr, - ITextureSource *texturesource, IGameDef *gamedef, + ITextureSource *texturesource, Client *client, IrrlichtDevice *device); ~ClientEnvironment(); Map & getMap(); ClientMap & getClientMap(); - IGameDef *getGameDef() - { return m_gamedef; } + Client *getGameDef() { return m_client; } void step(f32 dtime); @@ -175,7 +175,7 @@ private: LocalPlayer *m_local_player; scene::ISceneManager *m_smgr; ITextureSource *m_texturesource; - IGameDef *m_gamedef; + Client *m_client; IrrlichtDevice *m_irr; UNORDERED_MAP m_active_objects; std::vector m_simple_objects; diff --git a/src/clientmap.cpp b/src/clientmap.cpp index 542eb03e8..7e688daad 100644 --- a/src/clientmap.cpp +++ b/src/clientmap.cpp @@ -35,13 +35,12 @@ with this program; if not, write to the Free Software Foundation, Inc., ClientMap::ClientMap( Client *client, - IGameDef *gamedef, MapDrawControl &control, scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id ): - Map(dout_client, gamedef), + Map(dout_client, client), scene::ISceneNode(parent, mgr, id), m_client(client), m_control(control), @@ -140,7 +139,7 @@ static bool isOccluded(Map *map, v3s16 p0, v3s16 p1, float step, float stepfac, return false; } -void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes, +void ClientMap::getBlocksInViewRange(v3s16 cam_pos_nodes, v3s16 *p_blocks_min, v3s16 *p_blocks_max) { v3s16 box_nodes_d = m_control.wanted_range * v3s16(1, 1, 1); @@ -766,7 +765,7 @@ void ClientMap::renderPostFx(CameraMode cam_mode) const ContentFeatures& features = m_nodedef->get(n); video::SColor post_effect_color = features.post_effect_color; if(features.solidness == 2 && !(g_settings->getBool("noclip") && - m_gamedef->checkLocalPrivilege("noclip")) && + m_client->checkLocalPrivilege("noclip")) && cam_mode == CAMERA_MODE_FIRST) { post_effect_color = video::SColor(255, 0, 0, 0); diff --git a/src/clientmap.h b/src/clientmap.h index cb686ff33..84228f4ca 100644 --- a/src/clientmap.h +++ b/src/clientmap.h @@ -59,7 +59,7 @@ class ITextureSource; /* ClientMap - + This is the only map class that is able to render itself on screen. */ @@ -68,7 +68,6 @@ class ClientMap : public Map, public scene::ISceneNode public: ClientMap( Client *client, - IGameDef *gamedef, MapDrawControl &control, scene::ISceneNode* parent, scene::ISceneManager* mgr, @@ -114,13 +113,13 @@ public: driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); renderMap(driver, SceneManager->getSceneNodeRenderPass()); } - + virtual const aabb3f &getBoundingBox() const { return m_box; } - - void getBlocksInViewRange(v3s16 cam_pos_nodes, + + void getBlocksInViewRange(v3s16 cam_pos_nodes, v3s16 *p_blocks_min, v3s16 *p_blocks_max); void updateDrawList(video::IVideoDriver* driver); void renderMap(video::IVideoDriver* driver, s32 pass); @@ -132,20 +131,14 @@ public: // For debug printing virtual void PrintInfo(std::ostream &out); - - // Check if sector was drawn on last render() - bool sectorWasDrawn(v2s16 p) - { - return (m_last_drawn_sectors.find(p) != m_last_drawn_sectors.end()); - } const MapDrawControl & getControl() const { return m_control; } f32 getCameraFov() const { return m_camera_fov; } private: Client *m_client; - + aabb3f m_box; - + MapDrawControl &m_control; v3f m_camera_position; @@ -154,7 +147,7 @@ private: v3s16 m_camera_offset; std::map m_drawlist; - + std::set m_last_drawn_sectors; bool m_cache_trilinear_filter; diff --git a/src/clientobject.cpp b/src/clientobject.cpp index ff3f47187..89a0474a4 100644 --- a/src/clientobject.cpp +++ b/src/clientobject.cpp @@ -20,16 +20,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clientobject.h" #include "debug.h" #include "porting.h" -#include "constants.h" /* ClientActiveObject */ -ClientActiveObject::ClientActiveObject(u16 id, IGameDef *gamedef, +ClientActiveObject::ClientActiveObject(u16 id, Client *client, ClientEnvironment *env): ActiveObject(id), - m_gamedef(gamedef), + m_client(client), m_env(env) { } @@ -40,7 +39,7 @@ ClientActiveObject::~ClientActiveObject() } ClientActiveObject* ClientActiveObject::create(ActiveObjectType type, - IGameDef *gamedef, ClientEnvironment *env) + Client *client, ClientEnvironment *env) { // Find factory function UNORDERED_MAP::iterator n = m_types.find(type); @@ -52,7 +51,7 @@ ClientActiveObject* ClientActiveObject::create(ActiveObjectType type, } Factory f = n->second; - ClientActiveObject *object = (*f)(gamedef, env); + ClientActiveObject *object = (*f)(client, env); return object; } diff --git a/src/clientobject.h b/src/clientobject.h index 83931e438..f0bde0adc 100644 --- a/src/clientobject.h +++ b/src/clientobject.h @@ -25,20 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "util/cpp11_container.h" -/* - -Some planning -------------- - -* Client receives a network packet with information of added objects - in it -* Client supplies the information to its ClientEnvironment -* The environment adds the specified objects to itself - -*/ - class ClientEnvironment; class ITextureSource; +class Client; class IGameDef; class LocalPlayer; struct ItemStack; @@ -47,7 +36,7 @@ class WieldMeshSceneNode; class ClientActiveObject : public ActiveObject { public: - ClientActiveObject(u16 id, IGameDef *gamedef, ClientEnvironment *env); + ClientActiveObject(u16 id, Client *client, ClientEnvironment *env); virtual ~ClientActiveObject(); virtual void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, @@ -89,7 +78,7 @@ public: virtual void initialize(const std::string &data){} // Create a certain type of ClientActiveObject - static ClientActiveObject* create(ActiveObjectType type, IGameDef *gamedef, + static ClientActiveObject* create(ActiveObjectType type, Client *client, ClientEnvironment *env); // If returns true, punch will not be sent to the server @@ -99,9 +88,9 @@ public: protected: // Used for creating objects based on type - typedef ClientActiveObject* (*Factory)(IGameDef *gamedef, ClientEnvironment *env); + typedef ClientActiveObject* (*Factory)(Client *client, ClientEnvironment *env); static void registerType(u16 type, Factory f); - IGameDef *m_gamedef; + Client *m_client; ClientEnvironment *m_env; private: // Used for creating objects based on type diff --git a/src/collision.cpp b/src/collision.cpp index 595fa8059..c0891c152 100644 --- a/src/collision.cpp +++ b/src/collision.cpp @@ -22,9 +22,12 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" #include "nodedef.h" #include "gamedef.h" +#ifndef SERVER #include "clientenvironment.h" +#endif #include "serverenvironment.h" #include "serverobject.h" +#include "util/timetaker.h" #include "profiler.h" // float error is 10 - 9.96875 = 0.03125 diff --git a/src/content_cao.cpp b/src/content_cao.cpp index a02d5168e..a4c0bf14d 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -33,7 +33,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "collision.h" #include "settings.h" #include "serialization.h" // For decompressZlib -#include "gamedef.h" #include "clientobject.h" #include "mesh.h" #include "itemdef.h" @@ -139,7 +138,7 @@ static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill, class TestCAO : public ClientActiveObject { public: - TestCAO(IGameDef *gamedef, ClientEnvironment *env); + TestCAO(Client *client, ClientEnvironment *env); virtual ~TestCAO(); ActiveObjectType getType() const @@ -147,7 +146,7 @@ public: return ACTIVEOBJECT_TYPE_TEST; } - static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + static ClientActiveObject* create(Client *client, ClientEnvironment *env); void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, IrrlichtDevice *irr); @@ -169,8 +168,8 @@ private: // Prototype TestCAO proto_TestCAO(NULL, NULL); -TestCAO::TestCAO(IGameDef *gamedef, ClientEnvironment *env): - ClientActiveObject(0, gamedef, env), +TestCAO::TestCAO(Client *client, ClientEnvironment *env): + ClientActiveObject(0, client, env), m_node(NULL), m_position(v3f(0,10*BS,0)) { @@ -181,9 +180,9 @@ TestCAO::~TestCAO() { } -ClientActiveObject* TestCAO::create(IGameDef *gamedef, ClientEnvironment *env) +ClientActiveObject* TestCAO::create(Client *client, ClientEnvironment *env) { - return new TestCAO(gamedef, env); + return new TestCAO(client, env); } void TestCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, @@ -283,7 +282,7 @@ void TestCAO::processMessage(const std::string &data) class ItemCAO : public ClientActiveObject { public: - ItemCAO(IGameDef *gamedef, ClientEnvironment *env); + ItemCAO(Client *client, ClientEnvironment *env); virtual ~ItemCAO(); ActiveObjectType getType() const @@ -291,7 +290,7 @@ public: return ACTIVEOBJECT_TYPE_ITEM; } - static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env); + static ClientActiveObject* create(Client *client, ClientEnvironment *env); void addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, IrrlichtDevice *irr); @@ -331,13 +330,13 @@ private: // Prototype ItemCAO proto_ItemCAO(NULL, NULL); -ItemCAO::ItemCAO(IGameDef *gamedef, ClientEnvironment *env): - ClientActiveObject(0, gamedef, env), +ItemCAO::ItemCAO(Client *client, ClientEnvironment *env): + ClientActiveObject(0, client, env), m_selection_box(-BS/3.,0.0,-BS/3., BS/3.,BS*2./3.,BS/3.), m_node(NULL), m_position(v3f(0,10*BS,0)) { - if(!gamedef && !env) + if(!client && !env) { ClientActiveObject::registerType(getType(), create); } @@ -347,9 +346,9 @@ ItemCAO::~ItemCAO() { } -ClientActiveObject* ItemCAO::create(IGameDef *gamedef, ClientEnvironment *env) +ClientActiveObject* ItemCAO::create(Client *client, ClientEnvironment *env) { - return new ItemCAO(gamedef, env); + return new ItemCAO(client, env); } void ItemCAO::addToScene(scene::ISceneManager *smgr, ITextureSource *tsrc, @@ -433,7 +432,7 @@ void ItemCAO::updateNodePos() void ItemCAO::updateInfoText() { try{ - IItemDefManager *idef = m_gamedef->idef(); + IItemDefManager *idef = m_client->idef(); ItemStack item; item.deSerialize(m_itemstring, idef); if(item.isKnown(idef)) @@ -458,10 +457,10 @@ void ItemCAO::updateTexture() std::istringstream is(m_itemstring, std::ios_base::binary); video::ITexture *texture = NULL; try{ - IItemDefManager *idef = m_gamedef->idef(); + IItemDefManager *idef = m_client->idef(); ItemStack item; item.deSerialize(is, idef); - texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_gamedef); + texture = idef->getInventoryTexture(item.getDefinition(idef).name, m_client); } catch(SerializationError &e) { @@ -538,15 +537,15 @@ void ItemCAO::initialize(const std::string &data) #include "genericobject.h" -GenericCAO::GenericCAO(IGameDef *gamedef, ClientEnvironment *env): - ClientActiveObject(0, gamedef, env), +GenericCAO::GenericCAO(Client *client, ClientEnvironment *env): + ClientActiveObject(0, client, env), // m_is_player(false), m_is_local_player(false), // m_smgr(NULL), m_irr(NULL), - m_gamedef(NULL), + m_client(NULL), m_selection_box(-BS/3.,-BS/3.,-BS/3., BS/3.,BS/3.,BS/3.), m_meshnode(NULL), m_animated_meshnode(NULL), @@ -581,10 +580,10 @@ GenericCAO::GenericCAO(IGameDef *gamedef, ClientEnvironment *env): m_last_light(255), m_is_visible(false) { - if (gamedef == NULL) { + if (client == NULL) { ClientActiveObject::registerType(getType(), create); } else { - m_gamedef = gamedef; + m_client = client; } } @@ -793,7 +792,7 @@ void GenericCAO::removeFromScene(bool permanent) } if (m_nametag) { - m_gamedef->getCamera()->removeNametag(m_nametag); + m_client->getCamera()->removeNametag(m_nametag); m_nametag = NULL; } } @@ -906,7 +905,7 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, } else if(m_prop.visual == "mesh") { infostream<<"GenericCAO::addToScene(): mesh"<getMesh(m_prop.mesh); + scene::IAnimatedMesh *mesh = m_client->getMesh(m_prop.mesh); if(mesh) { m_animated_meshnode = smgr->addAnimatedMeshSceneNode(mesh, NULL); @@ -937,12 +936,12 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, infostream<<"textures: "<= 1){ infostream<<"textures[0]: "<idef(); + IItemDefManager *idef = m_client->idef(); ItemStack item(m_prop.textures[0], 1, 0, "", idef); m_wield_meshnode = new WieldMeshSceneNode( smgr->getRootSceneNode(), smgr, -1); - m_wield_meshnode->setItem(item, m_gamedef); + m_wield_meshnode->setItem(item, m_client); m_wield_meshnode->setScale(v3f(m_prop.visual_size.X/2, m_prop.visual_size.Y/2, @@ -959,7 +958,7 @@ void GenericCAO::addToScene(scene::ISceneManager *smgr, scene::ISceneNode *node = getSceneNode(); if (node && m_prop.nametag != "" && !m_is_local_player) { // Add nametag - m_nametag = m_gamedef->getCamera()->addNametag(node, + m_nametag = m_client->getCamera()->addNametag(node, m_prop.nametag, m_prop.nametag_color); } @@ -1058,11 +1057,11 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) // increase speed if using fast or flying fast if((g_settings->getBool("fast_move") && - m_gamedef->checkLocalPrivilege("fast")) && + m_client->checkLocalPrivilege("fast")) && (controls.aux1 || (!player->touching_ground && g_settings->getBool("free_move") && - m_gamedef->checkLocalPrivilege("fly")))) + m_client->checkLocalPrivilege("fly")))) new_speed *= 1.5; // slowdown speed if sneeking if(controls.sneak && walking) @@ -1129,7 +1128,7 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) } removeFromScene(false); - addToScene(m_smgr, m_gamedef->tsrc(), m_irr); + addToScene(m_smgr, m_client->tsrc(), m_irr); // Attachments, part 2: Now that the parent has been refreshed, put its attachments back for (std::vector::size_type i = 0; i < m_children.size(); i++) { @@ -1199,12 +1198,12 @@ void GenericCAO::step(float dtime, ClientEnvironment *env) m_step_distance_counter = 0; if(!m_is_local_player && m_prop.makes_footstep_sound) { - INodeDefManager *ndef = m_gamedef->ndef(); + INodeDefManager *ndef = m_client->ndef(); v3s16 p = floatToInt(getPosition() + v3f(0, (m_prop.collisionbox.MinEdge.Y-0.5)*BS, 0), BS); MapNode n = m_env->getMap().getNodeNoEx(p); SimpleSoundSpec spec = ndef->get(n).sound_footstep; - m_gamedef->sound()->playSoundAt(spec, false, getPosition()); + m_client->sound()->playSoundAt(spec, false, getPosition()); } } } @@ -1305,7 +1304,7 @@ void GenericCAO::updateTexturePos() void GenericCAO::updateTextures(const std::string &mod) { - ITextureSource *tsrc = m_gamedef->tsrc(); + ITextureSource *tsrc = m_client->tsrc(); bool use_trilinear_filter = g_settings->getBool("trilinear_filter"); bool use_bilinear_filter = g_settings->getBool("bilinear_filter"); @@ -1778,7 +1777,7 @@ bool GenericCAO::directReportPunch(v3f dir, const ItemStack *punchitem, { assert(punchitem); // pre-condition const ToolCapabilities *toolcap = - &punchitem->getToolCapabilities(m_gamedef->idef()); + &punchitem->getToolCapabilities(m_client->idef()); PunchDamageResult result = getPunchDamage( m_armor_groups, toolcap, diff --git a/src/content_cao.h b/src/content_cao.h index a158e8296..96a160055 100644 --- a/src/content_cao.h +++ b/src/content_cao.h @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemgroup.h" class Camera; +class Client; struct Nametag; /* @@ -68,7 +69,7 @@ private: // scene::ISceneManager *m_smgr; IrrlichtDevice *m_irr; - IGameDef *m_gamedef; + Client *m_client; aabb3f m_selection_box; scene::IMeshSceneNode *m_meshnode; scene::IAnimatedMeshSceneNode *m_animated_meshnode; @@ -109,13 +110,13 @@ private: std::vector m_children; public: - GenericCAO(IGameDef *gamedef, ClientEnvironment *env); + GenericCAO(Client *client, ClientEnvironment *env); ~GenericCAO(); - static ClientActiveObject* create(IGameDef *gamedef, ClientEnvironment *env) + static ClientActiveObject* create(Client *client, ClientEnvironment *env) { - return new GenericCAO(gamedef, env); + return new GenericCAO(client, env); } inline ActiveObjectType getType() const diff --git a/src/content_cso.cpp b/src/content_cso.cpp index c0407f460..aca71212b 100644 --- a/src/content_cso.cpp +++ b/src/content_cso.cpp @@ -21,20 +21,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "client/tile.h" #include "clientenvironment.h" -#include "gamedef.h" +#include "client.h" #include "map.h" -/* -static void setBillboardTextureMatrix(scene::IBillboardSceneNode *bill, - float txs, float tys, int col, int row) -{ - video::SMaterial& material = bill->getMaterial(0); - core::matrix4& matrix = material.getTextureMatrix(0); - matrix.setTextureTranslate(txs*col, tys*row); - matrix.setTextureScale(txs, tys); -} -*/ - class SmokePuffCSO: public ClientSimpleObject { float m_age; diff --git a/src/content_mapblock.cpp b/src/content_mapblock.cpp index 8ce0f1e0a..a7134590b 100644 --- a/src/content_mapblock.cpp +++ b/src/content_mapblock.cpp @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/tile.h" #include "mesh.h" #include -#include "gamedef.h" +#include "client.h" #include "log.h" #include "noise.h" @@ -188,8 +188,8 @@ static inline int NeighborToIndex(const v3s16 &pos) void mapblock_mesh_generate_special(MeshMakeData *data, MeshCollector &collector) { - INodeDefManager *nodedef = data->m_gamedef->ndef(); - scene::ISceneManager* smgr = data->m_gamedef->getSceneManager(); + INodeDefManager *nodedef = data->m_client->ndef(); + scene::ISceneManager* smgr = data->m_client->getSceneManager(); scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator(); // 0ms diff --git a/src/content_sao.cpp b/src/content_sao.cpp index f866d4372..dd8bdc592 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -273,7 +273,7 @@ void LuaEntitySAO::step(float dtime, bool send_recommended) v3f p_pos = m_base_position; v3f p_velocity = m_velocity; v3f p_acceleration = m_acceleration; - moveresult = collisionMoveSimple(m_env,m_env->getGameDef(), + moveresult = collisionMoveSimple(m_env, m_env->getGameDef(), pos_max_d, box, m_prop.stepheight, dtime, &p_pos, &p_velocity, p_acceleration, this, m_prop.collideWithObjects); @@ -945,7 +945,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) // get head position v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); MapNode n = m_env->getMap().getNodeNoEx(p); - const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n); + const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); // If node generates drown if (c.drowning > 0) { if (m_hp > 0 && m_breath > 0) @@ -954,7 +954,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) // No more breath, damage player if (m_breath == 0) { setHP(m_hp - c.drowning); - ((Server*) m_env->getGameDef())->SendPlayerHPOrDie(this); + m_env->getGameDef()->SendPlayerHPOrDie(this); } } } @@ -963,7 +963,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) // get head position v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); MapNode n = m_env->getMap().getNodeNoEx(p); - const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n); + const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); // If player is alive & no drowning, breath if (m_hp > 0 && c.drowning == 0) setBreath(m_breath + 1); @@ -985,7 +985,7 @@ void PlayerSAO::step(float dtime, bool send_recommended) m_attachment_position = v3f(0,0,0); m_attachment_rotation = v3f(0,0,0); setBasePosition(m_last_good_position); - ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); + m_env->getGameDef()->SendMovePlayer(m_peer_id); } //dstream<<"PlayerSAO::step: dtime: "<getGameDef())->SendMovePlayer(m_peer_id); + m_env->getGameDef()->SendMovePlayer(m_peer_id); } void PlayerSAO::moveTo(v3f pos, bool continuous) @@ -1118,7 +1118,7 @@ void PlayerSAO::moveTo(v3f pos, bool continuous) setBasePosition(pos); // Movement caused by this command is always valid m_last_good_position = pos; - ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); + m_env->getGameDef()->SendMovePlayer(m_peer_id); } void PlayerSAO::setYaw(const float yaw) @@ -1148,7 +1148,7 @@ void PlayerSAO::setWantedRange(const s16 range) void PlayerSAO::setYawAndSend(const float yaw) { setYaw(yaw); - ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); + m_env->getGameDef()->SendMovePlayer(m_peer_id); } void PlayerSAO::setPitch(const float pitch) @@ -1162,7 +1162,7 @@ void PlayerSAO::setPitch(const float pitch) void PlayerSAO::setPitchAndSend(const float pitch) { setPitch(pitch); - ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); + m_env->getGameDef()->SendMovePlayer(m_peer_id); } int PlayerSAO::punch(v3f dir, @@ -1273,7 +1273,7 @@ void PlayerSAO::setBreath(const u16 breath, bool send) m_breath = MYMIN(breath, PLAYER_MAX_BREATH); if (send) - ((Server *) m_env->getGameDef())->SendPlayerBreath(this); + m_env->getGameDef()->SendPlayerBreath(this); } void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups) diff --git a/src/emerge.cpp b/src/emerge.cpp index 25b2e924b..3f0a46010 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -89,13 +89,13 @@ private: //// EmergeManager //// -EmergeManager::EmergeManager(IGameDef *gamedef) +EmergeManager::EmergeManager(Server *server) { - this->ndef = gamedef->getNodeDefManager(); - this->biomemgr = new BiomeManager(gamedef); - this->oremgr = new OreManager(gamedef); - this->decomgr = new DecorationManager(gamedef); - this->schemmgr = new SchematicManager(gamedef); + this->ndef = server->getNodeDefManager(); + this->biomemgr = new BiomeManager(server); + this->oremgr = new OreManager(server); + this->decomgr = new DecorationManager(server); + this->schemmgr = new SchematicManager(server); this->gen_notify_on = 0; // Note that accesses to this variable are not synchronized. @@ -128,7 +128,7 @@ EmergeManager::EmergeManager(IGameDef *gamedef) m_qlimit_generate = 1; for (s16 i = 0; i < nthreads; i++) - m_threads.push_back(new EmergeThread((Server *)gamedef, i)); + m_threads.push_back(new EmergeThread(server, i)); infostream << "EmergeManager: using " << nthreads << " threads" << std::endl; } diff --git a/src/emerge.h b/src/emerge.h index 71ad97da3..76653e6cd 100644 --- a/src/emerge.h +++ b/src/emerge.h @@ -42,6 +42,7 @@ class BiomeManager; class OreManager; class DecorationManager; class SchematicManager; +class Server; // Structure containing inputs/outputs for chunk generation struct BlockMakeData { @@ -115,7 +116,7 @@ public: SchematicManager *schemmgr; // Methods - EmergeManager(IGameDef *gamedef); + EmergeManager(Server *server); ~EmergeManager(); bool initMapgens(MapgenParams *mgparams); diff --git a/src/environment.h b/src/environment.h index 14a18421b..0cc3222f9 100644 --- a/src/environment.h +++ b/src/environment.h @@ -42,13 +42,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "threading/atomic.h" #include "network/networkprotocol.h" // for AccessDeniedCode -class ITextureSource; -class IGameDef; -class Map; -class GameScripting; -class Player; -class PointedThing; - class Environment { public: diff --git a/src/game.cpp b/src/game.cpp index cfa6234ff..1070cb1b2 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -916,16 +916,14 @@ bool nodePlacementPrediction(Client &client, } static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, - InventoryManager *invmgr, IGameDef *gamedef, - IWritableTextureSource *tsrc, IrrlichtDevice *device, - JoystickController *joystick, - IFormSource *fs_src, TextDest *txt_dest, Client *client) + Client *client, IrrlichtDevice *device, JoystickController *joystick, + IFormSource *fs_src, TextDest *txt_dest) { if (*cur_formspec == 0) { *cur_formspec = new GUIFormSpecMenu(device, joystick, - guiroot, -1, &g_menumgr, invmgr, gamedef, tsrc, - fs_src, txt_dest, client); + guiroot, -1, &g_menumgr, client, client->getTextureSource(), + fs_src, txt_dest); (*cur_formspec)->doPause = false; /* @@ -950,9 +948,9 @@ static inline void create_formspec_menu(GUIFormSpecMenu **cur_formspec, #endif static void show_deathscreen(GUIFormSpecMenu **cur_formspec, - InventoryManager *invmgr, IGameDef *gamedef, + Client *client, IWritableTextureSource *tsrc, IrrlichtDevice *device, - JoystickController *joystick, Client *client) + JoystickController *joystick) { std::string formspec = std::string(FORMSPEC_VERSION_STRING) + @@ -968,13 +966,12 @@ static void show_deathscreen(GUIFormSpecMenu **cur_formspec, FormspecFormSource *fs_src = new FormspecFormSource(formspec); LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_DEATH_SCREEN", client); - create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, - joystick, fs_src, txt_dst, NULL); + create_formspec_menu(cur_formspec, client, device, joystick, fs_src, txt_dst); } /******************************************************************************/ static void show_pause_menu(GUIFormSpecMenu **cur_formspec, - InventoryManager *invmgr, IGameDef *gamedef, + Client *client, IWritableTextureSource *tsrc, IrrlichtDevice *device, JoystickController *joystick, bool singleplayermode) { @@ -1041,8 +1038,7 @@ static void show_pause_menu(GUIFormSpecMenu **cur_formspec, FormspecFormSource *fs_src = new FormspecFormSource(os.str()); LocalFormspecHandler *txt_dst = new LocalFormspecHandler("MT_PAUSE_MENU"); - create_formspec_menu(cur_formspec, invmgr, gamedef, tsrc, device, - joystick, fs_src, txt_dst, NULL); + create_formspec_menu(cur_formspec, client, device, joystick, fs_src, txt_dst); std::string con("btn_continue"); (*cur_formspec)->setFocus(con); (*cur_formspec)->doPause = true; @@ -1534,7 +1530,6 @@ private: bool *kill; std::string *error_message; bool *reconnect_requested; - IGameDef *gamedef; // Convenience (same as *client) scene::ISceneNode *skybox; bool random_input; @@ -2011,7 +2006,7 @@ bool Game::createClient(const std::string &playername, /* Camera */ - camera = new Camera(smgr, *draw_control, gamedef); + camera = new Camera(smgr, *draw_control, client); if (!camera || !camera->successfullyCreated(*error_message)) return false; client->setCamera(camera); @@ -2068,7 +2063,7 @@ bool Game::createClient(const std::string &playername, player->hurt_tilt_timer = 0; player->hurt_tilt_strength = 0; - hud = new Hud(driver, smgr, guienv, gamedef, player, local_inventory); + hud = new Hud(driver, smgr, guienv, client, player, local_inventory); if (!hud) { *error_message = "Memory error: could not create HUD"; @@ -2198,8 +2193,6 @@ bool Game::connectToServer(const std::string &playername, if (!client) return false; - gamedef = client; // Client acts as our GameDef - infostream << "Connecting to server at "; connect_address.print(&infostream); infostream << std::endl; @@ -2445,7 +2438,7 @@ inline bool Game::handleCallbacks() void Game::processQueues() { texture_src->processQueue(); - itemdef_manager->processQueue(gamedef); + itemdef_manager->processQueue(client); shader_src->processQueue(); } @@ -2617,7 +2610,7 @@ void Game::processKeyInput(VolatileRunFlags *flags, openInventory(); } else if (wasKeyDown(KeyType::ESC) || input->wasKeyDown(CancelKey)) { if (!gui_chat_console->isOpenInhibited()) { - show_pause_menu(¤t_formspec, client, gamedef, + show_pause_menu(¤t_formspec, client, texture_src, device, &input->joystick, simple_singleplayer_mode); } @@ -2769,8 +2762,7 @@ void Game::openInventory() PlayerInventoryFormSource *fs_src = new PlayerInventoryFormSource(client); TextDest *txt_dst = new TextDestPlayerInventory(client); - create_formspec_menu(¤t_formspec, client, gamedef, texture_src, - device, &input->joystick, fs_src, txt_dst, client); + create_formspec_menu(¤t_formspec, client, device, &input->joystick, fs_src, txt_dst); cur_formname = ""; InventoryLocation inventoryloc; @@ -3245,13 +3237,13 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) rangelim(event.player_damage.amount / 4, 1.0, 4.0); MtEvent *e = new SimpleTriggerEvent("PlayerDamage"); - gamedef->event()->put(e); + client->event()->put(e); } else if (event.type == CE_PLAYER_FORCE_MOVE) { cam->camera_yaw = event.player_force_move.yaw; cam->camera_pitch = event.player_force_move.pitch; } else if (event.type == CE_DEATHSCREEN) { - show_deathscreen(¤t_formspec, client, gamedef, texture_src, - device, &input->joystick, client); + show_deathscreen(¤t_formspec, client, texture_src, + device, &input->joystick); chat_backend->addMessage(L"", L"You died."); @@ -3271,9 +3263,8 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) TextDestPlayerInventory *txt_dst = new TextDestPlayerInventory(client, *(event.show_formspec.formname)); - create_formspec_menu(¤t_formspec, client, gamedef, - texture_src, device, &input->joystick, - fs_src, txt_dst, client); + create_formspec_menu(¤t_formspec, client, device, &input->joystick, + fs_src, txt_dst); cur_formname = *(event.show_formspec.formname); } @@ -3282,7 +3273,7 @@ void Game::processClientEvents(CameraOrientation *cam, float *damage_flash) } else if ((event.type == CE_SPAWN_PARTICLE) || (event.type == CE_ADD_PARTICLESPAWNER) || (event.type == CE_DELETE_PARTICLESPAWNER)) { - client->getParticleManager()->handleParticleEvent(&event, gamedef, + client->getParticleManager()->handleParticleEvent(&event, client, smgr, player); } else if (event.type == CE_HUDADD) { u32 id = event.hudadd.id; @@ -3840,8 +3831,8 @@ void Game::handlePointingAtNode(GameRunData *runData, &client->getEnv().getClientMap(), nodepos); TextDest *txt_dst = new TextDestNodeMetadata(nodepos, client); - create_formspec_menu(¤t_formspec, client, gamedef, - texture_src, device, &input->joystick, fs_src, txt_dst, client); + create_formspec_menu(¤t_formspec, client, + device, &input->joystick, fs_src, txt_dst); cur_formname = ""; current_formspec->setFormSpec(meta->getString("formspec"), inventoryloc); @@ -3972,7 +3963,7 @@ void Game::handleDigging(GameRunData *runData, if (m_cache_enable_particles) { const ContentFeatures &features = client->getNodeDefManager()->get(n); - client->getParticleManager()->addPunchingParticles(gamedef, smgr, + client->getParticleManager()->addPunchingParticles(client, smgr, player, nodepos, features.tiles); } } @@ -4019,7 +4010,7 @@ void Game::handleDigging(GameRunData *runData, if (m_cache_enable_particles) { const ContentFeatures &features = client->getNodeDefManager()->get(wasnode); - client->getParticleManager()->addDiggingParticles(gamedef, smgr, + client->getParticleManager()->addDiggingParticles(client, smgr, player, nodepos, features.tiles); } @@ -4043,7 +4034,7 @@ void Game::handleDigging(GameRunData *runData, // Send event to trigger sound MtEvent *e = new NodeDugEvent(nodepos, wasnode); - gamedef->event()->put(e); + client->event()->put(e); } if (runData->dig_time_complete < 100000.0) { diff --git a/src/gamedef.h b/src/gamedef.h index 7e3da4cac..cb624bd6a 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -53,47 +53,22 @@ public: virtual INodeDefManager* getNodeDefManager()=0; virtual ICraftDefManager* getCraftDefManager()=0; - // This is always thread-safe, but referencing the irrlicht texture - // pointers in other threads than main thread will make things explode. - virtual ITextureSource* getTextureSource()=0; - - virtual IShaderSource* getShaderSource()=0; - // Used for keeping track of names/ids of unknown nodes virtual u16 allocateUnknownNodeId(const std::string &name)=0; - // Only usable on the client - virtual ISoundManager* getSoundManager()=0; virtual MtEventManager* getEventManager()=0; - virtual scene::IAnimatedMesh* getMesh(const std::string &filename) - { return NULL; } - virtual scene::ISceneManager* getSceneManager()=0; - - virtual Camera* getCamera() - { return NULL; } - virtual void setCamera(Camera *camera) {} // Only usable on the server, and NOT thread-safe. It is usable from the // environment thread. - virtual IRollbackManager* getRollbackManager(){return NULL;} - - // Only usable on the server. Thread safe if not written while running threads. - virtual EmergeManager *getEmergeManager() { return NULL; } - - // Used on the client - virtual bool checkLocalPrivilege(const std::string &priv) - { return false; } + virtual IRollbackManager* getRollbackManager() { return NULL; } // Shorthands IItemDefManager *idef() { return getItemDefManager(); } INodeDefManager *ndef() { return getNodeDefManager(); } ICraftDefManager *cdef() { return getCraftDefManager(); } - ITextureSource *tsrc() { return getTextureSource(); } - ISoundManager *sound() { return getSoundManager(); } - IShaderSource *shsrc() { return getShaderSource(); } + MtEventManager *event() { return getEventManager(); } IRollbackManager *rollback() { return getRollbackManager();} - EmergeManager *emerge() { return getEmergeManager(); } }; #endif diff --git a/src/guiEngine.cpp b/src/guiEngine.cpp index a3c35f68d..6d66ed08d 100644 --- a/src/guiEngine.cpp +++ b/src/guiEngine.cpp @@ -194,11 +194,9 @@ GUIEngine::GUIEngine( irr::IrrlichtDevice* dev, -1, m_menumanager, NULL /* &client */, - NULL /* gamedef */, m_texture_source, m_formspecgui, m_buttonhandler, - NULL, false); m_menu->allowClose(false); diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index bfc7a9b79..45b0e9c11 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -81,13 +81,12 @@ static unsigned int font_line_height(gui::IGUIFont *font) GUIFormSpecMenu::GUIFormSpecMenu(irr::IrrlichtDevice* dev, JoystickController *joystick, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, - InventoryManager *invmgr, IGameDef *gamedef, + Client *client, ISimpleTextureSource *tsrc, IFormSource* fsrc, TextDest* tdst, - Client* client, bool remap_dbl_click) : + bool remap_dbl_click) : GUIModalMenu(dev->getGUIEnvironment(), parent, id, menumgr), m_device(dev), - m_invmgr(invmgr), - m_gamedef(gamedef), + m_invmgr(client), m_tsrc(tsrc), m_client(client), m_selected_item(NULL), @@ -307,8 +306,8 @@ void GUIFormSpecMenu::parseContainerEnd(parserData* data) void GUIFormSpecMenu::parseList(parserData* data,std::string element) { - if (m_gamedef == 0) { - warningstream<<"invalid use of 'list' with m_gamedef==0"<explicit_size) warningstream<<"invalid use of item_image_button without a size[] element"<idef(); + IItemDefManager *idef = m_client->idef(); ItemStack item; item.deSerialize(item_name, idef); @@ -2297,14 +2296,14 @@ void GUIFormSpecMenu::drawList(const ListDrawSpec &s, int phase, if(!item.empty()) { drawItemStack(driver, m_font, item, - rect, &AbsoluteClippingRect, m_gamedef, + rect, &AbsoluteClippingRect, m_client, rotation_kind); } // Draw tooltip std::wstring tooltip_text = L""; if (hovering && !m_selected_item) { - tooltip_text = utf8_to_wide(item.getDefinition(m_gamedef->idef()).description); + tooltip_text = utf8_to_wide(item.getDefinition(m_client->idef()).description); } if (tooltip_text != L"") { std::vector tt_rows = str_split(tooltip_text, L'\n'); @@ -2349,7 +2348,7 @@ void GUIFormSpecMenu::drawSelectedItem() if (!m_selected_item) { drawItemStack(driver, m_font, ItemStack(), core::rect(v2s32(0, 0), v2s32(0, 0)), - NULL, m_gamedef, IT_ROT_DRAGGED); + NULL, m_client, IT_ROT_DRAGGED); return; } @@ -2363,7 +2362,7 @@ void GUIFormSpecMenu::drawSelectedItem() core::rect imgrect(0,0,imgsize.X,imgsize.Y); core::rect rect = imgrect + (m_pointer - imgrect.getCenter()); rect.constrainTo(driver->getViewPort()); - drawItemStack(driver, m_font, stack, rect, NULL, m_gamedef, IT_ROT_DRAGGED); + drawItemStack(driver, m_font, stack, rect, NULL, m_client, IT_ROT_DRAGGED); } void GUIFormSpecMenu::drawMenu() @@ -2488,11 +2487,11 @@ void GUIFormSpecMenu::drawMenu() */ for(u32 i=0; iidef(); + IItemDefManager *idef = m_client->idef(); ItemStack item; item.deSerialize(spec.item_name, idef); core::rect imgrect(0, 0, spec.geom.X, spec.geom.Y); @@ -2509,7 +2508,7 @@ void GUIFormSpecMenu::drawMenu() #endif } drawItemStack(driver, m_font, item, rect, &AbsoluteClippingRect, - m_gamedef, IT_ROT_NONE); + m_client, IT_ROT_NONE); } /* @@ -2527,7 +2526,7 @@ void GUIFormSpecMenu::drawMenu() if (!item_hovered) { drawItemStack(driver, m_font, ItemStack(), core::rect(v2s32(0, 0), v2s32(0, 0)), - NULL, m_gamedef, IT_ROT_HOVERED); + NULL, m_client, IT_ROT_HOVERED); } /* TODO find way to show tooltips on touchscreen */ @@ -3470,7 +3469,7 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) // Check how many items can be moved move_amount = stack_from.count = MYMIN(move_amount, stack_from.count); - ItemStack leftover = stack_to.addItem(stack_from, m_gamedef->idef()); + ItemStack leftover = stack_to.addItem(stack_from, m_client->idef()); // If source stack cannot be added to destination stack at all, // they are swapped if ((leftover.count == stack_from.count) && diff --git a/src/guiFormSpecMenu.h b/src/guiFormSpecMenu.h index 95df11e6a..94b52e6f0 100644 --- a/src/guiFormSpecMenu.h +++ b/src/guiFormSpecMenu.h @@ -34,7 +34,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/string.h" #include "util/enriched_string.h" -class IGameDef; class InventoryManager; class ISimpleTextureSource; class Client; @@ -289,12 +288,10 @@ public: JoystickController *joystick, gui::IGUIElement* parent, s32 id, IMenuManager *menumgr, - InventoryManager *invmgr, - IGameDef *gamedef, + Client *client, ISimpleTextureSource *tsrc, IFormSource* fs_src, TextDest* txt_dst, - Client* client, bool remap_dbl_click = true); ~GUIFormSpecMenu(); @@ -384,7 +381,6 @@ protected: irr::IrrlichtDevice* m_device; InventoryManager *m_invmgr; - IGameDef *m_gamedef; ISimpleTextureSource *m_tsrc; Client *m_client; diff --git a/src/hud.cpp b/src/hud.cpp index 43d957380..a602125e3 100644 --- a/src/hud.cpp +++ b/src/hud.cpp @@ -22,10 +22,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "hud.h" #include "settings.h" #include "util/numeric.h" -#include "util/string.h" #include "log.h" -#include "gamedef.h" -#include "itemdef.h" +#include "client.h" #include "inventory.h" #include "client/tile.h" #include "localplayer.h" @@ -41,13 +39,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr, - gui::IGUIEnvironment* guienv, IGameDef *gamedef, LocalPlayer *player, + gui::IGUIEnvironment* guienv, Client *client, LocalPlayer *player, Inventory *inventory) { this->driver = driver; this->smgr = smgr; this->guienv = guienv; - this->gamedef = gamedef; + this->client = client; this->player = player; this->inventory = inventory; @@ -61,7 +59,7 @@ Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr, for (unsigned int i = 0; i < 4; i++) hbar_colors[i] = video::SColor(255, 255, 255, 255); - tsrc = gamedef->getTextureSource(); + tsrc = client->getTextureSource(); v3f crosshair_color = g_settings->getV3F("crosshair_color"); u32 cross_r = rangelim(myround(crosshair_color.X), 0, 255); @@ -92,7 +90,7 @@ Hud::Hud(video::IVideoDriver *driver, scene::ISceneManager* smgr, m_selection_material.Lighting = false; if (g_settings->getBool("enable_shaders")) { - IShaderSource *shdrsrc = gamedef->getShaderSource(); + IShaderSource *shdrsrc = client->getShaderSource(); u16 shader_id = shdrsrc->getShader( mode == "halo" ? "selection_shader" : "default_shader", 1, 1); m_selection_material.MaterialType = shdrsrc->getShaderInfo(shader_id).material; @@ -193,7 +191,7 @@ void Hud::drawItem(const ItemStack &item, const core::rect& rect, if (!use_hotbar_image) driver->draw2DRectangle(bgcolor2, rect, NULL); drawItemStack(driver, g_fontengine->getFont(), item, rect, NULL, - gamedef, selected ? IT_ROT_SELECTED : IT_ROT_NONE); + client, selected ? IT_ROT_SELECTED : IT_ROT_NONE); } //NOTE: selectitem = 0 -> no selected; selectitem 1-based @@ -629,7 +627,7 @@ void drawItemStack(video::IVideoDriver *driver, const ItemStack &item, const core::rect &rect, const core::rect *clip, - IGameDef *gamedef, + Client *client, ItemRotationKind rotation_kind) { static MeshTimeInfo rotation_time_infos[IT_ROT_NONE]; @@ -643,8 +641,8 @@ void drawItemStack(video::IVideoDriver *driver, return; } - const ItemDefinition &def = item.getDefinition(gamedef->idef()); - scene::IMesh* mesh = gamedef->idef()->getWieldMesh(def.name, gamedef); + const ItemDefinition &def = item.getDefinition(client->idef()); + scene::IMesh* mesh = client->idef()->getWieldMesh(def.name, client); if (mesh) { driver->clearZBuffer(); diff --git a/src/hud.h b/src/hud.h index a4d7990e9..efa0c3648 100644 --- a/src/hud.h +++ b/src/hud.h @@ -95,7 +95,7 @@ struct HudElement { #include #include "irr_aabb3d.h" -class IGameDef; +class Client; class ITextureSource; class Inventory; class InventoryList; @@ -107,7 +107,7 @@ public: video::IVideoDriver *driver; scene::ISceneManager* smgr; gui::IGUIEnvironment *guienv; - IGameDef *gamedef; + Client *client; LocalPlayer *player; Inventory *inventory; ITextureSource *tsrc; @@ -121,7 +121,7 @@ public: bool use_hotbar_selected_image; Hud(video::IVideoDriver *driver,scene::ISceneManager* smgr, - gui::IGUIEnvironment* guienv, IGameDef *gamedef, LocalPlayer *player, + gui::IGUIEnvironment* guienv, Client *client, LocalPlayer *player, Inventory *inventory); ~Hud(); @@ -190,7 +190,7 @@ void drawItemStack(video::IVideoDriver *driver, const ItemStack &item, const core::rect &rect, const core::rect *clip, - IGameDef *gamedef, + Client *client, ItemRotationKind rotation_kind); #endif diff --git a/src/itemdef.cpp b/src/itemdef.cpp index 1aa6331dc..5ba9d8f9a 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemdef.h" -#include "gamedef.h" #include "nodedef.h" #include "tool.h" #include "inventory.h" @@ -29,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mesh.h" #include "wieldmesh.h" #include "client/tile.h" +#include "client.h" #endif #include "log.h" #include "settings.h" @@ -317,7 +317,7 @@ public: #ifndef SERVER public: ClientCached* createClientCachedDirect(const std::string &name, - IGameDef *gamedef) const + Client *client) const { infostream<<"Lazily creating item texture and mesh for \"" <getTextureSource(); + ITextureSource *tsrc = client->getTextureSource(); const ItemDefinition &def = get(name); // Create new ClientCached @@ -345,7 +345,7 @@ public: ItemStack item = ItemStack(); item.name = def.name; - scene::IMesh *mesh = getItemMesh(gamedef, item); + scene::IMesh *mesh = getItemMesh(client, item); cc->wield_mesh = mesh; // Put in cache @@ -354,7 +354,7 @@ public: return cc; } ClientCached* getClientCached(const std::string &name, - IGameDef *gamedef) const + Client *client) const { ClientCached *cc = NULL; m_clientcached.get(name, &cc); @@ -363,7 +363,7 @@ public: if(thr_is_current_thread(m_main_thread)) { - return createClientCachedDirect(name, gamedef); + return createClientCachedDirect(name, client); } else { @@ -392,18 +392,18 @@ public: } // Get item inventory texture virtual video::ITexture* getInventoryTexture(const std::string &name, - IGameDef *gamedef) const + Client *client) const { - ClientCached *cc = getClientCached(name, gamedef); + ClientCached *cc = getClientCached(name, client); if(!cc) return NULL; return cc->inventory_texture; } // Get item wield mesh virtual scene::IMesh* getWieldMesh(const std::string &name, - IGameDef *gamedef) const + Client *client) const { - ClientCached *cc = getClientCached(name, gamedef); + ClientCached *cc = getClientCached(name, client); if(!cc) return NULL; return cc->wield_mesh; @@ -543,7 +543,7 @@ public: request = m_get_clientcached_queue.pop(); m_get_clientcached_queue.pushResult(request, - createClientCachedDirect(request.key, gamedef)); + createClientCachedDirect(request.key, (Client *)gamedef)); } #endif } diff --git a/src/itemdef.h b/src/itemdef.h index dcb98e8a9..2ade6116a 100644 --- a/src/itemdef.h +++ b/src/itemdef.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "itemgroup.h" #include "sound.h" class IGameDef; +class Client; struct ToolCapabilities; /* @@ -107,10 +108,10 @@ public: #ifndef SERVER // Get item inventory texture virtual video::ITexture* getInventoryTexture(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; // Get item wield mesh virtual scene::IMesh* getWieldMesh(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; #endif virtual void serialize(std::ostream &os, u16 protocol_version)=0; @@ -133,10 +134,10 @@ public: #ifndef SERVER // Get item inventory texture virtual video::ITexture* getInventoryTexture(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; // Get item wield mesh virtual scene::IMesh* getWieldMesh(const std::string &name, - IGameDef *gamedef) const=0; + Client *client) const=0; #endif // Remove all registered item and node definitions and aliases diff --git a/src/localplayer.cpp b/src/localplayer.cpp index 4d0ca0600..b859c6455 100644 --- a/src/localplayer.cpp +++ b/src/localplayer.cpp @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "event.h" #include "collision.h" -#include "gamedef.h" #include "nodedef.h" #include "settings.h" #include "environment.h" @@ -32,8 +31,8 @@ with this program; if not, write to the Free Software Foundation, Inc., LocalPlayer */ -LocalPlayer::LocalPlayer(Client *gamedef, const char *name): - Player(name, gamedef->idef()), +LocalPlayer::LocalPlayer(Client *client, const char *name): + Player(name, client->idef()), parent(0), hp(PLAYER_MAX_HP), got_teleported(false), @@ -79,7 +78,7 @@ LocalPlayer::LocalPlayer(Client *gamedef, const char *name): camera_barely_in_ceiling(false), m_collisionbox(-BS * 0.30, 0.0, -BS * 0.30, BS * 0.30, BS * 1.75, BS * 0.30), m_cao(NULL), - m_gamedef(gamedef) + m_client(client) { // Initialize hp to 0, so that no hearts will be shown if server // doesn't support health points @@ -96,7 +95,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, std::vector *collision_info) { Map *map = &env->getMap(); - INodeDefManager *nodemgr = m_gamedef->ndef(); + INodeDefManager *nodemgr = m_client->ndef(); v3f position = getPosition(); @@ -109,8 +108,8 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, } // Skip collision detection if noclip mode is used - bool fly_allowed = m_gamedef->checkLocalPrivilege("fly"); - bool noclip = m_gamedef->checkLocalPrivilege("noclip") && + bool fly_allowed = m_client->checkLocalPrivilege("fly"); + bool noclip = m_client->checkLocalPrivilege("noclip") && g_settings->getBool("noclip"); bool free_move = noclip && fly_allowed && g_settings->getBool("free_move"); if (free_move) { @@ -241,7 +240,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, v3f accel_f = v3f(0,0,0); - collisionMoveResult result = collisionMoveSimple(env, m_gamedef, + collisionMoveResult result = collisionMoveSimple(env, m_client, pos_max_d, m_collisionbox, player_stepheight, dtime, &position, &m_speed, accel_f); @@ -376,7 +375,7 @@ void LocalPlayer::move(f32 dtime, Environment *env, f32 pos_max_d, if(!result.standing_on_object && !touching_ground_was && touching_ground) { MtEvent *e = new SimpleTriggerEvent("PlayerRegainGround"); - m_gamedef->event()->put(e); + m_client->event()->put(e); // Set camera impact value to be used for view bobbing camera_impact = getSpeed().Y * -1; @@ -448,8 +447,8 @@ void LocalPlayer::applyControl(float dtime) v3f speedH = v3f(0,0,0); // Horizontal (X, Z) v3f speedV = v3f(0,0,0); // Vertical (Y) - bool fly_allowed = m_gamedef->checkLocalPrivilege("fly"); - bool fast_allowed = m_gamedef->checkLocalPrivilege("fast"); + bool fly_allowed = m_client->checkLocalPrivilege("fly"); + bool fast_allowed = m_client->checkLocalPrivilege("fast"); bool free_move = fly_allowed && g_settings->getBool("free_move"); bool fast_move = fast_allowed && g_settings->getBool("fast_move"); @@ -599,7 +598,7 @@ void LocalPlayer::applyControl(float dtime) setSpeed(speedJ); MtEvent *e = new SimpleTriggerEvent("PlayerJump"); - m_gamedef->event()->put(e); + m_client->event()->put(e); } } else if(in_liquid) diff --git a/src/localplayer.h b/src/localplayer.h index 7a1cb7466..cbdcb9867 100644 --- a/src/localplayer.h +++ b/src/localplayer.h @@ -35,7 +35,7 @@ enum LocalPlayerAnimations {NO_ANIM, WALK_ANIM, DIG_ANIM, WD_ANIM}; // no local class LocalPlayer : public Player { public: - LocalPlayer(Client *gamedef, const char *name); + LocalPlayer(Client *client, const char *name); virtual ~LocalPlayer(); ClientActiveObject *parent; @@ -162,7 +162,7 @@ private: aabb3f m_collisionbox; GenericCAO* m_cao; - Client *m_gamedef; + Client *m_client; }; #endif diff --git a/src/mapblock_mesh.cpp b/src/mapblock_mesh.cpp index 977eabb6e..143adb410 100644 --- a/src/mapblock_mesh.cpp +++ b/src/mapblock_mesh.cpp @@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map.h" #include "profiler.h" #include "nodedef.h" -#include "gamedef.h" #include "mesh.h" #include "minimap.h" #include "content_mapblock.h" @@ -43,14 +42,14 @@ static void applyFacesShading(video::SColor &color, const float factor) MeshMakeData */ -MeshMakeData::MeshMakeData(IGameDef *gamedef, bool use_shaders, +MeshMakeData::MeshMakeData(Client *client, bool use_shaders, bool use_tangent_vertices): m_vmanip(), m_blockpos(-1337,-1337,-1337), m_crack_pos_relative(-1337, -1337, -1337), m_smooth_lighting(false), m_show_hud(false), - m_gamedef(gamedef), + m_client(client), m_use_shaders(use_shaders), m_use_tangent_vertices(use_tangent_vertices) {} @@ -233,7 +232,7 @@ static u16 getSmoothLightCombined(v3s16 p, MeshMakeData *data) v3s16(1,1,1), }; - INodeDefManager *ndef = data->m_gamedef->ndef(); + INodeDefManager *ndef = data->m_client->ndef(); u16 ambient_occlusion = 0; u16 light_count = 0; @@ -664,7 +663,7 @@ static u8 face_contents(content_t m1, content_t m2, bool *equivalent, */ TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data) { - INodeDefManager *ndef = data->m_gamedef->ndef(); + INodeDefManager *ndef = data->m_client->ndef(); TileSpec spec = ndef->get(mn).tiles[tileindex]; // Apply temporary crack if (p == data->m_crack_pos_relative) @@ -677,7 +676,7 @@ TileSpec getNodeTileN(MapNode mn, v3s16 p, u8 tileindex, MeshMakeData *data) */ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data) { - INodeDefManager *ndef = data->m_gamedef->ndef(); + INodeDefManager *ndef = data->m_client->ndef(); // Direction must be (1,0,0), (-1,0,0), (0,1,0), (0,-1,0), // (0,0,1), (0,0,-1) or (0,0,0) @@ -734,7 +733,7 @@ TileSpec getNodeTile(MapNode mn, v3s16 p, v3s16 dir, MeshMakeData *data) u16 tile_index=facedir*16 + dir_i; TileSpec spec = getNodeTileN(mn, p, dir_to_tile[tile_index], data); spec.rotation=dir_to_tile[tile_index + 1]; - spec.texture = data->m_gamedef->tsrc()->getTexture(spec.texture_id); + spec.texture = data->m_client->tsrc()->getTexture(spec.texture_id); return spec; } @@ -753,7 +752,7 @@ static void getTileInfo( ) { VoxelManipulator &vmanip = data->m_vmanip; - INodeDefManager *ndef = data->m_gamedef->ndef(); + INodeDefManager *ndef = data->m_client->ndef(); v3s16 blockpos_nodes = data->m_blockpos * MAP_BLOCKSIZE; MapNode &n0 = vmanip.getNodeRefUnsafe(blockpos_nodes + p); @@ -1020,10 +1019,10 @@ static void updateAllFastFaceRows(MeshMakeData *data, MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): m_mesh(new scene::SMesh()), m_minimap_mapblock(NULL), - m_gamedef(data->m_gamedef), - m_driver(m_gamedef->tsrc()->getDevice()->getVideoDriver()), - m_tsrc(m_gamedef->getTextureSource()), - m_shdrsrc(m_gamedef->getShaderSource()), + m_client(data->m_client), + m_driver(m_client->tsrc()->getDevice()->getVideoDriver()), + m_tsrc(m_client->getTextureSource()), + m_shdrsrc(m_client->getShaderSource()), m_animation_force_timer(0), // force initial animation m_last_crack(-1), m_crack_materials(), @@ -1243,7 +1242,7 @@ MapBlockMesh::MapBlockMesh(MeshMakeData *data, v3s16 camera_offset): if (m_use_tangent_vertices) { scene::IMeshManipulator* meshmanip = - m_gamedef->getSceneManager()->getMeshManipulator(); + m_client->getSceneManager()->getMeshManipulator(); meshmanip->recalculateTangents(m_mesh, true, false, false); } diff --git a/src/mapblock_mesh.h b/src/mapblock_mesh.h index 8376468da..5adb7df3f 100644 --- a/src/mapblock_mesh.h +++ b/src/mapblock_mesh.h @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/cpp11_container.h" #include -class IGameDef; +class Client; class IShaderSource; /* @@ -45,11 +45,11 @@ struct MeshMakeData bool m_smooth_lighting; bool m_show_hud; - IGameDef *m_gamedef; + Client *m_client; bool m_use_shaders; bool m_use_tangent_vertices; - MeshMakeData(IGameDef *gamedef, bool use_shaders, + MeshMakeData(Client *client, bool use_shaders, bool use_tangent_vertices = false); /* @@ -128,7 +128,7 @@ public: private: scene::IMesh *m_mesh; MinimapMapblock *m_minimap_mapblock; - IGameDef *m_gamedef; + Client *m_client; video::IVideoDriver *m_driver; ITextureSource *m_tsrc; IShaderSource *m_shdrsrc; diff --git a/src/mg_biome.cpp b/src/mg_biome.cpp index 78034bf6c..d564e9415 100644 --- a/src/mg_biome.cpp +++ b/src/mg_biome.cpp @@ -20,10 +20,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mg_biome.h" #include "mg_decoration.h" #include "emerge.h" -#include "gamedef.h" +#include "server.h" #include "nodedef.h" #include "map.h" //for MMVManip -#include "log.h" #include "util/numeric.h" #include "util/mathconstants.h" #include "porting.h" @@ -33,10 +32,10 @@ with this program; if not, write to the Free Software Foundation, Inc., /////////////////////////////////////////////////////////////////////////////// -BiomeManager::BiomeManager(IGameDef *gamedef) : - ObjDefManager(gamedef, OBJDEF_BIOME) +BiomeManager::BiomeManager(Server *server) : + ObjDefManager(server, OBJDEF_BIOME) { - m_gamedef = gamedef; + m_server = server; // Create default biome to be used in case none exist Biome *b = new Biome; @@ -73,7 +72,7 @@ BiomeManager::~BiomeManager() void BiomeManager::clear() { - EmergeManager *emerge = m_gamedef->getEmergeManager(); + EmergeManager *emerge = m_server->getEmergeManager(); // Remove all dangling references in Decorations DecorationManager *decomgr = emerge->decomgr; diff --git a/src/mg_biome.h b/src/mg_biome.h index a10193bc3..15088f7dd 100644 --- a/src/mg_biome.h +++ b/src/mg_biome.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "noise.h" +class Server; class Settings; class BiomeManager; @@ -186,7 +187,7 @@ private: class BiomeManager : public ObjDefManager { public: - BiomeManager(IGameDef *gamedef); + BiomeManager(Server *server); virtual ~BiomeManager(); const char *getObjectTitle() const @@ -223,7 +224,7 @@ public: virtual void clear(); private: - IGameDef *m_gamedef; + Server *m_server; }; diff --git a/src/mg_schematic.cpp b/src/mg_schematic.cpp index e028215dc..3d08d86fa 100644 --- a/src/mg_schematic.cpp +++ b/src/mg_schematic.cpp @@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include "mg_schematic.h" -#include "gamedef.h" +#include "server.h" #include "mapgen.h" #include "emerge.h" #include "map.h" @@ -34,16 +34,16 @@ with this program; if not, write to the Free Software Foundation, Inc., /////////////////////////////////////////////////////////////////////////////// -SchematicManager::SchematicManager(IGameDef *gamedef) : - ObjDefManager(gamedef, OBJDEF_SCHEMATIC) +SchematicManager::SchematicManager(Server *server) : + ObjDefManager(server, OBJDEF_SCHEMATIC) { - m_gamedef = gamedef; + m_server = server; } void SchematicManager::clear() { - EmergeManager *emerge = m_gamedef->getEmergeManager(); + EmergeManager *emerge = m_server->getEmergeManager(); // Remove all dangling references in Decorations DecorationManager *decomgr = emerge->decomgr; diff --git a/src/mg_schematic.h b/src/mg_schematic.h index da8859540..1d46e6ac4 100644 --- a/src/mg_schematic.h +++ b/src/mg_schematic.h @@ -29,7 +29,7 @@ class Mapgen; class MMVManip; class PseudoRandom; class NodeResolver; -class IGameDef; +class Server; /* Minetest Schematic File Format @@ -123,7 +123,7 @@ public: class SchematicManager : public ObjDefManager { public: - SchematicManager(IGameDef *gamedef); + SchematicManager(Server *server); virtual ~SchematicManager() {} virtual void clear(); @@ -139,7 +139,7 @@ public: } private: - IGameDef *m_gamedef; + Server *m_server; }; void generate_nodelist_and_update_ids(MapNode *nodes, size_t nodecount, diff --git a/src/nodedef.cpp b/src/nodedef.cpp index dbbdf95d2..b7d023897 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef SERVER #include "client/tile.h" #include "mesh.h" +#include "client.h" #include #endif #include "log.h" @@ -572,8 +573,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, #ifndef SERVER void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc, - scene::ISceneManager *smgr, scene::IMeshManipulator *meshmanip, - IGameDef *gamedef, const TextureSettings &tsettings) + scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings) { // minimap pixel color - the average color of a texture if (tsettings.enable_minimap && tiledef[0].name != "") @@ -709,7 +709,7 @@ void ContentFeatures::updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc if ((drawtype == NDT_MESH) && (mesh != "")) { // Meshnode drawtype // Read the mesh and apply scale - mesh_ptr[0] = gamedef->getMesh(mesh); + mesh_ptr[0] = client->getMesh(mesh); if (mesh_ptr[0]){ v3f scale = v3f(1.0, 1.0, 1.0) * BS * visual_scale; scaleMesh(mesh_ptr[0], scale); @@ -1316,9 +1316,11 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef, #ifndef SERVER infostream << "CNodeDefManager::updateTextures(): Updating " "textures in node definitions" << std::endl; - ITextureSource *tsrc = gamedef->tsrc(); - IShaderSource *shdsrc = gamedef->getShaderSource(); - scene::ISceneManager* smgr = gamedef->getSceneManager(); + + Client *client = (Client *)gamedef; + ITextureSource *tsrc = client->tsrc(); + IShaderSource *shdsrc = client->getShaderSource(); + scene::ISceneManager* smgr = client->getSceneManager(); scene::IMeshManipulator* meshmanip = smgr->getMeshManipulator(); TextureSettings tsettings; tsettings.readSettings(); @@ -1326,7 +1328,7 @@ void CNodeDefManager::updateTextures(IGameDef *gamedef, u32 size = m_content_features.size(); for (u32 i = 0; i < size; i++) { - m_content_features[i].updateTextures(tsrc, shdsrc, smgr, meshmanip, gamedef, tsettings); + m_content_features[i].updateTextures(tsrc, shdsrc, meshmanip, client, tsettings); progress_callback(progress_callback_args, i, size); } #endif diff --git a/src/nodedef.h b/src/nodedef.h index 284c4a198..183b95d87 100644 --- a/src/nodedef.h +++ b/src/nodedef.h @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef SERVER #include "client/tile.h" #include "shader.h" +class Client; #endif #include "itemgroup.h" #include "sound.h" // SimpleSoundSpec @@ -322,8 +323,7 @@ struct ContentFeatures u32 shader_id, bool use_normal_texture, bool backface_culling, u8 alpha, u8 material_type); void updateTextures(ITextureSource *tsrc, IShaderSource *shdsrc, - scene::ISceneManager *smgr, scene::IMeshManipulator *meshmanip, - IGameDef *gamedef, const TextureSettings &tsettings); + scene::IMeshManipulator *meshmanip, Client *client, const TextureSettings &tsettings); #endif }; diff --git a/src/particles.cpp b/src/particles.cpp index 97f42e2c4..d9eb3cfa5 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -18,11 +18,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "particles.h" -#include "constants.h" -#include "debug.h" -#include "settings.h" -#include "client/tile.h" -#include "gamedef.h" +#include "client.h" #include "collision.h" #include #include "util/numeric.h" @@ -452,7 +448,7 @@ void ParticleManager::clearAll () } } -void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef, +void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, scene::ISceneManager* smgr, LocalPlayer *player) { switch (event->type) { @@ -477,9 +473,9 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef, } video::ITexture *texture = - gamedef->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture)); + client->tsrc()->getTextureForMesh(*(event->add_particlespawner.texture)); - ParticleSpawner* toadd = new ParticleSpawner(gamedef, smgr, player, + ParticleSpawner* toadd = new ParticleSpawner(client, smgr, player, event->add_particlespawner.amount, event->add_particlespawner.spawntime, *event->add_particlespawner.minpos, @@ -520,9 +516,9 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, IGameDef *gamedef, } case CE_SPAWN_PARTICLE: { video::ITexture *texture = - gamedef->tsrc()->getTextureForMesh(*(event->spawn_particle.texture)); + client->tsrc()->getTextureForMesh(*(event->spawn_particle.texture)); - Particle* toadd = new Particle(gamedef, smgr, player, m_env, + Particle* toadd = new Particle(client, smgr, player, m_env, *event->spawn_particle.pos, *event->spawn_particle.vel, *event->spawn_particle.acc, diff --git a/src/particles.h b/src/particles.h index eb8c6665d..00cb2c08e 100644 --- a/src/particles.h +++ b/src/particles.h @@ -170,7 +170,7 @@ public: void step (float dtime); - void handleParticleEvent(ClientEvent *event,IGameDef *gamedef, + void handleParticleEvent(ClientEvent *event, Client *client, scene::ISceneManager* smgr, LocalPlayer *player); void addDiggingParticles(IGameDef* gamedef, scene::ISceneManager* smgr, diff --git a/src/pathfinder.cpp b/src/pathfinder.cpp index 84aa9252c..b240ec21f 100644 --- a/src/pathfinder.cpp +++ b/src/pathfinder.cpp @@ -24,12 +24,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "pathfinder.h" #include "serverenvironment.h" -#include "gamedef.h" +#include "server.h" #include "nodedef.h" -#include "map.h" -#include "log.h" -#include "irr_aabb3d.h" -#include "util/basic_macros.h" //#define PATHFINDER_DEBUG //#define PATHFINDER_CALC_TIME diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index 3cdd3cbfe..3d03c0c41 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -20,14 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_nodemeta.h" #include "lua_api/l_internal.h" #include "lua_api/l_inventory.h" -#include "common/c_converter.h" #include "common/c_content.h" #include "serverenvironment.h" #include "map.h" -#include "gamedef.h" -#include "nodemetadata.h" - - +#include "server.h" /* NodeMetaRef diff --git a/src/server.cpp b/src/server.cpp index 60dbef0d2..7380d37c2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -50,7 +50,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_abm.h" #include "content_sao.h" #include "mods.h" -#include "sound.h" // dummySoundManager #include "event_manager.h" #include "serverlist.h" #include "util/string.h" @@ -3310,29 +3309,12 @@ ICraftDefManager *Server::getCraftDefManager() { return m_craftdef; } -ITextureSource *Server::getTextureSource() -{ - return NULL; -} -IShaderSource *Server::getShaderSource() -{ - return NULL; -} -scene::ISceneManager *Server::getSceneManager() -{ - return NULL; -} u16 Server::allocateUnknownNodeId(const std::string &name) { return m_nodedef->allocateDummy(name); } -ISoundManager *Server::getSoundManager() -{ - return &dummySoundManager; -} - MtEventManager *Server::getEventManager() { return m_event; diff --git a/src/server.h b/src/server.h index fe7b50b77..a86f75f1d 100644 --- a/src/server.h +++ b/src/server.h @@ -283,13 +283,9 @@ public: virtual IItemDefManager* getItemDefManager(); virtual INodeDefManager* getNodeDefManager(); virtual ICraftDefManager* getCraftDefManager(); - virtual ITextureSource* getTextureSource(); - virtual IShaderSource* getShaderSource(); virtual u16 allocateUnknownNodeId(const std::string &name); - virtual ISoundManager* getSoundManager(); virtual MtEventManager* getEventManager(); - virtual scene::ISceneManager* getSceneManager(); - virtual IRollbackManager *getRollbackManager() { return m_rollback; } + IRollbackManager *getRollbackManager() { return m_rollback; } virtual EmergeManager *getEmergeManager() { return m_emerge; } IWritableItemDefManager* getWritableItemDefManager(); diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index c9fa64ec5..e1962bcff 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -352,11 +352,11 @@ void ActiveBlockList::update(std::vector &active_positions, */ ServerEnvironment::ServerEnvironment(ServerMap *map, - GameScripting *scriptIface, IGameDef *gamedef, + GameScripting *scriptIface, Server *server, const std::string &path_world) : m_map(map), m_script(scriptIface), - m_gamedef(gamedef), + m_server(server), m_path_world(path_world), m_send_recommended_timer(0), m_active_block_interval_overload_skip(0), @@ -487,7 +487,7 @@ void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason, for (std::vector::iterator it = m_players.begin(); it != m_players.end(); ++it) { RemotePlayer *player = dynamic_cast(*it); - ((Server*)m_gamedef)->DenyAccessVerCompliant(player->peer_id, + m_server->DenyAccessVerCompliant(player->peer_id, player->protocol_version, reason, str_reason, reconnect); } } @@ -501,7 +501,7 @@ void ServerEnvironment::saveLoadedPlayers() it != m_players.end(); ++it) { if ((*it)->checkModified()) { - (*it)->save(players_path, m_gamedef); + (*it)->save(players_path, m_server); } } } @@ -511,7 +511,7 @@ void ServerEnvironment::savePlayer(RemotePlayer *player) std::string players_path = m_path_world + DIR_DELIM "players"; fs::CreateDir(players_path); - player->save(players_path, m_gamedef); + player->save(players_path, m_server); } RemotePlayer *ServerEnvironment::loadPlayer(const std::string &playername, PlayerSAO *sao) @@ -523,7 +523,7 @@ RemotePlayer *ServerEnvironment::loadPlayer(const std::string &playername, Playe RemotePlayer *player = getPlayer(playername.c_str()); if (!player) { - player = new RemotePlayer("", m_gamedef->idef()); + player = new RemotePlayer("", m_server->idef()); newplayer = true; } @@ -632,7 +632,7 @@ void ServerEnvironment::loadMeta() } catch (SettingNotFoundException &e) { // No problem, this is expected. Just continue with an empty string } - m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_gamedef, m_game_time); + m_lbm_mgr.loadIntroductionTimes(lbm_introduction_times, m_server, m_game_time); m_day_count = args.exists("day_count") ? args.getU64("day_count") : 0; @@ -640,7 +640,7 @@ void ServerEnvironment::loadMeta() void ServerEnvironment::loadDefaultMeta() { - m_lbm_mgr.loadIntroductionTimes("", m_gamedef, m_game_time); + m_lbm_mgr.loadIntroductionTimes("", m_server, m_game_time); } struct ActiveABM @@ -902,7 +902,7 @@ void ServerEnvironment::addLoadingBlockModifierDef(LoadingBlockModifierDef *lbm) bool ServerEnvironment::setNode(v3s16 p, const MapNode &n) { - INodeDefManager *ndef = m_gamedef->ndef(); + INodeDefManager *ndef = m_server->ndef(); MapNode n_old = m_map->getNodeNoEx(p); // Call destructor @@ -929,7 +929,7 @@ bool ServerEnvironment::setNode(v3s16 p, const MapNode &n) bool ServerEnvironment::removeNode(v3s16 p) { - INodeDefManager *ndef = m_gamedef->ndef(); + INodeDefManager *ndef = m_server->ndef(); MapNode n_old = m_map->getNodeNoEx(p); // Call destructor diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 20a783ea5..d71d29a9c 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -29,6 +29,8 @@ class PlayerSAO; class ServerEnvironment; class ActiveBlockModifier; class ServerActiveObject; +class Server; +class GameScripting; /* {Active, Loading} block modifier interface. @@ -190,7 +192,7 @@ class ServerEnvironment : public Environment { public: ServerEnvironment(ServerMap *map, GameScripting *scriptIface, - IGameDef *gamedef, const std::string &path_world); + Server *server, const std::string &path_world); ~ServerEnvironment(); Map & getMap(); @@ -201,8 +203,8 @@ public: GameScripting* getScriptIface() { return m_script; } - IGameDef *getGameDef() - { return m_gamedef; } + Server *getGameDef() + { return m_server; } float getSendRecommendedInterval() { return m_recommended_send_interval; } @@ -377,8 +379,8 @@ private: ServerMap *m_map; // Lua state GameScripting* m_script; - // Game definition - IGameDef *m_gamedef; + // Server definition + Server *m_server; // World path const std::string m_path_world; // Active object list diff --git a/src/wieldmesh.cpp b/src/wieldmesh.cpp index 9c4d5b642..c305238fe 100644 --- a/src/wieldmesh.cpp +++ b/src/wieldmesh.cpp @@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "wieldmesh.h" #include "inventory.h" -#include "gamedef.h" +#include "client.h" #include "itemdef.h" #include "nodedef.h" #include "mesh.h" @@ -283,7 +283,7 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, video::SMaterial &material = m_meshnode->getMaterial(0); material.setTexture(0, tsrc->getTextureForMesh(imagename)); material.TextureLayer[0].TextureWrapU = video::ETC_CLAMP_TO_EDGE; - material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; + material.TextureLayer[0].TextureWrapV = video::ETC_CLAMP_TO_EDGE; material.MaterialType = m_material_type; material.setFlag(video::EMF_BACK_FACE_CULLING, true); // Enable bi/trilinear filtering only for high resolution textures @@ -304,12 +304,12 @@ void WieldMeshSceneNode::setExtruded(const std::string &imagename, } } -void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef) +void WieldMeshSceneNode::setItem(const ItemStack &item, Client *client) { - ITextureSource *tsrc = gamedef->getTextureSource(); - IItemDefManager *idef = gamedef->getItemDefManager(); - IShaderSource *shdrsrc = gamedef->getShaderSource(); - INodeDefManager *ndef = gamedef->getNodeDefManager(); + ITextureSource *tsrc = client->getTextureSource(); + IItemDefManager *idef = client->getItemDefManager(); + IShaderSource *shdrsrc = client->getShaderSource(); + INodeDefManager *ndef = client->getNodeDefManager(); const ItemDefinition &def = item.getDefinition(idef); const ContentFeatures &f = ndef->get(def.name); content_t id = ndef->getId(def.name); @@ -341,7 +341,7 @@ void WieldMeshSceneNode::setItem(const ItemStack &item, IGameDef *gamedef) } else if (f.drawtype == NDT_NORMAL || f.drawtype == NDT_ALLFACES) { setCube(f.tiles, def.wield_scale, tsrc); } else { - MeshMakeData mesh_make_data(gamedef, false); + MeshMakeData mesh_make_data(client, false); MapNode mesh_make_node(id, 255, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0)); @@ -435,11 +435,11 @@ void WieldMeshSceneNode::changeToMesh(scene::IMesh *mesh) m_meshnode->setVisible(true); } -scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item) +scene::IMesh *getItemMesh(Client *client, const ItemStack &item) { - ITextureSource *tsrc = gamedef->getTextureSource(); - IItemDefManager *idef = gamedef->getItemDefManager(); - INodeDefManager *ndef = gamedef->getNodeDefManager(); + ITextureSource *tsrc = client->getTextureSource(); + IItemDefManager *idef = client->getItemDefManager(); + INodeDefManager *ndef = client->getNodeDefManager(); const ItemDefinition &def = item.getDefinition(idef); const ContentFeatures &f = ndef->get(def.name); content_t id = ndef->getId(def.name); @@ -470,7 +470,7 @@ scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item) mesh = cloneMesh(g_extrusion_mesh_cache->createCube()); scaleMesh(mesh, v3f(1.2, 1.2, 1.2)); } else { - MeshMakeData mesh_make_data(gamedef, false); + MeshMakeData mesh_make_data(client, false); MapNode mesh_make_node(id, 255, 0); mesh_make_data.fillSingleNode(&mesh_make_node); MapBlockMesh mapblock_mesh(&mesh_make_data, v3s16(0, 0, 0)); diff --git a/src/wieldmesh.h b/src/wieldmesh.h index 0b3136bc1..0162c5e5a 100644 --- a/src/wieldmesh.h +++ b/src/wieldmesh.h @@ -24,7 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include struct ItemStack; -class IGameDef; +class Client; class ITextureSource; struct TileSpec; @@ -42,7 +42,7 @@ public: v3f wield_scale, ITextureSource *tsrc); void setExtruded(const std::string &imagename, v3f wield_scale, ITextureSource *tsrc, u8 num_frames); - void setItem(const ItemStack &item, IGameDef *gamedef); + void setItem(const ItemStack &item, Client *client); // Sets the vertex color of the wield mesh. // Must only be used if the constructor was called with lighting = false @@ -77,7 +77,7 @@ private: aabb3f m_bounding_box; }; -scene::IMesh *getItemMesh(IGameDef *gamedef, const ItemStack &item); +scene::IMesh *getItemMesh(Client *client, const ItemStack &item); scene::IMesh *getExtrudedMesh(ITextureSource *tsrc, const std::string &imagename); -- cgit v1.2.3 From f5070b44542edba97a20445c3774c221077cc4a2 Mon Sep 17 00:00:00 2001 From: sapier Date: Sun, 15 Jan 2017 13:36:53 +0100 Subject: Added lua tracebacks to some errors where you have been blind to what… (#5043) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added lua tracebacks to some errors where you have been blind to what actually went wrong --- src/emerge.cpp | 2 +- src/script/common/c_converter.cpp | 4 +++- src/script/cpp_api/s_env.cpp | 12 +++++++++--- src/server.cpp | 5 +++-- 4 files changed, 16 insertions(+), 7 deletions(-) (limited to 'src/server.cpp') diff --git a/src/emerge.cpp b/src/emerge.cpp index 3f0a46010..1c9719c48 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -564,7 +564,7 @@ MapBlock *EmergeThread::finishGen(v3s16 pos, BlockMakeData *bmdata, m_server->getScriptIface()->environment_OnGenerated( minp, maxp, m_mapgen->blockseed); } catch (LuaError &e) { - m_server->setAsyncFatalError("Lua: " + std::string(e.what())); + m_server->setAsyncFatalError("Lua: finishGen" + std::string(e.what())); } EMERGE_DBG_OUT("ended up with: " << analyze_block(block)); diff --git a/src/script/common/c_converter.cpp b/src/script/common/c_converter.cpp index f36298915..fc516d56a 100644 --- a/src/script/common/c_converter.cpp +++ b/src/script/common/c_converter.cpp @@ -26,15 +26,17 @@ extern "C" { #include "util/serialize.h" #include "util/string.h" #include "common/c_converter.h" +#include "common/c_internal.h" #include "constants.h" #define CHECK_TYPE(index, name, type) do { \ int t = lua_type(L, (index)); \ if (t != (type)) { \ + std::string traceback = script_get_backtrace(L); \ throw LuaError(std::string("Invalid ") + (name) + \ " (expected " + lua_typename(L, (type)) + \ - " got " + lua_typename(L, t) + ")."); \ + " got " + lua_typename(L, t) + ").\n" + traceback); \ } \ } while(0) #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER) diff --git a/src/script/cpp_api/s_env.cpp b/src/script/cpp_api/s_env.cpp index 913d8539d..b1404bf22 100644 --- a/src/script/cpp_api/s_env.cpp +++ b/src/script/cpp_api/s_env.cpp @@ -54,7 +54,9 @@ void ScriptApiEnv::environment_Step(float dtime) try { runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); } catch (LuaError &e) { - getServer()->setAsyncFatalError(e.what()); + getServer()->setAsyncFatalError( + std::string("environment_Step: ") + e.what() + "\n" + + script_get_backtrace(L)); } } @@ -75,7 +77,9 @@ void ScriptApiEnv::player_event(ServerActiveObject *player, const std::string &t try { runCallbacks(2, RUN_CALLBACKS_MODE_FIRST); } catch (LuaError &e) { - getServer()->setAsyncFatalError(e.what()); + getServer()->setAsyncFatalError( + std::string("player_event: ") + e.what() + "\n" + + script_get_backtrace(L) ); } } @@ -237,7 +241,9 @@ void ScriptApiEnv::on_emerge_area_completion( try { PCALL_RES(lua_pcall(L, 4, 0, error_handler)); } catch (LuaError &e) { - server->setAsyncFatalError(e.what()); + server->setAsyncFatalError( + std::string("on_emerge_area_completion: ") + e.what() + "\n" + + script_get_backtrace(L)); } lua_pop(L, 1); // Pop error handler diff --git a/src/server.cpp b/src/server.cpp index 7380d37c2..29dce5a4a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -107,7 +107,8 @@ void *ServerThread::run() } catch (con::ConnectionBindFailed &e) { m_server->setAsyncFatalError(e.what()); } catch (LuaError &e) { - m_server->setAsyncFatalError("Lua: " + std::string(e.what())); + m_server->setAsyncFatalError( + "ServerThread::run Lua: " + std::string(e.what())); } } @@ -487,7 +488,7 @@ void Server::step(float dtime) g_settings->get("kick_msg_crash"), g_settings->getBool("ask_reconnect_on_crash")); } - throw ServerError(async_err); + throw ServerError("AsyncErr: " + async_err); } } -- cgit v1.2.3 From 2f56a00d9eef82052614e5854a07b39b087efd0b Mon Sep 17 00:00:00 2001 From: red-001 Date: Mon, 16 Jan 2017 23:09:47 +0000 Subject: Remove client-side chat prediction. (#5055) Network lag isn't really a big issue with chat and chat prediction makes writing mods harder. --- builtin/game/features.lua | 1 + src/client.cpp | 11 +++++++---- src/network/networkprotocol.h | 1 + src/server.cpp | 8 ++++++++ 4 files changed, 17 insertions(+), 4 deletions(-) (limited to 'src/server.cpp') diff --git a/builtin/game/features.lua b/builtin/game/features.lua index 646b254ea..ef85fbbc3 100644 --- a/builtin/game/features.lua +++ b/builtin/game/features.lua @@ -10,6 +10,7 @@ core.features = { texture_names_parens = true, area_store_custom_ids = true, add_entity_with_staticdata = true, + no_chat_message_prediction = true, } function core.has_feature(arg) diff --git a/src/client.cpp b/src/client.cpp index c2471dbd7..30058a2b0 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -1563,10 +1563,13 @@ void Client::typeChatMessage(const std::wstring &message) } else { - LocalPlayer *player = m_env.getLocalPlayer(); - assert(player != NULL); - std::wstring name = narrow_to_wide(player->getName()); - m_chat_queue.push((std::wstring)L"<" + name + L"> " + message); + // compatibility code + if (m_proto_ver < 29) { + LocalPlayer *player = m_env.getLocalPlayer(); + assert(player != NULL); + std::wstring name = narrow_to_wide(player->getName()); + m_chat_queue.push((std::wstring)L"<" + name + L"> " + message); + } } } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 45bf76ff8..23c8a665b 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -142,6 +142,7 @@ with this program; if not, write to the Free Software Foundation, Inc., Server doesn't accept TOSERVER_BREATH anymore serialization of TileAnimation params changed TAT_SHEET_2D + Removed client-sided chat perdiction */ #define LATEST_PROTOCOL_VERSION 29 diff --git a/src/server.cpp b/src/server.cpp index 29dce5a4a..74d9541c9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2826,7 +2826,15 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna std::vector clients = m_clients.getClientIDs(); + /* + Send the message back to the inital sender + if they are using protocol version >= 29 + */ + u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT); + if (player->protocol_version >= 29) + peer_id_to_avoid_sending = PEER_ID_INEXISTENT; + for (u16 i = 0; i < clients.size(); i++) { u16 cid = clients[i]; if (cid != peer_id_to_avoid_sending) -- cgit v1.2.3 From 7279f0b37335396c85f6bdd7dc67ff56e53df0f9 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sat, 14 Jan 2017 16:48:49 +0100 Subject: Add particle animation, glow This is implemented by reusing and extending the TileAnimation code for the methods used by particles. --- doc/lua_api.txt | 7 ++- games/minimal/mods/experimental/init.lua | 37 ++++++++++++++ src/client.h | 5 ++ src/network/clientpackethandler.cpp | 18 +++++++ src/network/networkpacket.cpp | 2 +- src/network/networkpacket.h | 5 +- src/nodedef.cpp | 2 +- src/particles.cpp | 74 ++++++++++++++++++++++----- src/particles.h | 12 ++++- src/script/common/c_content.cpp | 60 +++++++++++++--------- src/script/common/c_content.h | 1 + src/script/lua_api/l_particles.cpp | 27 +++++++++- src/server.cpp | 85 +++++++++++++++++++++++--------- src/server.h | 18 ++++--- src/tileanimation.cpp | 32 ++++++++++-- src/tileanimation.h | 4 +- 16 files changed, 311 insertions(+), 78 deletions(-) (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index c96131455..9bdc01c07 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -4180,10 +4180,15 @@ The Biome API is still in an experimental phase and subject to change. -- ^ vertical: if true faces player using y axis only texture = "image.png", -- ^ Uses texture (string) - playername = "singleplayer" + playername = "singleplayer", -- ^ optional, if specified spawns particle only on the player's client + animation = {Tile Animation definition}, + -- ^ optional, specifies how to animate the particle texture + glow = 0 + -- ^ optional, specify particle self-luminescence in darkness } + ### `ParticleSpawner` definition (`add_particlespawner`) { diff --git a/games/minimal/mods/experimental/init.lua b/games/minimal/mods/experimental/init.lua index 142734cda..5e98e1a80 100644 --- a/games/minimal/mods/experimental/init.lua +++ b/games/minimal/mods/experimental/init.lua @@ -523,6 +523,43 @@ minetest.register_craft({ } }) +minetest.register_craftitem("experimental:tester_tool_2", { + description = "Tester Tool 2", + inventory_image = "experimental_tester_tool_1.png^[invert:g", + on_use = function(itemstack, user, pointed_thing) + local pos = minetest.get_pointed_thing_position(pointed_thing, true) + if pos == nil then return end + pos = vector.add(pos, {x=0, y=0.5, z=0}) + local tex, anim + if math.random(0, 1) == 0 then + tex = "default_lava_source_animated.png" + anim = {type="sheet_2d", frames_w=3, frames_h=2, frame_length=0.5} + else + tex = "default_lava_flowing_animated.png" + anim = {type="vertical_frames", aspect_w=16, aspect_h=16, length=3.3} + end + + minetest.add_particle({ + pos = pos, + velocity = {x=0, y=0, z=0}, + acceleration = {x=0, y=0.04, z=0}, + expirationtime = 6, + collisiondetection = true, + texture = tex, + animation = anim, + size = 4, + glow = math.random(0, 5), + }) + end, +}) + +minetest.register_craft({ + output = 'experimental:tester_tool_2', + recipe = { + {'group:crumbly','group:crumbly'}, + } +}) + --[[minetest.register_on_joinplayer(function(player) minetest.after(3, function() player:set_inventory_formspec("size[8,7.5]".. diff --git a/src/client.h b/src/client.h index f84246deb..b33358d94 100644 --- a/src/client.h +++ b/src/client.h @@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "hud.h" #include "particles.h" #include "mapnode.h" +#include "tileanimation.h" struct MeshMakeData; class MapBlockMesh; @@ -186,6 +187,8 @@ struct ClientEvent bool collision_removal; bool vertical; std::string *texture; + struct TileAnimationParams animation; + u8 glow; } spawn_particle; struct{ u16 amount; @@ -206,6 +209,8 @@ struct ClientEvent bool vertical; std::string *texture; u32 id; + struct TileAnimationParams animation; + u8 glow; } add_particlespawner; struct{ u32 id; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 411982f69..b11f73e86 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -32,6 +32,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "network/clientopcodes.h" #include "util/serialize.h" #include "util/srp.h" +#include "tileanimation.h" void Client::handleCommand_Deprecated(NetworkPacket* pkt) { @@ -896,9 +897,14 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt) std::string texture = deSerializeLongString(is); bool vertical = false; bool collision_removal = false; + struct TileAnimationParams animation; + animation.type = TAT_NONE; + u8 glow = 0; try { vertical = readU8(is); collision_removal = readU8(is); + animation.deSerialize(is, m_proto_ver); + glow = readU8(is); } catch (...) {} ClientEvent event; @@ -912,6 +918,8 @@ void Client::handleCommand_SpawnParticle(NetworkPacket* pkt) 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); } @@ -943,12 +951,20 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) bool vertical = false; bool collision_removal = false; + struct TileAnimationParams animation; + animation.type = TAT_NONE; + u8 glow = 0; u16 attached_id = 0; try { *pkt >> vertical; *pkt >> collision_removal; *pkt >> attached_id; + // This is horrible but required (why are there two ways to deserialize pkts?) + std::string datastring(pkt->getRemainingString(), pkt->getRemainingBytes()); + std::istringstream is(datastring, std::ios_base::binary); + animation.deSerialize(is, m_proto_ver); + glow = readU8(is); } catch (...) {} ClientEvent event; @@ -971,6 +987,8 @@ void Client::handleCommand_AddParticleSpawner(NetworkPacket* pkt) 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); } diff --git a/src/network/networkpacket.cpp b/src/network/networkpacket.cpp index 388afc18e..91e6c58e2 100644 --- a/src/network/networkpacket.cpp +++ b/src/network/networkpacket.cpp @@ -63,7 +63,7 @@ void NetworkPacket::putRawPacket(u8 *data, u32 datasize, u16 peer_id) m_data = std::vector(&data[2], &data[2 + m_datasize]); } -char* NetworkPacket::getString(u32 from_offset) +const char* NetworkPacket::getString(u32 from_offset) { checkReadOffset(from_offset, 0); diff --git a/src/network/networkpacket.h b/src/network/networkpacket.h index 524470999..3e436aba9 100644 --- a/src/network/networkpacket.h +++ b/src/network/networkpacket.h @@ -41,12 +41,15 @@ public: u16 getPeerId() { return m_peer_id; } u16 getCommand() { return m_command; } const u32 getRemainingBytes() const { return m_datasize - m_read_offset; } + const char* getRemainingString() { return getString(m_read_offset); } // Returns a c-string without copying. // A better name for this would be getRawString() - char* getString(u32 from_offset); + const char* getString(u32 from_offset); // major difference to putCString(): doesn't write len into the buffer void putRawString(const char* src, u32 len); + void putRawString(const std::string &src) + { putRawString(src.c_str(), src.size()); } NetworkPacket& operator>>(std::string& dst); NetworkPacket& operator<<(std::string src); diff --git a/src/nodedef.cpp b/src/nodedef.cpp index b7d023897..a4af26e87 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -541,7 +541,7 @@ void ContentFeatures::fillTileAttribs(ITextureSource *tsrc, TileSpec *tile, if (tile->material_flags & MATERIAL_FLAG_ANIMATION) { int frame_length_ms; tiledef->animation.determineParams(tile->texture->getOriginalSize(), - &frame_count, &frame_length_ms); + &frame_count, &frame_length_ms, NULL); tile->animation_frame_count = frame_count; tile->animation_frame_length_ms = frame_length_ms; } diff --git a/src/particles.cpp b/src/particles.cpp index d9eb3cfa5..5f17763e0 100644 --- a/src/particles.cpp +++ b/src/particles.cpp @@ -54,7 +54,9 @@ Particle::Particle( bool vertical, video::ITexture *texture, v2f texpos, - v2f texsize + v2f texsize, + const struct TileAnimationParams &anim, + u8 glow ): scene::ISceneNode(smgr->getRootSceneNode(), smgr) { @@ -71,7 +73,9 @@ Particle::Particle( m_material.setTexture(0, texture); m_texpos = texpos; m_texsize = texsize; - + m_animation = anim; + m_animation_frame = 0; + m_animation_time = 0.0; // Particle related m_pos = pos; @@ -84,6 +88,7 @@ Particle::Particle( m_collisiondetection = collisiondetection; m_collision_removal = collision_removal; m_vertical = vertical; + m_glow = glow; // Irrlicht stuff m_collisionbox = aabb3f @@ -142,6 +147,18 @@ void Particle::step(float dtime) m_velocity += m_acceleration * dtime; m_pos += m_velocity * dtime; } + if (m_animation.type != TAT_NONE) { + m_animation_time += dtime; + int frame_length_i, frame_count; + m_animation.determineParams( + m_material.getTexture(0)->getSize(), + &frame_count, &frame_length_i, NULL); + float frame_length = frame_length_i / 1000.0; + while (m_animation_time > frame_length) { + m_animation_frame++; + m_animation_time -= frame_length; + } + } // Update lighting updateLight(); @@ -166,16 +183,32 @@ void Particle::updateLight() else light = blend_light(m_env->getDayNightRatio(), LIGHT_SUN, 0); - m_light = decode_light(light); + m_light = decode_light(light + m_glow); } void Particle::updateVertices() { video::SColor c(255, m_light, m_light, m_light); - f32 tx0 = m_texpos.X; - f32 tx1 = m_texpos.X + m_texsize.X; - f32 ty0 = m_texpos.Y; - f32 ty1 = m_texpos.Y + m_texsize.Y; + f32 tx0, tx1, ty0, ty1; + + if (m_animation.type != TAT_NONE) { + const v2u32 texsize = m_material.getTexture(0)->getSize(); + v2f texcoord, framesize_f; + v2u32 framesize; + texcoord = m_animation.getTextureCoords(texsize, m_animation_frame); + m_animation.determineParams(texsize, NULL, NULL, &framesize); + framesize_f = v2f(framesize.X / (float) texsize.X, framesize.Y / (float) texsize.Y); + + tx0 = m_texpos.X + texcoord.X; + tx1 = m_texpos.X + texcoord.X + framesize_f.X * m_texsize.X; + ty0 = m_texpos.Y + texcoord.Y; + ty1 = m_texpos.Y + texcoord.Y + framesize_f.Y * m_texsize.Y; + } else { + tx0 = m_texpos.X; + tx1 = m_texpos.X + m_texsize.X; + ty0 = m_texpos.Y; + ty1 = m_texpos.Y + m_texsize.Y; + } m_vertices[0] = video::S3DVertex(-m_size/2,-m_size/2,0, 0,0,0, c, tx0, ty1); @@ -210,7 +243,9 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime, float minsize, float maxsize, bool collisiondetection, bool collision_removal, u16 attached_id, bool vertical, - video::ITexture *texture, u32 id, ParticleManager *p_manager) : + video::ITexture *texture, u32 id, const struct TileAnimationParams &anim, + u8 glow, + ParticleManager *p_manager) : m_particlemanager(p_manager) { m_gamedef = gamedef; @@ -234,6 +269,8 @@ ParticleSpawner::ParticleSpawner(IGameDef* gamedef, scene::ISceneManager *smgr, m_vertical = vertical; m_texture = texture; m_time = 0; + m_animation = anim; + m_glow = glow; for (u16 i = 0; i<=m_amount; i++) { @@ -309,7 +346,9 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env) m_vertical, m_texture, v2f(0.0, 0.0), - v2f(1.0, 1.0)); + v2f(1.0, 1.0), + m_animation, + m_glow); m_particlemanager->addParticle(toadd); } i = m_spawntimes.erase(i); @@ -363,7 +402,9 @@ void ParticleSpawner::step(float dtime, ClientEnvironment* env) m_vertical, m_texture, v2f(0.0, 0.0), - v2f(1.0, 1.0)); + v2f(1.0, 1.0), + m_animation, + m_glow); m_particlemanager->addParticle(toadd); } } @@ -494,6 +535,8 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, event->add_particlespawner.vertical, texture, event->add_particlespawner.id, + event->add_particlespawner.animation, + event->add_particlespawner.glow, this); /* delete allocated content of event */ @@ -529,13 +572,16 @@ void ParticleManager::handleParticleEvent(ClientEvent *event, Client *client, event->spawn_particle.vertical, texture, v2f(0.0, 0.0), - v2f(1.0, 1.0)); + v2f(1.0, 1.0), + event->spawn_particle.animation, + event->spawn_particle.glow); addParticle(toadd); delete event->spawn_particle.pos; delete event->spawn_particle.vel; delete event->spawn_particle.acc; + delete event->spawn_particle.texture; break; } @@ -564,6 +610,8 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s // Texture u8 texid = myrand_range(0, 5); video::ITexture *texture; + struct TileAnimationParams anim; + anim.type = TAT_NONE; // Only use first frame of animated texture if (tiles[texid].material_flags & MATERIAL_FLAG_ANIMATION) @@ -605,7 +653,9 @@ void ParticleManager::addNodeParticle(IGameDef* gamedef, scene::ISceneManager* s false, texture, texpos, - texsize); + texsize, + anim, + 0); addParticle(toadd); } diff --git a/src/particles.h b/src/particles.h index 00cb2c08e..5464e6672 100644 --- a/src/particles.h +++ b/src/particles.h @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/tile.h" #include "localplayer.h" #include "environment.h" +#include "tileanimation.h" struct ClientEvent; class ParticleManager; @@ -50,7 +51,9 @@ class Particle : public scene::ISceneNode bool vertical, video::ITexture *texture, v2f texpos, - v2f texsize + v2f texsize, + const struct TileAnimationParams &anim, + u8 glow ); ~Particle(); @@ -102,6 +105,10 @@ private: bool m_collision_removal; bool m_vertical; v3s16 m_camera_offset; + struct TileAnimationParams m_animation; + float m_animation_time; + int m_animation_frame; + u8 m_glow; }; class ParticleSpawner @@ -123,6 +130,7 @@ class ParticleSpawner bool vertical, video::ITexture *texture, u32 id, + const struct TileAnimationParams &anim, u8 glow, ParticleManager* p_manager); ~ParticleSpawner(); @@ -156,6 +164,8 @@ class ParticleSpawner bool m_collision_removal; bool m_vertical; u16 m_attached_id; + struct TileAnimationParams m_animation; + u8 m_glow; }; /** diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index b9bcfef69..84af4583b 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -322,7 +322,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype) } else if(lua_istable(L, index)) { - // {name="default_lava.png", animation={}} + // name="default_lava.png" tiledef.name = ""; getstringfield(L, index, "name", tiledef.name); getstringfield(L, index, "image", tiledef.name); // MaterialSpec compat. @@ -334,28 +334,7 @@ TileDef read_tiledef(lua_State *L, int index, u8 drawtype) L, index, "tileable_vertical", default_tiling); // animation = {} lua_getfield(L, index, "animation"); - if(lua_istable(L, -1)){ - tiledef.animation.type = (TileAnimationType) - getenumfield(L, -1, "type", es_TileAnimationType, - TAT_NONE); - if (tiledef.animation.type == TAT_VERTICAL_FRAMES) { - // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} - tiledef.animation.vertical_frames.aspect_w = - getintfield_default(L, -1, "aspect_w", 16); - tiledef.animation.vertical_frames.aspect_h = - getintfield_default(L, -1, "aspect_h", 16); - tiledef.animation.vertical_frames.length = - getfloatfield_default(L, -1, "length", 1.0); - } else if (tiledef.animation.type == TAT_SHEET_2D) { - // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5} - getintfield(L, -1, "frames_w", - tiledef.animation.sheet_2d.frames_w); - getintfield(L, -1, "frames_h", - tiledef.animation.sheet_2d.frames_h); - getfloatfield(L, -1, "frame_length", - tiledef.animation.sheet_2d.frame_length); - } - } + tiledef.animation = read_animation_definition(L, -1); lua_pop(L, 1); } @@ -925,6 +904,41 @@ void read_inventory_list(lua_State *L, int tableindex, } } +/******************************************************************************/ +struct TileAnimationParams read_animation_definition(lua_State *L, int index) +{ + if(index < 0) + index = lua_gettop(L) + 1 + index; + + struct TileAnimationParams anim; + anim.type = TAT_NONE; + if (!lua_istable(L, index)) + return anim; + + anim.type = (TileAnimationType) + getenumfield(L, index, "type", es_TileAnimationType, + TAT_NONE); + if (anim.type == TAT_VERTICAL_FRAMES) { + // {type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0} + anim.vertical_frames.aspect_w = + getintfield_default(L, index, "aspect_w", 16); + anim.vertical_frames.aspect_h = + getintfield_default(L, index, "aspect_h", 16); + anim.vertical_frames.length = + getfloatfield_default(L, index, "length", 1.0); + } else if (anim.type == TAT_SHEET_2D) { + // {type="sheet_2d", frames_w=5, frames_h=3, frame_length=0.5} + getintfield(L, index, "frames_w", + anim.sheet_2d.frames_w); + getintfield(L, index, "frames_h", + anim.sheet_2d.frames_h); + getfloatfield(L, index, "frame_length", + anim.sheet_2d.frame_length); + } + + return anim; +} + /******************************************************************************/ ToolCapabilities read_tool_capabilities( lua_State *L, int table) diff --git a/src/script/common/c_content.h b/src/script/common/c_content.h index 2a2228b6d..9641f5c9e 100644 --- a/src/script/common/c_content.h +++ b/src/script/common/c_content.h @@ -79,6 +79,7 @@ void push_hit_params (lua_State *L, ItemStack read_item (lua_State *L, int index, Server *srv); +struct TileAnimationParams read_animation_definition(lua_State *L, int index); ToolCapabilities read_tool_capabilities (lua_State *L, int table); void push_tool_capabilities (lua_State *L, diff --git a/src/script/lua_api/l_particles.cpp b/src/script/lua_api/l_particles.cpp index 667ac7272..7f415844a 100644 --- a/src/script/lua_api/l_particles.cpp +++ b/src/script/lua_api/l_particles.cpp @@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_object.h" #include "lua_api/l_internal.h" #include "common/c_converter.h" +#include "common/c_content.h" #include "server.h" #include "particles.h" @@ -34,6 +35,8 @@ with this program; if not, write to the Free Software Foundation, Inc., // collision_removal = bool // vertical = bool // texture = e.g."default_wood.png" +// animation = TileAnimation definition +// glow = num int ModApiParticles::l_add_particle(lua_State *L) { MAP_LOCK_REQUIRED; @@ -47,10 +50,13 @@ int ModApiParticles::l_add_particle(lua_State *L) bool collisiondetection, vertical, collision_removal; collisiondetection = vertical = collision_removal = false; + struct TileAnimationParams animation; std::string texture = ""; std::string playername = ""; + u8 glow = 0; + if (lua_gettop(L) > 1) // deprecated { log_deprecated(L, "Deprecated add_particle call with individual parameters instead of definition"); @@ -101,11 +107,18 @@ int ModApiParticles::l_add_particle(lua_State *L) collision_removal = getboolfield_default(L, 1, "collision_removal", collision_removal); vertical = getboolfield_default(L, 1, "vertical", vertical); + + lua_getfield(L, 1, "animation"); + animation = read_animation_definition(L, -1); + lua_pop(L, 1); + texture = getstringfield_default(L, 1, "texture", ""); playername = getstringfield_default(L, 1, "playername", ""); + + glow = getintfield_default(L, 1, "glow", 0); } getServer(L)->spawnParticle(playername, pos, vel, acc, expirationtime, size, - collisiondetection, collision_removal, vertical, texture); + collisiondetection, collision_removal, vertical, texture, animation, glow); return 1; } @@ -127,6 +140,8 @@ int ModApiParticles::l_add_particle(lua_State *L) // collision_removal = bool // vertical = bool // texture = e.g."default_wood.png" +// animation = TileAnimation definition +// glow = num int ModApiParticles::l_add_particlespawner(lua_State *L) { MAP_LOCK_REQUIRED; @@ -139,9 +154,11 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) time= minexptime= maxexptime= minsize= maxsize= 1; bool collisiondetection, vertical, collision_removal; collisiondetection = vertical = collision_removal = false; + struct TileAnimationParams animation; ServerActiveObject *attached = NULL; std::string texture = ""; std::string playername = ""; + u8 glow = 0; if (lua_gettop(L) > 1) //deprecated { @@ -201,6 +218,10 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) collision_removal = getboolfield_default(L, 1, "collision_removal", collision_removal); + lua_getfield(L, 1, "animation"); + animation = read_animation_definition(L, -1); + lua_pop(L, 1); + lua_getfield(L, 1, "attached"); if (!lua_isnil(L, -1)) { ObjectRef *ref = ObjectRef::checkobject(L, -1); @@ -211,6 +232,7 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) vertical = getboolfield_default(L, 1, "vertical", vertical); texture = getstringfield_default(L, 1, "texture", ""); playername = getstringfield_default(L, 1, "playername", ""); + glow = getintfield_default(L, 1, "glow", 0); } u32 id = getServer(L)->addParticleSpawner(amount, time, @@ -223,7 +245,8 @@ int ModApiParticles::l_add_particlespawner(lua_State *L) collision_removal, attached, vertical, - texture, playername); + texture, playername, + animation, glow); lua_pushnumber(L, id); return 1; diff --git a/src/server.cpp b/src/server.cpp index 74d9541c9..d3d5fd3d1 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1662,12 +1662,28 @@ void Server::SendShowFormspecMessage(u16 peer_id, const std::string &formspec, } // Spawns a particle on peer with peer_id -void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f acceleration, +void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version, + v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture) + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow) { DSTACK(FUNCTION_NAME); + if (peer_id == PEER_ID_INEXISTENT) { + // This sucks and should be replaced by a better solution in a refactor: + std::vector clients = m_clients.getClientIDs(); + for (std::vector::iterator i = clients.begin(); i != clients.end(); ++i) { + RemotePlayer *player = m_env->getPlayer(*i); + if (!player) + continue; + SendSpawnParticle(*i, player->protocol_version, + pos, velocity, acceleration, + expirationtime, size, collisiondetection, + collision_removal, vertical, texture, animation, glow); + } + return; + } NetworkPacket pkt(TOCLIENT_SPAWN_PARTICLE, 0, peer_id); @@ -1676,22 +1692,39 @@ void Server::SendSpawnParticle(u16 peer_id, v3f pos, v3f velocity, v3f accelerat pkt.putLongString(texture); pkt << vertical; pkt << collision_removal; + // This is horrible but required (why are there two ways to serialize pkts?) + std::ostringstream os(std::ios_base::binary); + animation.serialize(os, protocol_version); + pkt.putRawString(os.str()); + pkt << glow; - if (peer_id != PEER_ID_INEXISTENT) { - Send(&pkt); - } - else { - m_clients.sendToAll(0, &pkt, true); - } + Send(&pkt); } // Adds a ParticleSpawner on peer with peer_id -void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3f minpos, v3f maxpos, +void Server::SendAddParticleSpawner(u16 peer_id, u16 protocol_version, + u16 amount, float spawntime, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, float minexptime, float maxexptime, float minsize, float maxsize, bool collisiondetection, bool collision_removal, - u16 attached_id, bool vertical, const std::string &texture, u32 id) + u16 attached_id, bool vertical, const std::string &texture, u32 id, + const struct TileAnimationParams &animation, u8 glow) { DSTACK(FUNCTION_NAME); + if (peer_id == PEER_ID_INEXISTENT) { + // This sucks and should be replaced: + std::vector clients = m_clients.getClientIDs(); + for (std::vector::iterator i = clients.begin(); i != clients.end(); ++i) { + RemotePlayer *player = m_env->getPlayer(*i); + if (!player) + continue; + SendAddParticleSpawner(*i, player->protocol_version, + amount, spawntime, minpos, maxpos, + minvel, maxvel, minacc, maxacc, minexptime, maxexptime, + minsize, maxsize, collisiondetection, collision_removal, + attached_id, vertical, texture, id, animation, glow); + } + return; + } NetworkPacket pkt(TOCLIENT_ADD_PARTICLESPAWNER, 0, peer_id); @@ -1704,13 +1737,13 @@ void Server::SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, v3 pkt << id << vertical; pkt << collision_removal; pkt << attached_id; + // This is horrible but required + std::ostringstream os(std::ios_base::binary); + animation.serialize(os, protocol_version); + pkt.putRawString(os.str()); + pkt << glow; - if (peer_id != PEER_ID_INEXISTENT) { - Send(&pkt); - } - else { - m_clients.sendToAll(0, &pkt, true); - } + Send(&pkt); } void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id) @@ -3165,23 +3198,25 @@ void Server::spawnParticle(const std::string &playername, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture) + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow) { // m_env will be NULL if the server is initializing if (!m_env) return; - u16 peer_id = PEER_ID_INEXISTENT; + u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0; if (playername != "") { RemotePlayer *player = m_env->getPlayer(playername.c_str()); if (!player) return; peer_id = player->peer_id; + proto_ver = player->protocol_version; } - SendSpawnParticle(peer_id, pos, velocity, acceleration, + SendSpawnParticle(peer_id, proto_ver, pos, velocity, acceleration, expirationtime, size, collisiondetection, - collision_removal, vertical, texture); + collision_removal, vertical, texture, animation, glow); } u32 Server::addParticleSpawner(u16 amount, float spawntime, @@ -3189,18 +3224,20 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime, float minexptime, float maxexptime, float minsize, float maxsize, bool collisiondetection, bool collision_removal, ServerActiveObject *attached, bool vertical, const std::string &texture, - const std::string &playername) + const std::string &playername, const struct TileAnimationParams &animation, + u8 glow) { // m_env will be NULL if the server is initializing if (!m_env) return -1; - u16 peer_id = PEER_ID_INEXISTENT; + u16 peer_id = PEER_ID_INEXISTENT, proto_ver = 0; if (playername != "") { RemotePlayer *player = m_env->getPlayer(playername.c_str()); if (!player) return -1; peer_id = player->peer_id; + proto_ver = player->protocol_version; } u16 attached_id = attached ? attached->getId() : 0; @@ -3211,11 +3248,11 @@ u32 Server::addParticleSpawner(u16 amount, float spawntime, else id = m_env->addParticleSpawner(spawntime, attached_id); - SendAddParticleSpawner(peer_id, amount, spawntime, + SendAddParticleSpawner(peer_id, proto_ver, amount, spawntime, minpos, maxpos, minvel, maxvel, minacc, maxacc, minexptime, maxexptime, minsize, maxsize, collisiondetection, collision_removal, attached_id, vertical, - texture, id); + texture, id, animation, glow); return id; } diff --git a/src/server.h b/src/server.h index a86f75f1d..e5121bdc3 100644 --- a/src/server.h +++ b/src/server.h @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mods.h" #include "inventorymanager.h" #include "subgame.h" +#include "tileanimation.h" // struct TileAnimationParams #include "util/numeric.h" #include "util/thread.h" #include "util/basic_macros.h" @@ -252,7 +253,8 @@ public: v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture); + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow); u32 addParticleSpawner(u16 amount, float spawntime, v3f minpos, v3f maxpos, @@ -263,7 +265,8 @@ public: bool collisiondetection, bool collision_removal, ServerActiveObject *attached, bool vertical, const std::string &texture, - const std::string &playername); + const std::string &playername, const struct TileAnimationParams &animation, + u8 glow); void deleteParticleSpawner(const std::string &playername, u32 id); @@ -428,7 +431,8 @@ private: void sendDetachedInventories(u16 peer_id); // Adds a ParticleSpawner on peer with peer_id (PEER_ID_INEXISTENT == all) - void SendAddParticleSpawner(u16 peer_id, u16 amount, float spawntime, + void SendAddParticleSpawner(u16 peer_id, u16 protocol_version, + u16 amount, float spawntime, v3f minpos, v3f maxpos, v3f minvel, v3f maxvel, v3f minacc, v3f maxacc, @@ -436,16 +440,18 @@ private: float minsize, float maxsize, bool collisiondetection, bool collision_removal, u16 attached_id, - bool vertical, const std::string &texture, u32 id); + bool vertical, const std::string &texture, u32 id, + const struct TileAnimationParams &animation, u8 glow); void SendDeleteParticleSpawner(u16 peer_id, u32 id); // Spawns particle on peer with peer_id (PEER_ID_INEXISTENT == all) - void SendSpawnParticle(u16 peer_id, + void SendSpawnParticle(u16 peer_id, u16 protocol_version, v3f pos, v3f velocity, v3f acceleration, float expirationtime, float size, bool collisiondetection, bool collision_removal, - bool vertical, const std::string &texture); + bool vertical, const std::string &texture, + const struct TileAnimationParams &animation, u8 glow); u32 SendActiveObjectRemoveAdd(u16 peer_id, const std::string &datas); void SendActiveObjectMessages(u16 peer_id, const std::string &datas, bool reliable = true); diff --git a/src/tileanimation.cpp b/src/tileanimation.cpp index a23eecc2e..67d27d396 100644 --- a/src/tileanimation.cpp +++ b/src/tileanimation.cpp @@ -69,7 +69,8 @@ void TileAnimationParams::deSerialize(std::istream &is, u16 protocol_version) } } -void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const +void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, + int *frame_length_ms, v2u32 *frame_size) const { if (type == TAT_VERTICAL_FRAMES) { int frame_height = (float)texture_size.X / @@ -80,15 +81,17 @@ void TileAnimationParams::determineParams(v2u32 texture_size, int *frame_count, *frame_count = _frame_count; if (frame_length_ms) *frame_length_ms = 1000.0 * vertical_frames.length / _frame_count; + if (frame_size) + *frame_size = v2u32(texture_size.X, frame_height); } else if (type == TAT_SHEET_2D) { if (frame_count) *frame_count = sheet_2d.frames_w * sheet_2d.frames_h; if (frame_length_ms) *frame_length_ms = 1000 * sheet_2d.frame_length; - } else { // TAT_NONE - *frame_count = 1; - *frame_length_ms = 1000; + if (frame_size) + *frame_size = v2u32(texture_size.X / sheet_2d.frames_w, texture_size.Y / sheet_2d.frames_h); } + // caller should check for TAT_NONE } void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const @@ -97,7 +100,7 @@ void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size return; if (type == TAT_VERTICAL_FRAMES) { int frame_count; - determineParams(texture_size, &frame_count, NULL); + determineParams(texture_size, &frame_count, NULL, NULL); os << "^[verticalframe:" << frame_count << ":" << frame; } else if (type == TAT_SHEET_2D) { int q, r; @@ -107,3 +110,22 @@ void TileAnimationParams::getTextureModifer(std::ostream &os, v2u32 texture_size << ":" << r << "," << q; } } + +v2f TileAnimationParams::getTextureCoords(v2u32 texture_size, int frame) const +{ + v2u32 ret(0, 0); + if (type == TAT_VERTICAL_FRAMES) { + int frame_height = (float)texture_size.X / + (float)vertical_frames.aspect_w * + (float)vertical_frames.aspect_h; + ret = v2u32(0, frame_height * frame); + } else if (type == TAT_SHEET_2D) { + v2u32 frame_size; + determineParams(texture_size, NULL, NULL, &frame_size); + int q, r; + q = frame / sheet_2d.frames_w; + r = frame % sheet_2d.frames_w; + ret = v2u32(r * frame_size.X, q * frame_size.Y); + } + return v2f(ret.X / (float) texture_size.X, ret.Y / (float) texture_size.Y); +} diff --git a/src/tileanimation.h b/src/tileanimation.h index 289ce515b..eecd3eb96 100644 --- a/src/tileanimation.h +++ b/src/tileanimation.h @@ -48,8 +48,10 @@ struct TileAnimationParams { void serialize(std::ostream &os, u16 protocol_version) const; void deSerialize(std::istream &is, u16 protocol_version); - void determineParams(v2u32 texture_size, int *frame_count, int *frame_length_ms) const; + void determineParams(v2u32 texture_size, int *frame_count, + int *frame_length_ms, v2u32 *frame_size) const; void getTextureModifer(std::ostream &os, v2u32 texture_size, int frame) const; + v2f getTextureCoords(v2u32 texture_size, int frame) const; }; #endif -- cgit v1.2.3 From 0dada51a550c5eb52faf700dcbde4cee22a6bc70 Mon Sep 17 00:00:00 2001 From: red-001 Date: Fri, 20 Jan 2017 22:19:41 +0000 Subject: Remove `mathconstants.h` and use the correct way to get `M_PI` in MSVC. (#5072) --- src/CMakeLists.txt | 2 ++ src/camera.cpp | 1 - src/clientiface.cpp | 1 - src/clientmap.cpp | 1 - src/content_cao.cpp | 1 - src/content_sao.cpp | 1 - src/map.cpp | 1 - src/mg_biome.cpp | 1 - src/server.cpp | 1 - src/treegen.cpp | 1 - src/util/mathconstants.h | 7 ------- src/util/numeric.cpp | 1 - 12 files changed, 2 insertions(+), 17 deletions(-) delete mode 100644 src/util/mathconstants.h (limited to 'src/server.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f90542be9..cab5a1139 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -284,6 +284,8 @@ if(WIN32) set(PLATFORM_LIBS dbghelp.lib ${PLATFORM_LIBS}) # Surpress some useless warnings add_definitions ( /D "_CRT_SECURE_NO_DEPRECATE" /W1 ) + # Get M_PI to work + add_definitions(/D "_USE_MATH_DEFINES") else() # Probably MinGW = GCC set(PLATFORM_LIBS "") endif() diff --git a/src/camera.cpp b/src/camera.cpp index 4768e8778..2ad835817 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -31,7 +31,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "event.h" #include "profiler.h" #include "util/numeric.h" -#include "util/mathconstants.h" #include "constants.h" #include "fontengine.h" diff --git a/src/clientiface.cpp b/src/clientiface.cpp index 1610c21fd..47730343c 100644 --- a/src/clientiface.cpp +++ b/src/clientiface.cpp @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clientiface.h" #include "util/numeric.h" -#include "util/mathconstants.h" #include "remoteplayer.h" #include "settings.h" #include "mapblock.h" diff --git a/src/clientmap.cpp b/src/clientmap.cpp index fa326f0b4..11719539f 100644 --- a/src/clientmap.cpp +++ b/src/clientmap.cpp @@ -29,7 +29,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "settings.h" #include "camera.h" // CameraModes -#include "util/mathconstants.h" #include "util/basic_macros.h" #include diff --git a/src/content_cao.cpp b/src/content_cao.cpp index 83756c963..93ac1f785 100644 --- a/src/content_cao.cpp +++ b/src/content_cao.cpp @@ -26,7 +26,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_cao.h" #include "util/numeric.h" // For IntervalLimiter #include "util/serialize.h" -#include "util/mathconstants.h" #include "util/basic_macros.h" #include "client/tile.h" #include "environment.h" diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 840e04ed9..bf8282af4 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -18,7 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "content_sao.h" -#include "util/mathconstants.h" #include "util/serialize.h" #include "collision.h" #include "environment.h" diff --git a/src/map.cpp b/src/map.cpp index 0659f66aa..f2a4b7ffe 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -32,7 +32,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "gamedef.h" #include "util/directiontables.h" -#include "util/mathconstants.h" #include "util/basic_macros.h" #include "rollback_interface.h" #include "environment.h" diff --git a/src/mg_biome.cpp b/src/mg_biome.cpp index d564e9415..ef7e52685 100644 --- a/src/mg_biome.cpp +++ b/src/mg_biome.cpp @@ -24,7 +24,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "map.h" //for MMVManip #include "util/numeric.h" -#include "util/mathconstants.h" #include "porting.h" #include "settings.h" diff --git a/src/server.cpp b/src/server.cpp index d3d5fd3d1..1656b9f5a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -53,7 +53,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "event_manager.h" #include "serverlist.h" #include "util/string.h" -#include "util/mathconstants.h" #include "rollback.h" #include "util/serialize.h" #include "util/thread.h" diff --git a/src/treegen.cpp b/src/treegen.cpp index e6c514ab9..4df574f34 100644 --- a/src/treegen.cpp +++ b/src/treegen.cpp @@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "util/pointer.h" #include "util/numeric.h" -#include "util/mathconstants.h" #include "map.h" #include "serverenvironment.h" #include "nodedef.h" diff --git a/src/util/mathconstants.h b/src/util/mathconstants.h deleted file mode 100644 index 1b478aa95..000000000 --- a/src/util/mathconstants.h +++ /dev/null @@ -1,7 +0,0 @@ -#include - -// MSVC doesn't seem to define this -#ifndef M_PI - #define M_PI 3.1415926535 -#endif - diff --git a/src/util/numeric.cpp b/src/util/numeric.cpp index a9e7ae584..87f1040ea 100644 --- a/src/util/numeric.cpp +++ b/src/util/numeric.cpp @@ -18,7 +18,6 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include "numeric.h" -#include "mathconstants.h" #include "log.h" #include "../constants.h" // BS, MAP_BLOCKSIZE -- cgit v1.2.3 From 72535d33281ed4c863013590e5fd032c39f0b781 Mon Sep 17 00:00:00 2001 From: red-001 Date: Sat, 21 Jan 2017 15:11:55 +0000 Subject: Detach the player from entities on death. (#5077) --- src/content_sao.cpp | 10 ++++++++++ src/content_sao.h | 1 + src/script/lua_api/l_object.cpp | 15 +-------------- src/server.cpp | 2 ++ src/serverobject.h | 2 ++ 5 files changed, 16 insertions(+), 14 deletions(-) (limited to 'src/server.cpp') diff --git a/src/content_sao.cpp b/src/content_sao.cpp index bf8282af4..d6581144f 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -203,6 +203,16 @@ void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position, *rotation = m_attachment_rotation; } +void UnitSAO::detachFromParent() +{ + ServerActiveObject *parent = NULL; + if (m_attachment_parent_id) + parent = m_env->getActiveObject(m_attachment_parent_id); + setAttachment(NULL, "", v3f(0, 0, 0), v3f(0, 0, 0)); + if (parent != NULL) + parent->removeAttachmentChild(m_id); +} + void UnitSAO::addAttachmentChild(int child_id) { m_attachment_child_ids.insert(child_id); diff --git a/src/content_sao.h b/src/content_sao.h index 4abe93250..884f0f406 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -49,6 +49,7 @@ public: void setBonePosition(const std::string &bone, v3f position, v3f rotation); void getBonePosition(const std::string &bone, v3f *position, v3f *rotation); void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation); + void detachFromParent(); void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation); void addAttachmentChild(int child_id); void removeAttachmentChild(int child_id); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 59c04f301..f579c0b86 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -710,20 +710,7 @@ int ObjectRef::l_set_detach(lua_State *L) ServerActiveObject *co = getobject(ref); if (co == NULL) return 0; - - int parent_id = 0; - std::string bone = ""; - v3f position; - v3f rotation; - co->getAttachment(&parent_id, &bone, &position, &rotation); - ServerActiveObject *parent = NULL; - if (parent_id) - parent = env->getActiveObject(parent_id); - - // Do it - co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0)); - if (parent != NULL) - parent->removeAttachmentChild(co->getId()); + co->detachFromParent(); return 0; } diff --git a/src/server.cpp b/src/server.cpp index 1656b9f5a..1e5704042 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2560,6 +2560,8 @@ void Server::DiePlayer(u16 peer_id) if (!playersao) return; + playersao->detachFromParent(); + infostream << "Server::DiePlayer(): Player " << playersao->getPlayer()->getName() << " dies" << std::endl; diff --git a/src/serverobject.h b/src/serverobject.h index 38204980e..dfe6312f0 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -166,6 +166,8 @@ public: {} virtual void removeAttachmentChild(int child_id) {} + virtual void detachFromParent() + {} virtual const UNORDERED_SET &getAttachmentChildIds() { static const UNORDERED_SET rv; return rv; } virtual ObjectProperties* accessObjectProperties() -- cgit v1.2.3 From bc29e03b597be350fa856b1ae3d8623778a808b3 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sat, 21 Jan 2017 17:30:55 +0100 Subject: Revert "Detach the player from entities on death." (#5087) --- src/content_sao.cpp | 10 ---------- src/content_sao.h | 1 - src/script/lua_api/l_object.cpp | 15 ++++++++++++++- src/server.cpp | 2 -- src/serverobject.h | 2 -- 5 files changed, 14 insertions(+), 16 deletions(-) (limited to 'src/server.cpp') diff --git a/src/content_sao.cpp b/src/content_sao.cpp index f0973082d..bb62aea7d 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -203,16 +203,6 @@ void UnitSAO::getAttachment(int *parent_id, std::string *bone, v3f *position, *rotation = m_attachment_rotation; } -void UnitSAO::detachFromParent() -{ - ServerActiveObject *parent = NULL; - if (m_attachment_parent_id) - parent = m_env->getActiveObject(m_attachment_parent_id); - setAttachment(NULL, "", v3f(0, 0, 0), v3f(0, 0, 0)); - if (parent != NULL) - parent->removeAttachmentChild(m_id); -} - void UnitSAO::addAttachmentChild(int child_id) { m_attachment_child_ids.insert(child_id); diff --git a/src/content_sao.h b/src/content_sao.h index 56a26fb0d..c3674fa2d 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -49,7 +49,6 @@ public: void setBonePosition(const std::string &bone, v3f position, v3f rotation); void getBonePosition(const std::string &bone, v3f *position, v3f *rotation); void setAttachment(int parent_id, const std::string &bone, v3f position, v3f rotation); - void detachFromParent(); void getAttachment(int *parent_id, std::string *bone, v3f *position, v3f *rotation); void addAttachmentChild(int child_id); void removeAttachmentChild(int child_id); diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 1fa3663ca..be4451704 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -710,7 +710,20 @@ int ObjectRef::l_set_detach(lua_State *L) ServerActiveObject *co = getobject(ref); if (co == NULL) return 0; - co->detachFromParent(); + + int parent_id = 0; + std::string bone = ""; + v3f position; + v3f rotation; + co->getAttachment(&parent_id, &bone, &position, &rotation); + ServerActiveObject *parent = NULL; + if (parent_id) + parent = env->getActiveObject(parent_id); + + // Do it + co->setAttachment(0, "", v3f(0,0,0), v3f(0,0,0)); + if (parent != NULL) + parent->removeAttachmentChild(co->getId()); return 0; } diff --git a/src/server.cpp b/src/server.cpp index 1e5704042..1656b9f5a 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2560,8 +2560,6 @@ void Server::DiePlayer(u16 peer_id) if (!playersao) return; - playersao->detachFromParent(); - infostream << "Server::DiePlayer(): Player " << playersao->getPlayer()->getName() << " dies" << std::endl; diff --git a/src/serverobject.h b/src/serverobject.h index dfe6312f0..38204980e 100644 --- a/src/serverobject.h +++ b/src/serverobject.h @@ -166,8 +166,6 @@ public: {} virtual void removeAttachmentChild(int child_id) {} - virtual void detachFromParent() - {} virtual const UNORDERED_SET &getAttachmentChildIds() { static const UNORDERED_SET rv; return rv; } virtual ObjectProperties* accessObjectProperties() -- cgit v1.2.3 From 6d5a40713347424084af8ba04e76278961506881 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sat, 21 Jan 2017 19:30:42 +0100 Subject: Add show_statusline_on_connect setting (#5084) Add show_statusline_on_connect setting --- builtin/settingtypes.txt | 3 +++ minetest.conf.example | 6 +++++- src/defaultsettings.cpp | 1 + src/server.cpp | 2 +- 4 files changed, 10 insertions(+), 2 deletions(-) (limited to 'src/server.cpp') diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 2dfe86e04..0f416bc9a 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -703,6 +703,9 @@ map-dir (Map directory) path # Setting it to -1 disables the feature. item_entity_ttl (Item entity TTL) int 900 +# If enabled, show the server status message on player connection. +show_statusline_on_connect (Status message on connection) bool true + # Enable players getting damage and dying. enable_damage (Damage) bool false diff --git a/minetest.conf.example b/minetest.conf.example index 3b686aa61..515b6cfd4 100644 --- a/minetest.conf.example +++ b/minetest.conf.example @@ -841,6 +841,10 @@ # type: int # item_entity_ttl = 900 +# If enabled, show the server status message on player connection. +# type: bool +# show_statusline_on_connect = true + # Enable players getting damage and dying. # type: bool # enable_damage = false @@ -1558,7 +1562,7 @@ # profiler.default_report_format = txt # The file path relative to your worldpath in which profiles will be saved to. -# +# # type: string # profiler.report_path = "" diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 59cfdd50d..e154a63c8 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -255,6 +255,7 @@ void set_default_settings(Settings *settings) settings->setDefault("motd", ""); settings->setDefault("max_users", "15"); settings->setDefault("creative_mode", "false"); + settings->setDefault("show_statusline_on_connect", "true"); settings->setDefault("enable_damage", "true"); settings->setDefault("give_initial_stuff", "false"); settings->setDefault("default_password", ""); diff --git a/src/server.cpp b/src/server.cpp index 1656b9f5a..7e1ab30ac 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1118,7 +1118,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id) SendDeathscreen(peer_id, false, v3f(0,0,0)); // Note things in chat if not in simple singleplayer mode - if(!m_simple_singleplayer_mode) { + if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) { // Send information about server to player in chat SendChatMessage(peer_id, getStatusString()); } -- cgit v1.2.3 From 43822de5c6b35646feced5ac65331313f82f78ce Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 22 Jan 2017 20:17:13 +0100 Subject: Fix potential crash in chat handling (since 2f56a00d9eef82052614e5854a07b39b087efd0b) --- src/server.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index 7e1ab30ac..c7d4fcba9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2864,7 +2864,7 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna */ u16 peer_id_to_avoid_sending = (player ? player->peer_id : PEER_ID_INEXISTENT); - if (player->protocol_version >= 29) + if (player && player->protocol_version >= 29) peer_id_to_avoid_sending = PEER_ID_INEXISTENT; for (u16 i = 0; i < clients.size(); i++) { -- cgit v1.2.3 From 08911160aa5294883a7ebfb681fbf0c1a858dc78 Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Wed, 25 Jan 2017 09:57:33 +0000 Subject: Block spam messages before calling on_chatmessage callbacks (#4805) Fixes #4799 --- src/server.cpp | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index c7d4fcba9..e5714ac03 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2790,40 +2790,41 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna RollbackScopeActor rollback_scope(m_rollback, std::string("player:") + name); - // Line to send - std::wstring line; - // Whether to send line to the player that sent the message, or to all players - bool broadcast_line = true; - - // Run script hook - bool ate = m_script->on_chat_message(name, - wide_to_utf8(wmessage)); - // If script ate the message, don't proceed - if (ate) - return L""; - if (player) { switch (player->canSendChatMessage()) { case RPLAYER_CHATRESULT_FLOODING: { std::wstringstream ws; ws << L"You cannot send more messages. You are limited to " - << g_settings->getFloat("chat_message_limit_per_10sec") - << L" messages per 10 seconds."; + << g_settings->getFloat("chat_message_limit_per_10sec") + << L" messages per 10 seconds."; return ws.str(); } case RPLAYER_CHATRESULT_KICK: - DenyAccess_Legacy(player->peer_id, L"You have been kicked due to message flooding."); + DenyAccess_Legacy(player->peer_id, + L"You have been kicked due to message flooding."); return L""; - case RPLAYER_CHATRESULT_OK: break; - default: FATAL_ERROR("Unhandled chat filtering result found."); + case RPLAYER_CHATRESULT_OK: + break; + default: + FATAL_ERROR("Unhandled chat filtering result found."); } } - if (m_max_chatmessage_length > 0 && wmessage.length() > m_max_chatmessage_length) { + if (m_max_chatmessage_length > 0 + && wmessage.length() > m_max_chatmessage_length) { return L"Your message exceed the maximum chat message limit set on the server. " - L"It was refused. Send a shorter message"; + L"It was refused. Send a shorter message"; } + // Run script hook, exit if script ate the chat message + if (m_script->on_chat_message(name, wide_to_utf8(wmessage))) + return L""; + + // Line to send + std::wstring line; + // Whether to send line to the player that sent the message, or to all players + bool broadcast_line = true; + // Commands are implemented in Lua, so only catch invalid // commands that were not "eaten" and send an error back if (wmessage[0] == L'/') { -- cgit v1.2.3 From ef6feca501fcf0d5a1fd2021f1d4df96a4533f65 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Wed, 8 Feb 2017 00:15:55 +0100 Subject: Add ModMetadata API (#5131) * mod can create a ModMetadata object where store its values and retrieve it. * Modmetadata object can only be fetched at mod loading * Save when modified using same time as map interval or at server stop * add helper function to get mod storage path * ModMetadata has exactly same calls than all every other Metadata --- doc/lua_api.txt | 10 ++- src/metadata.cpp | 20 +++++- src/metadata.h | 2 +- src/mods.cpp | 80 ++++++++++++++++++++- src/mods.h | 21 ++++++ src/remoteplayer.cpp | 2 +- src/script/lua_api/CMakeLists.txt | 1 + src/script/lua_api/l_storage.cpp | 143 ++++++++++++++++++++++++++++++++++++++ src/script/lua_api/l_storage.h | 62 +++++++++++++++++ src/script/scripting_game.cpp | 3 + src/server.cpp | 43 +++++++++++- src/server.h | 9 ++- 12 files changed, 384 insertions(+), 12 deletions(-) create mode 100644 src/script/lua_api/l_storage.cpp create mode 100644 src/script/lua_api/l_storage.h (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index dd20ae904..4774e8a5a 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2629,6 +2629,11 @@ These functions return the leftover itemstack. * `HTTPApiTable.fetch_async_get(handle)`: returns HTTPRequestResult * Return response data for given asynchronous HTTP request +### Storage API: +* `minetest.get_mod_storage()`: + * returns reference to mod private `StorageRef` + * must be called during mod load time + ### Misc. * `minetest.get_connected_players()`: returns list of `ObjectRefs` * `minetest.player_exists(name)`: boolean, whether player exists (regardless of online status) @@ -2791,7 +2796,7 @@ Class reference --------------- ### `MetaDataRef` -See `NodeMetaRef` and `ItemStackMetaRef`. +See `StorageRef`, `NodeMetaRef` and `ItemStackMetaRef`. #### Methods * `set_string(name, value)` @@ -2845,6 +2850,9 @@ Can be gotten via `minetest.get_node_timer(pos)`. * `is_started()`: returns boolean state of timer * returns `true` if timer is started, otherwise `false` +### `StorageRef` +This is basically a reference to a C++ `ModMetadata` + ### `ObjectRef` Moving things in the game are generally these. diff --git a/src/metadata.cpp b/src/metadata.cpp index 3cc45f919..2ce9af5af 100644 --- a/src/metadata.cpp +++ b/src/metadata.cpp @@ -76,13 +76,27 @@ const std::string &Metadata::getString(const std::string &name, return resolveString(it->second, recursion); } -void Metadata::setString(const std::string &name, const std::string &var) +/** + * Sets var to name key in the metadata storage + * + * @param name + * @param var + * @return true if key-value pair is created or changed + */ +bool Metadata::setString(const std::string &name, const std::string &var) { if (var.empty()) { m_stringvars.erase(name); - } else { - m_stringvars[name] = var; + return true; + } + + StringMap::iterator it = m_stringvars.find(name); + if (it != m_stringvars.end() && it->second == var) { + return false; } + + m_stringvars[name] = var; + return true; } const std::string &Metadata::resolveString(const std::string &str, diff --git a/src/metadata.h b/src/metadata.h index 4bb3c2ee7..a8270b4c4 100644 --- a/src/metadata.h +++ b/src/metadata.h @@ -46,7 +46,7 @@ public: size_t size() const; bool contains(const std::string &name) const; const std::string &getString(const std::string &name, u16 recursion = 0) const; - void setString(const std::string &name, const std::string &var); + virtual bool setString(const std::string &name, const std::string &var); const StringMap &getStrings() const { return m_stringvars; diff --git a/src/mods.cpp b/src/mods.cpp index 1b1bdb07b..bae9a42d3 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -21,13 +21,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include "mods.h" #include "filesys.h" -#include "util/strfnd.h" #include "log.h" #include "subgame.h" #include "settings.h" -#include "util/strfnd.h" #include "convert_json.h" -#include "exceptions.h" static bool parseDependsLine(std::istream &is, std::string &dep, std::set &symbols) @@ -356,3 +353,80 @@ Json::Value getModstoreUrl(std::string url) } #endif + +ModMetadata::ModMetadata(const std::string &mod_name): + m_mod_name(mod_name), + m_modified(false) +{ + m_stringvars.clear(); +} + +void ModMetadata::clear() +{ + Metadata::clear(); + m_modified = true; +} + +bool ModMetadata::save(const std::string &root_path) +{ + Json::Value json; + for (StringMap::const_iterator it = m_stringvars.begin(); + it != m_stringvars.end(); ++it) { + json[it->first] = it->second; + } + + if (!fs::PathExists(root_path)) { + if (!fs::CreateAllDirs(root_path)) { + errorstream << "ModMetadata[" << m_mod_name << "]: Unable to save. '" + << root_path << "' tree cannot be created." << std::endl; + return false; + } + } else if (!fs::IsDir(root_path)) { + errorstream << "ModMetadata[" << m_mod_name << "]: Unable to save. '" + << root_path << "' is not a directory." << std::endl; + return false; + } + + bool w_ok = fs::safeWriteToFile(root_path + DIR_DELIM + m_mod_name, + Json::FastWriter().write(json)); + + if (w_ok) { + m_modified = false; + } else { + errorstream << "ModMetadata[" << m_mod_name << "]: failed write file." << std::endl; + } + return w_ok; +} + +bool ModMetadata::load(const std::string &root_path) +{ + m_stringvars.clear(); + + std::ifstream is((root_path + DIR_DELIM + m_mod_name).c_str(), std::ios_base::binary); + if (!is.good()) { + return false; + } + + Json::Reader reader; + Json::Value root; + if (!reader.parse(is, root)) { + errorstream << "ModMetadata[" << m_mod_name << "]: failed read data " + "(Json decoding failure)." << std::endl; + return false; + } + + const Json::Value::Members attr_list = root.getMemberNames(); + for (Json::Value::Members::const_iterator it = attr_list.begin(); + it != attr_list.end(); ++it) { + Json::Value attr_value = root[*it]; + m_stringvars[*it] = attr_value.asString(); + } + + return true; +} + +bool ModMetadata::setString(const std::string &name, const std::string &var) +{ + m_modified = Metadata::setString(name, var); + return m_modified; +} diff --git a/src/mods.h b/src/mods.h index af7777d18..61af5e5d1 100644 --- a/src/mods.h +++ b/src/mods.h @@ -28,6 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include "config.h" +#include "metadata.h" #define MODNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_" @@ -205,4 +206,24 @@ struct ModStoreModDetails { bool valid; }; +class ModMetadata: public Metadata +{ +public: + ModMetadata(const std::string &mod_name); + ~ModMetadata() {} + + virtual void clear(); + + bool save(const std::string &root_path); + bool load(const std::string &root_path); + + bool isModified() const { return m_modified; } + const std::string &getModName() const { return m_mod_name; } + + virtual bool setString(const std::string &name, const std::string &var); +private: + std::string m_mod_name; + bool m_modified; +}; + #endif diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp index 6853ad6d9..0a4591410 100644 --- a/src/remoteplayer.cpp +++ b/src/remoteplayer.cpp @@ -174,7 +174,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername, const Json::Value::Members attr_list = attr_root.getMemberNames(); for (Json::Value::Members::const_iterator it = attr_list.begin(); - it != attr_list.end(); ++it) { + it != attr_list.end(); ++it) { Json::Value attr_value = attr_root[*it]; sao->setExtendedAttribute(*it, attr_value.asString()); } diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt index 070234eba..e82560696 100644 --- a/src/script/lua_api/CMakeLists.txt +++ b/src/script/lua_api/CMakeLists.txt @@ -15,6 +15,7 @@ set(common_SCRIPT_LUA_API_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/l_particles.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_rollback.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_server.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/l_storage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_util.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_vmanip.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp diff --git a/src/script/lua_api/l_storage.cpp b/src/script/lua_api/l_storage.cpp new file mode 100644 index 000000000..42928255f --- /dev/null +++ b/src/script/lua_api/l_storage.cpp @@ -0,0 +1,143 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#include "lua_api/l_storage.h" +#include "l_internal.h" +#include "mods.h" +#include "server.h" + +int ModApiStorage::l_get_mod_storage(lua_State *L) +{ + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); + if (!lua_isstring(L, -1)) { + return 0; + } + + std::string mod_name = lua_tostring(L, -1); + + ModMetadata *store = new ModMetadata(mod_name); + // For server side + if (Server *server = getServer(L)) { + store->load(server->getModStoragePath()); + server->registerModStorage(store); + } else { + assert(false); // this should not happen + } + + StorageRef::create(L, store); + int object = lua_gettop(L); + + lua_pushvalue(L, object); + return 1; +} + +void ModApiStorage::Initialize(lua_State *L, int top) +{ + API_FCT(get_mod_storage); +} + +StorageRef::StorageRef(ModMetadata *object): + m_object(object) +{ +} + +void StorageRef::create(lua_State *L, ModMetadata *object) +{ + StorageRef *o = new StorageRef(object); + *(void **)(lua_newuserdata(L, sizeof(void *))) = o; + luaL_getmetatable(L, className); + lua_setmetatable(L, -2); +} + +int StorageRef::gc_object(lua_State *L) +{ + StorageRef *o = *(StorageRef **)(lua_touserdata(L, 1)); + // Server side + if (Server *server = getServer(L)) + server->unregisterModStorage(getobject(o)->getModName()); + delete o; + return 0; +} + +void StorageRef::Register(lua_State *L) +{ + lua_newtable(L); + int methodtable = lua_gettop(L); + luaL_newmetatable(L, className); + int metatable = lua_gettop(L); + + lua_pushliteral(L, "__metatable"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); // hide metatable from Lua getmetatable() + + lua_pushliteral(L, "metadata_class"); + lua_pushlstring(L, className, strlen(className)); + lua_settable(L, metatable); + + lua_pushliteral(L, "__index"); + lua_pushvalue(L, methodtable); + lua_settable(L, metatable); + + lua_pushliteral(L, "__gc"); + lua_pushcfunction(L, gc_object); + lua_settable(L, metatable); + + lua_pop(L, 1); // drop metatable + + luaL_openlib(L, 0, methods, 0); // fill methodtable + lua_pop(L, 1); // drop methodtable +} + +StorageRef* StorageRef::checkobject(lua_State *L, int narg) +{ + luaL_checktype(L, narg, LUA_TUSERDATA); + void *ud = luaL_checkudata(L, narg, className); + if (!ud) luaL_typerror(L, narg, className); + return *(StorageRef**)ud; // unbox pointer +} + +ModMetadata* StorageRef::getobject(StorageRef *ref) +{ + ModMetadata *co = ref->m_object; + return co; +} + +Metadata* StorageRef::getmeta(bool auto_create) +{ + return m_object; +} + +void StorageRef::clearMeta() +{ + m_object->clear(); +} + +const char StorageRef::className[] = "StorageRef"; +const luaL_reg StorageRef::methods[] = { + luamethod(MetaDataRef, get_string), + luamethod(MetaDataRef, set_string), + luamethod(MetaDataRef, get_int), + luamethod(MetaDataRef, set_int), + luamethod(MetaDataRef, get_float), + luamethod(MetaDataRef, set_float), + luamethod(MetaDataRef, to_table), + luamethod(MetaDataRef, from_table), + {0,0} +}; diff --git a/src/script/lua_api/l_storage.h b/src/script/lua_api/l_storage.h new file mode 100644 index 000000000..fde2828ad --- /dev/null +++ b/src/script/lua_api/l_storage.h @@ -0,0 +1,62 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#ifndef __L_STORAGE_H__ +#define __L_STORAGE_H__ + +#include "lua_api/l_base.h" +#include "l_metadata.h" + +class ModMetadata; + +class ModApiStorage: public ModApiBase +{ +protected: + static int l_get_mod_storage(lua_State *L); +public: + static void Initialize(lua_State *L, int top); + +}; + +class StorageRef: public MetaDataRef +{ +private: + ModMetadata *m_object; + + static const char className[]; + static const luaL_reg methods[]; + + virtual Metadata* getmeta(bool auto_create); + virtual void clearMeta(); + + // garbage collector + static int gc_object(lua_State *L); +public: + StorageRef(ModMetadata *object); + ~StorageRef() {} + + static void Register(lua_State *L); + static void create(lua_State *L, ModMetadata *object); + + static StorageRef *checkobject(lua_State *L, int narg); + static ModMetadata* getobject(StorageRef *ref); +}; + +#endif /* __L_STORAGE_H__ */ diff --git a/src/script/scripting_game.cpp b/src/script/scripting_game.cpp index 7becef6dc..4da752263 100644 --- a/src/script/scripting_game.cpp +++ b/src/script/scripting_game.cpp @@ -41,6 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_vmanip.h" #include "lua_api/l_settings.h" #include "lua_api/l_http.h" +#include "lua_api/l_storage.h" extern "C" { #include "lualib.h" @@ -92,6 +93,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top) ModApiServer::Initialize(L, top); ModApiUtil::Initialize(L, top); ModApiHttp::Initialize(L, top); + ModApiStorage::Initialize(L, top); // Register reference classes (userdata) InvRef::Register(L); @@ -108,6 +110,7 @@ void GameScripting::InitializeModApi(lua_State *L, int top) NodeTimerRef::Register(L); ObjectRef::Register(L); LuaSettings::Register(L); + StorageRef::Register(L); } void log_deprecated(const std::string &message) diff --git a/src/server.cpp b/src/server.cpp index e5714ac03..8b9f46f85 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -178,8 +178,8 @@ Server::Server( m_admin_chat(iface), m_ignore_map_edit_events(false), m_ignore_map_edit_events_peer_id(0), - m_next_sound_id(0) - + m_next_sound_id(0), + m_mod_storage_save_timer(10.0f) { m_liquid_transform_timer = 0.0; m_liquid_transform_every = 1.0; @@ -788,6 +788,18 @@ void Server::AsyncRunStep(bool initial_step) << "packet size is " << pktSize << std::endl; } m_clients.unlock(); + + m_mod_storage_save_timer -= dtime; + if (m_mod_storage_save_timer <= 0.0f) { + infostream << "Saving registered mod storages." << std::endl; + m_mod_storage_save_timer = g_settings->getFloat("server_map_save_interval"); + for (UNORDERED_MAP::const_iterator + it = m_mod_storages.begin(); it != m_mod_storages.end(); ++it) { + if (it->second->isModified()) { + it->second->save(getModStoragePath()); + } + } + } } /* @@ -3404,6 +3416,11 @@ std::string Server::getBuiltinLuaPath() return porting::path_share + DIR_DELIM + "builtin"; } +std::string Server::getModStoragePath() const +{ + return m_path_world + DIR_DELIM + "mod_storage"; +} + v3f Server::findSpawnPos() { ServerMap &map = m_env->getServerMap(); @@ -3525,6 +3542,28 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version return playersao; } +bool Server::registerModStorage(ModMetadata *storage) +{ + if (m_mod_storages.find(storage->getModName()) != m_mod_storages.end()) { + errorstream << "Unable to register same mod storage twice. Storage name: " + << storage->getModName() << std::endl; + return false; + } + + m_mod_storages[storage->getModName()] = storage; + return true; +} + +void Server::unregisterModStorage(const std::string &name) +{ + UNORDERED_MAP::const_iterator it = m_mod_storages.find(name); + if (it != m_mod_storages.end()) { + // Save unconditionaly on unregistration + it->second->save(getModStoragePath()); + m_mod_storages.erase(name); + } +} + void dedicated_server_loop(Server &server, bool &kill) { DSTACK(FUNCTION_NAME); diff --git a/src/server.h b/src/server.h index 8f553ce38..3eee67b78 100644 --- a/src/server.h +++ b/src/server.h @@ -299,7 +299,8 @@ public: const ModSpec* getModSpec(const std::string &modname) const; void getModNames(std::vector &modlist); std::string getBuiltinLuaPath(); - inline std::string getWorldPath() const { return m_path_world; } + inline const std::string &getWorldPath() const { return m_path_world; } + std::string getModStoragePath() const; inline bool isSingleplayer() { return m_simple_singleplayer_mode; } @@ -360,6 +361,9 @@ public: void SendInventory(PlayerSAO* playerSAO); void SendMovePlayer(u16 peer_id); + bool registerModStorage(ModMetadata *storage); + void unregisterModStorage(const std::string &name); + // Bind address Address m_bind_addr; @@ -650,6 +654,9 @@ private: // value = "" (visible to all players) or player name std::map m_detached_inventories_player; + UNORDERED_MAP m_mod_storages; + float m_mod_storage_save_timer; + DISABLE_CLASS_COPY(Server); }; -- cgit v1.2.3 From 2efae3ffd720095222c800e016286a45c9fe1e5c Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Sat, 21 Jan 2017 15:02:08 +0100 Subject: [CSM] Client side modding * rename GameScripting to ServerScripting * Make getBuiltinLuaPath static serverside * Add on_shutdown callback * Add on_receiving_chat_message & on_sending_chat_message callbacks * ScriptApiBase: use IGameDef instead of Server This permits to share common attribute between client & server * Enable mod security in client side modding without conditions --- builtin/client/init.lua | 22 +++++++ builtin/client/register.lua | 62 +++++++++++++++++++ builtin/init.lua | 3 + src/client.cpp | 45 +++++++++++--- src/client.h | 10 +++ src/content_abm.cpp | 2 +- src/content_sao.cpp | 2 +- src/emerge.cpp | 2 +- src/environment.cpp | 2 +- src/game.cpp | 2 + src/gamedef.h | 7 ++- src/guiFormSpecMenu.cpp | 2 +- src/inventorymanager.cpp | 2 +- src/network/clientpackethandler.cpp | 6 +- src/network/serverpackethandler.cpp | 2 +- src/script/CMakeLists.txt | 7 ++- src/script/clientscripting.cpp | 54 ++++++++++++++++ src/script/clientscripting.h | 40 ++++++++++++ src/script/cpp_api/CMakeLists.txt | 1 + src/script/cpp_api/s_base.cpp | 21 +++++-- src/script/cpp_api/s_base.h | 14 ++++- src/script/cpp_api/s_client.cpp | 61 ++++++++++++++++++ src/script/cpp_api/s_client.h | 36 +++++++++++ src/script/cpp_api/s_security.cpp | 12 ++-- src/script/lua_api/CMakeLists.txt | 1 + src/script/lua_api/l_client.cpp | 33 ++++++++++ src/script/lua_api/l_client.h | 36 +++++++++++ src/script/lua_api/l_env.cpp | 6 +- src/script/lua_api/l_env.h | 2 +- src/script/lua_api/l_object.cpp | 2 +- src/script/scripting_game.cpp | 119 ------------------------------------ src/script/scripting_game.h | 57 ----------------- src/script/serverscripting.cpp | 119 ++++++++++++++++++++++++++++++++++++ src/script/serverscripting.h | 57 +++++++++++++++++ src/server.cpp | 6 +- src/server.h | 10 +-- src/serverenvironment.cpp | 4 +- src/serverenvironment.h | 8 +-- src/unittest/test.cpp | 9 ++- 39 files changed, 655 insertions(+), 231 deletions(-) create mode 100644 builtin/client/init.lua create mode 100644 builtin/client/register.lua create mode 100644 src/script/clientscripting.cpp create mode 100644 src/script/clientscripting.h create mode 100644 src/script/cpp_api/s_client.cpp create mode 100644 src/script/cpp_api/s_client.h create mode 100644 src/script/lua_api/l_client.cpp create mode 100644 src/script/lua_api/l_client.h delete mode 100644 src/script/scripting_game.cpp delete mode 100644 src/script/scripting_game.h create mode 100644 src/script/serverscripting.cpp create mode 100644 src/script/serverscripting.h (limited to 'src/server.cpp') diff --git a/builtin/client/init.lua b/builtin/client/init.lua new file mode 100644 index 000000000..d14301ade --- /dev/null +++ b/builtin/client/init.lua @@ -0,0 +1,22 @@ +-- Minetest: builtin/client/init.lua +local scriptpath = core.get_builtin_path()..DIR_DELIM +local clientpath = scriptpath.."client"..DIR_DELIM + +dofile(clientpath .. "register.lua") + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_shutdown(function() + print("shutdown client") +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_receiving_chat_messages(function(message) + print("Received message " .. message) + return false +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_sending_chat_messages(function(message) + print("Sending message " .. message) + return false +end) diff --git a/builtin/client/register.lua b/builtin/client/register.lua new file mode 100644 index 000000000..c793195a1 --- /dev/null +++ b/builtin/client/register.lua @@ -0,0 +1,62 @@ + +core.callback_origins = {} + +function core.run_callbacks(callbacks, mode, ...) + assert(type(callbacks) == "table") + local cb_len = #callbacks + if cb_len == 0 then + if mode == 2 or mode == 3 then + return true + elseif mode == 4 or mode == 5 then + return false + end + end + local ret + for i = 1, cb_len do + local cb_ret = callbacks[i](...) + + if mode == 0 and i == 1 or mode == 1 and i == cb_len then + ret = cb_ret + elseif mode == 2 then + if not cb_ret or i == 1 then + ret = cb_ret + end + elseif mode == 3 then + if cb_ret then + return cb_ret + end + ret = cb_ret + elseif mode == 4 then + if (cb_ret and not ret) or i == 1 then + ret = cb_ret + end + elseif mode == 5 and cb_ret then + return cb_ret + end + end + return ret +end + +-- +-- Callback registration +-- + +local function make_registration() + local t = {} + local registerfunc = function(func) + t[#t + 1] = func + core.callback_origins[func] = { + mod = core.get_current_modname() or "??", + name = debug.getinfo(1, "n").name or "??" + } + --local origin = core.callback_origins[func] + --print(origin.name .. ": " .. origin.mod .. " registering cbk " .. tostring(func)) + end + return t, registerfunc +end + +core.registered_on_shutdown, core.register_on_shutdown = make_registration() +core.registered_on_receiving_chat_messages, core.register_on_receiving_chat_messages = make_registration() +core.registered_on_sending_chat_messages, core.register_on_sending_chat_messages = make_registration() + + diff --git a/builtin/init.lua b/builtin/init.lua index b34ad14a0..590f7fa8c 100644 --- a/builtin/init.lua +++ b/builtin/init.lua @@ -27,6 +27,7 @@ minetest = core -- Load other files local scriptdir = core.get_builtin_path() .. DIR_DELIM local gamepath = scriptdir .. "game" .. DIR_DELIM +local clientpath = scriptdir .. "client" .. DIR_DELIM local commonpath = scriptdir .. "common" .. DIR_DELIM local asyncpath = scriptdir .. "async" .. DIR_DELIM @@ -45,6 +46,8 @@ elseif INIT == "mainmenu" then end elseif INIT == "async" then dofile(asyncpath .. "init.lua") +elseif INIT == "client" then + dofile(clientpath .. "init.lua") else error(("Unrecognized builtin initialization type %s!"):format(tostring(INIT))) end diff --git a/src/client.cpp b/src/client.cpp index 30058a2b0..faf454b35 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -32,28 +32,20 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client.h" #include "network/clientopcodes.h" #include "filesys.h" -#include "porting.h" #include "mapblock_mesh.h" #include "mapblock.h" #include "minimap.h" -#include "settings.h" +#include "mods.h" #include "profiler.h" #include "gettext.h" -#include "log.h" -#include "nodemetadata.h" -#include "itemdef.h" -#include "shader.h" #include "clientmap.h" #include "clientmedia.h" -#include "sound.h" -#include "IMeshCache.h" -#include "config.h" #include "version.h" #include "drawscene.h" #include "database-sqlite3.h" #include "serialization.h" #include "guiscalingfilter.h" -#include "raycast.h" +#include "script/clientscripting.h" extern gui::IGUIEnvironment* guienv; @@ -269,10 +261,36 @@ Client::Client( m_cache_use_tangent_vertices = m_cache_enable_shaders && ( g_settings->getBool("enable_bumpmapping") || g_settings->getBool("enable_parallax_occlusion")); + + m_script = new ClientScripting(this); +} + +void Client::initMods() +{ + std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua"; + + m_script->loadMod(script_path, BUILTIN_MOD_NAME); +} + +const std::string Client::getBuiltinLuaPath() +{ + return porting::path_share + DIR_DELIM + "builtin"; +} + +const std::vector& Client::getMods() const +{ + static std::vector client_modspec_temp; + return client_modspec_temp; +} + +const ModSpec* Client::getModSpec(const std::string &modname) const +{ + return NULL; } void Client::Stop() { + m_script->on_shutdown(); //request all client managed threads to stop m_mesh_update_thread.stop(); // Save local server map @@ -280,6 +298,8 @@ void Client::Stop() infostream << "Local map saving ended." << std::endl; m_localdb->endSave(); } + + delete m_script; } bool Client::isShutdown() @@ -1553,6 +1573,11 @@ void Client::typeChatMessage(const std::wstring &message) if(message == L"") return; + // If message was ate by script API, don't send it to server + if (m_script->on_sending_message(wide_to_utf8(message))) { + return; + } + // Send to others sendChatMessage(message); diff --git a/src/client.h b/src/client.h index b33358d94..2fdade61a 100644 --- a/src/client.h +++ b/src/client.h @@ -305,6 +305,8 @@ private: std::map m_packets; }; +class ClientScripting; + class Client : public con::PeerHandler, public InventoryManager, public IGameDef { public: @@ -328,6 +330,8 @@ public: ~Client(); + void initMods(); + /* request all threads managed by client to be stopped */ @@ -428,6 +432,10 @@ public: ClientEnvironment& getEnv() { return m_env; } ITextureSource *tsrc() { return getTextureSource(); } ISoundManager *sound() { return getSoundManager(); } + static const std::string getBuiltinLuaPath(); + + virtual const std::vector &getMods() const; + virtual const ModSpec* getModSpec(const std::string &modname) const; // Causes urgent mesh updates (unlike Map::add/removeNodeWithEvent) void removeNode(v3s16 p); @@ -692,6 +700,8 @@ private: bool m_cache_enable_shaders; bool m_cache_use_tangent_vertices; + ClientScripting *m_script; + DISABLE_CLASS_COPY(Client); }; diff --git a/src/content_abm.cpp b/src/content_abm.cpp index ee444ae77..2ab3a968c 100644 --- a/src/content_abm.cpp +++ b/src/content_abm.cpp @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "mapblock.h" // For getNodeBlockPos #include "map.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "log.h" void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) { diff --git a/src/content_sao.cpp b/src/content_sao.cpp index d4a218505..93662b035 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "remoteplayer.h" #include "server.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "genericobject.h" std::map ServerActiveObject::m_types; diff --git a/src/emerge.cpp b/src/emerge.cpp index 1c9719c48..8719a9eb3 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mg_schematic.h" #include "nodedef.h" #include "profiler.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "server.h" #include "serverobject.h" #include "settings.h" diff --git a/src/environment.cpp b/src/environment.cpp index 8c1aad9d3..737d93ecd 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "collision.h" #include "serverobject.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "server.h" #include "daynightratio.h" #include "emerge.h" diff --git a/src/game.cpp b/src/game.cpp index 55b2ccec9..9868142f7 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -2222,6 +2222,8 @@ bool Game::connectToServer(const std::string &playername, fps_control.last_time = device->getTimer()->getTime(); + client->initMods(); + while (device->run()) { limitFps(&fps_control, &dtime); diff --git a/src/gamedef.h b/src/gamedef.h index cb624bd6a..16b53e24f 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -39,6 +39,7 @@ namespace irr { namespace scene { class ISceneManager; }} +struct ModSpec; /* An interface for fetching game-global definitions like tool and mapnode properties @@ -68,7 +69,11 @@ public: ICraftDefManager *cdef() { return getCraftDefManager(); } MtEventManager *event() { return getEventManager(); } - IRollbackManager *rollback() { return getRollbackManager();} + IRollbackManager *rollback() { return getRollbackManager(); } + + virtual const std::vector &getMods() const = 0; + virtual const ModSpec* getModSpec(const std::string &modname) const = 0; + virtual std::string getWorldPath() const { return ""; } }; #endif diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index ae3fad7c6..19cac6241 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "gettime.h" #include "gettext.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "porting.h" #include "settings.h" #include "client.h" diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index 469e7396b..6ebc2994b 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inventorymanager.h" #include "log.h" #include "serverenvironment.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "serverobject.h" #include "settings.h" #include "craftdef.h" diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index b11f73e86..f1c44c7d8 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 "server.h" #include "util/strfnd.h" #include "network/clientopcodes.h" +#include "script/clientscripting.h" #include "util/serialize.h" #include "util/srp.h" #include "tileanimation.h" @@ -411,7 +412,10 @@ void Client::handleCommand_ChatMessage(NetworkPacket* pkt) message += (wchar_t)read_wchar; } - m_chat_queue.push(message); + // If chat message not consummed by client lua API + if (!m_script->on_receiving_message(wide_to_utf8(message))) { + m_chat_queue.push(message); + } } void Client::handleCommand_ActiveObjectRemoveAdd(NetworkPacket* pkt) diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index ac428e8ed..b707c6fad 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "player.h" #include "rollback_interface.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "settings.h" #include "tool.h" #include "version.h" diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt index 5ef672ca9..c96ccc816 100644 --- a/src/script/CMakeLists.txt +++ b/src/script/CMakeLists.txt @@ -3,16 +3,17 @@ add_subdirectory(cpp_api) add_subdirectory(lua_api) # Used by server and client -set(common_SCRIPT_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/scripting_game.cpp +set(common_SCRIPT_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/serverscripting.cpp ${common_SCRIPT_COMMON_SRCS} ${common_SCRIPT_CPP_API_SRCS} ${common_SCRIPT_LUA_API_SRCS} PARENT_SCOPE) # Used by client only -set(client_SCRIPT_SRCS +set(client_SCRIPT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/scripting_mainmenu.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/clientscripting.cpp ${client_SCRIPT_COMMON_SRCS} ${client_SCRIPT_CPP_API_SRCS} ${client_SCRIPT_LUA_API_SRCS} diff --git a/src/script/clientscripting.cpp b/src/script/clientscripting.cpp new file mode 100644 index 000000000..43bc6f94e --- /dev/null +++ b/src/script/clientscripting.cpp @@ -0,0 +1,54 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#include "clientscripting.h" +#include "client.h" +#include "cpp_api/s_internal.h" +#include "lua_api/l_client.h" +#include "lua_api/l_util.h" + +ClientScripting::ClientScripting(Client *client): + ScriptApiBase() +{ + setGameDef(client); + + SCRIPTAPI_PRECHECKHEADER + + // Security is mandatory client side + initializeSecurity(); + + lua_getglobal(L, "core"); + int top = lua_gettop(L); + + InitializeModApi(L, top); + lua_pop(L, 1); + + // Push builtin initialization type + lua_pushstring(L, "client"); + lua_setglobal(L, "INIT"); + + infostream << "SCRIPTAPI: Initialized client game modules" << std::endl; +} + +void ClientScripting::InitializeModApi(lua_State *L, int top) +{ + ModApiUtil::Initialize(L, top); + ModApiClient::Initialize(L, top); +} diff --git a/src/script/clientscripting.h b/src/script/clientscripting.h new file mode 100644 index 000000000..e2a91f695 --- /dev/null +++ b/src/script/clientscripting.h @@ -0,0 +1,40 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#ifndef CLIENT_SCRIPTING_H_ +#define CLIENT_SCRIPTING_H_ + +#include "cpp_api/s_base.h" +#include "cpp_api/s_client.h" +#include "cpp_api/s_security.h" + +class Client; +class ClientScripting: + virtual public ScriptApiBase, + public ScriptApiSecurity, + public ScriptApiClient +{ +public: + ClientScripting(Client *client); + +private: + virtual void InitializeModApi(lua_State *L, int top); +}; +#endif diff --git a/src/script/cpp_api/CMakeLists.txt b/src/script/cpp_api/CMakeLists.txt index be4d0131e..4b13356a8 100644 --- a/src/script/cpp_api/CMakeLists.txt +++ b/src/script/cpp_api/CMakeLists.txt @@ -13,6 +13,7 @@ set(common_SCRIPT_CPP_API_SRCS PARENT_SCOPE) set(client_SCRIPT_CPP_API_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/s_client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/s_mainmenu.cpp PARENT_SCOPE) diff --git a/src/script/cpp_api/s_base.cpp b/src/script/cpp_api/s_base.cpp index cbe5735a7..6a843810f 100644 --- a/src/script/cpp_api/s_base.cpp +++ b/src/script/cpp_api/s_base.cpp @@ -23,12 +23,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_object.h" #include "common/c_converter.h" #include "serverobject.h" -#include "debug.h" #include "filesys.h" -#include "log.h" #include "mods.h" #include "porting.h" #include "util/string.h" +#include "server.h" +#ifndef SERVER +#include "client.h" +#endif extern "C" { @@ -69,7 +71,8 @@ public: */ ScriptApiBase::ScriptApiBase() : - m_luastackmutex() + m_luastackmutex(), + m_gamedef(NULL) { #ifdef SCRIPTAPI_LOCK_DEBUG m_lock_recursion_count = 0; @@ -113,7 +116,6 @@ ScriptApiBase::ScriptApiBase() : // Default to false otherwise m_secure = false; - m_server = NULL; m_environment = NULL; m_guiengine = NULL; } @@ -333,3 +335,14 @@ void ScriptApiBase::objectrefGet(lua_State *L, u16 id) lua_remove(L, -2); // object_refs lua_remove(L, -2); // core } + +Server* ScriptApiBase::getServer() +{ + return dynamic_cast(m_gamedef); +} +#ifndef SERVER +Client* ScriptApiBase::getClient() +{ + return dynamic_cast(m_gamedef); +} +#endif diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index c27235255..19d71df65 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -55,6 +55,10 @@ extern "C" { setOriginFromTableRaw(index, __FUNCTION__) class Server; +#ifndef SERVER +class Client; +#endif +class IGameDef; class Environment; class GUIEngine; class ServerActiveObject; @@ -75,7 +79,11 @@ public: void addObjectReference(ServerActiveObject *cobj); void removeObjectReference(ServerActiveObject *cobj); - Server* getServer() { return m_server; } + IGameDef *getGameDef() { return m_gamedef; } + Server* getServer(); +#ifndef SERVER + Client* getClient(); +#endif std::string getOrigin() { return m_last_run_mod; } void setOriginDirect(const char *origin); @@ -98,7 +106,7 @@ protected: void scriptError(int result, const char *fxn); void stackDump(std::ostream &o); - void setServer(Server* server) { m_server = server; } + void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; } Environment* getEnv() { return m_environment; } void setEnv(Environment* env) { m_environment = env; } @@ -122,7 +130,7 @@ private: lua_State* m_luastack; - Server* m_server; + IGameDef* m_gamedef; Environment* m_environment; GUIEngine* m_guiengine; }; diff --git a/src/script/cpp_api/s_client.cpp b/src/script/cpp_api/s_client.cpp new file mode 100644 index 000000000..08af8ebdc --- /dev/null +++ b/src/script/cpp_api/s_client.cpp @@ -0,0 +1,61 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#include "s_client.h" +#include "s_internal.h" + +void ScriptApiClient::on_shutdown() +{ + SCRIPTAPI_PRECHECKHEADER + + // Get registered shutdown hooks + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_shutdown"); + // Call callbacks + runCallbacks(0, RUN_CALLBACKS_MODE_FIRST); +} + +bool ScriptApiClient::on_sending_message(const std::string &message) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_chat_messages + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_sending_chat_messages"); + // Call callbacks + lua_pushstring(L, message.c_str()); + runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + bool ate = lua_toboolean(L, -1); + return ate; +} + +bool ScriptApiClient::on_receiving_message(const std::string &message) +{ + SCRIPTAPI_PRECHECKHEADER + + // Get core.registered_on_chat_messages + lua_getglobal(L, "core"); + lua_getfield(L, -1, "registered_on_receiving_chat_messages"); + // Call callbacks + lua_pushstring(L, message.c_str()); + runCallbacks(1, RUN_CALLBACKS_MODE_OR_SC); + bool ate = lua_toboolean(L, -1); + return ate; +} diff --git a/src/script/cpp_api/s_client.h b/src/script/cpp_api/s_client.h new file mode 100644 index 000000000..08fdd8fc0 --- /dev/null +++ b/src/script/cpp_api/s_client.h @@ -0,0 +1,36 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#ifndef S_CLIENT_H_ +#define S_CLIENT_H_ + +#include "cpp_api/s_base.h" + +class ScriptApiClient: virtual public ScriptApiBase +{ +public: + // Calls on_shutdown handlers + void on_shutdown(); + + // Chat message handlers + bool on_sending_message(const std::string &message); + bool on_receiving_message(const std::string &message); +}; +#endif diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index be2b884cc..f85cd0c9c 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -382,9 +382,9 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_SCRIPTAPI); ScriptApiBase *script = (ScriptApiBase *) lua_touserdata(L, -1); lua_pop(L, 1); - const Server *server = script->getServer(); - - if (!server) return false; + const IGameDef *gamedef = script->getGameDef(); + if (!gamedef) + return false; // Get mod name lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); @@ -400,7 +400,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, // Allow paths in mod path // Don't bother if write access isn't important, since it will be handled later if (write_required || write_allowed != NULL) { - const ModSpec *mod = server->getModSpec(mod_name); + const ModSpec *mod = gamedef->getModSpec(mod_name); if (mod) { str = fs::AbsolutePath(mod->path); if (!str.empty() && fs::PathStartsWith(abs_path, str)) { @@ -414,7 +414,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, // Allow read-only access to all mod directories if (!write_required) { - const std::vector mods = server->getMods(); + const std::vector mods = gamedef->getMods(); for (size_t i = 0; i < mods.size(); ++i) { str = fs::AbsolutePath(mods[i].path); if (!str.empty() && fs::PathStartsWith(abs_path, str)) { @@ -423,7 +423,7 @@ bool ScriptApiSecurity::checkPath(lua_State *L, const char *path, } } - str = fs::AbsolutePath(server->getWorldPath()); + str = fs::AbsolutePath(gamedef->getWorldPath()); if (!str.empty()) { // Don't allow access to other paths in the world mod/game path. // These have to be blocked so you can't override a trusted mod diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt index e82560696..ea3d75ffa 100644 --- a/src/script/lua_api/CMakeLists.txt +++ b/src/script/lua_api/CMakeLists.txt @@ -23,5 +23,6 @@ set(common_SCRIPT_LUA_API_SRCS PARENT_SCOPE) set(client_SCRIPT_LUA_API_SRCS + ${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp PARENT_SCOPE) diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp new file mode 100644 index 000000000..9c478602a --- /dev/null +++ b/src/script/lua_api/l_client.cpp @@ -0,0 +1,33 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#include "l_client.h" +#include "l_internal.h" + +int ModApiClient::l_get_current_modname(lua_State *L) +{ + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); + return 1; +} + +void ModApiClient::Initialize(lua_State *L, int top) +{ + API_FCT(get_current_modname); +} diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h new file mode 100644 index 000000000..332f00132 --- /dev/null +++ b/src/script/lua_api/l_client.h @@ -0,0 +1,36 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#ifndef L_CLIENT_H_ +#define L_CLIENT_H_ + +#include "lua_api/l_base.h" + +class ModApiClient : public ModApiBase +{ +private: + // get_current_modname() + static int l_get_current_modname(lua_State *L); + +public: + static void Initialize(lua_State *L, int top); +}; + +#endif diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 2722e35a4..442c4b99a 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_vmanip.h" #include "common/c_converter.h" #include "common/c_content.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "environment.h" #include "server.h" #include "nodedef.h" @@ -49,7 +49,7 @@ struct EnumString ModApiEnvMod::es_ClearObjectsMode[] = void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, u32 active_object_count, u32 active_object_count_wider) { - GameScripting *scriptIface = env->getScriptIface(); + ServerScripting *scriptIface = env->getScriptIface(); scriptIface->realityCheck(); lua_State *L = scriptIface->getStack(); @@ -92,7 +92,7 @@ void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n, void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n) { - GameScripting *scriptIface = env->getScriptIface(); + ServerScripting *scriptIface = env->getScriptIface(); scriptIface->realityCheck(); lua_State *L = scriptIface->getStack(); diff --git a/src/script/lua_api/l_env.h b/src/script/lua_api/l_env.h index 21b235f84..322959411 100644 --- a/src/script/lua_api/l_env.h +++ b/src/script/lua_api/l_env.h @@ -242,7 +242,7 @@ public: }; struct ScriptCallbackState { - GameScripting *script; + ServerScripting *script; int callback_ref; int args_ref; unsigned int refcount; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 9352812ab..be454ad45 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_sao.h" #include "server.h" #include "hud.h" -#include "scripting_game.h" +#include "serverscripting.h" struct EnumString es_HudElementType[] = { diff --git a/src/script/scripting_game.cpp b/src/script/scripting_game.cpp deleted file mode 100644 index 4da752263..000000000 --- a/src/script/scripting_game.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola - -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. -*/ - -#include "scripting_game.h" -#include "server.h" -#include "log.h" -#include "settings.h" -#include "cpp_api/s_internal.h" -#include "lua_api/l_areastore.h" -#include "lua_api/l_base.h" -#include "lua_api/l_craft.h" -#include "lua_api/l_env.h" -#include "lua_api/l_inventory.h" -#include "lua_api/l_item.h" -#include "lua_api/l_itemstackmeta.h" -#include "lua_api/l_mapgen.h" -#include "lua_api/l_nodemeta.h" -#include "lua_api/l_nodetimer.h" -#include "lua_api/l_noise.h" -#include "lua_api/l_object.h" -#include "lua_api/l_particles.h" -#include "lua_api/l_rollback.h" -#include "lua_api/l_server.h" -#include "lua_api/l_util.h" -#include "lua_api/l_vmanip.h" -#include "lua_api/l_settings.h" -#include "lua_api/l_http.h" -#include "lua_api/l_storage.h" - -extern "C" { -#include "lualib.h" -} - -GameScripting::GameScripting(Server* server) -{ - setServer(server); - - // setEnv(env) is called by ScriptApiEnv::initializeEnvironment() - // once the environment has been created - - SCRIPTAPI_PRECHECKHEADER - - if (g_settings->getBool("secure.enable_security")) { - initializeSecurity(); - } - - lua_getglobal(L, "core"); - int top = lua_gettop(L); - - lua_newtable(L); - lua_setfield(L, -2, "object_refs"); - - lua_newtable(L); - lua_setfield(L, -2, "luaentities"); - - // Initialize our lua_api modules - InitializeModApi(L, top); - lua_pop(L, 1); - - // Push builtin initialization type - lua_pushstring(L, "game"); - lua_setglobal(L, "INIT"); - - infostream << "SCRIPTAPI: Initialized game modules" << std::endl; -} - -void GameScripting::InitializeModApi(lua_State *L, int top) -{ - // Initialize mod api modules - ModApiCraft::Initialize(L, top); - ModApiEnvMod::Initialize(L, top); - ModApiInventory::Initialize(L, top); - ModApiItemMod::Initialize(L, top); - ModApiMapgen::Initialize(L, top); - ModApiParticles::Initialize(L, top); - ModApiRollback::Initialize(L, top); - ModApiServer::Initialize(L, top); - ModApiUtil::Initialize(L, top); - ModApiHttp::Initialize(L, top); - ModApiStorage::Initialize(L, top); - - // Register reference classes (userdata) - InvRef::Register(L); - ItemStackMetaRef::Register(L); - LuaAreaStore::Register(L); - LuaItemStack::Register(L); - LuaPerlinNoise::Register(L); - LuaPerlinNoiseMap::Register(L); - LuaPseudoRandom::Register(L); - LuaPcgRandom::Register(L); - LuaSecureRandom::Register(L); - LuaVoxelManip::Register(L); - NodeMetaRef::Register(L); - NodeTimerRef::Register(L); - ObjectRef::Register(L); - LuaSettings::Register(L); - StorageRef::Register(L); -} - -void log_deprecated(const std::string &message) -{ - log_deprecated(NULL, message); -} diff --git a/src/script/scripting_game.h b/src/script/scripting_game.h deleted file mode 100644 index 970b3e80d..000000000 --- a/src/script/scripting_game.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola - -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. -*/ - -#ifndef SCRIPTING_GAME_H_ -#define SCRIPTING_GAME_H_ - -#include "cpp_api/s_base.h" -#include "cpp_api/s_entity.h" -#include "cpp_api/s_env.h" -#include "cpp_api/s_inventory.h" -#include "cpp_api/s_node.h" -#include "cpp_api/s_player.h" -#include "cpp_api/s_server.h" -#include "cpp_api/s_security.h" - -/*****************************************************************************/ -/* Scripting <-> Game Interface */ -/*****************************************************************************/ - -class GameScripting : - virtual public ScriptApiBase, - public ScriptApiDetached, - public ScriptApiEntity, - public ScriptApiEnv, - public ScriptApiNode, - public ScriptApiPlayer, - public ScriptApiServer, - public ScriptApiSecurity -{ -public: - GameScripting(Server* server); - - // use ScriptApiBase::loadMod() to load mods - -private: - void InitializeModApi(lua_State *L, int top); -}; - -void log_deprecated(const std::string &message); - -#endif /* SCRIPTING_GAME_H_ */ diff --git a/src/script/serverscripting.cpp b/src/script/serverscripting.cpp new file mode 100644 index 000000000..215b2cfd7 --- /dev/null +++ b/src/script/serverscripting.cpp @@ -0,0 +1,119 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +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. +*/ + +#include "serverscripting.h" +#include "server.h" +#include "log.h" +#include "settings.h" +#include "cpp_api/s_internal.h" +#include "lua_api/l_areastore.h" +#include "lua_api/l_base.h" +#include "lua_api/l_craft.h" +#include "lua_api/l_env.h" +#include "lua_api/l_inventory.h" +#include "lua_api/l_item.h" +#include "lua_api/l_itemstackmeta.h" +#include "lua_api/l_mapgen.h" +#include "lua_api/l_nodemeta.h" +#include "lua_api/l_nodetimer.h" +#include "lua_api/l_noise.h" +#include "lua_api/l_object.h" +#include "lua_api/l_particles.h" +#include "lua_api/l_rollback.h" +#include "lua_api/l_server.h" +#include "lua_api/l_util.h" +#include "lua_api/l_vmanip.h" +#include "lua_api/l_settings.h" +#include "lua_api/l_http.h" +#include "lua_api/l_storage.h" + +extern "C" { +#include "lualib.h" +} + +ServerScripting::ServerScripting(Server* server) +{ + setGameDef(server); + + // setEnv(env) is called by ScriptApiEnv::initializeEnvironment() + // once the environment has been created + + SCRIPTAPI_PRECHECKHEADER + + if (g_settings->getBool("secure.enable_security")) { + initializeSecurity(); + } + + lua_getglobal(L, "core"); + int top = lua_gettop(L); + + lua_newtable(L); + lua_setfield(L, -2, "object_refs"); + + lua_newtable(L); + lua_setfield(L, -2, "luaentities"); + + // Initialize our lua_api modules + InitializeModApi(L, top); + lua_pop(L, 1); + + // Push builtin initialization type + lua_pushstring(L, "game"); + lua_setglobal(L, "INIT"); + + infostream << "SCRIPTAPI: Initialized game modules" << std::endl; +} + +void ServerScripting::InitializeModApi(lua_State *L, int top) +{ + // Initialize mod api modules + ModApiCraft::Initialize(L, top); + ModApiEnvMod::Initialize(L, top); + ModApiInventory::Initialize(L, top); + ModApiItemMod::Initialize(L, top); + ModApiMapgen::Initialize(L, top); + ModApiParticles::Initialize(L, top); + ModApiRollback::Initialize(L, top); + ModApiServer::Initialize(L, top); + ModApiUtil::Initialize(L, top); + ModApiHttp::Initialize(L, top); + ModApiStorage::Initialize(L, top); + + // Register reference classes (userdata) + InvRef::Register(L); + ItemStackMetaRef::Register(L); + LuaAreaStore::Register(L); + LuaItemStack::Register(L); + LuaPerlinNoise::Register(L); + LuaPerlinNoiseMap::Register(L); + LuaPseudoRandom::Register(L); + LuaPcgRandom::Register(L); + LuaSecureRandom::Register(L); + LuaVoxelManip::Register(L); + NodeMetaRef::Register(L); + NodeTimerRef::Register(L); + ObjectRef::Register(L); + LuaSettings::Register(L); + StorageRef::Register(L); +} + +void log_deprecated(const std::string &message) +{ + log_deprecated(NULL, message); +} diff --git a/src/script/serverscripting.h b/src/script/serverscripting.h new file mode 100644 index 000000000..fd97ea40b --- /dev/null +++ b/src/script/serverscripting.h @@ -0,0 +1,57 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +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. +*/ + +#ifndef SERVER_SCRIPTING_H_ +#define SERVER_SCRIPTING_H_ + +#include "cpp_api/s_base.h" +#include "cpp_api/s_entity.h" +#include "cpp_api/s_env.h" +#include "cpp_api/s_inventory.h" +#include "cpp_api/s_node.h" +#include "cpp_api/s_player.h" +#include "cpp_api/s_server.h" +#include "cpp_api/s_security.h" + +/*****************************************************************************/ +/* Scripting <-> Server Game Interface */ +/*****************************************************************************/ + +class ServerScripting: + virtual public ScriptApiBase, + public ScriptApiDetached, + public ScriptApiEntity, + public ScriptApiEnv, + public ScriptApiNode, + public ScriptApiPlayer, + public ScriptApiServer, + public ScriptApiSecurity +{ +public: + ServerScripting(Server* server); + + // use ScriptApiBase::loadMod() to load mods + +private: + void InitializeModApi(lua_State *L, int top); +}; + +void log_deprecated(const std::string &message); + +#endif /* SCRIPTING_GAME_H_ */ diff --git a/src/server.cpp b/src/server.cpp index 8b9f46f85..3adbf40cc 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "profiler.h" #include "log.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "nodedef.h" #include "itemdef.h" #include "craftdef.h" @@ -269,7 +269,7 @@ Server::Server( // Initialize scripting infostream<<"Server: Initializing Lua"< &modlist) modlist.push_back(it->name); } -std::string Server::getBuiltinLuaPath() +const std::string Server::getBuiltinLuaPath() { return porting::path_share + DIR_DELIM + "builtin"; } diff --git a/src/server.h b/src/server.h index 3eee67b78..417d31bd8 100644 --- a/src/server.h +++ b/src/server.h @@ -53,7 +53,7 @@ class PlayerSAO; class IRollbackManager; struct RollbackAction; class EmergeManager; -class GameScripting; +class ServerScripting; class ServerEnvironment; struct SimpleSoundSpec; class ServerThread; @@ -274,7 +274,7 @@ public: Inventory* createDetachedInventory(const std::string &name, const std::string &player=""); // Envlock and conlock should be locked when using scriptapi - GameScripting *getScriptIface(){ return m_script; } + ServerScripting *getScriptIface(){ return m_script; } // actions: time-reversed list // Return value: success/failure @@ -295,8 +295,8 @@ public: IWritableNodeDefManager* getWritableNodeDefManager(); IWritableCraftDefManager* getWritableCraftDefManager(); - const std::vector &getMods() const { return m_mods; } - const ModSpec* getModSpec(const std::string &modname) const; + virtual const std::vector &getMods() const { return m_mods; } + virtual const ModSpec* getModSpec(const std::string &modname) const; void getModNames(std::vector &modlist); std::string getBuiltinLuaPath(); inline const std::string &getWorldPath() const { return m_path_world; } @@ -540,7 +540,7 @@ private: // Scripting // Envlock and conlock should be locked when using Lua - GameScripting *m_script; + ServerScripting *m_script; // Item definition manager IWritableItemDefManager *m_itemdef; diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index f3f489092..ecc7c3150 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "raycast.h" #include "remoteplayer.h" -#include "scripting_game.h" +#include "serverscripting.h" #include "server.h" #include "voxelalgorithms.h" #include "util/serialize.h" @@ -352,7 +352,7 @@ void ActiveBlockList::update(std::vector &active_positions, */ ServerEnvironment::ServerEnvironment(ServerMap *map, - GameScripting *scriptIface, Server *server, + ServerScripting *scriptIface, Server *server, const std::string &path_world) : m_map(map), m_script(scriptIface), diff --git a/src/serverenvironment.h b/src/serverenvironment.h index b7056c00c..b7796b5f1 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -33,7 +33,7 @@ class ServerEnvironment; class ActiveBlockModifier; class ServerActiveObject; class Server; -class GameScripting; +class ServerScripting; /* {Active, Loading} block modifier interface. @@ -194,7 +194,7 @@ typedef UNORDERED_MAP ActiveObjectMap; class ServerEnvironment : public Environment { public: - ServerEnvironment(ServerMap *map, GameScripting *scriptIface, + ServerEnvironment(ServerMap *map, ServerScripting *scriptIface, Server *server, const std::string &path_world); ~ServerEnvironment(); @@ -203,7 +203,7 @@ public: ServerMap & getServerMap(); //TODO find way to remove this fct! - GameScripting* getScriptIface() + ServerScripting* getScriptIface() { return m_script; } Server *getGameDef() @@ -381,7 +381,7 @@ private: // The map ServerMap *m_map; // Lua state - GameScripting* m_script; + ServerScripting* m_script; // Server definition Server *m_server; // World path diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index 41ccf0d2d..9beb0afa6 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -19,10 +19,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "test.h" -#include "log.h" #include "nodedef.h" #include "itemdef.h" #include "gamedef.h" +#include "mods.h" content_t t_CONTENT_STONE; content_t t_CONTENT_GRASS; @@ -59,6 +59,13 @@ public: void defineSomeNodes(); + virtual const std::vector &getMods() const + { + static std::vector testmodspec; + return testmodspec; + } + virtual const ModSpec* getModSpec(const std::string &modname) const { return NULL; } + private: IItemDefManager *m_itemdef; INodeDefManager *m_nodedef; -- cgit v1.2.3 From 92b45b2a189b703fc7cfc8ddbc09a7ad563a13bc Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Fri, 27 Jan 2017 07:41:10 +0100 Subject: [CSM] implement client side mod loading (#5123) * client side mods are located in clientmods/ * move builtin/preview.lua to clientmods/preview/init.lua as a preview mod * refactor ModConfiguration class to work properly with client and server using child objects * move some Server constructor mod load code to ModConfiguration to reduce code duplication between client and server * remove mods.{cpp,h} unused functions * use UNORDERED_SET instead of std::set in some modspec storages --- CMakeLists.txt | 1 + builtin/client/chatcommands.lua | 14 +-- builtin/client/init.lua | 1 - builtin/client/preview.lua | 42 --------- clientmods/preview/init.lua | 42 +++++++++ src/client.cpp | 44 ++++++++- src/client.h | 3 +- src/mods.cpp | 197 +++++++++++++++++++++------------------- src/mods.h | 57 +++++++----- src/server.cpp | 25 ++--- 10 files changed, 236 insertions(+), 190 deletions(-) delete mode 100644 builtin/client/preview.lua create mode 100644 clientmods/preview/init.lua (limited to 'src/server.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index d2568a9ae..7fe950c81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -152,6 +152,7 @@ endif() install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/builtin" DESTINATION "${SHAREDIR}") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/client" DESTINATION "${SHAREDIR}") +install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/clientmods" DESTINATION "${SHAREDIR}") install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/games" DESTINATION "${SHAREDIR}" PATTERN ".git*" EXCLUDE) if(BUILD_CLIENT) diff --git a/builtin/client/chatcommands.lua b/builtin/client/chatcommands.lua index b49c222ef..43b4d9a72 100644 --- a/builtin/client/chatcommands.lua +++ b/builtin/client/chatcommands.lua @@ -5,24 +5,24 @@ core.register_on_sending_chat_messages(function(message) if not (message:sub(1,1) == "/") then return false end - + core.display_chat_message("issued command: " .. message) - + local cmd, param = string.match(message, "^/([^ ]+) *(.*)") if not param then param = "" end - + local cmd_def = core.registered_chatcommands[cmd] - + if cmd_def then core.set_last_run_mod(cmd_def.mod_origin) - local success, message = cmd_def.func(param) + local _, message = cmd_def.func(param) if message then core.display_chat_message(message) end return true end - + return false -end) \ No newline at end of file +end) diff --git a/builtin/client/init.lua b/builtin/client/init.lua index b204ee5e6..592274540 100644 --- a/builtin/client/init.lua +++ b/builtin/client/init.lua @@ -7,7 +7,6 @@ dofile(clientpath .. "register.lua") dofile(commonpath .. "after.lua") dofile(commonpath .. "chatcommands.lua") dofile(clientpath .. "chatcommands.lua") -dofile(clientpath .. "preview.lua") core.register_on_death(function() core.display_chat_message("You died.") diff --git a/builtin/client/preview.lua b/builtin/client/preview.lua deleted file mode 100644 index 4c01d665f..000000000 --- a/builtin/client/preview.lua +++ /dev/null @@ -1,42 +0,0 @@ --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_shutdown(function() - print("[PREVIEW] shutdown client") -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_receiving_chat_messages(function(message) - print("[PREVIEW] Received message " .. message) - return false -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_sending_chat_messages(function(message) - print("[PREVIEW] Sending message " .. message) - return false -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_hp_modification(function(hp) - print("[PREVIEW] HP modified " .. hp) -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_on_damage_taken(function(hp) - print("[PREVIEW] Damage taken " .. hp) -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_globalstep(function(dtime) - -- print("[PREVIEW] globalstep " .. dtime) -end) - --- This is an example function to ensure it's working properly, should be removed before merge -core.register_chatcommand("dump", { - func = function(param) - return true, dump(_G) - end, -}) - -core.after(2, function() - print("After 2") -end) diff --git a/clientmods/preview/init.lua b/clientmods/preview/init.lua new file mode 100644 index 000000000..4c01d665f --- /dev/null +++ b/clientmods/preview/init.lua @@ -0,0 +1,42 @@ +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_shutdown(function() + print("[PREVIEW] shutdown client") +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_receiving_chat_messages(function(message) + print("[PREVIEW] Received message " .. message) + return false +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_sending_chat_messages(function(message) + print("[PREVIEW] Sending message " .. message) + return false +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_hp_modification(function(hp) + print("[PREVIEW] HP modified " .. hp) +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_on_damage_taken(function(hp) + print("[PREVIEW] Damage taken " .. hp) +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_globalstep(function(dtime) + -- print("[PREVIEW] globalstep " .. dtime) +end) + +-- This is an example function to ensure it's working properly, should be removed before merge +core.register_chatcommand("dump", { + func = function(param) + return true, dump(_G) + end, +}) + +core.after(2, function() + print("After 2") +end) diff --git a/src/client.cpp b/src/client.cpp index 3b8074252..4bb63fef1 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -268,14 +268,50 @@ Client::Client( void Client::initMods() { - std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua"; + m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME); + + ClientModConfiguration modconf(getClientModsLuaPath()); + std::vector mods = modconf.getMods(); + std::vector unsatisfied_mods = modconf.getUnsatisfiedMods(); + // complain about mods with unsatisfied dependencies + if (!modconf.isConsistent()) { + modconf.printUnsatisfiedModsError(); + } + + // Print mods + infostream << "Client Loading mods: "; + for (std::vector::const_iterator i = mods.begin(); + i != mods.end(); ++i) { + infostream << (*i).name << " "; + } + + infostream << std::endl; + // Load and run "mod" scripts + for (std::vector::const_iterator it = mods.begin(); + it != mods.end(); ++it) { + const ModSpec &mod = *it; + if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) { + throw ModError("Error loading mod \"" + mod.name + + "\": Mod name does not follow naming conventions: " + "Only chararacters [a-z0-9_] are allowed."); + } + std::string script_path = mod.path + DIR_DELIM + "init.lua"; + infostream << " [" << padStringRight(mod.name, 12) << "] [\"" + << script_path << "\"]" << std::endl; + m_script->loadMod(script_path, mod.name); + } +} - m_script->loadMod(script_path, BUILTIN_MOD_NAME); +const std::string &Client::getBuiltinLuaPath() +{ + static const std::string builtin_dir = porting::path_share + DIR_DELIM + "builtin"; + return builtin_dir; } -const std::string Client::getBuiltinLuaPath() +const std::string &Client::getClientModsLuaPath() { - return porting::path_share + DIR_DELIM + "builtin"; + static const std::string clientmods_dir = porting::path_share + DIR_DELIM + "clientmods"; + return clientmods_dir; } const std::vector& Client::getMods() const diff --git a/src/client.h b/src/client.h index d170f9a07..9b7130268 100644 --- a/src/client.h +++ b/src/client.h @@ -433,7 +433,8 @@ public: ClientEnvironment& getEnv() { return m_env; } ITextureSource *tsrc() { return getTextureSource(); } ISoundManager *sound() { return getSoundManager(); } - static const std::string getBuiltinLuaPath(); + static const std::string &getBuiltinLuaPath(); + static const std::string &getClientModsLuaPath(); virtual const std::vector &getMods() const; virtual const ModSpec* getModSpec(const std::string &modname) const; diff --git a/src/mods.cpp b/src/mods.cpp index bae9a42d3..5a7dc6dca 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -25,6 +25,8 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "subgame.h" #include "settings.h" #include "convert_json.h" +#include "exceptions.h" +#include "porting.h" static bool parseDependsLine(std::istream &is, std::string &dep, std::set &symbols) @@ -107,28 +109,6 @@ std::map getModsInPath(std::string path, bool part_of_modp return result; } -std::map flattenModTree(std::map mods) -{ - std::map result; - for(std::map::iterator it = mods.begin(); - it != mods.end(); ++it) - { - ModSpec mod = (*it).second; - if(mod.is_modpack) - { - std::map content = - flattenModTree(mod.modpack_content); - result.insert(content.begin(),content.end()); - result.insert(std::make_pair(mod.name,mod)); - } - else //not a modpack - { - result.insert(std::make_pair(mod.name,mod)); - } - } - return result; -} - std::vector flattenMods(std::map mods) { std::vector result; @@ -151,78 +131,32 @@ std::vector flattenMods(std::map mods) return result; } -ModConfiguration::ModConfiguration(std::string worldpath) +ModConfiguration::ModConfiguration(const std::string &worldpath): + m_unsatisfied_mods(), + m_sorted_mods(), + m_name_conflicts() { - SubgameSpec gamespec = findWorldSubgame(worldpath); - - // Add all game mods and all world mods - addModsInPath(gamespec.gamemods_path); - addModsInPath(worldpath + DIR_DELIM + "worldmods"); - - // check world.mt file for mods explicitely declared to be - // loaded or not by a load_mod_ = ... line. - std::string worldmt = worldpath+DIR_DELIM+"world.mt"; - Settings worldmt_settings; - worldmt_settings.readConfigFile(worldmt.c_str()); - std::vector names = worldmt_settings.getNames(); - std::set include_mod_names; - for(std::vector::iterator it = names.begin(); - it != names.end(); ++it) - { - std::string name = *it; - // for backwards compatibility: exclude only mods which are - // explicitely excluded. if mod is not mentioned at all, it is - // enabled. So by default, all installed mods are enabled. - if (name.compare(0,9,"load_mod_") == 0 && - worldmt_settings.getBool(name)) - { - include_mod_names.insert(name.substr(9)); - } - } - - // Collect all mods that are also in include_mod_names - std::vector addon_mods; - for(std::set::const_iterator it_path = gamespec.addon_mods_paths.begin(); - it_path != gamespec.addon_mods_paths.end(); ++it_path) - { - std::vector addon_mods_in_path = flattenMods(getModsInPath(*it_path)); - for(std::vector::iterator it = addon_mods_in_path.begin(); - it != addon_mods_in_path.end(); ++it) - { - ModSpec& mod = *it; - if(include_mod_names.count(mod.name) != 0) - addon_mods.push_back(mod); - else - worldmt_settings.setBool("load_mod_" + mod.name, false); - } - } - worldmt_settings.updateConfigFile(worldmt.c_str()); - - addMods(addon_mods); +} - // report on name conflicts - if(!m_name_conflicts.empty()){ - std::string s = "Unresolved name conflicts for mods "; - for(std::set::const_iterator it = m_name_conflicts.begin(); - it != m_name_conflicts.end(); ++it) - { - if(it != m_name_conflicts.begin()) s += ", "; - s += std::string("\"") + (*it) + "\""; - } - s += "."; - throw ModError(s); +void ModConfiguration::printUnsatisfiedModsError() const +{ + for (std::vector::const_iterator it = m_unsatisfied_mods.begin(); + it != m_unsatisfied_mods.end(); ++it) { + ModSpec mod = *it; + errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: "; + for (UNORDERED_SET::iterator dep_it = mod.unsatisfied_depends.begin(); + dep_it != mod.unsatisfied_depends.end(); ++dep_it) + errorstream << " \"" << *dep_it << "\""; + errorstream << std::endl; } - - // get the mods in order - resolveDependencies(); } -void ModConfiguration::addModsInPath(std::string path) +void ModConfiguration::addModsInPath(const std::string &path) { addMods(flattenMods(getModsInPath(path))); } -void ModConfiguration::addMods(std::vector new_mods) +void ModConfiguration::addMods(const std::vector &new_mods) { // Maintain a map of all existing m_unsatisfied_mods. // Keys are mod names and values are indices into m_unsatisfied_mods. @@ -240,8 +174,8 @@ void ModConfiguration::addMods(std::vector new_mods) std::set seen_this_iteration; - for(std::vector::const_iterator it = new_mods.begin(); - it != new_mods.end(); ++it){ + for (std::vector::const_iterator it = new_mods.begin(); + it != new_mods.end(); ++it) { const ModSpec &mod = *it; if(mod.part_of_modpack != (bool)want_from_modpack) continue; @@ -280,6 +214,24 @@ void ModConfiguration::addMods(std::vector new_mods) } } +void ModConfiguration::checkConflictsAndDeps() +{ + // report on name conflicts + if (!m_name_conflicts.empty()) { + std::string s = "Unresolved name conflicts for mods "; + for (UNORDERED_SET::const_iterator it = m_name_conflicts.begin(); + it != m_name_conflicts.end(); ++it) { + if (it != m_name_conflicts.begin()) s += ", "; + s += std::string("\"") + (*it) + "\""; + } + s += "."; + throw ModError(s); + } + + // get the mods in order + resolveDependencies(); +} + void ModConfiguration::resolveDependencies() { // Step 1: Compile a list of the mod names we're working with @@ -293,19 +245,19 @@ void ModConfiguration::resolveDependencies() // of each mod, split mods into satisfied and unsatisfied std::list satisfied; std::list unsatisfied; - for(std::vector::iterator it = m_unsatisfied_mods.begin(); - it != m_unsatisfied_mods.end(); ++it){ + for (std::vector::iterator it = m_unsatisfied_mods.begin(); + it != m_unsatisfied_mods.end(); ++it) { ModSpec mod = *it; mod.unsatisfied_depends = mod.depends; // check which optional dependencies actually exist - for(std::set::iterator it_optdep = mod.optdepends.begin(); - it_optdep != mod.optdepends.end(); ++it_optdep){ + for (UNORDERED_SET::iterator it_optdep = mod.optdepends.begin(); + it_optdep != mod.optdepends.end(); ++it_optdep) { std::string optdep = *it_optdep; - if(modnames.count(optdep) != 0) + if (modnames.count(optdep) != 0) mod.unsatisfied_depends.insert(optdep); } // if a mod has no depends it is initially satisfied - if(mod.unsatisfied_depends.empty()) + if (mod.unsatisfied_depends.empty()) satisfied.push_back(mod); else unsatisfied.push_back(mod); @@ -335,6 +287,65 @@ void ModConfiguration::resolveDependencies() m_unsatisfied_mods.assign(unsatisfied.begin(), unsatisfied.end()); } +ServerModConfiguration::ServerModConfiguration(const std::string &worldpath): + ModConfiguration(worldpath) +{ + SubgameSpec gamespec = findWorldSubgame(worldpath); + + // Add all game mods and all world mods + addModsInPath(gamespec.gamemods_path); + addModsInPath(worldpath + DIR_DELIM + "worldmods"); + + // check world.mt file for mods explicitely declared to be + // loaded or not by a load_mod_ = ... line. + std::string worldmt = worldpath+DIR_DELIM+"world.mt"; + Settings worldmt_settings; + worldmt_settings.readConfigFile(worldmt.c_str()); + std::vector names = worldmt_settings.getNames(); + std::set include_mod_names; + for (std::vector::const_iterator it = names.begin(); + it != names.end(); ++it) { + std::string name = *it; + // for backwards compatibility: exclude only mods which are + // explicitely excluded. if mod is not mentioned at all, it is + // enabled. So by default, all installed mods are enabled. + if (name.compare(0,9,"load_mod_") == 0 && + worldmt_settings.getBool(name)) { + include_mod_names.insert(name.substr(9)); + } + } + + // Collect all mods that are also in include_mod_names + std::vector addon_mods; + for (std::set::const_iterator it_path = gamespec.addon_mods_paths.begin(); + it_path != gamespec.addon_mods_paths.end(); ++it_path) { + std::vector addon_mods_in_path = flattenMods(getModsInPath(*it_path)); + for (std::vector::const_iterator it = addon_mods_in_path.begin(); + it != addon_mods_in_path.end(); ++it) { + const ModSpec& mod = *it; + if (include_mod_names.count(mod.name) != 0) + addon_mods.push_back(mod); + else + worldmt_settings.setBool("load_mod_" + mod.name, false); + } + } + worldmt_settings.updateConfigFile(worldmt.c_str()); + + addMods(addon_mods); + + checkConflictsAndDeps(); +} + +#ifndef SERVER +ClientModConfiguration::ClientModConfiguration(const std::string &path): + ModConfiguration(path) +{ + addModsInPath(path); + addModsInPath(porting::path_user + DIR_DELIM + "clientmods"); + checkConflictsAndDeps(); +} +#endif + #if USE_CURL Json::Value getModstoreUrl(std::string url) { diff --git a/src/mods.h b/src/mods.h index 61af5e5d1..c9bd51d99 100644 --- a/src/mods.h +++ b/src/mods.h @@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include "util/cpp11_container.h" #include "config.h" #include "metadata.h" @@ -37,9 +38,9 @@ struct ModSpec std::string name; std::string path; //if normal mod: - std::set depends; - std::set optdepends; - std::set unsatisfied_depends; + UNORDERED_SET depends; + UNORDERED_SET optdepends; + UNORDERED_SET unsatisfied_depends; bool part_of_modpack; bool is_modpack; @@ -62,12 +63,6 @@ void parseModContents(ModSpec &mod); std::map getModsInPath(std::string path, bool part_of_modpack = false); -// If failed, returned modspec has name=="" -ModSpec findCommonMod(const std::string &modname); - -// expands modpack contents, but does not replace them. -std::map flattenModTree(std::map mods); - // replaces modpack Modspecs with their content std::vector flattenMods(std::map mods); @@ -77,17 +72,8 @@ std::vector flattenMods(std::map mods); class ModConfiguration { public: - ModConfiguration(): - m_unsatisfied_mods(), - m_sorted_mods(), - m_name_conflicts() - {} - - - ModConfiguration(std::string worldpath); - // checks if all dependencies are fullfilled. - bool isConsistent() + bool isConsistent() const { return m_unsatisfied_mods.empty(); } @@ -97,19 +83,24 @@ public: return m_sorted_mods; } - std::vector getUnsatisfiedMods() + const std::vector &getUnsatisfiedMods() const { return m_unsatisfied_mods; } -private: + void printUnsatisfiedModsError() const; + +protected: + ModConfiguration(const std::string &worldpath); // adds all mods in the given path. used for games, modpacks // and world-specific mods (worldmods-folders) - void addModsInPath(std::string path); + void addModsInPath(const std::string &path); // adds all mods in the set. - void addMods(std::vector new_mods); + void addMods(const std::vector &new_mods); + void checkConflictsAndDeps(); +private: // move mods from m_unsatisfied_mods to m_sorted_mods // in an order that satisfies dependencies void resolveDependencies(); @@ -132,10 +123,28 @@ private: // 1. game mod in modpack; 2. game mod; // 3. world mod in modpack; 4. world mod; // 5. addon mod in modpack; 6. addon mod. - std::set m_name_conflicts; + UNORDERED_SET m_name_conflicts; + + // Deleted default constructor + ModConfiguration() {} }; +class ServerModConfiguration: public ModConfiguration +{ +public: + ServerModConfiguration(const std::string &worldpath); + +}; + +#ifndef SERVER +class ClientModConfiguration: public ModConfiguration +{ +public: + ClientModConfiguration(const std::string &path); +}; +#endif + #if USE_CURL Json::Value getModstoreUrl(std::string url); #else diff --git a/src/server.cpp b/src/server.cpp index 3adbf40cc..dd6c9a418 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -218,20 +218,12 @@ Server::Server( std::string ban_path = m_path_world + DIR_DELIM "ipban.txt"; m_banmanager = new BanManager(ban_path); - ModConfiguration modconf(m_path_world); + ServerModConfiguration modconf(m_path_world); m_mods = modconf.getMods(); std::vector unsatisfied_mods = modconf.getUnsatisfiedMods(); // complain about mods with unsatisfied dependencies - if(!modconf.isConsistent()) { - for(std::vector::iterator it = unsatisfied_mods.begin(); - it != unsatisfied_mods.end(); ++it) { - ModSpec mod = *it; - errorstream << "mod \"" << mod.name << "\" has unsatisfied dependencies: "; - for(std::set::iterator dep_it = mod.unsatisfied_depends.begin(); - dep_it != mod.unsatisfied_depends.end(); ++dep_it) - errorstream << " \"" << *dep_it << "\""; - errorstream << std::endl; - } + if (!modconf.isConsistent()) { + modconf.printUnsatisfiedModsError(); } Settings worldmt_settings; @@ -271,20 +263,17 @@ Server::Server( m_script = new ServerScripting(this); - std::string script_path = getBuiltinLuaPath() + DIR_DELIM "init.lua"; - - m_script->loadMod(script_path, BUILTIN_MOD_NAME); + m_script->loadMod(getBuiltinLuaPath() + DIR_DELIM "init.lua", BUILTIN_MOD_NAME); // Print mods infostream << "Server: Loading mods: "; - for(std::vector::iterator i = m_mods.begin(); + for (std::vector::const_iterator i = m_mods.begin(); i != m_mods.end(); ++i) { - const ModSpec &mod = *i; - infostream << mod.name << " "; + infostream << (*i).name << " "; } infostream << std::endl; // Load and run "mod" scripts - for (std::vector::iterator it = m_mods.begin(); + for (std::vector::const_iterator it = m_mods.begin(); it != m_mods.end(); ++it) { const ModSpec &mod = *it; if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) { -- cgit v1.2.3 From ba66fce8339f818a638f97679bd29da064a8c1c6 Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Sat, 28 Jan 2017 18:31:23 +0100 Subject: [CSM] storage + fixes --- clientmods/preview/init.lua | 4 +++- src/script/clientscripting.cpp | 2 ++ src/script/lua_api/CMakeLists.txt | 1 + src/script/lua_api/l_client.h | 3 +-- src/script/lua_api/l_util.cpp | 6 ------ src/server.cpp | 2 +- src/server.h | 2 +- 7 files changed, 9 insertions(+), 11 deletions(-) (limited to 'src/server.cpp') diff --git a/clientmods/preview/init.lua b/clientmods/preview/init.lua index 4c01d665f..f03e8e112 100644 --- a/clientmods/preview/init.lua +++ b/clientmods/preview/init.lua @@ -1,3 +1,5 @@ +local modname = core.get_current_modname() or "??" + -- This is an example function to ensure it's working properly, should be removed before merge core.register_on_shutdown(function() print("[PREVIEW] shutdown client") @@ -38,5 +40,5 @@ core.register_chatcommand("dump", { }) core.after(2, function() - print("After 2") + print("[PREVIEW] loaded " .. modname .. " mod") end) diff --git a/src/script/clientscripting.cpp b/src/script/clientscripting.cpp index 390d21a3a..aaed2865d 100644 --- a/src/script/clientscripting.cpp +++ b/src/script/clientscripting.cpp @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client.h" #include "cpp_api/s_internal.h" #include "lua_api/l_client.h" +#include "lua_api/l_storage.h" #include "lua_api/l_sound.h" #include "lua_api/l_util.h" @@ -53,4 +54,5 @@ void ClientScripting::InitializeModApi(lua_State *L, int top) ModApiUtil::InitializeClient(L, top); ModApiClient::Initialize(L, top); ModApiSound::Initialize(L, top); + ModApiStorage::Initialize(L, top); } diff --git a/src/script/lua_api/CMakeLists.txt b/src/script/lua_api/CMakeLists.txt index 17bcdde4c..2d25d845c 100644 --- a/src/script/lua_api/CMakeLists.txt +++ b/src/script/lua_api/CMakeLists.txt @@ -25,5 +25,6 @@ set(common_SCRIPT_LUA_API_SRCS set(client_SCRIPT_LUA_API_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/l_client.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/l_storage.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_sound.cpp PARENT_SCOPE) diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h index 14ef5aecc..d0e230630 100644 --- a/src/script/lua_api/l_client.h +++ b/src/script/lua_api/l_client.h @@ -23,8 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_base.h" -class ModApiClient: - public ModApiBase +class ModApiClient: public ModApiBase { private: // get_current_modname() diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index b9c334121..809a2eb68 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -532,12 +532,6 @@ void ModApiUtil::InitializeClient(lua_State *L, int top) API_FCT(get_us_time); - API_FCT(setting_set); - API_FCT(setting_get); - API_FCT(setting_setbool); - API_FCT(setting_getbool); - API_FCT(setting_save); - API_FCT(parse_json); API_FCT(write_json); diff --git a/src/server.cpp b/src/server.cpp index dd6c9a418..293b32a81 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3400,7 +3400,7 @@ void Server::getModNames(std::vector &modlist) modlist.push_back(it->name); } -const std::string Server::getBuiltinLuaPath() +std::string Server::getBuiltinLuaPath() { return porting::path_share + DIR_DELIM + "builtin"; } diff --git a/src/server.h b/src/server.h index 417d31bd8..f0bab1bbf 100644 --- a/src/server.h +++ b/src/server.h @@ -299,7 +299,7 @@ public: virtual const ModSpec* getModSpec(const std::string &modname) const; void getModNames(std::vector &modlist); std::string getBuiltinLuaPath(); - inline const std::string &getWorldPath() const { return m_path_world; } + std::string getWorldPath() const { return m_path_world; } std::string getModStoragePath() const; inline bool isSingleplayer() -- cgit v1.2.3 From b8484ef24e8e1ec90a2967372808ab2bea538c7c Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Thu, 15 Oct 2015 13:04:15 -0400 Subject: Server list cleanup This removes the hacky server_dedicated pseudo-setting. --- src/game.cpp | 2 +- src/main.cpp | 10 +++------- src/server.cpp | 30 +++++++++++++++--------------- src/server.h | 3 +++ src/serverlist.cpp | 22 ++++++++++++---------- src/serverlist.h | 39 ++++++++++++++++++++++----------------- 6 files changed, 56 insertions(+), 50 deletions(-) (limited to 'src/server.cpp') diff --git a/src/game.cpp b/src/game.cpp index cb3820870..12c81bf2f 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1899,7 +1899,7 @@ bool Game::createSingleplayerServer(const std::string map_dir, } server = new Server(map_dir, gamespec, simple_singleplayer_mode, - bind_addr.isIPv6()); + bind_addr.isIPv6(), false); server->start(bind_addr); diff --git a/src/main.cpp b/src/main.cpp index a54454653..3599a36ce 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -213,10 +213,6 @@ int main(int argc, char *argv[]) infostream << "Using commanded world path [" << game_params.world_path << "]" << std::endl; - //Run dedicated server if asked to or no other option - g_settings->set("server_dedicated", - game_params.is_dedicated_server ? "true" : "false"); - if (game_params.is_dedicated_server) return run_dedicated_server(game_params, cmd_args) ? 0 : 1; @@ -852,8 +848,8 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & try { // Create server - Server server(game_params.world_path, - game_params.game_spec, false, bind_addr.isIPv6(), &iface); + Server server(game_params.world_path, game_params.game_spec, + false, bind_addr.isIPv6(), true, &iface); g_term_console.setup(&iface, &kill, admin_nick); @@ -887,7 +883,7 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & try { // Create server Server server(game_params.world_path, game_params.game_spec, false, - bind_addr.isIPv6()); + bind_addr.isIPv6(), true); server.start(bind_addr); // Run server diff --git a/src/server.cpp b/src/server.cpp index 293b32a81..9ed2a045d 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -148,11 +148,13 @@ Server::Server( const SubgameSpec &gamespec, bool simple_singleplayer_mode, bool ipv6, + bool dedicated, ChatInterface *iface ): m_path_world(path_world), m_gamespec(gamespec), m_simple_singleplayer_mode(simple_singleplayer_mode), + m_dedicated(dedicated), m_async_fatal_error(""), m_env(NULL), m_con(PROTOCOL_ID, @@ -629,10 +631,10 @@ void Server::AsyncRunStep(bool initial_step) // send masterserver announce { float &counter = m_masterserver_timer; - if(!isSingleplayer() && (!counter || counter >= 300.0) && - g_settings->getBool("server_announce")) - { - ServerList::sendAnnounce(counter ? "update" : "start", + if (!isSingleplayer() && (!counter || counter >= 300.0) && + g_settings->getBool("server_announce")) { + ServerList::sendAnnounce(counter ? ServerList::AA_UPDATE : + ServerList::AA_START, m_bind_addr.getPort(), m_clients.getPlayerNames(), m_uptime.get(), @@ -640,7 +642,8 @@ void Server::AsyncRunStep(bool initial_step) m_lag, m_gamespec.id, Mapgen::getMapgenName(m_emerge->mgparams->mgtype), - m_mods); + m_mods, + m_dedicated); counter = 0.01; } counter += dtime; @@ -3574,16 +3577,6 @@ void dedicated_server_loop(Server &server, bool &kill) } server.step(steplen); - if(server.getShutdownRequested() || kill) - { - infostream<<"Dedicated server quitting"<getBool("server_announce")) - ServerList::sendAnnounce("delete", server.m_bind_addr.getPort()); -#endif - break; - } - /* Profiler */ @@ -3596,4 +3589,11 @@ void dedicated_server_loop(Server &server, bool &kill) } } } + + infostream << "Dedicated server quitting" << std::endl; +#if USE_CURL + if (g_settings->getBool("server_announce")) + ServerList::sendAnnounce(ServerList::AA_DELETE, + server.m_bind_addr.getPort()); +#endif } diff --git a/src/server.h b/src/server.h index e1e8f84dc..1df9d0a93 100644 --- a/src/server.h +++ b/src/server.h @@ -148,6 +148,7 @@ public: const SubgameSpec &gamespec, bool simple_singleplayer_mode, bool ipv6, + bool dedicated, ChatInterface *iface = NULL ); ~Server(); @@ -510,6 +511,8 @@ private: // functionality bool m_simple_singleplayer_mode; u16 m_max_chatmessage_length; + // For "dedicated" server list flag + bool m_dedicated; // Thread can set; step() will throw as ServerError MutexedVariable m_async_fatal_error; diff --git a/src/serverlist.cpp b/src/serverlist.cpp index 87ca5dc04..cc38ec8ce 100644 --- a/src/serverlist.cpp +++ b/src/serverlist.cpp @@ -196,7 +196,7 @@ const std::string serializeJson(const std::vector &serverlist) #if USE_CURL -void sendAnnounce(const std::string &action, +void sendAnnounce(AnnounceAction action, const u16 port, const std::vector &clients_names, const double uptime, @@ -204,15 +204,17 @@ void sendAnnounce(const std::string &action, const float lag, const std::string &gameid, const std::string &mg_name, - const std::vector &mods) + const std::vector &mods, + bool dedicated) { + static const char *aa_names[] = {"start", "update", "delete"}; Json::Value server; - server["action"] = action; + server["action"] = aa_names[action]; server["port"] = port; if (g_settings->exists("server_address")) { server["address"] = g_settings->get("server_address"); } - if (action != "delete") { + if (action != AA_DELETE) { bool strict_checking = g_settings->getBool("strict_protocol_version_checking"); server["name"] = g_settings->get("server_name"); server["description"] = g_settings->get("server_description"); @@ -237,20 +239,19 @@ void sendAnnounce(const std::string &action, if (gameid != "") server["gameid"] = gameid; } - if (action == "start") { - server["dedicated"] = g_settings->getBool("server_dedicated"); + if (action == AA_START) { + server["dedicated"] = dedicated; server["rollback"] = g_settings->getBool("enable_rollback_recording"); server["mapgen"] = mg_name; server["privs"] = g_settings->get("default_privs"); server["can_see_far_names"] = g_settings->getS16("player_transfer_distance") <= 0; server["mods"] = Json::Value(Json::arrayValue); for (std::vector::const_iterator it = mods.begin(); - it != mods.end(); - ++it) { + it != mods.end(); ++it) { server["mods"].append(it->name); } actionstream << "Announcing to " << g_settings->get("serverlist_url") << std::endl; - } else { + } else if (action == AA_UPDATE) { if (lag) server["lag"] = lag; } @@ -264,4 +265,5 @@ void sendAnnounce(const std::string &action, } #endif -} //namespace ServerList +} // namespace ServerList + diff --git a/src/serverlist.h b/src/serverlist.h index 0747c3920..079026199 100644 --- a/src/serverlist.h +++ b/src/serverlist.h @@ -29,22 +29,27 @@ typedef Json::Value ServerListSpec; namespace ServerList { - std::vector getLocal(); - std::vector getOnline(); - bool deleteEntry(const ServerListSpec &server); - bool insert(const ServerListSpec &server); - std::vector deSerialize(const std::string &liststring); - const std::string serialize(const std::vector &serverlist); - std::vector deSerializeJson(const std::string &liststring); - const std::string serializeJson(const std::vector &serverlist); - #if USE_CURL - void sendAnnounce(const std::string &action, const u16 port, - const std::vector &clients_names = std::vector(), - const double uptime = 0, const u32 game_time = 0, - const float lag = 0, const std::string &gameid = "", - const std::string &mg_name = "", - const std::vector &mods = std::vector()); - #endif -} // ServerList namespace +std::vector getLocal(); +std::vector getOnline(); + +bool deleteEntry(const ServerListSpec &server); +bool insert(const ServerListSpec &server); + +std::vector deSerialize(const std::string &liststring); +const std::string serialize(const std::vector &serverlist); +std::vector deSerializeJson(const std::string &liststring); +const std::string serializeJson(const std::vector &serverlist); + +#if USE_CURL +enum AnnounceAction {AA_START, AA_UPDATE, AA_DELETE}; +void sendAnnounce(AnnounceAction, u16 port, + const std::vector &clients_names = std::vector(), + double uptime = 0, u32 game_time = 0, float lag = 0, + const std::string &gameid = "", const std::string &mg_name = "", + const std::vector &mods = std::vector(), + bool dedicated = false); +#endif + +} // namespace ServerList #endif -- cgit v1.2.3 From f8ad01ab7c4cf012781bd4caa821544e676c9267 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sun, 19 Mar 2017 08:44:29 +0100 Subject: Update server min protocol version to v24 (#5411) * Update server min protocol version to v24 It's based on @sfan5 stats. See https://kitsunemimi.pw/tmp/serverlist_stats_2017-03-17.txt v24 was bumped 25/08/14 and 0.4.11 was released 25/12/14 * Drop protocol v23 and lesser code --- src/content_sao.cpp | 166 +++++++++++++++--------------------- src/itemdef.cpp | 35 +++----- src/map.cpp | 7 -- src/mapblock.cpp | 14 ++- src/mapblock.h | 8 +- src/network/networkprotocol.h | 4 +- src/network/serverpackethandler.cpp | 21 ----- src/nodedef.cpp | 123 +++----------------------- src/server.cpp | 10 +-- src/tool.cpp | 27 +++--- 10 files changed, 116 insertions(+), 299 deletions(-) (limited to 'src/server.cpp') diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 93662b035..69f80d356 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -470,57 +470,43 @@ std::string LuaEntitySAO::getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); - if(protocol_version >= 14) - { - writeU8(os, 1); // version - os< >::const_iterator - ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { - msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first, - (*ii).second.X, (*ii).second.Y)); // m_bone_position.size - } - msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, - m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4 - int message_count = 4 + m_bone_position.size(); - for (UNORDERED_SET::const_iterator ii = m_attachment_child_ids.begin(); - (ii != m_attachment_child_ids.end()); ++ii) { - if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { - message_count++; - msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), - obj->getClientInitializationData(protocol_version))); - } - } - - msg_os << serializeLongString(gob_cmd_set_texture_mod(m_current_texture_modifier)); - message_count++; + // protocol >= 14 + writeU8(os, 1); // version + os << serializeString(""); // name + writeU8(os, 0); // is_player + writeS16(os, getId()); //id + writeV3F1000(os, m_base_position); + writeF1000(os, m_yaw); + writeS16(os, m_hp); - writeU8(os, message_count); - os.write(msg_os.str().c_str(), msg_os.str().size()); + std::ostringstream msg_os(std::ios::binary); + msg_os << serializeLongString(getPropertyPacket()); // message 1 + msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2 + msg_os << serializeLongString(gob_cmd_update_animation( + m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3 + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y)); // m_bone_position.size } - else - { - writeU8(os, 0); // version - os<::const_iterator ii = m_attachment_child_ids.begin(); + (ii != m_attachment_child_ids.end()); ++ii) { + if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { + message_count++; + msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), + obj->getClientInitializationData(protocol_version))); + } } + msg_os << serializeLongString(gob_cmd_set_texture_mod(m_current_texture_modifier)); + message_count++; + + writeU8(os, message_count); + os.write(msg_os.str().c_str(), msg_os.str().size()); + // return result return os.str(); } @@ -877,59 +863,45 @@ std::string PlayerSAO::getClientInitializationData(u16 protocol_version) { std::ostringstream os(std::ios::binary); - if(protocol_version >= 15) - { - writeU8(os, 1); // version - os<getName()); // name - writeU8(os, 1); // is_player - writeS16(os, getId()); //id - writeV3F1000(os, m_base_position + v3f(0,BS*1,0)); - writeF1000(os, m_yaw); - writeS16(os, getHP()); - - std::ostringstream msg_os(std::ios::binary); - msg_os << serializeLongString(getPropertyPacket()); // message 1 - msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2 - msg_os << serializeLongString(gob_cmd_update_animation( - m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3 - for (UNORDERED_MAP >::const_iterator - ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { - msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first, - (*ii).second.X, (*ii).second.Y)); // m_bone_position.size - } - msg_os << serializeLongString(gob_cmd_update_attachment(m_attachment_parent_id, - m_attachment_bone, m_attachment_position, m_attachment_rotation)); // 4 - msg_os << serializeLongString(gob_cmd_update_physics_override(m_physics_override_speed, - m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak, - m_physics_override_sneak_glitch)); // 5 - // (GENERIC_CMD_UPDATE_NAMETAG_ATTRIBUTES) : Deprecated, for backwards compatibility only. - msg_os << serializeLongString(gob_cmd_update_nametag_attributes(m_prop.nametag_color)); // 6 - int message_count = 6 + m_bone_position.size(); - for (UNORDERED_SET::const_iterator ii = m_attachment_child_ids.begin(); - ii != m_attachment_child_ids.end(); ++ii) { - if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { - message_count++; - msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), - obj->getClientInitializationData(protocol_version))); - } - } - - writeU8(os, message_count); - os.write(msg_os.str().c_str(), msg_os.str().size()); + // Protocol >= 15 + writeU8(os, 1); // version + os << serializeString(m_player->getName()); // name + writeU8(os, 1); // is_player + writeS16(os, getId()); //id + writeV3F1000(os, m_base_position + v3f(0,BS*1,0)); + writeF1000(os, m_yaw); + writeS16(os, getHP()); + + std::ostringstream msg_os(std::ios::binary); + msg_os << serializeLongString(getPropertyPacket()); // message 1 + msg_os << serializeLongString(gob_cmd_update_armor_groups(m_armor_groups)); // 2 + msg_os << serializeLongString(gob_cmd_update_animation( + m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop)); // 3 + for (UNORDERED_MAP >::const_iterator + ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { + msg_os << serializeLongString(gob_cmd_update_bone_position((*ii).first, + (*ii).second.X, (*ii).second.Y)); // m_bone_position.size } - else - { - writeU8(os, 0); // version - os<getName()); // name - writeU8(os, 1); // is_player - writeV3F1000(os, m_base_position + v3f(0,BS*1,0)); - writeF1000(os, m_yaw); - writeS16(os, getHP()); - writeU8(os, 2); // number of messages stuffed in here - os<::const_iterator ii = m_attachment_child_ids.begin(); + ii != m_attachment_child_ids.end(); ++ii) { + if (ServerActiveObject *obj = m_env->getActiveObject(*ii)) { + message_count++; + msg_os << serializeLongString(gob_cmd_update_infant(*ii, obj->getSendType(), + obj->getClientInitializationData(protocol_version))); + } } + writeU8(os, message_count); + os.write(msg_os.str().c_str(), msg_os.str().size()); + // return result return os.str(); } diff --git a/src/itemdef.cpp b/src/itemdef.cpp index 5ba9d8f9a..f43e5c970 100644 --- a/src/itemdef.cpp +++ b/src/itemdef.cpp @@ -123,17 +123,13 @@ void ItemDefinition::reset() void ItemDefinition::serialize(std::ostream &os, u16 protocol_version) const { - if(protocol_version <= 17) - writeU8(os, 1); // version - else if(protocol_version <= 20) - writeU8(os, 2); // version - else - writeU8(os, 3); // version + + writeU8(os, 3); // version (proto > 20) writeU8(os, type); - os<serialize(tmp_os, protocol_version); tool_capabilities_s = tmp_os.str(); } - os<first); writeS16(os, i->second); } - os< 17){ - //serializeSimpleSoundSpec(sound_place, os); - os< 20) { - writeF1000(os, range); - os << serializeString(sound_place_failed.name); - writeF1000(os, sound_place_failed.gain); - } + os << serializeString(node_placement_prediction); + os << serializeString(sound_place.name); + writeF1000(os, sound_place.gain); + writeF1000(os, range); + os << serializeString(sound_place_failed.name); + writeF1000(os, sound_place_failed.gain); } void ItemDefinition::deSerialize(std::istream &is) diff --git a/src/map.cpp b/src/map.cpp index 43a49dc2f..689112c7d 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2438,13 +2438,6 @@ void ServerMap::loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool throw SerializationError("ServerMap::loadBlock(): Failed" " to read MapBlock version"); - /*u32 block_size = MapBlock::serializedLength(version); - SharedBuffer data(block_size); - is.read((char*)*data, block_size);*/ - - // This will always return a sector because we're the server - //MapSector *sector = emergeSector(p2d); - MapBlock *block = NULL; bool created_new = false; block = sector->getBlockNoCreateNoEx(p3d.Y); diff --git a/src/mapblock.cpp b/src/mapblock.cpp index 840cb9b39..1a0b01f2b 100644 --- a/src/mapblock.cpp +++ b/src/mapblock.cpp @@ -640,19 +640,15 @@ void MapBlock::serialize(std::ostream &os, u8 version, bool disk) } } -void MapBlock::serializeNetworkSpecific(std::ostream &os, u16 net_proto_version) +void MapBlock::serializeNetworkSpecific(std::ostream &os) { - if(data == NULL) - { + if (!data) { throw SerializationError("ERROR: Not writing dummy block."); } - if(net_proto_version >= 21){ - int version = 1; - writeU8(os, version); - writeF1000(os, 0); // deprecated heat - writeF1000(os, 0); // deprecated humidity - } + writeU8(os, 1); // version + writeF1000(os, 0); // deprecated heat + writeF1000(os, 0); // deprecated humidity } void MapBlock::deSerialize(std::istream &is, u8 version, bool disk) diff --git a/src/mapblock.h b/src/mapblock.h index bec3b6f56..8a7dfc11d 100644 --- a/src/mapblock.h +++ b/src/mapblock.h @@ -541,7 +541,7 @@ public: // unknown blocks from id-name mapping to wndef void deSerialize(std::istream &is, u8 version, bool disk); - void serializeNetworkSpecific(std::ostream &os, u16 net_proto_version); + void serializeNetworkSpecific(std::ostream &os); void deSerializeNetworkSpecific(std::istream &is); private: /* @@ -698,11 +698,11 @@ inline bool blockpos_over_limit(v3s16 p) { const u16 map_gen_limit = MYMIN(MAX_MAP_GENERATION_LIMIT, g_settings->getU16("map_generation_limit")); - return (p.X * MAP_BLOCKSIZE < -map_gen_limit + return (p.X * MAP_BLOCKSIZE < -map_gen_limit || (p.X + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit - || p.Y * MAP_BLOCKSIZE < -map_gen_limit + || p.Y * MAP_BLOCKSIZE < -map_gen_limit || (p.Y + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit - || p.Z * MAP_BLOCKSIZE < -map_gen_limit + || p.Z * MAP_BLOCKSIZE < -map_gen_limit || (p.Z + 1) * MAP_BLOCKSIZE - 1 > map_gen_limit); } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 5301cc91c..ea532d9e0 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -153,14 +153,14 @@ with this program; if not, write to the Free Software Foundation, Inc., #define LATEST_PROTOCOL_VERSION 30 // Server's supported network protocol range -#define SERVER_PROTOCOL_VERSION_MIN 13 +#define SERVER_PROTOCOL_VERSION_MIN 24 #define SERVER_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION // Client's supported network protocol range // The minimal version depends on whether // send_pre_v25_init is enabled or not #define CLIENT_PROTOCOL_VERSION_MIN 25 -#define CLIENT_PROTOCOL_VERSION_MIN_LEGACY 13 +#define CLIENT_PROTOCOL_VERSION_MIN_LEGACY 24 #define CLIENT_PROTOCOL_VERSION_MAX LATEST_PROTOCOL_VERSION // Constant that differentiates the protocol from random data and other protocols diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index b707c6fad..e0ea4bf83 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -614,20 +614,6 @@ void Server::handleCommand_Init2(NetworkPacket* pkt) u16 protocol_version = m_clients.getProtocolVersion(pkt->getPeerId()); - ///// begin compatibility code - PlayerSAO* playersao = NULL; - if (protocol_version <= 22) { - playersao = StageTwoClientInit(pkt->getPeerId()); - - if (playersao == NULL) { - actionstream - << "TOSERVER_INIT2 stage 2 client init failed for peer " - << pkt->getPeerId() << std::endl; - return; - } - } - ///// end compatibility code - /* Send some initialization data */ @@ -657,13 +643,6 @@ void Server::handleCommand_Init2(NetworkPacket* pkt) float time_speed = g_settings->getFloat("time_speed"); SendTimeOfDay(pkt->getPeerId(), time, time_speed); - ///// begin compatibility code - if (protocol_version <= 22) { - m_clients.event(pkt->getPeerId(), CSE_SetClientReady); - m_script->on_joinplayer(playersao); - } - ///// end compatibility code - // Warnings about protocol version can be issued here if (getClient(pkt->getPeerId())->net_proto_version < LATEST_PROTOCOL_VERSION) { SendChatMessage(pkt->getPeerId(), L"# Server: WARNING: YOUR CLIENT'S " diff --git a/src/nodedef.cpp b/src/nodedef.cpp index c717b62b9..3532eea1e 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -61,11 +61,10 @@ void NodeBox::reset() void NodeBox::serialize(std::ostream &os, u16 protocol_version) const { - int version = 1; + // Protocol >= 21 + int version = 2; if (protocol_version >= 27) version = 3; - else if (protocol_version >= 21) - version = 2; writeU8(os, version); switch (type) { @@ -195,14 +194,12 @@ void TileDef::serialize(std::ostream &os, u16 protocol_version) const writeU8(os, 3); else if (protocol_version >= 26) writeU8(os, 2); - else if (protocol_version >= 17) - writeU8(os, 1); else - writeU8(os, 0); - os<= 17) - writeU8(os, backface_culling); + writeU8(os, backface_culling); if (protocol_version >= 26) { writeU8(os, tileable_horizontal); writeU8(os, tileable_vertical); @@ -1615,109 +1612,8 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const if (protocol_version < 30 && drawtype == NDT_PLANTLIKE) compatible_visual_scale = sqrt(visual_scale); - if (protocol_version == 13) - { - writeU8(os, 5); // version - os<first); - writeS16(os, i->second); - } - writeU8(os, drawtype); - writeF1000(os, compatible_visual_scale); - writeU8(os, 6); - for (u32 i = 0; i < 6; i++) - tiledef[i].serialize(os, protocol_version); - //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24 - writeU8(os, 2); - for (u32 i = 0; i < 2; i++) - tiledef_special[i].serialize(os, protocol_version); - writeU8(os, alpha); - writeU8(os, post_effect_color.getAlpha()); - writeU8(os, post_effect_color.getRed()); - writeU8(os, post_effect_color.getGreen()); - writeU8(os, post_effect_color.getBlue()); - writeU8(os, param_type); - writeU8(os, compatible_param_type_2); - writeU8(os, is_ground_content); - writeU8(os, light_propagates); - writeU8(os, sunlight_propagates); - writeU8(os, walkable); - writeU8(os, pointable); - writeU8(os, diggable); - writeU8(os, climbable); - writeU8(os, buildable_to); - os< 13 && protocol_version < 24) { - writeU8(os, 6); // version - os<first); - writeS16(os, i->second); - } - writeU8(os, drawtype); - writeF1000(os, compatible_visual_scale); - writeU8(os, 6); - for (u32 i = 0; i < 6; i++) - tiledef[i].serialize(os, protocol_version); - //CF_SPECIAL_COUNT = 2 before cf ver. 7 and protocol ver. 24 - writeU8(os, 2); - for (u32 i = 0; i < 2; i++) - tiledef_special[i].serialize(os, protocol_version); - writeU8(os, alpha); - writeU8(os, post_effect_color.getAlpha()); - writeU8(os, post_effect_color.getRed()); - writeU8(os, post_effect_color.getGreen()); - writeU8(os, post_effect_color.getBlue()); - writeU8(os, param_type); - writeU8(os, compatible_param_type_2); - writeU8(os, is_ground_content); - writeU8(os, light_propagates); - writeU8(os, sunlight_propagates); - writeU8(os, walkable); - writeU8(os, pointable); - writeU8(os, diggable); - writeU8(os, climbable); - writeU8(os, buildable_to); - os<= 24 && protocol_version < 30) { + // Protocol >= 24 + if (protocol_version < 30) { writeU8(os, protocol_version < 27 ? 7 : 8); os << serializeString(name); @@ -1778,9 +1674,10 @@ void ContentFeatures::serializeOld(std::ostream &os, u16 protocol_version) const i != connects_to_ids.end(); ++i) writeU16(os, *i); writeU8(os, connect_sides); - } else + } else { throw SerializationError("ContentFeatures::serialize(): " "Unsupported version requested"); + } } void ContentFeatures::deSerializeOld(std::istream &is, int version) diff --git a/src/server.cpp b/src/server.cpp index 9ed2a045d..8e9313464 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2147,14 +2147,6 @@ void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id, if (client != 0) { pkt << p << n.param0 << n.param1 << n.param2 << (u8) (remove_metadata ? 0 : 1); - - if (!remove_metadata) { - if (client->net_proto_version <= 21) { - // Old clients always clear metadata; fix it - // by sending the full block again. - client->SetBlockNotSent(getNodeBlockPos(p)); - } - } } m_clients.unlock(); @@ -2188,7 +2180,7 @@ void Server::SendBlockNoLock(u16 peer_id, MapBlock *block, u8 ver, u16 net_proto std::ostringstream os(std::ios_base::binary); block->serialize(os, ver, false); - block->serializeNetworkSpecific(os, net_proto_version); + block->serializeNetworkSpecific(os); std::string s = os.str(); NetworkPacket pkt(TOCLIENT_BLOCKDATA, 2 + 2 + 2 + 2 + s.size(), peer_id); diff --git a/src/tool.cpp b/src/tool.cpp index 20b71fb31..1877a1cf8 100644 --- a/src/tool.cpp +++ b/src/tool.cpp @@ -27,33 +27,30 @@ with this program; if not, write to the Free Software Foundation, Inc., void ToolCapabilities::serialize(std::ostream &os, u16 protocol_version) const { - if(protocol_version <= 17) - writeU8(os, 1); // version - else - writeU8(os, 2); // version + writeU8(os, 2); // version (protocol >= 18) writeF1000(os, full_punch_interval); writeS16(os, max_drop_level); writeU32(os, groupcaps.size()); for (ToolGCMap::const_iterator i = groupcaps.begin(); i != groupcaps.end(); ++i) { const std::string *name = &i->first; const ToolGroupCap *cap = &i->second; - os<uses); writeS16(os, cap->maxlevel); writeU32(os, cap->times.size()); for (UNORDERED_MAP::const_iterator - i = cap->times.begin(); i != cap->times.end(); ++i) { - writeS16(os, i->first); - writeF1000(os, i->second); + j = cap->times.begin(); j != cap->times.end(); ++j) { + writeS16(os, j->first); + writeF1000(os, j->second); } } - if(protocol_version > 17){ - writeU32(os, damageGroups.size()); - for (DamageGroup::const_iterator i = damageGroups.begin(); - i != damageGroups.end(); ++i) { - os<first); - writeS16(os, i->second); - } + + writeU32(os, damageGroups.size()); + + for (DamageGroup::const_iterator i = damageGroups.begin(); + i != damageGroups.end(); ++i) { + os << serializeString(i->first); + writeS16(os, i->second); } } -- cgit v1.2.3 From 525d2a0d511bc9e9f3691af6ed2f5284dd205e33 Mon Sep 17 00:00:00 2001 From: sfan5 Date: Sun, 19 Mar 2017 18:17:59 +0100 Subject: Fix /shutdown or ^C no longer causing server exit Broken since b8484ef24e8e1ec90a2967372808ab2bea538c7c --- src/server.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index 8e9313464..0daa61054 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3569,6 +3569,9 @@ void dedicated_server_loop(Server &server, bool &kill) } server.step(steplen); + if (server.getShutdownRequested() || kill) + break; + /* Profiler */ -- cgit v1.2.3 From 351cc2e79a7d78f7ec97ff9b33e4f0bad4042b19 Mon Sep 17 00:00:00 2001 From: presstabstart Date: Fri, 7 Apr 2017 04:32:50 +0100 Subject: Fix multiple death messages (#5305) Fix multiple death messages (#3565) and damage server logs after death. --- src/content_sao.cpp | 4 ++-- src/network/serverpackethandler.cpp | 7 +++++++ src/server.cpp | 11 +++++------ 3 files changed, 14 insertions(+), 8 deletions(-) (limited to 'src/server.cpp') diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 69f80d356..ea2a4ebf6 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -919,8 +919,8 @@ void PlayerSAO::step(float dtime, bool send_recommended) MapNode n = m_env->getMap().getNodeNoEx(p); const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n); // If node generates drown - if (c.drowning > 0) { - if (m_hp > 0 && m_breath > 0) + if (c.drowning > 0 && m_hp > 0) { + if (m_breath > 0) setBreath(m_breath - 1); // No more breath, damage player diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index e0ea4bf83..95df6fc4f 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1107,6 +1107,13 @@ void Server::handleCommand_Damage(NetworkPacket* pkt) } if (g_settings->getBool("enable_damage")) { + if (playerSAO->isDead()) { + verbosestream << "Server::ProcessData(): Info: " + "Ignoring damage as player " << player->getName() + << " is already dead." << std::endl; + return; + } + actionstream << player->getName() << " damaged by " << (int)damage << " hp at " << PP(playersao->getBasePosition() / BS) << std::endl; diff --git a/src/server.cpp b/src/server.cpp index 0daa61054..224af47a7 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1111,16 +1111,15 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id) // Send inventory SendInventory(playersao); - // Send HP - SendPlayerHPOrDie(playersao); + // Send HP or death screen + if (playersao->isDead()) + SendDeathscreen(peer_id, false, v3f(0,0,0)); + else + SendPlayerHPOrDie(playersao); // Send Breath SendPlayerBreath(playersao); - // Show death screen if necessary - if (playersao->isDead()) - SendDeathscreen(peer_id, false, v3f(0,0,0)); - // Note things in chat if not in simple singleplayer mode if (!m_simple_singleplayer_mode && g_settings->getBool("show_statusline_on_connect")) { // Send information about server to player in chat -- cgit v1.2.3 From d4e9dd4643607192f5adebeecda86f25074f02cd Mon Sep 17 00:00:00 2001 From: red-001 Date: Sat, 8 Apr 2017 19:03:57 +0100 Subject: Move chat command handling code from C++ to Lua (#5528) --- builtin/game/chatcommands.lua | 15 ++++++++++++--- src/server.cpp | 23 ++++++----------------- 2 files changed, 18 insertions(+), 20 deletions(-) (limited to 'src/server.cpp') diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua index 16f5f3be9..8df3903d2 100644 --- a/builtin/game/chatcommands.lua +++ b/builtin/game/chatcommands.lua @@ -7,13 +7,22 @@ core.chatcommands = core.registered_chatcommands -- BACKWARDS COMPATIBILITY core.register_on_chat_message(function(name, message) + if message:sub(1,1) ~= "/" then + return + end + local cmd, param = string.match(message, "^/([^ ]+) *(.*)") - if not param then - param = "" + if not cmd then + core.chat_send_player(name, "-!- Empty command") + return true end + + param = param or "" + local cmd_def = core.registered_chatcommands[cmd] if not cmd_def then - return false + core.chat_send_player(name, "-!- Invalid command: " .. cmd) + return true end local has_privs, missing_privs = core.check_player_privs(name, cmd_def.privs) if has_privs then diff --git a/src/server.cpp b/src/server.cpp index 224af47a7..02e365718 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2820,25 +2820,14 @@ std::wstring Server::handleChat(const std::string &name, const std::wstring &wna // Whether to send line to the player that sent the message, or to all players bool broadcast_line = true; - // Commands are implemented in Lua, so only catch invalid - // commands that were not "eaten" and send an error back - if (wmessage[0] == L'/') { - std::wstring wcmd = wmessage.substr(1); + if (check_shout_priv && !checkPriv(name, "shout")) { + line += L"-!- You don't have permission to shout."; broadcast_line = false; - if (wcmd.length() == 0) - line += L"-!- Empty command"; - else - line += L"-!- Invalid command: " + str_split(wcmd, L' ')[0]; } else { - if (check_shout_priv && !checkPriv(name, "shout")) { - line += L"-!- You don't have permission to shout."; - broadcast_line = false; - } else { - line += L"<"; - line += wname; - line += L"> "; - line += wmessage; - } + line += L"<"; + line += wname; + line += L"> "; + line += wmessage; } /* -- cgit v1.2.3 From b0be7ab61ec9ca04f2618db2d60f75396f205a58 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Fri, 14 Apr 2017 15:34:01 +0200 Subject: ClientIface::sendToAll: honor packet configuration (#5590) --- src/clientiface.cpp | 12 +++++++----- src/clientiface.h | 2 +- src/server.cpp | 8 ++++---- 3 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src/server.cpp') diff --git a/src/clientiface.cpp b/src/clientiface.cpp index 39223d3eb..64fa1c6b7 100644 --- a/src/clientiface.cpp +++ b/src/clientiface.cpp @@ -30,6 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "emerge.h" #include "content_sao.h" // TODO this is used for cleanup of only #include "log.h" +#include "network/serveropcodes.h" #include "util/srp.h" const char *ClientInterface::statenames[] = { @@ -678,16 +679,17 @@ void ClientInterface::send(u16 peer_id, u8 channelnum, m_con->Send(peer_id, channelnum, pkt, reliable); } -void ClientInterface::sendToAll(u16 channelnum, - NetworkPacket* pkt, bool reliable) +void ClientInterface::sendToAll(NetworkPacket *pkt) { MutexAutoLock clientslock(m_clients_mutex); - for(UNORDERED_MAP::iterator i = m_clients.begin(); - i != m_clients.end(); ++i) { + for (UNORDERED_MAP::iterator i = m_clients.begin(); + i != m_clients.end(); ++i) { RemoteClient *client = i->second; if (client->net_proto_version != 0) { - m_con->Send(client->peer_id, channelnum, pkt, reliable); + m_con->Send(client->peer_id, + clientCommandFactoryTable[pkt->getCommand()].channel, pkt, + clientCommandFactoryTable[pkt->getCommand()].reliable); } } } diff --git a/src/clientiface.h b/src/clientiface.h index f002f37fb..403cd0420 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -458,7 +458,7 @@ public: void send(u16 peer_id, u8 channelnum, NetworkPacket* pkt, bool reliable); /* send to all clients */ - void sendToAll(u16 channelnum, NetworkPacket* pkt, bool reliable); + void sendToAll(NetworkPacket *pkt); /* delete a client */ void DeleteClient(u16 peer_id); diff --git a/src/server.cpp b/src/server.cpp index 02e365718..7ed8a8bf4 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1642,7 +1642,7 @@ void Server::SendChatMessage(u16 peer_id, const std::wstring &message) Send(&pkt); } else { - m_clients.sendToAll(0, &pkt, true); + m_clients.sendToAll(&pkt); } } @@ -1761,7 +1761,7 @@ void Server::SendDeleteParticleSpawner(u16 peer_id, u32 id) Send(&pkt); } else { - m_clients.sendToAll(0, &pkt, true); + m_clients.sendToAll(&pkt); } } @@ -1866,7 +1866,7 @@ void Server::SendTimeOfDay(u16 peer_id, u16 time, f32 time_speed) pkt << time << time_speed; if (peer_id == PEER_ID_INEXISTENT) { - m_clients.sendToAll(0, &pkt, true); + m_clients.sendToAll(&pkt); } else { Send(&pkt); @@ -2519,7 +2519,7 @@ void Server::sendDetachedInventory(const std::string &name, u16 peer_id) const std::string &check = m_detached_inventories_player[name]; if (peer_id == PEER_ID_INEXISTENT) { if (check == "") - return m_clients.sendToAll(0, &pkt, true); + return m_clients.sendToAll(&pkt); RemotePlayer *p = m_env->getPlayer(check.c_str()); if (p) m_clients.send(p->peer_id, 0, &pkt, true); -- cgit v1.2.3 From 34d32ce55ae4f3f29d7b645075dc8efacb2c96d2 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sat, 15 Apr 2017 23:19:18 +0200 Subject: Implement delayed server shutdown with cancelation (#4664) --- builtin/game/chatcommands.lua | 16 ++++++--- builtin/game/misc.lua | 5 +++ doc/lua_api.txt | 8 +++-- src/network/serverpackethandler.cpp | 7 ++++ src/script/lua_api/l_server.cpp | 3 +- src/server.cpp | 67 +++++++++++++++++++++++++++++++++++++ src/server.h | 8 ++--- src/util/string.h | 24 +++++++++++++ 8 files changed, 124 insertions(+), 14 deletions(-) (limited to 'src/server.cpp') diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua index 8df3903d2..25cc06178 100644 --- a/builtin/game/chatcommands.lua +++ b/builtin/game/chatcommands.lua @@ -763,14 +763,20 @@ core.register_chatcommand("days", { core.register_chatcommand("shutdown", { description = "Shutdown server", - params = "[reconnect] [message]", + params = "[delay_in_seconds(0..inf) or -1 for cancel] [reconnect] [message]", privs = {server=true}, func = function(name, param) - core.log("action", name .. " shuts down server") - core.chat_send_all("*** Server shutting down (operator request).") - local reconnect, message = param:match("([^ ]+)(.*)") + local delay, reconnect, message = param:match("([^ ][-]?[0-9]+)([^ ]+)(.*)") message = message or "" - core.request_shutdown(message:trim(), core.is_yes(reconnect)) + + if delay ~= "" then + delay = tonumber(param) or 0 + else + delay = 0 + core.log("action", name .. " shuts down server") + core.chat_send_all("*** Server shutting down (operator request).") + end + core.request_shutdown(message:trim(), core.is_yes(reconnect), delay) end, }) diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua index 618d4d97f..a3eb26ac2 100644 --- a/builtin/game/misc.lua +++ b/builtin/game/misc.lua @@ -173,3 +173,8 @@ end function core.close_formspec(player_name, formname) return minetest.show_formspec(player_name, formname, "") end + +function core.cancel_shutdown_requests() + core.request_shutdown("", false, -1) +end + diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 721f5448a..7b967726d 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2576,8 +2576,12 @@ These functions return the leftover itemstack. * Optional: Variable number of arguments that are passed to `func` ### Server -* `minetest.request_shutdown([message],[reconnect])`: request for server shutdown. Will display `message` to clients, - and `reconnect` == true displays a reconnect button. +* `minetest.request_shutdown([message],[reconnect],[delay])`: request for server shutdown. Will display `message` to clients, + `reconnect` == true displays a reconnect button, + `delay` adds an optional delay (in seconds) before shutdown + negative delay cancels the current active shutdown + zero delay triggers an immediate shutdown. +* `minetest.cancel_shutdown_requests()`: cancel current delayed shutdown * `minetest.get_server_status()`: returns server status string * `minetest.get_server_uptime()`: returns the server uptime in seconds diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 27c33a4f6..2e4c5b6be 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -722,6 +722,13 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt) m_clients.event(peer_id, CSE_SetClientReady); m_script->on_joinplayer(playersao); + // Send shutdown timer if shutdown has been scheduled + if (m_shutdown_timer > 0.0f) { + std::wstringstream ws; + ws << L"*** Server shutting down in " + << duration_to_string(round(m_shutdown_timer)).c_str() << "."; + SendChatMessage(pkt->getPeerId(), ws.str()); + } } void Server::handleCommand_GotBlocks(NetworkPacket* pkt) diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index b6d44e0ff..343d11b7e 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -33,7 +33,8 @@ int ModApiServer::l_request_shutdown(lua_State *L) NO_MAP_LOCK_REQUIRED; const char *msg = lua_tolstring(L, 1, NULL); bool reconnect = lua_toboolean(L, 2); - getServer(L)->requestShutdown(msg ? msg : "", reconnect); + float seconds_before_shutdown = lua_tonumber(L, 3); + getServer(L)->requestShutdown(msg ? msg : "", reconnect, seconds_before_shutdown); return 0; } diff --git a/src/server.cpp b/src/server.cpp index 7ed8a8bf4..5328b6897 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -177,6 +177,7 @@ Server::Server( m_clients(&m_con), m_shutdown_requested(false), m_shutdown_ask_reconnect(false), + m_shutdown_timer(0.0f), m_admin_chat(iface), m_ignore_map_edit_events(false), m_ignore_map_edit_events_peer_id(0), @@ -1029,6 +1030,39 @@ void Server::AsyncRunStep(bool initial_step) m_env->saveMeta(); } } + + // Timed shutdown + static const float shutdown_msg_times[] = + { + 1, 2, 3, 4, 5, 10, 15, 20, 25, 30, 45, 60, 120, 180, 300, 600, 1200, 1800, 3600 + }; + + if (m_shutdown_timer > 0.0f) { + // Automated messages + if (m_shutdown_timer < shutdown_msg_times[ARRLEN(shutdown_msg_times) - 1]) { + for (u16 i = 0; i < ARRLEN(shutdown_msg_times) - 1; i++) { + // If shutdown timer matches an automessage, shot it + if (m_shutdown_timer > shutdown_msg_times[i] && + m_shutdown_timer - dtime < shutdown_msg_times[i]) { + std::wstringstream ws; + + ws << L"*** Server shutting down in " + << duration_to_string(round(m_shutdown_timer - dtime)).c_str() + << "."; + + infostream << wide_to_utf8(ws.str()).c_str() << std::endl; + SendChatMessage(PEER_ID_INEXISTENT, ws.str()); + break; + } + } + } + + m_shutdown_timer -= dtime; + if (m_shutdown_timer < 0.0f) { + m_shutdown_timer = 0.0f; + m_shutdown_requested = true; + } + } } void Server::Receive() @@ -3443,6 +3477,39 @@ v3f Server::findSpawnPos() return nodeposf; } +void Server::requestShutdown(const std::string &msg, bool reconnect, float delay) +{ + if (delay == 0.0f) { + // No delay, shutdown immediately + m_shutdown_requested = true; + } else if (delay < 0.0f && m_shutdown_timer > 0.0f) { + // Negative delay, cancel shutdown if requested + m_shutdown_timer = 0.0f; + m_shutdown_msg = ""; + m_shutdown_ask_reconnect = false; + m_shutdown_requested = false; + std::wstringstream ws; + + ws << L"*** Server shutdown canceled."; + + infostream << wide_to_utf8(ws.str()).c_str() << std::endl; + SendChatMessage(PEER_ID_INEXISTENT, ws.str()); + } else if (delay > 0.0f) { + // Positive delay, delay the shutdown + m_shutdown_timer = delay; + m_shutdown_msg = msg; + m_shutdown_ask_reconnect = reconnect; + std::wstringstream ws; + + ws << L"*** Server shutting down in " + << duration_to_string(round(m_shutdown_timer)).c_str() + << "."; + + infostream << wide_to_utf8(ws.str()).c_str() << std::endl; + SendChatMessage(PEER_ID_INEXISTENT, ws.str()); + } +} + PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version) { bool newplayer = false; diff --git a/src/server.h b/src/server.h index 1df9d0a93..e2445f833 100644 --- a/src/server.h +++ b/src/server.h @@ -226,12 +226,7 @@ public: inline bool getShutdownRequested() const { return m_shutdown_requested; } // request server to shutdown - void requestShutdown(const std::string &msg, bool reconnect) - { - m_shutdown_requested = true; - m_shutdown_msg = msg; - m_shutdown_ask_reconnect = reconnect; - } + void requestShutdown(const std::string &msg, bool reconnect, float delay = 0.0f); // Returns -1 if failed, sound handle on success // Envlock @@ -602,6 +597,7 @@ private: bool m_shutdown_requested; std::string m_shutdown_msg; bool m_shutdown_ask_reconnect; + float m_shutdown_timer; ChatInterface *m_admin_chat; std::string m_admin_nick; diff --git a/src/util/string.h b/src/util/string.h index 572c37150..c155d2f4a 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -614,4 +614,28 @@ inline const char *bool_to_cstr(bool val) return val ? "true" : "false"; } +inline const std::string duration_to_string(int sec) +{ + int min = floor(sec / 60); + sec %= 60; + int hour = floor(min / 60); + min %= 60; + + std::stringstream ss; + if (hour > 0) { + ss << hour << "h "; + } + + if (min > 0) { + ss << min << "m "; + } + + if (sec > 0) { + ss << sec << "s "; + } + + return ss.str(); +} + + #endif -- cgit v1.2.3 From 61202513208b23d3e7a2a91d10aba154e6cbf352 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Mon, 17 Apr 2017 13:49:48 +0200 Subject: Fix MSVC build broken by 34d32ce `round` -> `myround` Remove superflous `floor` calls --- src/network/serverpackethandler.cpp | 2 +- src/server.cpp | 4 ++-- src/util/string.h | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src/server.cpp') diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index 2e4c5b6be..174b827f0 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -726,7 +726,7 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt) if (m_shutdown_timer > 0.0f) { std::wstringstream ws; ws << L"*** Server shutting down in " - << duration_to_string(round(m_shutdown_timer)).c_str() << "."; + << duration_to_string(myround(m_shutdown_timer)).c_str() << "."; SendChatMessage(pkt->getPeerId(), ws.str()); } } diff --git a/src/server.cpp b/src/server.cpp index 5328b6897..a9e5c3d08 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1047,7 +1047,7 @@ void Server::AsyncRunStep(bool initial_step) std::wstringstream ws; ws << L"*** Server shutting down in " - << duration_to_string(round(m_shutdown_timer - dtime)).c_str() + << duration_to_string(myround(m_shutdown_timer - dtime)).c_str() << "."; infostream << wide_to_utf8(ws.str()).c_str() << std::endl; @@ -3502,7 +3502,7 @@ void Server::requestShutdown(const std::string &msg, bool reconnect, float delay std::wstringstream ws; ws << L"*** Server shutting down in " - << duration_to_string(round(m_shutdown_timer)).c_str() + << duration_to_string(myround(m_shutdown_timer)).c_str() << "."; infostream << wide_to_utf8(ws.str()).c_str() << std::endl; diff --git a/src/util/string.h b/src/util/string.h index c155d2f4a..1a0b9f60d 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -616,9 +616,9 @@ inline const char *bool_to_cstr(bool val) inline const std::string duration_to_string(int sec) { - int min = floor(sec / 60); + int min = sec / 60; sec %= 60; - int hour = floor(min / 60); + int hour = min / 60; min %= 60; std::stringstream ss; -- cgit v1.2.3 From f151b2322003bbc89c2cd3c603ef1e1ab9d46439 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Fri, 21 Apr 2017 19:31:59 +0200 Subject: Fix #5617 - respect message and reconnect parameters when shutting down immediately (#5621) --- src/server.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index a9e5c3d08..a921423d2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -3479,9 +3479,16 @@ v3f Server::findSpawnPos() void Server::requestShutdown(const std::string &msg, bool reconnect, float delay) { + m_shutdown_timer = delay; + m_shutdown_msg = msg; + m_shutdown_ask_reconnect = reconnect; + if (delay == 0.0f) { // No delay, shutdown immediately m_shutdown_requested = true; + // only print to the infostream, a chat message saying + // "Server Shutting Down" is sent when the server destructs. + infostream << "*** Immediate Server shutdown requested." << std::endl; } else if (delay < 0.0f && m_shutdown_timer > 0.0f) { // Negative delay, cancel shutdown if requested m_shutdown_timer = 0.0f; @@ -3495,10 +3502,7 @@ void Server::requestShutdown(const std::string &msg, bool reconnect, float delay infostream << wide_to_utf8(ws.str()).c_str() << std::endl; SendChatMessage(PEER_ID_INEXISTENT, ws.str()); } else if (delay > 0.0f) { - // Positive delay, delay the shutdown - m_shutdown_timer = delay; - m_shutdown_msg = msg; - m_shutdown_ask_reconnect = reconnect; + // Positive delay, tell the clients when the server will shut down std::wstringstream ws; ws << L"*** Server shutting down in " -- cgit v1.2.3 From cca58fe0fd1aac4246a23e1fc4f8469bdd280c6d Mon Sep 17 00:00:00 2001 From: Auke Kok Date: Wed, 19 Apr 2017 23:10:39 -0700 Subject: Add on_flood() callback. This callback is called if a liquid definitely floods a non-air node on the map. The callback arguments are (pos, oldnode, newnode) and can return a `bool` value indicating whether flooding the node should be cancelled (`return true` will prevent the node from flooding). Documentation is added, the callback function was tested with a modified minetest_game. Note that `return true` will likely cause the node's `on_flood()` callback to be called every second until the node gets removed, so care must be taken to prevent many callbacks from using this return value. The current default liquid update interval is 1.0 seconds, which isn't unmanageable. The larger aim of this patch is to remove the lava cooling ABM, which is a significant cost to idle servers that have lava on their map. This callback will be much more efficient. --- doc/lua_api.txt | 7 +++++++ src/map.cpp | 12 +++++++++++- src/map.h | 3 ++- src/script/cpp_api/s_node.cpp | 21 +++++++++++++++++++++ src/script/cpp_api/s_node.h | 1 + src/server.cpp | 2 +- 6 files changed, 43 insertions(+), 3 deletions(-) (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 4e328ac76..774b1e992 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -4002,6 +4002,13 @@ Definition tables ^ Node destructor; called after removing node ^ Not called for bulk node placement (i.e. schematics and VoxelManip) ^ default: nil ]] + on_flood = func(pos, oldnode, newnode), --[[ + ^ Called when a liquid (newnode) is about to flood oldnode, if + ^ it has `floodable = true` in the nodedef. Not called for bulk + ^ node placement (i.e. schematics and VoxelManip) or air nodes. If + ^ return true the node is not flooded, but on_flood callback will + ^ most likely be called over and over again every liquid update + ^ interval. Default: nil ]] after_place_node = func(pos, placer, itemstack, pointed_thing) --[[ ^ Called after constructing node when node was placed using diff --git a/src/map.cpp b/src/map.cpp index 8754813dd..75dcee350 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database.h" #include "database-dummy.h" #include "database-sqlite3.h" +#include "script/serverscripting.h" #include #include #if USE_LEVELDB @@ -637,7 +638,8 @@ s32 Map::transforming_liquid_size() { return m_transforming_liquid.size(); } -void Map::transformLiquids(std::map &modified_blocks) +void Map::transformLiquids(std::map &modified_blocks, + ServerEnvironment *env) { DSTACK(FUNCTION_NAME); //TimeTaker timer("transformLiquids()"); @@ -897,8 +899,16 @@ void Map::transformLiquids(std::map &modified_blocks) // set the liquid level and flow bit to 0 n0.param2 = ~(LIQUID_LEVEL_MASK | LIQUID_FLOW_DOWN_MASK); } + + // change the node. n0.setContent(new_node_content); + // on_flood() the node + if (floodable_node != CONTENT_AIR) { + if (env->getScriptIface()->node_on_flood(p0, n00, n0)) + continue; + } + // Ignore light (because calling voxalgo::update_lighting_nodes) n0.setLight(LIGHTBANK_DAY, 0, m_nodedef); n0.setLight(LIGHTBANK_NIGHT, 0, m_nodedef); diff --git a/src/map.h b/src/map.h index 739cdb59b..4d7079823 100644 --- a/src/map.h +++ b/src/map.h @@ -266,7 +266,8 @@ public: // For debug printing. Prints "Map: ", "ServerMap: " or "ClientMap: " virtual void PrintInfo(std::ostream &out); - void transformLiquids(std::map & modified_blocks); + void transformLiquids(std::map & modified_blocks, + ServerEnvironment *env); /* Node metadata diff --git a/src/script/cpp_api/s_node.cpp b/src/script/cpp_api/s_node.cpp index adad01e45..2723f84e1 100644 --- a/src/script/cpp_api/s_node.cpp +++ b/src/script/cpp_api/s_node.cpp @@ -178,6 +178,27 @@ void ScriptApiNode::node_on_destruct(v3s16 p, MapNode node) lua_pop(L, 1); // Pop error handler } +bool ScriptApiNode::node_on_flood(v3s16 p, MapNode node, MapNode newnode) +{ + SCRIPTAPI_PRECHECKHEADER + + int error_handler = PUSH_ERROR_HANDLER(L); + + INodeDefManager *ndef = getServer()->ndef(); + + // Push callback function on stack + if (!getItemCallback(ndef->get(node).name.c_str(), "on_flood")) + return false; + + // Call function + push_v3s16(L, p); + pushnode(L, node, ndef); + pushnode(L, newnode, ndef); + PCALL_RES(lua_pcall(L, 3, 1, error_handler)); + lua_remove(L, error_handler); + return (bool) lua_isboolean(L, -1) && (bool) lua_toboolean(L, -1) == true; +} + void ScriptApiNode::node_after_destruct(v3s16 p, MapNode node) { SCRIPTAPI_PRECHECKHEADER diff --git a/src/script/cpp_api/s_node.h b/src/script/cpp_api/s_node.h index fe1180cb3..eb127909d 100644 --- a/src/script/cpp_api/s_node.h +++ b/src/script/cpp_api/s_node.h @@ -42,6 +42,7 @@ public: ServerActiveObject *digger); void node_on_construct(v3s16 p, MapNode node); void node_on_destruct(v3s16 p, MapNode node); + bool node_on_flood(v3s16 p, MapNode node, MapNode newnode); void node_after_destruct(v3s16 p, MapNode node); bool node_on_timer(v3s16 p, MapNode node, f32 dtime); void node_on_receive_fields(v3s16 p, diff --git a/src/server.cpp b/src/server.cpp index a921423d2..ac6265d09 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -599,7 +599,7 @@ void Server::AsyncRunStep(bool initial_step) ScopeProfiler sp(g_profiler, "Server: liquid transform"); std::map modified_blocks; - m_env->getMap().transformLiquids(modified_blocks); + m_env->getMap().transformLiquids(modified_blocks, m_env); #if 0 /* Update lighting -- cgit v1.2.3 From 29ab20c27229672c24a7699afbcd54caad903331 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sun, 23 Apr 2017 14:35:08 +0200 Subject: Player data to Database (#5475) * Player data to Database Add player data into databases (SQLite3 & PG only) PostgreSQL & SQLite: better POO Design for databases Add --migrate-players argument to server + deprecation warning * Remove players directory if empty --- build/android/jni/Android.mk | 1 + builtin/game/chatcommands.lua | 25 +++ doc/lua_api.txt | 2 + src/CMakeLists.txt | 1 + src/client.cpp | 2 +- src/client.h | 4 +- src/content_sao.cpp | 7 +- src/content_sao.h | 4 +- src/database-dummy.h | 9 +- src/database-files.cpp | 179 +++++++++++++++ src/database-files.h | 46 ++++ src/database-leveldb.h | 4 +- src/database-postgresql.cpp | 470 ++++++++++++++++++++++++++++++++++------ src/database-postgresql.h | 115 +++++++--- src/database-redis.h | 2 +- src/database-sqlite3.cpp | 399 +++++++++++++++++++++++++++++++--- src/database-sqlite3.h | 158 ++++++++++++-- src/database.cpp | 4 +- src/database.h | 24 +- src/main.cpp | 21 +- src/map.cpp | 13 +- src/map.h | 8 +- src/remoteplayer.cpp | 48 ---- src/remoteplayer.h | 2 +- src/script/lua_api/l_server.cpp | 17 ++ src/script/lua_api/l_server.h | 3 + src/server.cpp | 50 +---- src/server.h | 3 +- src/serverenvironment.cpp | 234 ++++++++++++++++---- src/serverenvironment.h | 13 +- src/unittest/test_player.cpp | 49 ----- 31 files changed, 1547 insertions(+), 370 deletions(-) create mode 100644 src/database-files.cpp create mode 100644 src/database-files.h (limited to 'src/server.cpp') diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index 2929eaba1..b652c6b5e 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -134,6 +134,7 @@ LOCAL_SRC_FILES := \ jni/src/convert_json.cpp \ jni/src/craftdef.cpp \ jni/src/database-dummy.cpp \ + jni/src/database-files.cpp \ jni/src/database-sqlite3.cpp \ jni/src/database.cpp \ jni/src/debug.cpp \ diff --git a/builtin/game/chatcommands.lua b/builtin/game/chatcommands.lua index 84f2c3fed..cbf75c1bc 100644 --- a/builtin/game/chatcommands.lua +++ b/builtin/game/chatcommands.lua @@ -279,6 +279,31 @@ core.register_chatcommand("auth_reload", { end, }) +core.register_chatcommand("remove_player", { + params = "", + description = "Remove player data", + privs = {server=true}, + func = function(name, param) + local toname = param + if toname == "" then + return false, "Name field required" + end + + local rc = core.remove_player(toname) + + if rc == 0 then + core.log("action", name .. " removed player data of " .. toname .. ".") + return true, "Player \"" .. toname .. "\" removed." + elseif rc == 1 then + return true, "No such player \"" .. toname .. "\" to remove." + elseif rc == 2 then + return true, "Player \"" .. toname .. "\" is connected, cannot remove." + end + + return false, "Unhandled remove_player return code " .. rc .. "" + end, +}) + core.register_chatcommand("teleport", { params = ",, | | ,, | ", description = "Teleport to player or position", diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 33254fb2a..c3d8d2bf6 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2599,6 +2599,8 @@ These functions return the leftover itemstack. * `minetest.cancel_shutdown_requests()`: cancel current delayed shutdown * `minetest.get_server_status()`: returns server status string * `minetest.get_server_uptime()`: returns the server uptime in seconds +* `minetest.remove_player(name)`: remove player from database (if he is not connected). + * Returns a code (0: successful, 1: no such player, 2: player is connected) ### Bans * `minetest.get_ban_list()`: returns the ban list (same as `minetest.get_ban_description("")`) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 37f72a44d..7f779db10 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -377,6 +377,7 @@ set(common_SRCS convert_json.cpp craftdef.cpp database-dummy.cpp + database-files.cpp database-leveldb.cpp database-postgresql.cpp database-redis.cpp diff --git a/src/client.cpp b/src/client.cpp index ce42d025e..94c808a57 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -770,7 +770,7 @@ void Client::initLocalMapSaving(const Address &address, fs::CreateAllDirs(world_path); - m_localdb = new Database_SQLite3(world_path); + m_localdb = new MapDatabaseSQLite3(world_path); m_localdb->beginSave(); actionstream << "Local map saving started, map will be saved at '" << world_path << "'" << std::endl; } diff --git a/src/client.h b/src/client.h index 5dc3f9bc8..328a24f90 100644 --- a/src/client.h +++ b/src/client.h @@ -49,7 +49,7 @@ class ClientMediaDownloader; struct MapDrawControl; class MtEventManager; struct PointedThing; -class Database; +class MapDatabase; class Minimap; struct MinimapMapblock; class Camera; @@ -645,7 +645,7 @@ private: LocalClientState m_state; // Used for saving server map to disk client-side - Database *m_localdb; + MapDatabase *m_localdb; IntervalLimiter m_localdb_save_interval; u16 m_cache_save_interval; diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 355453fc9..caf6dcbab 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -764,9 +764,10 @@ bool LuaEntitySAO::collideWithObjects() const // No prototype, PlayerSAO does not need to be deserialized -PlayerSAO::PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer): +PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id_, + bool is_singleplayer): UnitSAO(env_, v3f(0,0,0)), - m_player(NULL), + m_player(player_), m_peer_id(peer_id_), m_inventory(NULL), m_damage(0), @@ -819,7 +820,7 @@ PlayerSAO::~PlayerSAO() delete m_inventory; } -void PlayerSAO::initialize(RemotePlayer *player, const std::set &privs) +void PlayerSAO::finalize(RemotePlayer *player, const std::set &privs) { assert(player); m_player = player; diff --git a/src/content_sao.h b/src/content_sao.h index e53e8ecce..e08795579 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -194,7 +194,7 @@ class RemotePlayer; class PlayerSAO : public UnitSAO { public: - PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer); + PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id_, bool is_singleplayer); ~PlayerSAO(); ActiveObjectType getType() const { return ACTIVEOBJECT_TYPE_PLAYER; } @@ -349,7 +349,7 @@ public: bool getCollisionBox(aabb3f *toset) const; bool collideWithObjects() const { return true; } - void initialize(RemotePlayer *player, const std::set &privs); + void finalize(RemotePlayer *player, const std::set &privs); v3f getEyePosition() const { return m_base_position + getEyeOffset(); } v3f getEyeOffset() const; diff --git a/src/database-dummy.h b/src/database-dummy.h index 9083850cb..7d1cb2279 100644 --- a/src/database-dummy.h +++ b/src/database-dummy.h @@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database.h" #include "irrlichttypes.h" -class Database_Dummy : public Database +class Database_Dummy : public MapDatabase, public PlayerDatabase { public: bool saveBlock(const v3s16 &pos, const std::string &data); @@ -33,6 +33,13 @@ public: bool deleteBlock(const v3s16 &pos); void listAllLoadableBlocks(std::vector &dst); + void savePlayer(RemotePlayer *player) {} + bool loadPlayer(RemotePlayer *player, PlayerSAO *sao) { return true; } + bool removePlayer(const std::string &name) { return true; } + void listPlayers(std::vector &) {} + + void beginSave() {} + void endSave() {} private: std::map m_database; }; diff --git a/src/database-files.cpp b/src/database-files.cpp new file mode 100644 index 000000000..08a1f2d03 --- /dev/null +++ b/src/database-files.cpp @@ -0,0 +1,179 @@ +/* +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. +*/ + +#include +#include +#include "database-files.h" +#include "content_sao.h" +#include "remoteplayer.h" +#include "settings.h" +#include "porting.h" +#include "filesys.h" + +// !!! WARNING !!! +// This backend is intended to be used on Minetest 0.4.16 only for the transition backend for +// player files + +void PlayerDatabaseFiles::serialize(std::ostringstream &os, RemotePlayer *player) +{ + // Utilize a Settings object for storing values + Settings args; + args.setS32("version", 1); + args.set("name", player->getName()); + + sanity_check(player->getPlayerSAO()); + args.setS32("hp", player->getPlayerSAO()->getHP()); + args.setV3F("position", player->getPlayerSAO()->getBasePosition()); + args.setFloat("pitch", player->getPlayerSAO()->getPitch()); + args.setFloat("yaw", player->getPlayerSAO()->getYaw()); + args.setS32("breath", player->getPlayerSAO()->getBreath()); + + std::string extended_attrs = ""; + player->serializeExtraAttributes(extended_attrs); + args.set("extended_attributes", extended_attrs); + + args.writeLines(os); + + os << "PlayerArgsEnd\n"; + + player->inventory.serialize(os); +} + +void PlayerDatabaseFiles::savePlayer(RemotePlayer *player) +{ + std::string savedir = m_savedir + DIR_DELIM; + std::string path = savedir + player->getName(); + bool path_found = false; + RemotePlayer testplayer("", NULL); + + for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES && !path_found; i++) { + if (!fs::PathExists(path)) { + path_found = true; + continue; + } + + // Open and deserialize file to check player name + std::ifstream is(path.c_str(), std::ios_base::binary); + if (!is.good()) { + errorstream << "Failed to open " << path << std::endl; + return; + } + + testplayer.deSerialize(is, path, NULL); + is.close(); + if (strcmp(testplayer.getName(), player->getName()) == 0) { + path_found = true; + continue; + } + + path = savedir + player->getName() + itos(i); + } + + if (!path_found) { + errorstream << "Didn't find free file for player " << player->getName() + << std::endl; + return; + } + + // Open and serialize file + std::ostringstream ss(std::ios_base::binary); + serialize(ss, player); + if (!fs::safeWriteToFile(path, ss.str())) { + infostream << "Failed to write " << path << std::endl; + } + player->setModified(false); +} + +bool PlayerDatabaseFiles::removePlayer(const std::string &name) +{ + std::string players_path = m_savedir + DIR_DELIM; + std::string path = players_path + name; + + RemotePlayer temp_player("", NULL); + for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) { + // Open file and deserialize + std::ifstream is(path.c_str(), std::ios_base::binary); + if (!is.good()) + continue; + + temp_player.deSerialize(is, path, NULL); + is.close(); + + if (temp_player.getName() == name) { + fs::DeleteSingleFileOrEmptyDirectory(path); + return true; + } + + path = players_path + name + itos(i); + } + + return false; +} + +bool PlayerDatabaseFiles::loadPlayer(RemotePlayer *player, PlayerSAO *sao) +{ + std::string players_path = m_savedir + DIR_DELIM; + std::string path = players_path + player->getName(); + + const std::string player_to_load = player->getName(); + for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) { + // Open file and deserialize + std::ifstream is(path.c_str(), std::ios_base::binary); + if (!is.good()) + continue; + + player->deSerialize(is, path, sao); + is.close(); + + if (player->getName() == player_to_load) + return true; + + path = players_path + player_to_load + itos(i); + } + + infostream << "Player file for player " << player_to_load << " not found" << std::endl; + return false; +} + +void PlayerDatabaseFiles::listPlayers(std::vector &res) +{ + std::vector files = fs::GetDirListing(m_savedir); + // list files into players directory + for (std::vector::const_iterator it = files.begin(); it != + files.end(); ++it) { + // Ignore directories + if (it->dir) + continue; + + const std::string &filename = it->name; + std::string full_path = m_savedir + DIR_DELIM + filename; + std::ifstream is(full_path.c_str(), std::ios_base::binary); + if (!is.good()) + continue; + + RemotePlayer player(filename.c_str(), NULL); + // Null env & dummy peer_id + PlayerSAO playerSAO(NULL, &player, 15789, false); + + player.deSerialize(is, "", &playerSAO); + is.close(); + + res.push_back(player.getName()); + } +} diff --git a/src/database-files.h b/src/database-files.h new file mode 100644 index 000000000..d23069c2a --- /dev/null +++ b/src/database-files.h @@ -0,0 +1,46 @@ +/* +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. +*/ + +#ifndef DATABASE_FILES_HEADER +#define DATABASE_FILES_HEADER + +// !!! WARNING !!! +// This backend is intended to be used on Minetest 0.4.16 only for the transition backend for +// player files + +#include "database.h" + +class PlayerDatabaseFiles : public PlayerDatabase +{ +public: + PlayerDatabaseFiles(const std::string &savedir) : m_savedir(savedir) {} + virtual ~PlayerDatabaseFiles() {} + + void savePlayer(RemotePlayer *player); + bool loadPlayer(RemotePlayer *player, PlayerSAO *sao); + bool removePlayer(const std::string &name); + void listPlayers(std::vector &res); + +private: + void serialize(std::ostringstream &os, RemotePlayer *player); + + std::string m_savedir; +}; + +#endif diff --git a/src/database-leveldb.h b/src/database-leveldb.h index 171946741..52ccebe70 100644 --- a/src/database-leveldb.h +++ b/src/database-leveldb.h @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database.h" #include "leveldb/db.h" -class Database_LevelDB : public Database +class Database_LevelDB : public MapDatabase { public: Database_LevelDB(const std::string &savedir); @@ -39,6 +39,8 @@ public: bool deleteBlock(const v3s16 &pos); void listAllLoadableBlocks(std::vector &dst); + void beginSave() {} + void endSave() {} private: leveldb::DB *m_database; }; diff --git a/src/database-postgresql.cpp b/src/database-postgresql.cpp index 83678fd52..a6b62bad5 100644 --- a/src/database-postgresql.cpp +++ b/src/database-postgresql.cpp @@ -39,13 +39,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "exceptions.h" #include "settings.h" +#include "content_sao.h" +#include "remoteplayer.h" -Database_PostgreSQL::Database_PostgreSQL(const Settings &conf) : - m_connect_string(""), +Database_PostgreSQL::Database_PostgreSQL(const std::string &connect_string) : + m_connect_string(connect_string), m_conn(NULL), m_pgversion(0) { - if (!conf.getNoEx("pgsql_connection", m_connect_string)) { + if (m_connect_string.empty()) { throw SettingNotFoundException( "Set pgsql_connection string in world.mt to " "use the postgresql backend\n" @@ -57,8 +59,6 @@ Database_PostgreSQL::Database_PostgreSQL(const Settings &conf) : "DELETE rights on the database.\n" "Don't create mt_user as a SUPERUSER!"); } - - connectToDatabase(); } Database_PostgreSQL::~Database_PostgreSQL() @@ -118,40 +118,6 @@ bool Database_PostgreSQL::initialized() const return (PQstatus(m_conn) == CONNECTION_OK); } -void Database_PostgreSQL::initStatements() -{ - prepareStatement("read_block", - "SELECT data FROM blocks " - "WHERE posX = $1::int4 AND posY = $2::int4 AND " - "posZ = $3::int4"); - - if (m_pgversion < 90500) { - prepareStatement("write_block_insert", - "INSERT INTO blocks (posX, posY, posZ, data) SELECT " - "$1::int4, $2::int4, $3::int4, $4::bytea " - "WHERE NOT EXISTS (SELECT true FROM blocks " - "WHERE posX = $1::int4 AND posY = $2::int4 AND " - "posZ = $3::int4)"); - - prepareStatement("write_block_update", - "UPDATE blocks SET data = $4::bytea " - "WHERE posX = $1::int4 AND posY = $2::int4 AND " - "posZ = $3::int4"); - } else { - prepareStatement("write_block", - "INSERT INTO blocks (posX, posY, posZ, data) VALUES " - "($1::int4, $2::int4, $3::int4, $4::bytea) " - "ON CONFLICT ON CONSTRAINT blocks_pkey DO " - "UPDATE SET data = $4::bytea"); - } - - prepareStatement("delete_block", "DELETE FROM blocks WHERE " - "posX = $1::int4 AND posY = $2::int4 AND posZ = $3::int4"); - - prepareStatement("list_all_loadable_blocks", - "SELECT posX, posY, posZ FROM blocks"); -} - PGresult *Database_PostgreSQL::checkResults(PGresult *result, bool clear) { ExecStatusType statusType = PQresultStatus(result); @@ -173,30 +139,21 @@ PGresult *Database_PostgreSQL::checkResults(PGresult *result, bool clear) return result; } -void Database_PostgreSQL::createDatabase() +void Database_PostgreSQL::createTableIfNotExists(const std::string &table_name, + const std::string &definition) { - PGresult *result = checkResults(PQexec(m_conn, - "SELECT relname FROM pg_class WHERE relname='blocks';"), - false); + std::string sql_check_table = "SELECT relname FROM pg_class WHERE relname='" + + table_name + "';"; + PGresult *result = checkResults(PQexec(m_conn, sql_check_table.c_str()), false); // If table doesn't exist, create it if (!PQntuples(result)) { - static const char* dbcreate_sql = "CREATE TABLE blocks (" - "posX INT NOT NULL," - "posY INT NOT NULL," - "posZ INT NOT NULL," - "data BYTEA," - "PRIMARY KEY (posX,posY,posZ)" - ");"; - checkResults(PQexec(m_conn, dbcreate_sql)); + checkResults(PQexec(m_conn, definition.c_str())); } PQclear(result); - - infostream << "PostgreSQL: Game Database was inited." << std::endl; } - void Database_PostgreSQL::beginSave() { verifyDatabase(); @@ -208,14 +165,70 @@ void Database_PostgreSQL::endSave() checkResults(PQexec(m_conn, "COMMIT;")); } -bool Database_PostgreSQL::saveBlock(const v3s16 &pos, - const std::string &data) +MapDatabasePostgreSQL::MapDatabasePostgreSQL(const std::string &connect_string): + Database_PostgreSQL(connect_string), + MapDatabase() +{ + connectToDatabase(); +} + + +void MapDatabasePostgreSQL::createDatabase() +{ + createTableIfNotExists("blocks", + "CREATE TABLE blocks (" + "posX INT NOT NULL," + "posY INT NOT NULL," + "posZ INT NOT NULL," + "data BYTEA," + "PRIMARY KEY (posX,posY,posZ)" + ");" + ); + + infostream << "PostgreSQL: Map Database was initialized." << std::endl; +} + +void MapDatabasePostgreSQL::initStatements() +{ + prepareStatement("read_block", + "SELECT data FROM blocks " + "WHERE posX = $1::int4 AND posY = $2::int4 AND " + "posZ = $3::int4"); + + if (getPGVersion() < 90500) { + prepareStatement("write_block_insert", + "INSERT INTO blocks (posX, posY, posZ, data) SELECT " + "$1::int4, $2::int4, $3::int4, $4::bytea " + "WHERE NOT EXISTS (SELECT true FROM blocks " + "WHERE posX = $1::int4 AND posY = $2::int4 AND " + "posZ = $3::int4)"); + + prepareStatement("write_block_update", + "UPDATE blocks SET data = $4::bytea " + "WHERE posX = $1::int4 AND posY = $2::int4 AND " + "posZ = $3::int4"); + } else { + prepareStatement("write_block", + "INSERT INTO blocks (posX, posY, posZ, data) VALUES " + "($1::int4, $2::int4, $3::int4, $4::bytea) " + "ON CONFLICT ON CONSTRAINT blocks_pkey DO " + "UPDATE SET data = $4::bytea"); + } + + prepareStatement("delete_block", "DELETE FROM blocks WHERE " + "posX = $1::int4 AND posY = $2::int4 AND posZ = $3::int4"); + + prepareStatement("list_all_loadable_blocks", + "SELECT posX, posY, posZ FROM blocks"); +} + +bool MapDatabasePostgreSQL::saveBlock(const v3s16 &pos, const std::string &data) { // Verify if we don't overflow the platform integer with the mapblock size if (data.size() > INT_MAX) { errorstream << "Database_PostgreSQL::saveBlock: Data truncation! " - << "data.size() over 0xFFFF (== " << data.size() - << ")" << std::endl; + << "data.size() over 0xFFFFFFFF (== " << data.size() + << ")" << std::endl; return false; } @@ -232,7 +245,7 @@ bool Database_PostgreSQL::saveBlock(const v3s16 &pos, }; const int argFmt[] = { 1, 1, 1, 1 }; - if (m_pgversion < 90500) { + if (getPGVersion() < 90500) { execPrepared("write_block_update", ARRLEN(args), args, argLen, argFmt); execPrepared("write_block_insert", ARRLEN(args), args, argLen, argFmt); } else { @@ -241,8 +254,7 @@ bool Database_PostgreSQL::saveBlock(const v3s16 &pos, return true; } -void Database_PostgreSQL::loadBlock(const v3s16 &pos, - std::string *block) +void MapDatabasePostgreSQL::loadBlock(const v3s16 &pos, std::string *block) { verifyDatabase(); @@ -256,19 +268,17 @@ void Database_PostgreSQL::loadBlock(const v3s16 &pos, const int argFmt[] = { 1, 1, 1 }; PGresult *results = execPrepared("read_block", ARRLEN(args), args, - argLen, argFmt, false); + argLen, argFmt, false); *block = ""; - if (PQntuples(results)) { - *block = std::string(PQgetvalue(results, 0, 0), - PQgetlength(results, 0, 0)); - } + if (PQntuples(results)) + *block = std::string(PQgetvalue(results, 0, 0), PQgetlength(results, 0, 0)); PQclear(results); } -bool Database_PostgreSQL::deleteBlock(const v3s16 &pos) +bool MapDatabasePostgreSQL::deleteBlock(const v3s16 &pos) { verifyDatabase(); @@ -286,18 +296,338 @@ bool Database_PostgreSQL::deleteBlock(const v3s16 &pos) return true; } -void Database_PostgreSQL::listAllLoadableBlocks(std::vector &dst) +void MapDatabasePostgreSQL::listAllLoadableBlocks(std::vector &dst) { verifyDatabase(); PGresult *results = execPrepared("list_all_loadable_blocks", 0, - NULL, NULL, NULL, false, false); + NULL, NULL, NULL, false, false); int numrows = PQntuples(results); - for (int row = 0; row < numrows; ++row) { + for (int row = 0; row < numrows; ++row) dst.push_back(pg_to_v3s16(results, 0, 0)); + + PQclear(results); +} + +/* + * Player Database + */ +PlayerDatabasePostgreSQL::PlayerDatabasePostgreSQL(const std::string &connect_string): + Database_PostgreSQL(connect_string), + PlayerDatabase() +{ + connectToDatabase(); +} + + +void PlayerDatabasePostgreSQL::createDatabase() +{ + createTableIfNotExists("player", + "CREATE TABLE player (" + "name VARCHAR(60) NOT NULL," + "pitch NUMERIC(15, 7) NOT NULL," + "yaw NUMERIC(15, 7) NOT NULL," + "posX NUMERIC(15, 7) NOT NULL," + "posY NUMERIC(15, 7) NOT NULL," + "posZ NUMERIC(15, 7) NOT NULL," + "hp INT NOT NULL," + "breath INT NOT NULL," + "creation_date TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT NOW()," + "modification_date TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT NOW()," + "PRIMARY KEY (name)" + ");" + ); + + createTableIfNotExists("player_inventories", + "CREATE TABLE player_inventories (" + "player VARCHAR(60) NOT NULL," + "inv_id INT NOT NULL," + "inv_width INT NOT NULL," + "inv_name TEXT NOT NULL DEFAULT ''," + "inv_size INT NOT NULL," + "PRIMARY KEY(player, inv_id)," + "CONSTRAINT player_inventories_fkey FOREIGN KEY (player) REFERENCES " + "player (name) ON DELETE CASCADE" + ");" + ); + + createTableIfNotExists("player_inventory_items", + "CREATE TABLE player_inventory_items (" + "player VARCHAR(60) NOT NULL," + "inv_id INT NOT NULL," + "slot_id INT NOT NULL," + "item TEXT NOT NULL DEFAULT ''," + "PRIMARY KEY(player, inv_id, slot_id)," + "CONSTRAINT player_inventory_items_fkey FOREIGN KEY (player) REFERENCES " + "player (name) ON DELETE CASCADE" + ");" + ); + + createTableIfNotExists("player_metadata", + "CREATE TABLE player_metadata (" + "player VARCHAR(60) NOT NULL," + "attr VARCHAR(256) NOT NULL," + "value TEXT," + "PRIMARY KEY(player, attr)," + "CONSTRAINT player_metadata_fkey FOREIGN KEY (player) REFERENCES " + "player (name) ON DELETE CASCADE" + ");" + ); + + infostream << "PostgreSQL: Player Database was inited." << std::endl; +} + +void PlayerDatabasePostgreSQL::initStatements() +{ + if (getPGVersion() < 90500) { + prepareStatement("create_player", + "INSERT INTO player(name, pitch, yaw, posX, posY, posZ, hp, breath) VALUES " + "($1, $2, $3, $4, $5, $6, $7::int, $8::int)"); + + prepareStatement("update_player", + "UPDATE SET pitch = $2, yaw = $3, posX = $4, posY = $5, posZ = $6, hp = $7::int, " + "breath = $8::int, modification_date = NOW() WHERE name = $1"); + } else { + prepareStatement("save_player", + "INSERT INTO player(name, pitch, yaw, posX, posY, posZ, hp, breath) VALUES " + "($1, $2, $3, $4, $5, $6, $7::int, $8::int)" + "ON CONFLICT ON CONSTRAINT player_pkey DO UPDATE SET pitch = $2, yaw = $3, " + "posX = $4, posY = $5, posZ = $6, hp = $7::int, breath = $8::int, " + "modification_date = NOW()"); + } + + prepareStatement("remove_player", "DELETE FROM player WHERE name = $1"); + + prepareStatement("load_player_list", "SELECT name FROM player"); + + prepareStatement("remove_player_inventories", + "DELETE FROM player_inventories WHERE player = $1"); + + prepareStatement("remove_player_inventory_items", + "DELETE FROM player_inventory_items WHERE player = $1"); + + prepareStatement("add_player_inventory", + "INSERT INTO player_inventories (player, inv_id, inv_width, inv_name, inv_size) VALUES " + "($1, $2::int, $3::int, $4, $5::int)"); + + prepareStatement("add_player_inventory_item", + "INSERT INTO player_inventory_items (player, inv_id, slot_id, item) VALUES " + "($1, $2::int, $3::int, $4)"); + + prepareStatement("load_player_inventories", + "SELECT inv_id, inv_width, inv_name, inv_size FROM player_inventories " + "WHERE player = $1 ORDER BY inv_id"); + + prepareStatement("load_player_inventory_items", + "SELECT slot_id, item FROM player_inventory_items WHERE " + "player = $1 AND inv_id = $2::int"); + + prepareStatement("load_player", + "SELECT pitch, yaw, posX, posY, posZ, hp, breath FROM player WHERE name = $1"); + + prepareStatement("remove_player_metadata", + "DELETE FROM player_metadata WHERE player = $1"); + + prepareStatement("save_player_metadata", + "INSERT INTO player_metadata (player, attr, value) VALUES ($1, $2, $3)"); + + prepareStatement("load_player_metadata", + "SELECT attr, value FROM player_metadata WHERE player = $1"); + +} + +bool PlayerDatabasePostgreSQL::playerDataExists(const std::string &playername) +{ + verifyDatabase(); + + const char *values[] = { playername.c_str() }; + PGresult *results = execPrepared("load_player", 1, values, false); + + bool res = (PQntuples(results) > 0); + PQclear(results); + return res; +} + +void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player) +{ + PlayerSAO* sao = player->getPlayerSAO(); + if (!sao) + return; + + verifyDatabase(); + + v3f pos = sao->getBasePosition(); + std::string pitch = ftos(sao->getPitch()); + std::string yaw = ftos(sao->getYaw()); + std::string posx = ftos(pos.X); + std::string posy = ftos(pos.Y); + std::string posz = ftos(pos.Z); + std::string hp = itos(sao->getHP()); + std::string breath = itos(sao->getBreath()); + const char *values[] = { + player->getName(), + pitch.c_str(), + yaw.c_str(), + posx.c_str(), posy.c_str(), posz.c_str(), + hp.c_str(), + breath.c_str() + }; + + const char* rmvalues[] = { player->getName() }; + beginSave(); + + if (getPGVersion() < 90500) { + if (!playerDataExists(player->getName())) + execPrepared("create_player", 8, values, true, false); + else + execPrepared("update_player", 8, values, true, false); + } + else + execPrepared("save_player", 8, values, true, false); + + // Write player inventories + execPrepared("remove_player_inventories", 1, rmvalues); + execPrepared("remove_player_inventory_items", 1, rmvalues); + + std::vector inventory_lists = sao->getInventory()->getLists(); + for (u16 i = 0; i < inventory_lists.size(); i++) { + const InventoryList* list = inventory_lists[i]; + std::string name = list->getName(), width = itos(list->getWidth()), + inv_id = itos(i), lsize = itos(list->getSize()); + + const char* inv_values[] = { + player->getName(), + inv_id.c_str(), + width.c_str(), + name.c_str(), + lsize.c_str() + }; + execPrepared("add_player_inventory", 5, inv_values); + + for (u32 j = 0; j < list->getSize(); j++) { + std::ostringstream os; + list->getItem(j).serialize(os); + std::string itemStr = os.str(), slotId = itos(j); + + const char* invitem_values[] = { + player->getName(), + inv_id.c_str(), + slotId.c_str(), + itemStr.c_str() + }; + execPrepared("add_player_inventory_item", 4, invitem_values); + } + } + + execPrepared("remove_player_metadata", 1, rmvalues); + const PlayerAttributes &attrs = sao->getExtendedAttributes(); + for (PlayerAttributes::const_iterator it = attrs.begin(); it != attrs.end(); ++it) { + const char *meta_values[] = { + player->getName(), + it->first.c_str(), + it->second.c_str() + }; + execPrepared("save_player_metadata", 3, meta_values); } + endSave(); +} + +bool PlayerDatabasePostgreSQL::loadPlayer(RemotePlayer *player, PlayerSAO *sao) +{ + sanity_check(sao); + verifyDatabase(); + + const char *values[] = { player->getName() }; + PGresult *results = execPrepared("load_player", 1, values, false, false); + + // Player not found, return not found + if (!PQntuples(results)) { + PQclear(results); + return false; + } + + sao->setPitch(pg_to_float(results, 0, 0)); + sao->setYaw(pg_to_float(results, 0, 1)); + sao->setBasePosition(v3f( + pg_to_float(results, 0, 2), + pg_to_float(results, 0, 3), + pg_to_float(results, 0, 4)) + ); + sao->setHPRaw((s16) pg_to_int(results, 0, 5)); + sao->setBreath((u16) pg_to_int(results, 0, 6), false); + + PQclear(results); + + // Load inventory + results = execPrepared("load_player_inventories", 1, values, false, false); + + int resultCount = PQntuples(results); + + for (int row = 0; row < resultCount; ++row) { + InventoryList* invList = player->inventory. + addList(PQgetvalue(results, row, 2), pg_to_uint(results, row, 3)); + invList->setWidth(pg_to_uint(results, row, 1)); + + u32 invId = pg_to_uint(results, row, 0); + std::string invIdStr = itos(invId); + + const char* values2[] = { + player->getName(), + invIdStr.c_str() + }; + PGresult *results2 = execPrepared("load_player_inventory_items", 2, + values2, false, false); + + int resultCount2 = PQntuples(results2); + for (int row2 = 0; row2 < resultCount2; row2++) { + const std::string itemStr = PQgetvalue(results2, row2, 1); + if (itemStr.length() > 0) { + ItemStack stack; + stack.deSerialize(itemStr); + invList->addItem(pg_to_uint(results2, row2, 0), stack); + } + } + PQclear(results2); + } + + PQclear(results); + + results = execPrepared("load_player_metadata", 1, values, false); + + int numrows = PQntuples(results); + for (int row = 0; row < numrows; row++) { + sao->setExtendedAttribute(PQgetvalue(results, row, 0),PQgetvalue(results, row, 1)); + } + + PQclear(results); + + return true; +} + +bool PlayerDatabasePostgreSQL::removePlayer(const std::string &name) +{ + if (!playerDataExists(name)) + return false; + + verifyDatabase(); + + const char *values[] = { name.c_str() }; + execPrepared("remove_player", 1, values); + + return true; +} + +void PlayerDatabasePostgreSQL::listPlayers(std::vector &res) +{ + verifyDatabase(); + + PGresult *results = execPrepared("load_player_list", 0, NULL, false); + + int numrows = PQntuples(results); + for (int row = 0; row < numrows; row++) + res.push_back(PQgetvalue(results, row, 0)); PQclear(results); } diff --git a/src/database-postgresql.h b/src/database-postgresql.h index 1cfa544e3..d6f208fd9 100644 --- a/src/database-postgresql.h +++ b/src/database-postgresql.h @@ -27,53 +27,33 @@ with this program; if not, write to the Free Software Foundation, Inc., class Settings; -class Database_PostgreSQL : public Database +class Database_PostgreSQL: public Database { public: - Database_PostgreSQL(const Settings &conf); + Database_PostgreSQL(const std::string &connect_string); ~Database_PostgreSQL(); void beginSave(); void endSave(); - bool saveBlock(const v3s16 &pos, const std::string &data); - void loadBlock(const v3s16 &pos, std::string *block); - bool deleteBlock(const v3s16 &pos); - void listAllLoadableBlocks(std::vector &dst); bool initialized() const; -private: - // Database initialization - void connectToDatabase(); - void initStatements(); - void createDatabase(); - inline void prepareStatement(const std::string &name, const std::string &sql) +protected: + // Conversion helpers + inline int pg_to_int(PGresult *res, int row, int col) { - checkResults(PQprepare(m_conn, name.c_str(), sql.c_str(), 0, NULL)); + return atoi(PQgetvalue(res, row, col)); } - // Database connectivity checks - void ping(); - void verifyDatabase(); - - // Database usage - PGresult *checkResults(PGresult *res, bool clear = true); - - inline PGresult *execPrepared(const char *stmtName, const int paramsNumber, - const void **params, - const int *paramsLengths = NULL, const int *paramsFormats = NULL, - bool clear = true, bool nobinary = true) + inline u32 pg_to_uint(PGresult *res, int row, int col) { - return checkResults(PQexecPrepared(m_conn, stmtName, paramsNumber, - (const char* const*) params, paramsLengths, paramsFormats, - nobinary ? 1 : 0), clear); + return (u32) atoi(PQgetvalue(res, row, col)); } - // Conversion helpers - inline int pg_to_int(PGresult *res, int row, int col) + inline float pg_to_float(PGresult *res, int row, int col) { - return atoi(PQgetvalue(res, row, col)); + return (float) atof(PQgetvalue(res, row, col)); } inline v3s16 pg_to_v3s16(PGresult *res, int row, int col) @@ -85,11 +65,86 @@ private: ); } + inline PGresult *execPrepared(const char *stmtName, const int paramsNumber, + const void **params, + const int *paramsLengths = NULL, const int *paramsFormats = NULL, + bool clear = true, bool nobinary = true) + { + return checkResults(PQexecPrepared(m_conn, stmtName, paramsNumber, + (const char* const*) params, paramsLengths, paramsFormats, + nobinary ? 1 : 0), clear); + } + + inline PGresult *execPrepared(const char *stmtName, const int paramsNumber, + const char **params, bool clear = true, bool nobinary = true) + { + return execPrepared(stmtName, paramsNumber, + (const void **)params, NULL, NULL, clear, nobinary); + } + + void createTableIfNotExists(const std::string &table_name, const std::string &definition); + void verifyDatabase(); + + // Database initialization + void connectToDatabase(); + virtual void createDatabase() = 0; + virtual void initStatements() = 0; + inline void prepareStatement(const std::string &name, const std::string &sql) + { + checkResults(PQprepare(m_conn, name.c_str(), sql.c_str(), 0, NULL)); + } + + const int getPGVersion() const { return m_pgversion; } +private: + // Database connectivity checks + void ping(); + + // Database usage + PGresult *checkResults(PGresult *res, bool clear = true); + // Attributes std::string m_connect_string; PGconn *m_conn; int m_pgversion; }; +class MapDatabasePostgreSQL : private Database_PostgreSQL, public MapDatabase +{ +public: + MapDatabasePostgreSQL(const std::string &connect_string); + virtual ~MapDatabasePostgreSQL() {} + + bool saveBlock(const v3s16 &pos, const std::string &data); + void loadBlock(const v3s16 &pos, std::string *block); + bool deleteBlock(const v3s16 &pos); + void listAllLoadableBlocks(std::vector &dst); + + void beginSave() { Database_PostgreSQL::beginSave(); } + void endSave() { Database_PostgreSQL::endSave(); } + +protected: + virtual void createDatabase(); + virtual void initStatements(); +}; + +class PlayerDatabasePostgreSQL : private Database_PostgreSQL, public PlayerDatabase +{ +public: + PlayerDatabasePostgreSQL(const std::string &connect_string); + virtual ~PlayerDatabasePostgreSQL() {} + + void savePlayer(RemotePlayer *player); + bool loadPlayer(RemotePlayer *player, PlayerSAO *sao); + bool removePlayer(const std::string &name); + void listPlayers(std::vector &res); + +protected: + virtual void createDatabase(); + virtual void initStatements(); + +private: + bool playerDataExists(const std::string &playername); +}; + #endif diff --git a/src/database-redis.h b/src/database-redis.h index 214bc8dd6..fa15dd8a7 100644 --- a/src/database-redis.h +++ b/src/database-redis.h @@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., class Settings; -class Database_Redis : public Database +class Database_Redis : public MapDatabase { public: Database_Redis(Settings &conf); diff --git a/src/database-sqlite3.cpp b/src/database-sqlite3.cpp index 095d485c0..714f56c39 100644 --- a/src/database-sqlite3.cpp +++ b/src/database-sqlite3.cpp @@ -33,6 +33,8 @@ SQLite format specification: #include "settings.h" #include "porting.h" #include "util/string.h" +#include "content_sao.h" +#include "remoteplayer.h" #include @@ -111,27 +113,26 @@ int Database_SQLite3::busyHandler(void *data, int count) } -Database_SQLite3::Database_SQLite3(const std::string &savedir) : +Database_SQLite3::Database_SQLite3(const std::string &savedir, const std::string &dbname) : + m_database(NULL), m_initialized(false), m_savedir(savedir), - m_database(NULL), - m_stmt_read(NULL), - m_stmt_write(NULL), - m_stmt_list(NULL), - m_stmt_delete(NULL), + m_dbname(dbname), m_stmt_begin(NULL), m_stmt_end(NULL) { } -void Database_SQLite3::beginSave() { +void Database_SQLite3::beginSave() +{ verifyDatabase(); SQLRES(sqlite3_step(m_stmt_begin), SQLITE_DONE, "Failed to start SQLite3 transaction"); sqlite3_reset(m_stmt_begin); } -void Database_SQLite3::endSave() { +void Database_SQLite3::endSave() +{ verifyDatabase(); SQLRES(sqlite3_step(m_stmt_end), SQLITE_DONE, "Failed to commit SQLite3 transaction"); @@ -142,7 +143,7 @@ void Database_SQLite3::openDatabase() { if (m_database) return; - std::string dbp = m_savedir + DIR_DELIM + "map.sqlite"; + std::string dbp = m_savedir + DIR_DELIM + m_dbname + ".sqlite"; // Open the database connection @@ -170,6 +171,8 @@ void Database_SQLite3::openDatabase() + itos(g_settings->getU16("sqlite_synchronous")); SQLOK(sqlite3_exec(m_database, query_str.c_str(), NULL, NULL, NULL), "Failed to modify sqlite3 synchronous mode"); + SQLOK(sqlite3_exec(m_database, "PRAGMA foreign_keys = ON", NULL, NULL, NULL), + "Failed to enable sqlite3 foreign key support"); } void Database_SQLite3::verifyDatabase() @@ -178,8 +181,61 @@ void Database_SQLite3::verifyDatabase() openDatabase(); - PREPARE_STATEMENT(begin, "BEGIN"); - PREPARE_STATEMENT(end, "COMMIT"); + PREPARE_STATEMENT(begin, "BEGIN;"); + PREPARE_STATEMENT(end, "COMMIT;"); + + initStatements(); + + m_initialized = true; +} + +Database_SQLite3::~Database_SQLite3() +{ + FINALIZE_STATEMENT(m_stmt_begin) + FINALIZE_STATEMENT(m_stmt_end) + + SQLOK_ERRSTREAM(sqlite3_close(m_database), "Failed to close database"); +} + +/* + * Map database + */ + +MapDatabaseSQLite3::MapDatabaseSQLite3(const std::string &savedir): + Database_SQLite3(savedir, "map"), + MapDatabase(), + m_stmt_read(NULL), + m_stmt_write(NULL), + m_stmt_list(NULL), + m_stmt_delete(NULL) +{ + +} + +MapDatabaseSQLite3::~MapDatabaseSQLite3() +{ + FINALIZE_STATEMENT(m_stmt_read) + FINALIZE_STATEMENT(m_stmt_write) + FINALIZE_STATEMENT(m_stmt_list) + FINALIZE_STATEMENT(m_stmt_delete) +} + + +void MapDatabaseSQLite3::createDatabase() +{ + assert(m_database); // Pre-condition + + SQLOK(sqlite3_exec(m_database, + "CREATE TABLE IF NOT EXISTS `blocks` (\n" + " `pos` INT PRIMARY KEY,\n" + " `data` BLOB\n" + ");\n", + NULL, NULL, NULL), + "Failed to create database table"); +} + +void MapDatabaseSQLite3::initStatements() +{ PREPARE_STATEMENT(read, "SELECT `data` FROM `blocks` WHERE `pos` = ? LIMIT 1"); #ifdef __ANDROID__ PREPARE_STATEMENT(write, "INSERT INTO `blocks` (`pos`, `data`) VALUES (?, ?)"); @@ -189,18 +245,16 @@ void Database_SQLite3::verifyDatabase() PREPARE_STATEMENT(delete, "DELETE FROM `blocks` WHERE `pos` = ?"); PREPARE_STATEMENT(list, "SELECT `pos` FROM `blocks`"); - m_initialized = true; - verbosestream << "ServerMap: SQLite3 database opened." << std::endl; } -inline void Database_SQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index) +inline void MapDatabaseSQLite3::bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index) { SQLOK(sqlite3_bind_int64(stmt, index, getBlockAsInteger(pos)), "Internal error: failed to bind query at " __FILE__ ":" TOSTRING(__LINE__)); } -bool Database_SQLite3::deleteBlock(const v3s16 &pos) +bool MapDatabaseSQLite3::deleteBlock(const v3s16 &pos) { verifyDatabase(); @@ -216,7 +270,7 @@ bool Database_SQLite3::deleteBlock(const v3s16 &pos) return good; } -bool Database_SQLite3::saveBlock(const v3s16 &pos, const std::string &data) +bool MapDatabaseSQLite3::saveBlock(const v3s16 &pos, const std::string &data) { verifyDatabase(); @@ -243,7 +297,7 @@ bool Database_SQLite3::saveBlock(const v3s16 &pos, const std::string &data) return true; } -void Database_SQLite3::loadBlock(const v3s16 &pos, std::string *block) +void MapDatabaseSQLite3::loadBlock(const v3s16 &pos, std::string *block) { verifyDatabase(); @@ -264,37 +318,312 @@ void Database_SQLite3::loadBlock(const v3s16 &pos, std::string *block) sqlite3_reset(m_stmt_read); } -void Database_SQLite3::createDatabase() +void MapDatabaseSQLite3::listAllLoadableBlocks(std::vector &dst) +{ + verifyDatabase(); + + while (sqlite3_step(m_stmt_list) == SQLITE_ROW) + dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0))); + + sqlite3_reset(m_stmt_list); +} + +/* + * Player Database + */ + +PlayerDatabaseSQLite3::PlayerDatabaseSQLite3(const std::string &savedir): + Database_SQLite3(savedir, "players"), + PlayerDatabase(), + m_stmt_player_load(NULL), + m_stmt_player_add(NULL), + m_stmt_player_update(NULL), + m_stmt_player_remove(NULL), + m_stmt_player_list(NULL), + m_stmt_player_load_inventory(NULL), + m_stmt_player_load_inventory_items(NULL), + m_stmt_player_add_inventory(NULL), + m_stmt_player_add_inventory_items(NULL), + m_stmt_player_remove_inventory(NULL), + m_stmt_player_remove_inventory_items(NULL), + m_stmt_player_metadata_load(NULL), + m_stmt_player_metadata_remove(NULL), + m_stmt_player_metadata_add(NULL) +{ + +} +PlayerDatabaseSQLite3::~PlayerDatabaseSQLite3() +{ + FINALIZE_STATEMENT(m_stmt_player_load) + FINALIZE_STATEMENT(m_stmt_player_add) + FINALIZE_STATEMENT(m_stmt_player_update) + FINALIZE_STATEMENT(m_stmt_player_remove) + FINALIZE_STATEMENT(m_stmt_player_list) + FINALIZE_STATEMENT(m_stmt_player_add_inventory) + FINALIZE_STATEMENT(m_stmt_player_add_inventory_items) + FINALIZE_STATEMENT(m_stmt_player_remove_inventory) + FINALIZE_STATEMENT(m_stmt_player_remove_inventory_items) + FINALIZE_STATEMENT(m_stmt_player_load_inventory) + FINALIZE_STATEMENT(m_stmt_player_load_inventory_items) + FINALIZE_STATEMENT(m_stmt_player_metadata_load) + FINALIZE_STATEMENT(m_stmt_player_metadata_add) + FINALIZE_STATEMENT(m_stmt_player_metadata_remove) +}; + + +void PlayerDatabaseSQLite3::createDatabase() { assert(m_database); // Pre-condition + SQLOK(sqlite3_exec(m_database, - "CREATE TABLE IF NOT EXISTS `blocks` (\n" - " `pos` INT PRIMARY KEY,\n" - " `data` BLOB\n" - ");\n", + "CREATE TABLE IF NOT EXISTS `player` (" + "`name` VARCHAR(50) NOT NULL," + "`pitch` NUMERIC(11, 4) NOT NULL," + "`yaw` NUMERIC(11, 4) NOT NULL," + "`posX` NUMERIC(11, 4) NOT NULL," + "`posY` NUMERIC(11, 4) NOT NULL," + "`posZ` NUMERIC(11, 4) NOT NULL," + "`hp` INT NOT NULL," + "`breath` INT NOT NULL," + "`creation_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," + "`modification_date` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP," + "PRIMARY KEY (`name`));", NULL, NULL, NULL), - "Failed to create database table"); + "Failed to create player table"); + + SQLOK(sqlite3_exec(m_database, + "CREATE TABLE IF NOT EXISTS `player_metadata` (" + " `player` VARCHAR(50) NOT NULL," + " `metadata` VARCHAR(256) NOT NULL," + " `value` TEXT," + " PRIMARY KEY(`player`, `metadata`)," + " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );", + NULL, NULL, NULL), + "Failed to create player metadata table"); + + SQLOK(sqlite3_exec(m_database, + "CREATE TABLE IF NOT EXISTS `player_inventories` (" + " `player` VARCHAR(50) NOT NULL," + " `inv_id` INT NOT NULL," + " `inv_width` INT NOT NULL," + " `inv_name` TEXT NOT NULL DEFAULT ''," + " `inv_size` INT NOT NULL," + " PRIMARY KEY(player, inv_id)," + " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );", + NULL, NULL, NULL), + "Failed to create player inventory table"); + + SQLOK(sqlite3_exec(m_database, + "CREATE TABLE `player_inventory_items` (" + " `player` VARCHAR(50) NOT NULL," + " `inv_id` INT NOT NULL," + " `slot_id` INT NOT NULL," + " `item` TEXT NOT NULL DEFAULT ''," + " PRIMARY KEY(player, inv_id, slot_id)," + " FOREIGN KEY (`player`) REFERENCES player (`name`) ON DELETE CASCADE );", + NULL, NULL, NULL), + "Failed to create player inventory items table"); } -void Database_SQLite3::listAllLoadableBlocks(std::vector &dst) +void PlayerDatabaseSQLite3::initStatements() +{ + PREPARE_STATEMENT(player_load, "SELECT `pitch`, `yaw`, `posX`, `posY`, `posZ`, `hp`, " + "`breath`" + "FROM `player` WHERE `name` = ?") + PREPARE_STATEMENT(player_add, "INSERT INTO `player` (`name`, `pitch`, `yaw`, `posX`, " + "`posY`, `posZ`, `hp`, `breath`) VALUES (?, ?, ?, ?, ?, ?, ?, ?)") + PREPARE_STATEMENT(player_update, "UPDATE `player` SET `pitch` = ?, `yaw` = ?, " + "`posX` = ?, `posY` = ?, `posZ` = ?, `hp` = ?, `breath` = ?, " + "`modification_date` = CURRENT_TIMESTAMP WHERE `name` = ?") + PREPARE_STATEMENT(player_remove, "DELETE FROM `player` WHERE `name` = ?") + PREPARE_STATEMENT(player_list, "SELECT `name` FROM `player`") + + PREPARE_STATEMENT(player_add_inventory, "INSERT INTO `player_inventories` " + "(`player`, `inv_id`, `inv_width`, `inv_name`, `inv_size`) VALUES (?, ?, ?, ?, ?)") + PREPARE_STATEMENT(player_add_inventory_items, "INSERT INTO `player_inventory_items` " + "(`player`, `inv_id`, `slot_id`, `item`) VALUES (?, ?, ?, ?)") + PREPARE_STATEMENT(player_remove_inventory, "DELETE FROM `player_inventories` " + "WHERE `player` = ?") + PREPARE_STATEMENT(player_remove_inventory_items, "DELETE FROM `player_inventory_items` " + "WHERE `player` = ?") + PREPARE_STATEMENT(player_load_inventory, "SELECT `inv_id`, `inv_width`, `inv_name`, " + "`inv_size` FROM `player_inventories` WHERE `player` = ? ORDER BY inv_id") + PREPARE_STATEMENT(player_load_inventory_items, "SELECT `slot_id`, `item` " + "FROM `player_inventory_items` WHERE `player` = ? AND `inv_id` = ?") + + PREPARE_STATEMENT(player_metadata_load, "SELECT `metadata`, `value` FROM " + "`player_metadata` WHERE `player` = ?") + PREPARE_STATEMENT(player_metadata_add, "INSERT INTO `player_metadata` " + "(`player`, `metadata`, `value`) VALUES (?, ?, ?)") + PREPARE_STATEMENT(player_metadata_remove, "DELETE FROM `player_metadata` " + "WHERE `player` = ?") + verbosestream << "ServerEnvironment: SQLite3 database opened (players)." << std::endl; +} + +bool PlayerDatabaseSQLite3::playerDataExists(const std::string &name) { verifyDatabase(); + str_to_sqlite(m_stmt_player_load, 1, name); + bool res = (sqlite3_step(m_stmt_player_load) == SQLITE_ROW); + sqlite3_reset(m_stmt_player_load); + return res; +} - while (sqlite3_step(m_stmt_list) == SQLITE_ROW) { - dst.push_back(getIntegerAsBlock(sqlite3_column_int64(m_stmt_list, 0))); +void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player) +{ + PlayerSAO* sao = player->getPlayerSAO(); + sanity_check(sao); + + const v3f &pos = sao->getBasePosition(); + // Begin save in brace is mandatory + if (!playerDataExists(player->getName())) { + beginSave(); + str_to_sqlite(m_stmt_player_add, 1, player->getName()); + double_to_sqlite(m_stmt_player_add, 2, sao->getPitch()); + double_to_sqlite(m_stmt_player_add, 3, sao->getYaw()); + double_to_sqlite(m_stmt_player_add, 4, pos.X); + double_to_sqlite(m_stmt_player_add, 5, pos.Y); + double_to_sqlite(m_stmt_player_add, 6, pos.Z); + int64_to_sqlite(m_stmt_player_add, 7, sao->getHP()); + int64_to_sqlite(m_stmt_player_add, 8, sao->getBreath()); + + sqlite3_vrfy(sqlite3_step(m_stmt_player_add), SQLITE_DONE); + sqlite3_reset(m_stmt_player_add); + } else { + beginSave(); + double_to_sqlite(m_stmt_player_update, 1, sao->getPitch()); + double_to_sqlite(m_stmt_player_update, 2, sao->getYaw()); + double_to_sqlite(m_stmt_player_update, 3, pos.X); + double_to_sqlite(m_stmt_player_update, 4, pos.Y); + double_to_sqlite(m_stmt_player_update, 5, pos.Z); + int64_to_sqlite(m_stmt_player_update, 6, sao->getHP()); + int64_to_sqlite(m_stmt_player_update, 7, sao->getBreath()); + str_to_sqlite(m_stmt_player_update, 8, player->getName()); + + sqlite3_vrfy(sqlite3_step(m_stmt_player_update), SQLITE_DONE); + sqlite3_reset(m_stmt_player_update); } - sqlite3_reset(m_stmt_list); + + // Write player inventories + str_to_sqlite(m_stmt_player_remove_inventory, 1, player->getName()); + sqlite3_vrfy(sqlite3_step(m_stmt_player_remove_inventory), SQLITE_DONE); + sqlite3_reset(m_stmt_player_remove_inventory); + + str_to_sqlite(m_stmt_player_remove_inventory_items, 1, player->getName()); + sqlite3_vrfy(sqlite3_step(m_stmt_player_remove_inventory_items), SQLITE_DONE); + sqlite3_reset(m_stmt_player_remove_inventory_items); + + std::vector inventory_lists = sao->getInventory()->getLists(); + for (u16 i = 0; i < inventory_lists.size(); i++) { + const InventoryList* list = inventory_lists[i]; + + str_to_sqlite(m_stmt_player_add_inventory, 1, player->getName()); + int_to_sqlite(m_stmt_player_add_inventory, 2, i); + int_to_sqlite(m_stmt_player_add_inventory, 3, list->getWidth()); + str_to_sqlite(m_stmt_player_add_inventory, 4, list->getName()); + int_to_sqlite(m_stmt_player_add_inventory, 5, list->getSize()); + sqlite3_vrfy(sqlite3_step(m_stmt_player_add_inventory), SQLITE_DONE); + sqlite3_reset(m_stmt_player_add_inventory); + + for (u32 j = 0; j < list->getSize(); j++) { + std::ostringstream os; + list->getItem(j).serialize(os); + std::string itemStr = os.str(); + + str_to_sqlite(m_stmt_player_add_inventory_items, 1, player->getName()); + int_to_sqlite(m_stmt_player_add_inventory_items, 2, i); + int_to_sqlite(m_stmt_player_add_inventory_items, 3, j); + str_to_sqlite(m_stmt_player_add_inventory_items, 4, itemStr); + sqlite3_vrfy(sqlite3_step(m_stmt_player_add_inventory_items), SQLITE_DONE); + sqlite3_reset(m_stmt_player_add_inventory_items); + } + } + + str_to_sqlite(m_stmt_player_metadata_remove, 1, player->getName()); + sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_remove), SQLITE_DONE); + sqlite3_reset(m_stmt_player_metadata_remove); + + const PlayerAttributes &attrs = sao->getExtendedAttributes(); + for (PlayerAttributes::const_iterator it = attrs.begin(); it != attrs.end(); ++it) { + str_to_sqlite(m_stmt_player_metadata_add, 1, player->getName()); + str_to_sqlite(m_stmt_player_metadata_add, 2, it->first); + str_to_sqlite(m_stmt_player_metadata_add, 3, it->second); + sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_add), SQLITE_DONE); + sqlite3_reset(m_stmt_player_metadata_add); + } + + endSave(); } -Database_SQLite3::~Database_SQLite3() +bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao) { - FINALIZE_STATEMENT(m_stmt_read) - FINALIZE_STATEMENT(m_stmt_write) - FINALIZE_STATEMENT(m_stmt_list) - FINALIZE_STATEMENT(m_stmt_begin) - FINALIZE_STATEMENT(m_stmt_end) - FINALIZE_STATEMENT(m_stmt_delete) + verifyDatabase(); - SQLOK_ERRSTREAM(sqlite3_close(m_database), "Failed to close database"); + str_to_sqlite(m_stmt_player_load, 1, player->getName()); + if (sqlite3_step(m_stmt_player_load) != SQLITE_ROW) { + sqlite3_reset(m_stmt_player_load); + return false; + } + sao->setPitch(sqlite_to_float(m_stmt_player_load, 0)); + sao->setYaw(sqlite_to_float(m_stmt_player_load, 1)); + sao->setBasePosition(sqlite_to_v3f(m_stmt_player_load, 2)); + sao->setHPRaw((s16) MYMIN(sqlite_to_int(m_stmt_player_load, 5), S16_MAX)); + sao->setBreath((u16) MYMIN(sqlite_to_int(m_stmt_player_load, 6), U16_MAX), false); + sqlite3_reset(m_stmt_player_load); + + // Load inventory + str_to_sqlite(m_stmt_player_load_inventory, 1, player->getName()); + while (sqlite3_step(m_stmt_player_load_inventory) == SQLITE_ROW) { + InventoryList *invList = player->inventory.addList( + sqlite_to_string(m_stmt_player_load_inventory, 2), + sqlite_to_uint(m_stmt_player_load_inventory, 3)); + invList->setWidth(sqlite_to_uint(m_stmt_player_load_inventory, 1)); + + u32 invId = sqlite_to_uint(m_stmt_player_load_inventory, 0); + + str_to_sqlite(m_stmt_player_load_inventory_items, 1, player->getName()); + int_to_sqlite(m_stmt_player_load_inventory_items, 2, invId); + while (sqlite3_step(m_stmt_player_load_inventory_items) == SQLITE_ROW) { + const std::string itemStr = sqlite_to_string(m_stmt_player_load_inventory_items, 1); + if (itemStr.length() > 0) { + ItemStack stack; + stack.deSerialize(itemStr); + invList->addItem(sqlite_to_uint(m_stmt_player_load_inventory_items, 0), stack); + } + } + sqlite3_reset(m_stmt_player_load_inventory_items); + } + + sqlite3_reset(m_stmt_player_load_inventory); + + str_to_sqlite(m_stmt_player_metadata_load, 1, sao->getPlayer()->getName()); + while (sqlite3_step(m_stmt_player_metadata_load) == SQLITE_ROW) { + std::string attr = sqlite_to_string(m_stmt_player_metadata_load, 0); + std::string value = sqlite_to_string(m_stmt_player_metadata_load, 1); + + sao->setExtendedAttribute(attr, value); + } + sqlite3_reset(m_stmt_player_metadata_load); + return true; +} + +bool PlayerDatabaseSQLite3::removePlayer(const std::string &name) +{ + if (!playerDataExists(name)) + return false; + + str_to_sqlite(m_stmt_player_remove, 1, name); + sqlite3_vrfy(sqlite3_step(m_stmt_player_remove), SQLITE_DONE); + sqlite3_reset(m_stmt_player_remove); + return true; } +void PlayerDatabaseSQLite3::listPlayers(std::vector &res) +{ + verifyDatabase(); + + while (sqlite3_step(m_stmt_player_list) == SQLITE_ROW) + res.push_back(sqlite_to_string(m_stmt_player_list, 0)); + + sqlite3_reset(m_stmt_player_list); +} diff --git a/src/database-sqlite3.h b/src/database-sqlite3.h index 2ab4c8ee9..3244facc9 100644 --- a/src/database-sqlite3.h +++ b/src/database-sqlite3.h @@ -20,8 +20,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef DATABASE_SQLITE3_HEADER #define DATABASE_SQLITE3_HEADER +#include #include #include "database.h" +#include "exceptions.h" extern "C" { #include "sqlite3.h" @@ -30,37 +32,97 @@ extern "C" { class Database_SQLite3 : public Database { public: - Database_SQLite3(const std::string &savedir); - ~Database_SQLite3(); + virtual ~Database_SQLite3(); void beginSave(); void endSave(); - bool saveBlock(const v3s16 &pos, const std::string &data); - void loadBlock(const v3s16 &pos, std::string *block); - bool deleteBlock(const v3s16 &pos); - void listAllLoadableBlocks(std::vector &dst); bool initialized() const { return m_initialized; } +protected: + Database_SQLite3(const std::string &savedir, const std::string &dbname); -private: - // Open the database - void openDatabase(); - // Create the database structure - void createDatabase(); // Open and initialize the database if needed void verifyDatabase(); - void bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index = 1); + // Convertors + inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const std::string &str) const + { + sqlite3_vrfy(sqlite3_bind_text(s, iCol, str.c_str(), str.size(), NULL)); + } + + inline void str_to_sqlite(sqlite3_stmt *s, int iCol, const char *str) const + { + sqlite3_vrfy(sqlite3_bind_text(s, iCol, str, strlen(str), NULL)); + } + + inline void int_to_sqlite(sqlite3_stmt *s, int iCol, int val) const + { + sqlite3_vrfy(sqlite3_bind_int(s, iCol, val)); + } + + inline void int64_to_sqlite(sqlite3_stmt *s, int iCol, s64 val) const + { + sqlite3_vrfy(sqlite3_bind_int64(s, iCol, (sqlite3_int64) val)); + } + + inline void double_to_sqlite(sqlite3_stmt *s, int iCol, double val) const + { + sqlite3_vrfy(sqlite3_bind_double(s, iCol, val)); + } + + inline std::string sqlite_to_string(sqlite3_stmt *s, int iCol) + { + const char* text = reinterpret_cast(sqlite3_column_text(s, iCol)); + return std::string(text ? text : ""); + } + + inline s32 sqlite_to_int(sqlite3_stmt *s, int iCol) + { + return sqlite3_column_int(s, iCol); + } + + inline u32 sqlite_to_uint(sqlite3_stmt *s, int iCol) + { + return (u32) sqlite3_column_int(s, iCol); + } + + inline float sqlite_to_float(sqlite3_stmt *s, int iCol) + { + return (float) sqlite3_column_double(s, iCol); + } + + inline const v3f sqlite_to_v3f(sqlite3_stmt *s, int iCol) + { + return v3f(sqlite_to_float(s, iCol), sqlite_to_float(s, iCol + 1), + sqlite_to_float(s, iCol + 2)); + } + + // Query verifiers helpers + inline void sqlite3_vrfy(int s, const std::string &m = "", int r = SQLITE_OK) const + { + if (s != r) + throw DatabaseException(m + ": " + sqlite3_errmsg(m_database)); + } + + inline void sqlite3_vrfy(const int s, const int r, const std::string &m = "") const + { + sqlite3_vrfy(s, m, r); + } + + // Create the database structure + virtual void createDatabase() = 0; + virtual void initStatements() = 0; + + sqlite3 *m_database; +private: + // Open the database + void openDatabase(); bool m_initialized; std::string m_savedir; + std::string m_dbname; - sqlite3 *m_database; - sqlite3_stmt *m_stmt_read; - sqlite3_stmt *m_stmt_write; - sqlite3_stmt *m_stmt_list; - sqlite3_stmt *m_stmt_delete; sqlite3_stmt *m_stmt_begin; sqlite3_stmt *m_stmt_end; @@ -69,4 +131,66 @@ private: static int busyHandler(void *data, int count); }; +class MapDatabaseSQLite3 : private Database_SQLite3, public MapDatabase +{ +public: + MapDatabaseSQLite3(const std::string &savedir); + virtual ~MapDatabaseSQLite3(); + + bool saveBlock(const v3s16 &pos, const std::string &data); + void loadBlock(const v3s16 &pos, std::string *block); + bool deleteBlock(const v3s16 &pos); + void listAllLoadableBlocks(std::vector &dst); + + void beginSave() { Database_SQLite3::beginSave(); } + void endSave() { Database_SQLite3::endSave(); } +protected: + virtual void createDatabase(); + virtual void initStatements(); + +private: + void bindPos(sqlite3_stmt *stmt, const v3s16 &pos, int index = 1); + + // Map + sqlite3_stmt *m_stmt_read; + sqlite3_stmt *m_stmt_write; + sqlite3_stmt *m_stmt_list; + sqlite3_stmt *m_stmt_delete; +}; + +class PlayerDatabaseSQLite3 : private Database_SQLite3, public PlayerDatabase +{ +public: + PlayerDatabaseSQLite3(const std::string &savedir); + virtual ~PlayerDatabaseSQLite3(); + + void savePlayer(RemotePlayer *player); + bool loadPlayer(RemotePlayer *player, PlayerSAO *sao); + bool removePlayer(const std::string &name); + void listPlayers(std::vector &res); + +protected: + virtual void createDatabase(); + virtual void initStatements(); + +private: + bool playerDataExists(const std::string &name); + + // Players + sqlite3_stmt *m_stmt_player_load; + sqlite3_stmt *m_stmt_player_add; + sqlite3_stmt *m_stmt_player_update; + sqlite3_stmt *m_stmt_player_remove; + sqlite3_stmt *m_stmt_player_list; + sqlite3_stmt *m_stmt_player_load_inventory; + sqlite3_stmt *m_stmt_player_load_inventory_items; + sqlite3_stmt *m_stmt_player_add_inventory; + sqlite3_stmt *m_stmt_player_add_inventory_items; + sqlite3_stmt *m_stmt_player_remove_inventory; + sqlite3_stmt *m_stmt_player_remove_inventory_items; + sqlite3_stmt *m_stmt_player_metadata_load; + sqlite3_stmt *m_stmt_player_metadata_remove; + sqlite3_stmt *m_stmt_player_metadata_add; +}; + #endif diff --git a/src/database.cpp b/src/database.cpp index 262d475ec..8e1483893 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -48,7 +48,7 @@ static inline s64 pythonmodulo(s64 i, s16 mod) } -s64 Database::getBlockAsInteger(const v3s16 &pos) +s64 MapDatabase::getBlockAsInteger(const v3s16 &pos) { return (u64) pos.Z * 0x1000000 + (u64) pos.Y * 0x1000 + @@ -56,7 +56,7 @@ s64 Database::getBlockAsInteger(const v3s16 &pos) } -v3s16 Database::getIntegerAsBlock(s64 i) +v3s16 MapDatabase::getIntegerAsBlock(s64 i) { v3s16 pos; pos.X = unsigned_to_signed(pythonmodulo(i, 4096), 2048); diff --git a/src/database.h b/src/database.h index 7213f088a..5a2b844fd 100644 --- a/src/database.h +++ b/src/database.h @@ -29,10 +29,15 @@ with this program; if not, write to the Free Software Foundation, Inc., class Database { public: - virtual ~Database() {} + virtual void beginSave() = 0; + virtual void endSave() = 0; + virtual bool initialized() const { return true; } +}; - virtual void beginSave() {} - virtual void endSave() {} +class MapDatabase : public Database +{ +public: + virtual ~MapDatabase() {} virtual bool saveBlock(const v3s16 &pos, const std::string &data) = 0; virtual void loadBlock(const v3s16 &pos, std::string *block) = 0; @@ -42,8 +47,19 @@ public: static v3s16 getIntegerAsBlock(s64 i); virtual void listAllLoadableBlocks(std::vector &dst) = 0; +}; - virtual bool initialized() const { return true; } +class PlayerSAO; +class RemotePlayer; + +class PlayerDatabase +{ +public: + virtual ~PlayerDatabase() {} + virtual void savePlayer(RemotePlayer *player) = 0; + virtual bool loadPlayer(RemotePlayer *player, PlayerSAO *sao) = 0; + virtual bool removePlayer(const std::string &name) = 0; + virtual void listPlayers(std::vector &res) = 0; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 1ec278981..2ad4e2780 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -47,6 +47,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #endif #ifndef SERVER #include "client/clientlauncher.h" + #endif #ifdef HAVE_TOUCHSCREENGUI @@ -102,7 +103,7 @@ static bool get_game_from_cmdline(GameParams *game_params, const Settings &cmd_a static bool determine_subgame(GameParams *game_params); static bool run_dedicated_server(const GameParams &game_params, const Settings &cmd_args); -static bool migrate_database(const GameParams &game_params, const Settings &cmd_args); +static bool migrate_map_database(const GameParams &game_params, const Settings &cmd_args); /**********************************************************************/ @@ -292,6 +293,8 @@ static void set_allowed_options(OptionList *allowed_options) _("Set gameid (\"--gameid list\" prints available ones)")))); allowed_options->insert(std::make_pair("migrate", ValueSpec(VALUETYPE_STRING, _("Migrate from current map backend to another (Only works when using minetestserver or with --server)")))); + allowed_options->insert(std::make_pair("migrate-players", ValueSpec(VALUETYPE_STRING, + _("Migrate from current players backend to another (Only works when using minetestserver or with --server)")))); allowed_options->insert(std::make_pair("terminal", ValueSpec(VALUETYPE_FLAG, _("Feature an interactive terminal (Only works when using minetestserver or with --server)")))); #ifndef SERVER @@ -332,7 +335,7 @@ static void print_allowed_options(const OptionList &allowed_options) if (i->second.type != VALUETYPE_FLAG) os1 << _(" "); - std::cout << padStringRight(os1.str(), 24); + std::cout << padStringRight(os1.str(), 30); if (i->second.help != NULL) std::cout << i->second.help; @@ -828,7 +831,9 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & // Database migration if (cmd_args.exists("migrate")) - return migrate_database(game_params, cmd_args); + return migrate_map_database(game_params, cmd_args); + else if (cmd_args.exists("migrate-players")) + return ServerEnvironment::migratePlayersDatabase(game_params, cmd_args); if (cmd_args.exists("terminal")) { #if USE_CURSES @@ -912,7 +917,7 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings & return true; } -static bool migrate_database(const GameParams &game_params, const Settings &cmd_args) +static bool migrate_map_database(const GameParams &game_params, const Settings &cmd_args) { std::string migrate_to = cmd_args.get("migrate"); Settings world_mt; @@ -921,20 +926,23 @@ static bool migrate_database(const GameParams &game_params, const Settings &cmd_ errorstream << "Cannot read world.mt!" << std::endl; return false; } + if (!world_mt.exists("backend")) { errorstream << "Please specify your current backend in world.mt:" << std::endl - << " backend = {sqlite3|leveldb|redis|dummy}" + << " backend = {sqlite3|leveldb|redis|dummy|postgresql}" << std::endl; return false; } + std::string backend = world_mt.get("backend"); if (backend == migrate_to) { errorstream << "Cannot migrate: new backend is same" << " as the old one" << std::endl; return false; } - Database *old_db = ServerMap::createDatabase(backend, game_params.world_path, world_mt), + + MapDatabase *old_db = ServerMap::createDatabase(backend, game_params.world_path, world_mt), *new_db = ServerMap::createDatabase(migrate_to, game_params.world_path, world_mt); u32 count = 0; @@ -976,4 +984,3 @@ static bool migrate_database(const GameParams &game_params, const Settings &cmd_ return true; } - diff --git a/src/map.cpp b/src/map.cpp index 75dcee350..c148c51f1 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2286,13 +2286,13 @@ bool ServerMap::loadSectorFull(v2s16 p2d) } #endif -Database *ServerMap::createDatabase( +MapDatabase *ServerMap::createDatabase( const std::string &name, const std::string &savedir, Settings &conf) { if (name == "sqlite3") - return new Database_SQLite3(savedir); + return new MapDatabaseSQLite3(savedir); if (name == "dummy") return new Database_Dummy(); #if USE_LEVELDB @@ -2304,8 +2304,11 @@ Database *ServerMap::createDatabase( return new Database_Redis(conf); #endif #if USE_POSTGRESQL - else if (name == "postgresql") - return new Database_PostgreSQL(conf); + else if (name == "postgresql") { + std::string connect_string = ""; + conf.getNoEx("pgsql_connection", connect_string); + return new MapDatabasePostgreSQL(connect_string); + } #endif else throw BaseException(std::string("Database backend ") + name + " not supported."); @@ -2326,7 +2329,7 @@ bool ServerMap::saveBlock(MapBlock *block) return saveBlock(block, dbase); } -bool ServerMap::saveBlock(MapBlock *block, Database *db) +bool ServerMap::saveBlock(MapBlock *block, MapDatabase *db) { v3s16 p3d = block->getPos(); diff --git a/src/map.h b/src/map.h index 4d7079823..7e597bef6 100644 --- a/src/map.h +++ b/src/map.h @@ -37,7 +37,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "map_settings_manager.h" class Settings; -class Database; +class MapDatabase; class ClientMap; class MapSector; class ServerMapSector; @@ -430,7 +430,7 @@ public: /* Database functions */ - static Database *createDatabase(const std::string &name, const std::string &savedir, Settings &conf); + static MapDatabase *createDatabase(const std::string &name, const std::string &savedir, Settings &conf); // Returns true if the database file does not exist bool loadFromFolders(); @@ -458,7 +458,7 @@ public: bool loadSectorMeta(v2s16 p2d); bool saveBlock(MapBlock *block); - static bool saveBlock(MapBlock *block, Database *db); + static bool saveBlock(MapBlock *block, MapDatabase *db); // This will generate a sector with getSector if not found. void loadBlock(const std::string §ordir, const std::string &blockfile, MapSector *sector, bool save_after_load=false); @@ -510,7 +510,7 @@ private: This is reset to false when written on disk. */ bool m_map_metadata_changed; - Database *dbase; + MapDatabase *dbase; }; diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp index c8e5b9132..2dbfe9d9d 100644 --- a/src/remoteplayer.cpp +++ b/src/remoteplayer.cpp @@ -67,54 +67,6 @@ RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef): movement_gravity = g_settings->getFloat("movement_gravity") * BS; } -void RemotePlayer::save(std::string savedir, IGameDef *gamedef) -{ - /* - * We have to open all possible player files in the players directory - * and check their player names because some file systems are not - * case-sensitive and player names are case-sensitive. - */ - - // A player to deserialize files into to check their names - RemotePlayer testplayer("", gamedef->idef()); - - savedir += DIR_DELIM; - std::string path = savedir + m_name; - for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) { - if (!fs::PathExists(path)) { - // Open file and serialize - std::ostringstream ss(std::ios_base::binary); - serialize(ss); - if (!fs::safeWriteToFile(path, ss.str())) { - infostream << "Failed to write " << path << std::endl; - } - setModified(false); - return; - } - // Open file and deserialize - std::ifstream is(path.c_str(), std::ios_base::binary); - if (!is.good()) { - infostream << "Failed to open " << path << std::endl; - return; - } - testplayer.deSerialize(is, path, NULL); - is.close(); - if (strcmp(testplayer.getName(), m_name) == 0) { - // Open file and serialize - std::ostringstream ss(std::ios_base::binary); - serialize(ss); - if (!fs::safeWriteToFile(path, ss.str())) { - infostream << "Failed to write " << path << std::endl; - } - setModified(false); - return; - } - path = savedir + m_name + itos(i); - } - - infostream << "Didn't find free file for player " << m_name << std::endl; -} - void RemotePlayer::serializeExtraAttributes(std::string &output) { assert(m_sao); diff --git a/src/remoteplayer.h b/src/remoteplayer.h index 9d123393f..ce7db5608 100644 --- a/src/remoteplayer.h +++ b/src/remoteplayer.h @@ -37,11 +37,11 @@ enum RemotePlayerChatResult */ class RemotePlayer : public Player { + friend class PlayerDatabaseFiles; public: RemotePlayer(const char *name, IItemDefManager *idef); virtual ~RemotePlayer() {} - void save(std::string savedir, IGameDef *gamedef); void deSerialize(std::istream &is, const std::string &playername, PlayerSAO *sao); PlayerSAO *getPlayerSAO() { return m_sao; } diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 6ac4bb653..d94f3e31d 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -334,6 +334,22 @@ int ModApiServer::l_kick_player(lua_State *L) return 1; } +int ModApiServer::l_remove_player(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + std::string name = luaL_checkstring(L, 1); + ServerEnvironment *s_env = dynamic_cast(getEnv(L)); + assert(s_env); + + RemotePlayer *player = s_env->getPlayer(name.c_str()); + if (!player) + lua_pushinteger(L, s_env->removePlayerFromDatabase(name) ? 0 : 1); + else + lua_pushinteger(L, 2); + + return 1; +} + // unban_player_or_ip() int ModApiServer::l_unban_player_or_ip(lua_State *L) { @@ -510,6 +526,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(get_ban_description); API_FCT(ban_player); API_FCT(kick_player); + API_FCT(remove_player); API_FCT(unban_player_or_ip); API_FCT(notify_authentication_modified); diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index 008810784..e6c0df978 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -92,6 +92,9 @@ private: // kick_player(name, [message]) -> success static int l_kick_player(lua_State *L); + // remove_player(name) + static int l_remove_player(lua_State *L); + // notify_authentication_modified(name) static int l_notify_authentication_modified(lua_State *L); diff --git a/src/server.cpp b/src/server.cpp index ac6265d09..4c7e60286 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -60,6 +60,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/base64.h" #include "util/sha1.h" #include "util/hex.h" +#include "database.h" class ClientNotFoundException : public BaseException { @@ -2618,9 +2619,8 @@ void Server::RespawnPlayer(u16 peer_id) bool repositioned = m_script->on_respawnplayer(playersao); if (!repositioned) { - v3f pos = findSpawnPos(); // setPos will send the new position to client - playersao->setPos(pos); + playersao->setPos(findSpawnPos()); } SendPlayerHP(peer_id); @@ -3442,8 +3442,8 @@ v3f Server::findSpawnPos() s32 range = 1 + i; // We're going to try to throw the player to this position v2s16 nodepos2d = v2s16( - -range + (myrand() % (range * 2)), - -range + (myrand() % (range * 2))); + -range + (myrand() % (range * 2)), + -range + (myrand() % (range * 2))); // Get spawn level at point s16 spawn_level = m_emerge->getSpawnLevelAtPoint(nodepos2d); @@ -3516,8 +3516,6 @@ void Server::requestShutdown(const std::string &msg, bool reconnect, float delay PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version) { - bool newplayer = false; - /* Try to get an existing player */ @@ -3538,44 +3536,18 @@ PlayerSAO* Server::emergePlayer(const char *name, u16 peer_id, u16 proto_version return NULL; } - // Create a new player active object - PlayerSAO *playersao = new PlayerSAO(m_env, peer_id, isSingleplayer()); - player = m_env->loadPlayer(name, playersao); - - // Create player if it doesn't exist if (!player) { - newplayer = true; - player = new RemotePlayer(name, this->idef()); - // Set player position - infostream<<"Server: Finding spawn place for player \"" - <setBasePosition(findSpawnPos()); - - // Make sure the player is saved - player->setModified(true); - - // Add player to environment - m_env->addPlayer(player); - } else { - // If the player exists, ensure that they respawn inside legal bounds - // This fixes an assert crash when the player can't be added - // to the environment - if (objectpos_over_limit(playersao->getBasePosition())) { - actionstream << "Respawn position for player \"" - << name << "\" outside limits, resetting" << std::endl; - playersao->setBasePosition(findSpawnPos()); - } + player = new RemotePlayer(name, idef()); } - playersao->initialize(player, getPlayerEffectivePrivs(player->getName())); - - player->protocol_version = proto_version; + bool newplayer = false; - /* Clean up old HUD elements from previous sessions */ - player->clearHud(); + // Load player + PlayerSAO *playersao = m_env->loadPlayer(player, &newplayer, peer_id, isSingleplayer()); - /* Add object to environment */ - m_env->addActiveObject(playersao); + // Complete init with server parts + playersao->finalize(player, getPlayerEffectivePrivs(player->getName())); + player->protocol_version = proto_version; /* Run scripts */ if (newplayer) { diff --git a/src/server.h b/src/server.h index 4183bcda1..948fb8fc2 100644 --- a/src/server.h +++ b/src/server.h @@ -306,6 +306,7 @@ public: bool showFormspec(const char *name, const std::string &formspec, const std::string &formname); Map & getMap() { return m_env->getMap(); } ServerEnvironment & getEnv() { return *m_env; } + v3f findSpawnPos(); u32 hudAdd(RemotePlayer *player, HudElement *element); bool hudRemove(RemotePlayer *player, u32 id); @@ -472,8 +473,6 @@ private: RemotePlayer *player = NULL); void handleAdminChat(const ChatEventChat *evt); - v3f findSpawnPos(); - // When called, connection mutex should be locked RemoteClient* getClient(u16 peer_id,ClientState state_min=CS_Active); RemoteClient* getClientNoEx(u16 peer_id,ClientState state_min=CS_Active); diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index e09c7da16..c0dc0e0ea 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -36,6 +36,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/pointedthing.h" #include "threading/mutex_auto_lock.h" #include "filesys.h" +#include "gameparams.h" +#include "database-dummy.h" +#include "database-files.h" +#include "database-sqlite3.h" +#if USE_POSTGRESQL +#include "database-postgresql.h" +#endif #define LBM_NAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_:" @@ -365,8 +372,30 @@ ServerEnvironment::ServerEnvironment(ServerMap *map, m_game_time_fraction_counter(0), m_last_clear_objects_time(0), m_recommended_send_interval(0.1), - m_max_lag_estimate(0.1) + m_max_lag_estimate(0.1), + m_player_database(NULL) { + // Determine which database backend to use + std::string conf_path = path_world + DIR_DELIM + "world.mt"; + Settings conf; + bool succeeded = conf.readConfigFile(conf_path.c_str()); + if (!succeeded || !conf.exists("player_backend")) { + // fall back to files + conf.set("player_backend", "files"); + warningstream << "/!\\ You are using old player file backend. " + << "This backend is deprecated and will be removed in next release /!\\" + << std::endl << "Switching to SQLite3 or PostgreSQL is advised, " + << "please read http://wiki.minetest.net/Database_backends." << std::endl; + + if (!conf.updateConfigFile(conf_path.c_str())) { + errorstream << "ServerEnvironment::ServerEnvironment(): " + << "Failed to update world.mt!" << std::endl; + } + } + + std::string name = ""; + conf.getNoEx("player_backend", name); + m_player_database = openPlayerDatabase(name, path_world, conf); } ServerEnvironment::~ServerEnvironment() @@ -392,6 +421,8 @@ ServerEnvironment::~ServerEnvironment() i != m_players.end(); ++i) { delete (*i); } + + delete m_player_database; } Map & ServerEnvironment::getMap() @@ -455,6 +486,11 @@ void ServerEnvironment::removePlayer(RemotePlayer *player) } } +bool ServerEnvironment::removePlayerFromDatabase(const std::string &name) +{ + return m_player_database->removePlayer(name); +} + bool ServerEnvironment::line_of_sight(v3f pos1, v3f pos2, float stepsize, v3s16 *p) { float distance = pos1.getDistanceFrom(pos2); @@ -495,7 +531,7 @@ void ServerEnvironment::kickAllPlayers(AccessDeniedCode reason, void ServerEnvironment::saveLoadedPlayers() { - std::string players_path = m_path_world + DIR_DELIM "players"; + std::string players_path = m_path_world + DIR_DELIM + "players"; fs::CreateDir(players_path); for (std::vector::iterator it = m_players.begin(); @@ -503,63 +539,63 @@ void ServerEnvironment::saveLoadedPlayers() ++it) { if ((*it)->checkModified() || ((*it)->getPlayerSAO() && (*it)->getPlayerSAO()->extendedAttributesModified())) { - (*it)->save(players_path, m_server); + try { + m_player_database->savePlayer(*it); + } catch (DatabaseException &e) { + errorstream << "Failed to save player " << (*it)->getName() << " exception: " + << e.what() << std::endl; + throw; + } } } } void ServerEnvironment::savePlayer(RemotePlayer *player) { - std::string players_path = m_path_world + DIR_DELIM "players"; - fs::CreateDir(players_path); - - player->save(players_path, m_server); + try { + m_player_database->savePlayer(player); + } catch (DatabaseException &e) { + errorstream << "Failed to save player " << player->getName() << " exception: " + << e.what() << std::endl; + throw; + } } -RemotePlayer *ServerEnvironment::loadPlayer(const std::string &playername, PlayerSAO *sao) +PlayerSAO *ServerEnvironment::loadPlayer(RemotePlayer *player, bool *new_player, + u16 peer_id, bool is_singleplayer) { - bool newplayer = false; - bool found = false; - std::string players_path = m_path_world + DIR_DELIM "players" DIR_DELIM; - std::string path = players_path + playername; - - RemotePlayer *player = getPlayer(playername.c_str()); - if (!player) { - player = new RemotePlayer("", m_server->idef()); - newplayer = true; - } - - for (u32 i = 0; i < PLAYER_FILE_ALTERNATE_TRIES; i++) { - //// Open file and deserialize - std::ifstream is(path.c_str(), std::ios_base::binary); - if (!is.good()) - continue; - - player->deSerialize(is, path, sao); - is.close(); - - if (player->getName() == playername) { - found = true; - break; + PlayerSAO *playersao = new PlayerSAO(this, player, peer_id, is_singleplayer); + // Create player if it doesn't exist + if (!m_player_database->loadPlayer(player, playersao)) { + *new_player = true; + // Set player position + infostream << "Server: Finding spawn place for player \"" + << player->getName() << "\"" << std::endl; + playersao->setBasePosition(m_server->findSpawnPos()); + + // Make sure the player is saved + player->setModified(true); + } else { + // If the player exists, ensure that they respawn inside legal bounds + // This fixes an assert crash when the player can't be added + // to the environment + if (objectpos_over_limit(playersao->getBasePosition())) { + actionstream << "Respawn position for player \"" + << player->getName() << "\" outside limits, resetting" << std::endl; + playersao->setBasePosition(m_server->findSpawnPos()); } - - path = players_path + playername + itos(i); } - if (!found) { - infostream << "Player file for player " << playername - << " not found" << std::endl; - if (newplayer) - delete player; + // Add player to environment + addPlayer(player); - return NULL; - } + /* Clean up old HUD elements from previous sessions */ + player->clearHud(); - if (newplayer) { - addPlayer(player); - } - player->setModified(false); - return player; + /* Add object to environment */ + addActiveObject(playersao); + + return playersao; } void ServerEnvironment::saveMeta() @@ -2173,3 +2209,111 @@ void ServerEnvironment::deactivateFarObjects(bool _force_delete) m_active_objects.erase(*i); } } + +PlayerDatabase *ServerEnvironment::openPlayerDatabase(const std::string &name, + const std::string &savedir, const Settings &conf) +{ + + if (name == "sqlite3") + return new PlayerDatabaseSQLite3(savedir); + else if (name == "dummy") + return new Database_Dummy(); +#if USE_POSTGRESQL + else if (name == "postgresql") { + std::string connect_string = ""; + conf.getNoEx("pgsql_player_connection", connect_string); + return new PlayerDatabasePostgreSQL(connect_string); + } +#endif + else if (name == "files") + return new PlayerDatabaseFiles(savedir + DIR_DELIM + "players"); + else + throw BaseException(std::string("Database backend ") + name + " not supported."); +} + +bool ServerEnvironment::migratePlayersDatabase(const GameParams &game_params, + const Settings &cmd_args) +{ + std::string migrate_to = cmd_args.get("migrate-players"); + Settings world_mt; + std::string world_mt_path = game_params.world_path + DIR_DELIM + "world.mt"; + if (!world_mt.readConfigFile(world_mt_path.c_str())) { + errorstream << "Cannot read world.mt!" << std::endl; + return false; + } + + if (!world_mt.exists("player_backend")) { + errorstream << "Please specify your current backend in world.mt:" + << std::endl + << " player_backend = {files|sqlite3|postgresql}" + << std::endl; + return false; + } + + std::string backend = world_mt.get("player_backend"); + if (backend == migrate_to) { + errorstream << "Cannot migrate: new backend is same" + << " as the old one" << std::endl; + return false; + } + + const std::string players_backup_path = game_params.world_path + DIR_DELIM + + "players.bak"; + + if (backend == "files") { + // Create backup directory + fs::CreateDir(players_backup_path); + } + + try { + PlayerDatabase *srcdb = ServerEnvironment::openPlayerDatabase(backend, + game_params.world_path, world_mt); + PlayerDatabase *dstdb = ServerEnvironment::openPlayerDatabase(migrate_to, + game_params.world_path, world_mt); + + std::vector player_list; + srcdb->listPlayers(player_list); + for (std::vector::const_iterator it = player_list.begin(); + it != player_list.end(); ++it) { + actionstream << "Migrating player " << it->c_str() << std::endl; + RemotePlayer player(it->c_str(), NULL); + PlayerSAO playerSAO(NULL, &player, 15000, false); + + srcdb->loadPlayer(&player, &playerSAO); + + playerSAO.finalize(&player, std::set()); + player.setPlayerSAO(&playerSAO); + + dstdb->savePlayer(&player); + + // For files source, move player files to backup dir + if (backend == "files") { + fs::Rename( + game_params.world_path + DIR_DELIM + "players" + DIR_DELIM + (*it), + players_backup_path + DIR_DELIM + (*it)); + } + } + + actionstream << "Successfully migrated " << player_list.size() << " players" + << std::endl; + world_mt.set("player_backend", migrate_to); + if (!world_mt.updateConfigFile(world_mt_path.c_str())) + errorstream << "Failed to update world.mt!" << std::endl; + else + actionstream << "world.mt updated" << std::endl; + + // When migration is finished from file backend, remove players directory if empty + if (backend == "files") { + fs::DeleteSingleFileOrEmptyDirectory(game_params.world_path + DIR_DELIM + + "players"); + } + + delete srcdb; + delete dstdb; + + } catch (BaseException &e) { + errorstream << "An error occured during migration: " << e.what() << std::endl; + return false; + } + return true; +} diff --git a/src/serverenvironment.h b/src/serverenvironment.h index 99110542a..0e31aa41a 100644 --- a/src/serverenvironment.h +++ b/src/serverenvironment.h @@ -27,7 +27,9 @@ with this program; if not, write to the Free Software Foundation, Inc., class IGameDef; class ServerMap; +struct GameParams; class RemotePlayer; +class PlayerDatabase; class PlayerSAO; class ServerEnvironment; class ActiveBlockModifier; @@ -217,9 +219,11 @@ public: // Save players void saveLoadedPlayers(); void savePlayer(RemotePlayer *player); - RemotePlayer *loadPlayer(const std::string &playername, PlayerSAO *sao); + PlayerSAO *loadPlayer(RemotePlayer *player, bool *new_player, u16 peer_id, + bool is_singleplayer); void addPlayer(RemotePlayer *player); void removePlayer(RemotePlayer *player); + bool removePlayerFromDatabase(const std::string &name); /* Save and load time of day and game timer @@ -334,8 +338,13 @@ public: RemotePlayer *getPlayer(const u16 peer_id); RemotePlayer *getPlayer(const char* name); + + static bool migratePlayersDatabase(const GameParams &game_params, + const Settings &cmd_args); private: + static PlayerDatabase *openPlayerDatabase(const std::string &name, + const std::string &savedir, const Settings &conf); /* Internal ActiveObject interface ------------------------------------------- @@ -419,6 +428,8 @@ private: // peer_ids in here should be unique, except that there may be many 0s std::vector m_players; + PlayerDatabase *m_player_database; + // Particles IntervalLimiter m_particle_management_interval; UNORDERED_MAP m_particle_spawners; diff --git a/src/unittest/test_player.cpp b/src/unittest/test_player.cpp index b639878b2..e2b1cd855 100644 --- a/src/unittest/test_player.cpp +++ b/src/unittest/test_player.cpp @@ -31,59 +31,10 @@ public: const char *getName() { return "TestPlayer"; } void runTests(IGameDef *gamedef); - - void testSave(IGameDef *gamedef); - void testLoad(IGameDef *gamedef); }; static TestPlayer g_test_instance; void TestPlayer::runTests(IGameDef *gamedef) { - TEST(testSave, gamedef); - TEST(testLoad, gamedef); -} - -void TestPlayer::testSave(IGameDef *gamedef) -{ - RemotePlayer rplayer("testplayer_save", gamedef->idef()); - PlayerSAO sao(NULL, 1, false); - sao.initialize(&rplayer, std::set()); - rplayer.setPlayerSAO(&sao); - sao.setBreath(10, false); - sao.setHPRaw(8); - sao.setYaw(0.1f); - sao.setPitch(0.6f); - sao.setBasePosition(v3f(450.2f, -15.7f, 68.1f)); - rplayer.save(".", gamedef); - UASSERT(fs::PathExists("testplayer_save")); -} - -void TestPlayer::testLoad(IGameDef *gamedef) -{ - RemotePlayer rplayer("testplayer_load", gamedef->idef()); - PlayerSAO sao(NULL, 1, false); - sao.initialize(&rplayer, std::set()); - rplayer.setPlayerSAO(&sao); - sao.setBreath(10, false); - sao.setHPRaw(8); - sao.setYaw(0.1f); - sao.setPitch(0.6f); - sao.setBasePosition(v3f(450.2f, -15.7f, 68.1f)); - rplayer.save(".", gamedef); - UASSERT(fs::PathExists("testplayer_load")); - - RemotePlayer rplayer_load("testplayer_load", gamedef->idef()); - PlayerSAO sao_load(NULL, 2, false); - std::ifstream is("testplayer_load", std::ios_base::binary); - UASSERT(is.good()); - rplayer_load.deSerialize(is, "testplayer_load", &sao_load); - is.close(); - - UASSERT(strcmp(rplayer_load.getName(), "testplayer_load") == 0); - UASSERT(sao_load.getBreath() == 10); - UASSERT(sao_load.getHP() == 8); - UASSERT(sao_load.getYaw() == 0.1f); - UASSERT(sao_load.getPitch() == 0.6f); - UASSERT(sao_load.getBasePosition() == v3f(450.2f, -15.7f, 68.1f)); } -- cgit v1.2.3 From 2818d3f2244d2146a5cdb61cd41f6561c514f97c Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Tue, 25 Apr 2017 13:38:08 -0400 Subject: Rename Scripting API files for consistency --- src/client.cpp | 2 +- src/clientenvironment.cpp | 2 +- src/content_abm.cpp | 2 +- src/content_sao.cpp | 2 +- src/emerge.cpp | 2 +- src/environment.cpp | 2 +- src/game.cpp | 2 +- src/guiFormSpecMenu.cpp | 2 +- src/inventorymanager.cpp | 2 +- src/map.cpp | 2 +- src/network/clientpackethandler.cpp | 2 +- src/network/serverpackethandler.cpp | 2 +- src/script/CMakeLists.txt | 4 +- src/script/clientscripting.cpp | 80 ------------------------ src/script/clientscripting.h | 42 ------------- src/script/lua_api/l_env.cpp | 2 +- src/script/lua_api/l_object.cpp | 2 +- src/script/scripting_client.cpp | 80 ++++++++++++++++++++++++ src/script/scripting_client.h | 42 +++++++++++++ src/script/scripting_server.cpp | 119 ++++++++++++++++++++++++++++++++++++ src/script/scripting_server.h | 57 +++++++++++++++++ src/script/serverscripting.cpp | 119 ------------------------------------ src/script/serverscripting.h | 57 ----------------- src/server.cpp | 2 +- src/serverenvironment.cpp | 2 +- 25 files changed, 316 insertions(+), 316 deletions(-) delete mode 100644 src/script/clientscripting.cpp delete mode 100644 src/script/clientscripting.h create mode 100644 src/script/scripting_client.cpp create mode 100644 src/script/scripting_client.h create mode 100644 src/script/scripting_server.cpp create mode 100644 src/script/scripting_server.h delete mode 100644 src/script/serverscripting.cpp delete mode 100644 src/script/serverscripting.h (limited to 'src/server.cpp') diff --git a/src/client.cpp b/src/client.cpp index 94c808a57..19fe9b0ba 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -45,7 +45,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database-sqlite3.h" #include "serialization.h" #include "guiscalingfilter.h" -#include "script/clientscripting.h" +#include "script/scripting_client.h" #include "game.h" extern gui::IGUIEnvironment* guienv; diff --git a/src/clientenvironment.cpp b/src/clientenvironment.cpp index 4a8bbb066..cc75fd2d6 100644 --- a/src/clientenvironment.cpp +++ b/src/clientenvironment.cpp @@ -22,7 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "clientenvironment.h" #include "clientsimpleobject.h" #include "clientmap.h" -#include "clientscripting.h" +#include "scripting_client.h" #include "mapblock_mesh.h" #include "event.h" #include "collision.h" diff --git a/src/content_abm.cpp b/src/content_abm.cpp index 1e175c64f..162f93364 100644 --- a/src/content_abm.cpp +++ b/src/content_abm.cpp @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "mapblock.h" // For getNodeBlockPos #include "map.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "log.h" void add_legacy_abms(ServerEnvironment *env, INodeDefManager *nodedef) diff --git a/src/content_sao.cpp b/src/content_sao.cpp index caf6dcbab..81c6902f5 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -26,7 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "remoteplayer.h" #include "server.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "genericobject.h" std::map ServerActiveObject::m_types; diff --git a/src/emerge.cpp b/src/emerge.cpp index 4c3a83f7e..d24971e44 100644 --- a/src/emerge.cpp +++ b/src/emerge.cpp @@ -40,7 +40,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "mg_schematic.h" #include "nodedef.h" #include "profiler.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "server.h" #include "serverobject.h" #include "settings.h" diff --git a/src/environment.cpp b/src/environment.cpp index c1aeeec60..4e782db81 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -21,7 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "environment.h" #include "collision.h" #include "serverobject.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "server.h" #include "daynightratio.h" #include "emerge.h" diff --git a/src/game.cpp b/src/game.cpp index 31a48531c..97dc8c064 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -60,7 +60,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "version.h" #include "minimap.h" #include "mapblock_mesh.h" -#include "script/clientscripting.h" +#include "script/scripting_client.h" #include "sound.h" diff --git a/src/guiFormSpecMenu.cpp b/src/guiFormSpecMenu.cpp index 5861e9a81..14d576f8f 100644 --- a/src/guiFormSpecMenu.cpp +++ b/src/guiFormSpecMenu.cpp @@ -42,7 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "filesys.h" #include "gettime.h" #include "gettext.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "porting.h" #include "settings.h" #include "client.h" diff --git a/src/inventorymanager.cpp b/src/inventorymanager.cpp index 6ebc2994b..c976bd037 100644 --- a/src/inventorymanager.cpp +++ b/src/inventorymanager.cpp @@ -20,7 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "inventorymanager.h" #include "log.h" #include "serverenvironment.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "serverobject.h" #include "settings.h" #include "craftdef.h" diff --git a/src/map.cpp b/src/map.cpp index c148c51f1..9e8823f84 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -44,7 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "database.h" #include "database-dummy.h" #include "database-sqlite3.h" -#include "script/serverscripting.h" +#include "script/scripting_server.h" #include #include #if USE_LEVELDB diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 42c49be3c..772ffe905 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -30,7 +30,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "server.h" #include "util/strfnd.h" #include "network/clientopcodes.h" -#include "script/clientscripting.h" +#include "script/scripting_client.h" #include "util/serialize.h" #include "util/srp.h" #include "tileanimation.h" diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index c284cb6c8..5b026bbdb 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -27,7 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "nodedef.h" #include "player.h" #include "rollback_interface.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "settings.h" #include "tool.h" #include "version.h" diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt index c96ccc816..bebe2f037 100644 --- a/src/script/CMakeLists.txt +++ b/src/script/CMakeLists.txt @@ -4,7 +4,7 @@ add_subdirectory(lua_api) # Used by server and client set(common_SCRIPT_SRCS - ${CMAKE_CURRENT_SOURCE_DIR}/serverscripting.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/scripting_server.cpp ${common_SCRIPT_COMMON_SRCS} ${common_SCRIPT_CPP_API_SRCS} ${common_SCRIPT_LUA_API_SRCS} @@ -13,7 +13,7 @@ set(common_SCRIPT_SRCS # Used by client only set(client_SCRIPT_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/scripting_mainmenu.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/clientscripting.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/scripting_client.cpp ${client_SCRIPT_COMMON_SRCS} ${client_SCRIPT_CPP_API_SRCS} ${client_SCRIPT_LUA_API_SRCS} diff --git a/src/script/clientscripting.cpp b/src/script/clientscripting.cpp deleted file mode 100644 index ba3f910c0..000000000 --- a/src/script/clientscripting.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola -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. -*/ - -#include "clientscripting.h" -#include "client.h" -#include "cpp_api/s_internal.h" -#include "lua_api/l_client.h" -#include "lua_api/l_env.h" -#include "lua_api/l_minimap.h" -#include "lua_api/l_storage.h" -#include "lua_api/l_sound.h" -#include "lua_api/l_util.h" -#include "lua_api/l_item.h" -#include "lua_api/l_nodemeta.h" -#include "lua_api/l_localplayer.h" - -ClientScripting::ClientScripting(Client *client): - ScriptApiBase() -{ - setGameDef(client); - - SCRIPTAPI_PRECHECKHEADER - - // Security is mandatory client side - initializeSecurityClient(); - - lua_getglobal(L, "core"); - int top = lua_gettop(L); - - lua_newtable(L); - lua_setfield(L, -2, "ui"); - - InitializeModApi(L, top); - lua_pop(L, 1); - - LuaMinimap::create(L, client->getMinimap()); - - // Push builtin initialization type - lua_pushstring(L, "client"); - lua_setglobal(L, "INIT"); - - infostream << "SCRIPTAPI: Initialized client game modules" << std::endl; -} - -void ClientScripting::InitializeModApi(lua_State *L, int top) -{ - ModApiUtil::InitializeClient(L, top); - ModApiClient::Initialize(L, top); - ModApiStorage::Initialize(L, top); - ModApiEnvMod::InitializeClient(L, top); - - LuaItemStack::Register(L); - StorageRef::Register(L); - LuaMinimap::Register(L); - NodeMetaRef::RegisterClient(L); - LuaLocalPlayer::Register(L); -} - -void ClientScripting::on_client_ready(LocalPlayer *localplayer) -{ - lua_State *L = getStack(); - LuaLocalPlayer::create(L, localplayer); -} diff --git a/src/script/clientscripting.h b/src/script/clientscripting.h deleted file mode 100644 index df94e8b71..000000000 --- a/src/script/clientscripting.h +++ /dev/null @@ -1,42 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola -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. -*/ - -#ifndef CLIENT_SCRIPTING_H_ -#define CLIENT_SCRIPTING_H_ - -#include "cpp_api/s_base.h" -#include "cpp_api/s_client.h" -#include "cpp_api/s_security.h" - -class Client; -class LocalPlayer; -class ClientScripting: - virtual public ScriptApiBase, - public ScriptApiSecurity, - public ScriptApiClient -{ -public: - ClientScripting(Client *client); - void on_client_ready(LocalPlayer *localplayer); - -private: - virtual void InitializeModApi(lua_State *L, int top); -}; -#endif diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index 75b07fa37..85791f90b 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -25,7 +25,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_vmanip.h" #include "common/c_converter.h" #include "common/c_content.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "environment.h" #include "server.h" #include "nodedef.h" diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 95e977f9e..9668f76f7 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -29,7 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "content_sao.h" #include "server.h" #include "hud.h" -#include "serverscripting.h" +#include "scripting_server.h" struct EnumString es_HudElementType[] = { diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp new file mode 100644 index 000000000..8ff5abcc4 --- /dev/null +++ b/src/script/scripting_client.cpp @@ -0,0 +1,80 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#include "scripting_client.h" +#include "client.h" +#include "cpp_api/s_internal.h" +#include "lua_api/l_client.h" +#include "lua_api/l_env.h" +#include "lua_api/l_minimap.h" +#include "lua_api/l_storage.h" +#include "lua_api/l_sound.h" +#include "lua_api/l_util.h" +#include "lua_api/l_item.h" +#include "lua_api/l_nodemeta.h" +#include "lua_api/l_localplayer.h" + +ClientScripting::ClientScripting(Client *client): + ScriptApiBase() +{ + setGameDef(client); + + SCRIPTAPI_PRECHECKHEADER + + // Security is mandatory client side + initializeSecurityClient(); + + lua_getglobal(L, "core"); + int top = lua_gettop(L); + + lua_newtable(L); + lua_setfield(L, -2, "ui"); + + InitializeModApi(L, top); + lua_pop(L, 1); + + LuaMinimap::create(L, client->getMinimap()); + + // Push builtin initialization type + lua_pushstring(L, "client"); + lua_setglobal(L, "INIT"); + + infostream << "SCRIPTAPI: Initialized client game modules" << std::endl; +} + +void ClientScripting::InitializeModApi(lua_State *L, int top) +{ + ModApiUtil::InitializeClient(L, top); + ModApiClient::Initialize(L, top); + ModApiStorage::Initialize(L, top); + ModApiEnvMod::InitializeClient(L, top); + + LuaItemStack::Register(L); + StorageRef::Register(L); + LuaMinimap::Register(L); + NodeMetaRef::RegisterClient(L); + LuaLocalPlayer::Register(L); +} + +void ClientScripting::on_client_ready(LocalPlayer *localplayer) +{ + lua_State *L = getStack(); + LuaLocalPlayer::create(L, localplayer); +} diff --git a/src/script/scripting_client.h b/src/script/scripting_client.h new file mode 100644 index 000000000..df94e8b71 --- /dev/null +++ b/src/script/scripting_client.h @@ -0,0 +1,42 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +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. +*/ + +#ifndef CLIENT_SCRIPTING_H_ +#define CLIENT_SCRIPTING_H_ + +#include "cpp_api/s_base.h" +#include "cpp_api/s_client.h" +#include "cpp_api/s_security.h" + +class Client; +class LocalPlayer; +class ClientScripting: + virtual public ScriptApiBase, + public ScriptApiSecurity, + public ScriptApiClient +{ +public: + ClientScripting(Client *client); + void on_client_ready(LocalPlayer *localplayer); + +private: + virtual void InitializeModApi(lua_State *L, int top); +}; +#endif diff --git a/src/script/scripting_server.cpp b/src/script/scripting_server.cpp new file mode 100644 index 000000000..ce56fcf19 --- /dev/null +++ b/src/script/scripting_server.cpp @@ -0,0 +1,119 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +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. +*/ + +#include "scripting_server.h" +#include "server.h" +#include "log.h" +#include "settings.h" +#include "cpp_api/s_internal.h" +#include "lua_api/l_areastore.h" +#include "lua_api/l_base.h" +#include "lua_api/l_craft.h" +#include "lua_api/l_env.h" +#include "lua_api/l_inventory.h" +#include "lua_api/l_item.h" +#include "lua_api/l_itemstackmeta.h" +#include "lua_api/l_mapgen.h" +#include "lua_api/l_nodemeta.h" +#include "lua_api/l_nodetimer.h" +#include "lua_api/l_noise.h" +#include "lua_api/l_object.h" +#include "lua_api/l_particles.h" +#include "lua_api/l_rollback.h" +#include "lua_api/l_server.h" +#include "lua_api/l_util.h" +#include "lua_api/l_vmanip.h" +#include "lua_api/l_settings.h" +#include "lua_api/l_http.h" +#include "lua_api/l_storage.h" + +extern "C" { +#include "lualib.h" +} + +ServerScripting::ServerScripting(Server* server) +{ + setGameDef(server); + + // setEnv(env) is called by ScriptApiEnv::initializeEnvironment() + // once the environment has been created + + SCRIPTAPI_PRECHECKHEADER + + if (g_settings->getBool("secure.enable_security")) { + initializeSecurity(); + } + + lua_getglobal(L, "core"); + int top = lua_gettop(L); + + lua_newtable(L); + lua_setfield(L, -2, "object_refs"); + + lua_newtable(L); + lua_setfield(L, -2, "luaentities"); + + // Initialize our lua_api modules + InitializeModApi(L, top); + lua_pop(L, 1); + + // Push builtin initialization type + lua_pushstring(L, "game"); + lua_setglobal(L, "INIT"); + + infostream << "SCRIPTAPI: Initialized game modules" << std::endl; +} + +void ServerScripting::InitializeModApi(lua_State *L, int top) +{ + // Initialize mod api modules + ModApiCraft::Initialize(L, top); + ModApiEnvMod::Initialize(L, top); + ModApiInventory::Initialize(L, top); + ModApiItemMod::Initialize(L, top); + ModApiMapgen::Initialize(L, top); + ModApiParticles::Initialize(L, top); + ModApiRollback::Initialize(L, top); + ModApiServer::Initialize(L, top); + ModApiUtil::Initialize(L, top); + ModApiHttp::Initialize(L, top); + ModApiStorage::Initialize(L, top); + + // Register reference classes (userdata) + InvRef::Register(L); + ItemStackMetaRef::Register(L); + LuaAreaStore::Register(L); + LuaItemStack::Register(L); + LuaPerlinNoise::Register(L); + LuaPerlinNoiseMap::Register(L); + LuaPseudoRandom::Register(L); + LuaPcgRandom::Register(L); + LuaSecureRandom::Register(L); + LuaVoxelManip::Register(L); + NodeMetaRef::Register(L); + NodeTimerRef::Register(L); + ObjectRef::Register(L); + LuaSettings::Register(L); + StorageRef::Register(L); +} + +void log_deprecated(const std::string &message) +{ + log_deprecated(NULL, message); +} diff --git a/src/script/scripting_server.h b/src/script/scripting_server.h new file mode 100644 index 000000000..fd97ea40b --- /dev/null +++ b/src/script/scripting_server.h @@ -0,0 +1,57 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola + +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. +*/ + +#ifndef SERVER_SCRIPTING_H_ +#define SERVER_SCRIPTING_H_ + +#include "cpp_api/s_base.h" +#include "cpp_api/s_entity.h" +#include "cpp_api/s_env.h" +#include "cpp_api/s_inventory.h" +#include "cpp_api/s_node.h" +#include "cpp_api/s_player.h" +#include "cpp_api/s_server.h" +#include "cpp_api/s_security.h" + +/*****************************************************************************/ +/* Scripting <-> Server Game Interface */ +/*****************************************************************************/ + +class ServerScripting: + virtual public ScriptApiBase, + public ScriptApiDetached, + public ScriptApiEntity, + public ScriptApiEnv, + public ScriptApiNode, + public ScriptApiPlayer, + public ScriptApiServer, + public ScriptApiSecurity +{ +public: + ServerScripting(Server* server); + + // use ScriptApiBase::loadMod() to load mods + +private: + void InitializeModApi(lua_State *L, int top); +}; + +void log_deprecated(const std::string &message); + +#endif /* SCRIPTING_GAME_H_ */ diff --git a/src/script/serverscripting.cpp b/src/script/serverscripting.cpp deleted file mode 100644 index 215b2cfd7..000000000 --- a/src/script/serverscripting.cpp +++ /dev/null @@ -1,119 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola - -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. -*/ - -#include "serverscripting.h" -#include "server.h" -#include "log.h" -#include "settings.h" -#include "cpp_api/s_internal.h" -#include "lua_api/l_areastore.h" -#include "lua_api/l_base.h" -#include "lua_api/l_craft.h" -#include "lua_api/l_env.h" -#include "lua_api/l_inventory.h" -#include "lua_api/l_item.h" -#include "lua_api/l_itemstackmeta.h" -#include "lua_api/l_mapgen.h" -#include "lua_api/l_nodemeta.h" -#include "lua_api/l_nodetimer.h" -#include "lua_api/l_noise.h" -#include "lua_api/l_object.h" -#include "lua_api/l_particles.h" -#include "lua_api/l_rollback.h" -#include "lua_api/l_server.h" -#include "lua_api/l_util.h" -#include "lua_api/l_vmanip.h" -#include "lua_api/l_settings.h" -#include "lua_api/l_http.h" -#include "lua_api/l_storage.h" - -extern "C" { -#include "lualib.h" -} - -ServerScripting::ServerScripting(Server* server) -{ - setGameDef(server); - - // setEnv(env) is called by ScriptApiEnv::initializeEnvironment() - // once the environment has been created - - SCRIPTAPI_PRECHECKHEADER - - if (g_settings->getBool("secure.enable_security")) { - initializeSecurity(); - } - - lua_getglobal(L, "core"); - int top = lua_gettop(L); - - lua_newtable(L); - lua_setfield(L, -2, "object_refs"); - - lua_newtable(L); - lua_setfield(L, -2, "luaentities"); - - // Initialize our lua_api modules - InitializeModApi(L, top); - lua_pop(L, 1); - - // Push builtin initialization type - lua_pushstring(L, "game"); - lua_setglobal(L, "INIT"); - - infostream << "SCRIPTAPI: Initialized game modules" << std::endl; -} - -void ServerScripting::InitializeModApi(lua_State *L, int top) -{ - // Initialize mod api modules - ModApiCraft::Initialize(L, top); - ModApiEnvMod::Initialize(L, top); - ModApiInventory::Initialize(L, top); - ModApiItemMod::Initialize(L, top); - ModApiMapgen::Initialize(L, top); - ModApiParticles::Initialize(L, top); - ModApiRollback::Initialize(L, top); - ModApiServer::Initialize(L, top); - ModApiUtil::Initialize(L, top); - ModApiHttp::Initialize(L, top); - ModApiStorage::Initialize(L, top); - - // Register reference classes (userdata) - InvRef::Register(L); - ItemStackMetaRef::Register(L); - LuaAreaStore::Register(L); - LuaItemStack::Register(L); - LuaPerlinNoise::Register(L); - LuaPerlinNoiseMap::Register(L); - LuaPseudoRandom::Register(L); - LuaPcgRandom::Register(L); - LuaSecureRandom::Register(L); - LuaVoxelManip::Register(L); - NodeMetaRef::Register(L); - NodeTimerRef::Register(L); - ObjectRef::Register(L); - LuaSettings::Register(L); - StorageRef::Register(L); -} - -void log_deprecated(const std::string &message) -{ - log_deprecated(NULL, message); -} diff --git a/src/script/serverscripting.h b/src/script/serverscripting.h deleted file mode 100644 index fd97ea40b..000000000 --- a/src/script/serverscripting.h +++ /dev/null @@ -1,57 +0,0 @@ -/* -Minetest -Copyright (C) 2013 celeron55, Perttu Ahola - -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. -*/ - -#ifndef SERVER_SCRIPTING_H_ -#define SERVER_SCRIPTING_H_ - -#include "cpp_api/s_base.h" -#include "cpp_api/s_entity.h" -#include "cpp_api/s_env.h" -#include "cpp_api/s_inventory.h" -#include "cpp_api/s_node.h" -#include "cpp_api/s_player.h" -#include "cpp_api/s_server.h" -#include "cpp_api/s_security.h" - -/*****************************************************************************/ -/* Scripting <-> Server Game Interface */ -/*****************************************************************************/ - -class ServerScripting: - virtual public ScriptApiBase, - public ScriptApiDetached, - public ScriptApiEntity, - public ScriptApiEnv, - public ScriptApiNode, - public ScriptApiPlayer, - public ScriptApiServer, - public ScriptApiSecurity -{ -public: - ServerScripting(Server* server); - - // use ScriptApiBase::loadMod() to load mods - -private: - void InitializeModApi(lua_State *L, int top); -}; - -void log_deprecated(const std::string &message); - -#endif /* SCRIPTING_GAME_H_ */ diff --git a/src/server.cpp b/src/server.cpp index 4c7e60286..2edf83947 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -38,7 +38,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "settings.h" #include "profiler.h" #include "log.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "nodedef.h" #include "itemdef.h" #include "craftdef.h" diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index c0dc0e0ea..4d2c87a4d 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -28,7 +28,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "profiler.h" #include "raycast.h" #include "remoteplayer.h" -#include "serverscripting.h" +#include "scripting_server.h" #include "server.h" #include "voxelalgorithms.h" #include "util/serialize.h" -- cgit v1.2.3 From f1d7a26b7c341b468f34325cec5c3d495f175a8f Mon Sep 17 00:00:00 2001 From: Ben Deutsch Date: Fri, 17 Mar 2017 10:39:47 +0100 Subject: Add clouds API --- doc/lua_api.txt | 9 ++++ src/client.h | 11 +++++ src/cloudparams.h | 33 ++++++++++++++ src/clouds.cpp | 90 ++++++++++++++++++++----------------- src/clouds.h | 54 +++++++++++++++++++--- src/game.cpp | 13 ++++++ src/network/clientopcodes.cpp | 2 +- src/network/clientpackethandler.cpp | 28 ++++++++++++ src/network/networkprotocol.h | 10 +++++ src/network/serveropcodes.cpp | 2 +- src/remoteplayer.cpp | 8 ++++ src/remoteplayer.h | 12 +++++ src/script/lua_api/l_object.cpp | 81 +++++++++++++++++++++++++++++++++ src/script/lua_api/l_object.h | 6 +++ src/server.cpp | 30 +++++++++++++ src/server.h | 12 +++++ src/sky.cpp | 6 ++- 17 files changed, 357 insertions(+), 50 deletions(-) create mode 100644 src/cloudparams.h (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index eba8a5fef..479e38a2e 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3077,6 +3077,15 @@ This is basically a reference to a C++ `ServerActiveObject` * `"skybox"`: Uses 6 textures, `bgcolor` used * `"plain"`: Uses 0 textures, `bgcolor` used * `get_sky()`: returns bgcolor, type and a table with the textures +* `set_clouds(parameters)`: set cloud parameters + * `parameters` is a table with the following optional fields: + * `density`: from `0` (no clouds) to `1` (full clouds) (default `0.4`) + * `color`: basic cloud color, with alpha channel (default `#fff0f0e5`) + * `ambient`: cloud color lower bound, use for a "glow at night" effect (default `#000000`) + * `height`: cloud height, i.e. y of cloud base (default per conf, usually `120`) + * `thickness`: cloud thickness in nodes (default `16`) + * `speed`: 2D cloud speed + direction in nodes per second (default `{x=0, y=-2}`) +* `get_clouds()`: returns a table with the current cloud parameters as in `set_clouds` * `override_day_night_ratio(ratio or nil)` * `0`...`1`: Overrides day-night ratio, controlling sunlight to a specific amount * `nil`: Disables override, defaulting to sunlight based on day-night cycle diff --git a/src/client.h b/src/client.h index f5b03f19d..7cbfadd50 100644 --- a/src/client.h +++ b/src/client.h @@ -77,6 +77,7 @@ enum ClientEventType CE_HUDCHANGE, CE_SET_SKY, CE_OVERRIDE_DAY_NIGHT_RATIO, + CE_CLOUD_PARAMS, }; struct ClientEvent @@ -178,6 +179,15 @@ struct ClientEvent 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; }; }; @@ -331,6 +341,7 @@ public: void handleCommand_HudSetFlags(NetworkPacket* pkt); void handleCommand_HudSetParam(NetworkPacket* pkt); void handleCommand_HudSetSky(NetworkPacket* pkt); + void handleCommand_CloudParams(NetworkPacket* pkt); void handleCommand_OverrideDayNightRatio(NetworkPacket* pkt); void handleCommand_LocalPlayerAnimations(NetworkPacket* pkt); void handleCommand_EyeOffset(NetworkPacket* pkt); diff --git a/src/cloudparams.h b/src/cloudparams.h new file mode 100644 index 000000000..dafec4b27 --- /dev/null +++ b/src/cloudparams.h @@ -0,0 +1,33 @@ +/* +Minetest +Copyright (C) 2017 bendeutsch, Ben Deutsch + +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. +*/ + +#ifndef CLOUDPARAMS_HEADER +#define CLOUDPARAMS_HEADER + +struct CloudParams +{ + float density; + video::SColor color_bright; + video::SColor color_ambient; + float thickness; + float height; + v2f speed; +}; + +#endif diff --git a/src/clouds.cpp b/src/clouds.cpp index 82b63b6b3..627fac47a 100644 --- a/src/clouds.cpp +++ b/src/clouds.cpp @@ -32,6 +32,7 @@ irr::scene::ISceneManager *g_menucloudsmgr = NULL; static void cloud_3d_setting_changed(const std::string &settingname, void *data) { + // TODO: only re-read cloud settings, not height or radius ((Clouds *)data)->readSettings(); } @@ -44,9 +45,10 @@ Clouds::Clouds( ): scene::ISceneNode(parent, mgr, id), m_seed(seed), - m_camera_pos(0,0), - m_time(0), - m_camera_offset(0,0,0) + m_camera_pos(0.0f, 0.0f), + m_origin(0.0f, 0.0f), + m_camera_offset(0.0f, 0.0f, 0.0f), + m_color(1.0f, 1.0f, 1.0f, 1.0f) { m_material.setFlag(video::EMF_LIGHTING, false); //m_material.setFlag(video::EMF_BACK_FACE_CULLING, false); @@ -57,14 +59,18 @@ Clouds::Clouds( //m_material.MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; m_material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + m_params.density = 0.4f; + m_params.thickness = 16.0f; + m_params.color_bright = video::SColor(229, 255, 240, 240); + m_params.color_ambient = video::SColor(255, 0, 0, 0); + m_params.speed = v2f(0.0f, -2.0f); + m_passed_cloud_y = cloudheight; readSettings(); g_settings->registerChangedCallback("enable_3d_clouds", &cloud_3d_setting_changed, this); - m_box = aabb3f(-BS*1000000,m_cloud_y-BS,-BS*1000000, - BS*1000000,m_cloud_y+BS,BS*1000000); - + updateBox(); } Clouds::~Clouds() @@ -88,6 +94,10 @@ void Clouds::OnRegisterSceneNode() void Clouds::render() { + + if (m_params.density <= 0.0f) + return; // no need to do anything + video::IVideoDriver* driver = SceneManager->getVideoDriver(); if(SceneManager->getSceneNodeRenderPass() != scene::ESNRP_TRANSPARENT) @@ -107,15 +117,12 @@ void Clouds::render() Clouds move from Z+ towards Z- */ - const float cloud_size = BS * 64; - const v2f cloud_speed(0, -BS * 2); + static const float cloud_size = BS * 64.0f; const float cloud_full_radius = cloud_size * m_cloud_radius_i; - // Position of cloud noise origin in world coordinates - v2f world_cloud_origin_pos_f = m_time * cloud_speed; // Position of cloud noise origin from the camera - v2f cloud_origin_from_camera_f = world_cloud_origin_pos_f - m_camera_pos; + v2f cloud_origin_from_camera_f = m_origin - m_camera_pos; // The center point of drawing in the noise v2f center_of_drawing_in_noise_f = -cloud_origin_from_camera_f; // The integer center point of drawing in the noise @@ -127,7 +134,7 @@ void Clouds::render() v2f world_center_of_drawing_in_noise_f = v2f( center_of_drawing_in_noise_i.X * cloud_size, center_of_drawing_in_noise_i.Y * cloud_size - ) + world_cloud_origin_pos_f; + ) + m_origin; /*video::SColor c_top(128,b*240,b*240,b*255); video::SColor c_side_1(128,b*230,b*230,b*255); @@ -146,10 +153,6 @@ void Clouds::render() c_bottom_f.r *= 0.80; c_bottom_f.g *= 0.80; c_bottom_f.b *= 0.80; - c_top_f.a = 0.9; - c_side_1_f.a = 0.9; - c_side_2_f.a = 0.9; - c_bottom_f.a = 0.9; video::SColor c_top = c_top_f.toSColor(); video::SColor c_side_1 = c_side_1_f.toSColor(); video::SColor c_side_2 = c_side_2_f.toSColor(); @@ -187,11 +190,14 @@ void Clouds::render() zi + center_of_drawing_in_noise_i.Y ); - double noise = noise2d_perlin( + float noise = noise2d_perlin( (float)p_in_noise_i.X * cloud_size_noise, (float)p_in_noise_i.Y * cloud_size_noise, m_seed, 3, 0.5); - grid[i] = (noise >= 0.4); + // normalize to 0..1 (given 3 octaves) + static const float noise_bound = 1.0f + 0.5f + 0.25f; + float density = noise / noise_bound * 0.5f + 0.5f; + grid[i] = (density < m_params.density); } } @@ -236,8 +242,9 @@ void Clouds::render() v[3].Color.setBlue(255); }*/ - f32 rx = cloud_size/2; - f32 ry = 8 * BS; + f32 rx = cloud_size / 2.0f; + // if clouds are flat, the top layer should be at the given height + f32 ry = m_enable_3d ? m_params.thickness * BS : 0.0f; f32 rz = cloud_size / 2; for(int i=0; igetU16("cloud_radius"); m_enable_3d = g_settings->getBool("enable_3d_clouds"); } - diff --git a/src/clouds.h b/src/clouds.h index 9c6b41786..a0bda28df 100644 --- a/src/clouds.h +++ b/src/clouds.h @@ -23,6 +23,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes_extrabloated.h" #include #include "constants.h" +#include "cloudparams.h" // Menu clouds class Clouds; @@ -79,27 +80,68 @@ public: void updateCameraOffset(v3s16 camera_offset) { m_camera_offset = camera_offset; - m_box = aabb3f(-BS * 1000000, m_cloud_y - BS - BS * camera_offset.Y, -BS * 1000000, - BS * 1000000, m_cloud_y + BS - BS * camera_offset.Y, BS * 1000000); + updateBox(); } void readSettings(); + void setDensity(float density) + { + m_params.density = density; + // currently does not need bounding + } + + void setColorBright(const video::SColor &color_bright) + { + m_params.color_bright = color_bright; + } + + void setColorAmbient(const video::SColor &color_ambient) + { + m_params.color_ambient = color_ambient; + } + + void setHeight(float height) + { + m_params.height = height; // add bounding when necessary + updateBox(); + } + + void setSpeed(v2f speed) + { + m_params.speed = speed; + } + + void setThickness(float thickness) + { + m_params.thickness = thickness; + updateBox(); + } + private: + void updateBox() + { + float height_bs = m_params.height * BS; + float thickness_bs = m_params.thickness * BS; + m_box = aabb3f(-BS * 1000000.0f, height_bs - BS * m_camera_offset.Y, -BS * 1000000.0f, + BS * 1000000.0f, height_bs + thickness_bs - BS * m_camera_offset.Y, BS * 1000000.0f); + } + video::SMaterial m_material; aabb3f m_box; s16 m_passed_cloud_y; - float m_cloud_y; u16 m_cloud_radius_i; bool m_enable_3d; - video::SColorf m_color; u32 m_seed; v2f m_camera_pos; - float m_time; + v2f m_origin; + v2f m_speed; v3s16 m_camera_offset; + video::SColorf m_color; + CloudParams m_params; + }; #endif - diff --git a/src/game.cpp b/src/game.cpp index a1cc1ab15..ba6530d80 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3295,6 +3295,19 @@ void Game::processClientEvents(CameraOrientation *cam) 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; diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index 563baf77b..1be6e5522 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -108,7 +108,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_LOCAL_PLAYER_ANIMATIONS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_LocalPlayerAnimations }, // 0x51 { "TOCLIENT_EYE_OFFSET", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_EyeOffset }, // 0x52 { "TOCLIENT_DELETE_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53 - null_command_handler, + { "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54 null_command_handler, null_command_handler, null_command_handler, diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 772ffe905..defc83f31 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1168,6 +1168,34 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) m_client_event_queue.push(event); } +void Client::handleCommand_CloudParams(NetworkPacket* pkt) +{ + f32 density; + video::SColor color_bright; + video::SColor color_ambient; + f32 height; + f32 thickness; + v2f speed; + + *pkt >> density >> color_bright >> color_ambient + >> height >> thickness >> speed; + + ClientEvent event; + 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; + // same here: deconstruct to skip constructor + event.cloud_params.speed_x = speed.X; + event.cloud_params.speed_y = speed.Y; + m_client_event_queue.push(event); +} + void Client::handleCommand_OverrideDayNightRatio(NetworkPacket* pkt) { bool do_override; diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index e7a3469b7..a1a4f5bfa 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -610,6 +610,16 @@ enum ToClientCommand u32 id */ + TOCLIENT_CLOUD_PARAMS = 0x54, + /* + f1000 density + u8[4] color_diffuse (ARGB) + u8[4] color_ambient (ARGB) + f1000 height + f1000 thickness + v2f1000 speed + */ + TOCLIENT_SRP_BYTES_S_B = 0x60, /* Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP. diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index 31b571ff0..450730ca2 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -197,7 +197,7 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_LOCAL_PLAYER_ANIMATIONS", 0, true }, // 0x51 { "TOCLIENT_EYE_OFFSET", 0, true }, // 0x52 { "TOCLIENT_DELETE_PARTICLESPAWNER", 0, true }, // 0x53 - null_command_factory, + { "TOCLIENT_CLOUD_PARAMS", 0, true }, // 0x54 null_command_factory, null_command_factory, null_command_factory, diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp index 2dbfe9d9d..2b4db62f5 100644 --- a/src/remoteplayer.cpp +++ b/src/remoteplayer.cpp @@ -65,6 +65,14 @@ RemotePlayer::RemotePlayer(const char *name, IItemDefManager *idef): movement_liquid_fluidity_smooth = g_settings->getFloat("movement_liquid_fluidity_smooth") * BS; movement_liquid_sink = g_settings->getFloat("movement_liquid_sink") * BS; movement_gravity = g_settings->getFloat("movement_gravity") * BS; + + // copy defaults + m_cloud_params.density = 0.4f; + m_cloud_params.color_bright = video::SColor(255, 255, 240, 240); + m_cloud_params.color_ambient = video::SColor(255, 0, 0, 0); + m_cloud_params.height = 120.0f; + m_cloud_params.thickness = 16.0f; + m_cloud_params.speed = v2f(0.0f, -2.0f); } void RemotePlayer::serializeExtraAttributes(std::string &output) diff --git a/src/remoteplayer.h b/src/remoteplayer.h index 4b96835fc..b9d9c74f5 100644 --- a/src/remoteplayer.h +++ b/src/remoteplayer.h @@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #define REMOTEPLAYER_HEADER #include "player.h" +#include "cloudparams.h" class PlayerSAO; @@ -99,6 +100,16 @@ public: *params = m_sky_params; } + void setCloudParams(const CloudParams &cloud_params) + { + m_cloud_params = cloud_params; + } + + const CloudParams &getCloudParams() const + { + return m_cloud_params; + } + bool checkModified() const { return m_dirty || inventory.checkModified(); } void setModified(const bool x) @@ -154,6 +165,7 @@ private: std::string m_sky_type; video::SColor m_sky_bgcolor; std::vector m_sky_params; + CloudParams m_cloud_params; }; #endif diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index a5b6e3941..6cd852299 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1729,6 +1729,85 @@ int ObjectRef::l_get_sky(lua_State *L) return 3; } +// set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=}) +int ObjectRef::l_set_clouds(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + if (!lua_istable(L, 2)) + return 0; + + CloudParams cloud_params = player->getCloudParams(); + + cloud_params.density = getfloatfield_default(L, 2, "density", cloud_params.density); + + lua_getfield(L, 2, "color"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &cloud_params.color_bright); + lua_pop(L, 1); + lua_getfield(L, 2, "ambient"); + if (!lua_isnil(L, -1)) + read_color(L, -1, &cloud_params.color_ambient); + lua_pop(L, 1); + + cloud_params.height = getfloatfield_default(L, 2, "height", cloud_params.height ); + cloud_params.thickness = getfloatfield_default(L, 2, "thickness", cloud_params.thickness); + + lua_getfield(L, 2, "speed"); + if (lua_istable(L, -1)) { + v2f new_speed; + new_speed.X = getfloatfield_default(L, -1, "x", 0); + new_speed.Y = getfloatfield_default(L, -1, "y", 0); + cloud_params.speed = new_speed; + } + lua_pop(L, 1); + + if (!getServer(L)->setClouds(player, cloud_params.density, + cloud_params.color_bright, cloud_params.color_ambient, + cloud_params.height, cloud_params.thickness, + cloud_params.speed)) + return 0; + + player->setCloudParams(cloud_params); + + lua_pushboolean(L, true); + return 1; +} + +int ObjectRef::l_get_clouds(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkobject(L, 1); + RemotePlayer *player = getplayer(ref); + if (!player) + return 0; + const CloudParams &cloud_params = player->getCloudParams(); + + lua_newtable(L); + lua_pushnumber(L, cloud_params.density); + lua_setfield(L, -2, "density"); + push_ARGB8(L, cloud_params.color_bright); + lua_setfield(L, -2, "color"); + push_ARGB8(L, cloud_params.color_ambient); + lua_setfield(L, -2, "ambient"); + lua_pushnumber(L, cloud_params.height); + lua_setfield(L, -2, "height"); + lua_pushnumber(L, cloud_params.thickness); + lua_setfield(L, -2, "thickness"); + lua_newtable(L); + lua_pushnumber(L, cloud_params.speed.X); + lua_setfield(L, -2, "x"); + lua_pushnumber(L, cloud_params.speed.Y); + lua_setfield(L, -2, "y"); + lua_setfield(L, -2, "speed"); + + return 1; +} + + // override_day_night_ratio(self, brightness=0...1) int ObjectRef::l_override_day_night_ratio(lua_State *L) { @@ -1911,6 +1990,8 @@ const luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, hud_get_hotbar_selected_image), luamethod(ObjectRef, set_sky), luamethod(ObjectRef, get_sky), + luamethod(ObjectRef, set_clouds), + luamethod(ObjectRef, get_clouds), luamethod(ObjectRef, override_day_night_ratio), luamethod(ObjectRef, get_day_night_ratio), luamethod(ObjectRef, set_local_animation), diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 98f5c2b11..0912a1c49 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -289,6 +289,12 @@ private: // get_sky(self, type, list) static int l_get_sky(lua_State *L); + // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=}) + static int l_set_clouds(lua_State *L); + + // get_clouds(self) + static int l_get_clouds(lua_State *L); + // override_day_night_ratio(self, type) static int l_override_day_night_ratio(lua_State *L); diff --git a/src/server.cpp b/src/server.cpp index 2edf83947..9ef69cb37 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1882,6 +1882,20 @@ void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor, Send(&pkt); } +void Server::SendCloudParams(u16 peer_id, float density, + const video::SColor &color_bright, + const video::SColor &color_ambient, + float height, + float thickness, + const v2f &speed) +{ + NetworkPacket pkt(TOCLIENT_CLOUD_PARAMS, 0, peer_id); + pkt << density << color_bright << color_ambient + << height << thickness << speed; + + Send(&pkt); +} + void Server::SendOverrideDayNightRatio(u16 peer_id, bool do_override, float ratio) { @@ -3196,6 +3210,22 @@ bool Server::setSky(RemotePlayer *player, const video::SColor &bgcolor, return true; } +bool Server::setClouds(RemotePlayer *player, float density, + const video::SColor &color_bright, + const video::SColor &color_ambient, + float height, + float thickness, + const v2f &speed) +{ + if (!player) + return false; + + SendCloudParams(player->peer_id, density, + color_bright, color_ambient, height, + thickness, speed); + return true; +} + bool Server::overrideDayNightRatio(RemotePlayer *player, bool do_override, float ratio) { diff --git a/src/server.h b/src/server.h index 948fb8fc2..3a082b9a4 100644 --- a/src/server.h +++ b/src/server.h @@ -332,6 +332,12 @@ public: bool setSky(RemotePlayer *player, const video::SColor &bgcolor, const std::string &type, const std::vector ¶ms); + bool setClouds(RemotePlayer *player, float density, + const video::SColor &color_bright, + const video::SColor &color_ambient, + float height, + float thickness, + const v2f &speed); bool overrideDayNightRatio(RemotePlayer *player, bool do_override, float brightness); @@ -401,6 +407,12 @@ private: void SendHUDSetParam(u16 peer_id, u16 param, const std::string &value); void SendSetSky(u16 peer_id, const video::SColor &bgcolor, const std::string &type, const std::vector ¶ms); + void SendCloudParams(u16 peer_id, float density, + const video::SColor &color_bright, + const video::SColor &color_ambient, + float height, + float thickness, + const v2f &speed); void SendOverrideDayNightRatio(u16 peer_id, bool do_override, float ratio); /* diff --git a/src/sky.cpp b/src/sky.cpp index 211a2dcdc..7f999feb0 100644 --- a/src/sky.cpp +++ b/src/sky.cpp @@ -534,8 +534,10 @@ void Sky::update(float time_of_day, float time_brightness, video::SColorf skycolor_bright_dawn_f = video::SColor(255, 180, 186, 250); video::SColorf skycolor_bright_night_f = video::SColor(255, 0, 107, 255); - video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 240, 240, 255); - video::SColorf cloudcolor_bright_dawn_f = video::SColor(255, 255, 223, 191); + // pure white: becomes "diffuse light component" for clouds + video::SColorf cloudcolor_bright_normal_f = video::SColor(255, 255, 255, 255); + // dawn-factoring version of pure white (note: R is above 1.0) + video::SColorf cloudcolor_bright_dawn_f(255.0f/240.0f, 223.0f/240.0f, 191.0f/255.0f); float cloud_color_change_fraction = 0.95; if (sunlight_seen) { -- cgit v1.2.3 From bd921a7916f0fafc493b1c4d0eeb5e2bb1d6a7c2 Mon Sep 17 00:00:00 2001 From: Brandon Date: Sun, 10 Jul 2016 00:08:26 -0500 Subject: Sound API: Add fading sounds --- doc/lua_api.txt | 7 +++ src/client.cpp | 1 + src/client.h | 1 + src/network/clientopcodes.cpp | 2 +- src/network/clientpackethandler.cpp | 35 +++++++++++++- src/network/networkprotocol.h | 11 ++++- src/script/common/c_content.cpp | 2 + src/script/common/c_converter.h | 2 + src/script/lua_api/l_server.cpp | 11 +++++ src/script/lua_api/l_server.h | 3 ++ src/server.cpp | 64 +++++++++++++++++++++++-- src/server.h | 6 ++- src/sound.h | 28 +++++++---- src/sound_openal.cpp | 94 ++++++++++++++++++++++++++++++++++++- 14 files changed, 248 insertions(+), 19 deletions(-) (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 479e38a2e..77ffb88e2 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -456,11 +456,13 @@ Examples of sound parameter tables: -- Play locationless on all clients { gain = 1.0, -- default + fade = 0.0, -- default, change to a value > 0 to fade the sound in } -- Play locationless to one player { to_player = name, gain = 1.0, -- default + fade = 0.0, -- default, change to a value > 0 to fade the sound in } -- Play locationless to one player, looped { @@ -2587,6 +2589,11 @@ These functions return the leftover itemstack. * `spec` is a `SimpleSoundSpec` * `parameters` is a sound parameter table * `minetest.sound_stop(handle)` +* `minetest.sound_fade(handle, step, gain)` + * `handle` is a handle returned by minetest.sound_play + * `step` determines how fast a sound will fade. + Negative step will lower the sound volume, positive step will increase the sound volume + * `gain` the target gain for the fade. ### Timing * `minetest.after(time, func, ...)` diff --git a/src/client.cpp b/src/client.cpp index 3c5a70f21..3269c573a 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -407,6 +407,7 @@ void Client::step(float dtime) // Step environment m_env.step(dtime); + m_sound->step(dtime); /* Get events diff --git a/src/client.h b/src/client.h index 7cbfadd50..e8db7de44 100644 --- a/src/client.h +++ b/src/client.h @@ -328,6 +328,7 @@ public: void handleCommand_ItemDef(NetworkPacket* pkt); void handleCommand_PlaySound(NetworkPacket* pkt); void handleCommand_StopSound(NetworkPacket* pkt); + void handleCommand_FadeSound(NetworkPacket *pkt); void handleCommand_Privileges(NetworkPacket* pkt); void handleCommand_InventoryFormSpec(NetworkPacket* pkt); void handleCommand_DetachedInventory(NetworkPacket* pkt); diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index 1be6e5522..bdcb1dfce 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -109,7 +109,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] = { "TOCLIENT_EYE_OFFSET", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_EyeOffset }, // 0x52 { "TOCLIENT_DELETE_PARTICLESPAWNER", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_DeleteParticleSpawner }, // 0x53 { "TOCLIENT_CLOUD_PARAMS", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_CloudParams }, // 0x54 - null_command_handler, + { "TOCLIENT_FADE_SOUND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FadeSound }, // 0x55 null_command_handler, null_command_handler, null_command_handler, diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index defc83f31..a895acc84 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -755,21 +755,39 @@ void Client::handleCommand_ItemDef(NetworkPacket* pkt) void Client::handleCommand_PlaySound(NetworkPacket* pkt) { + /* + [0] u32 server_id + [4] u16 name length + [6] char name[len] + [ 6 + len] f32 gain + [10 + len] u8 type + [11 + len] (f32 * 3) pos + [23 + len] u16 object_id + [25 + len] bool loop + [26 + len] f32 fade + */ + s32 server_id; std::string name; + float gain; u8 type; // 0=local, 1=positional, 2=object v3f pos; u16 object_id; bool loop; + float fade = 0; *pkt >> server_id >> name >> gain >> type >> pos >> object_id >> loop; + try { + *pkt >> fade; + } catch (SerializationError &e) {}; + // Start playing int client_id = -1; switch(type) { case 0: // local - client_id = m_sound->playSound(name, loop, gain); + client_id = m_sound->playSound(name, loop, gain, fade); break; case 1: // positional client_id = m_sound->playSoundAt(name, loop, gain, pos); @@ -808,6 +826,21 @@ void Client::handleCommand_StopSound(NetworkPacket* pkt) } } +void Client::handleCommand_FadeSound(NetworkPacket *pkt) +{ + s32 sound_id; + float step; + float gain; + + *pkt >> sound_id >> step >> gain; + + UNORDERED_MAP::iterator i = + m_sounds_server_to_client.find(sound_id); + + if (i != m_sounds_server_to_client.end()) + m_sound->fadeSound(i->second, step, gain); +} + void Client::handleCommand_Privileges(NetworkPacket* pkt) { m_privileges.clear(); diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index a1a4f5bfa..70cad85d8 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -153,9 +153,11 @@ with this program; if not, write to the Free Software Foundation, Inc., PROTOCOL VERSION 31: Add tile overlay Stop sending TOSERVER_CLIENT_READY + PROTOCOL VERSION 32: + Add fading sounds */ -#define LATEST_PROTOCOL_VERSION 31 +#define LATEST_PROTOCOL_VERSION 32 // Server's supported network protocol range #define SERVER_PROTOCOL_VERSION_MIN 24 @@ -620,6 +622,13 @@ enum ToClientCommand v2f1000 speed */ + TOCLIENT_FADE_SOUND = 0x55, + /* + s32 sound_id + float step + float gain + */ + TOCLIENT_SRP_BYTES_S_B = 0x60, /* Belonging to AUTH_MECHANISM_LEGACY_PASSWORD and AUTH_MECHANISM_SRP. diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 5fe5af58d..8696ad7cb 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -680,6 +680,7 @@ void read_server_sound_params(lua_State *L, int index, if(lua_istable(L, index)){ getfloatfield(L, index, "gain", params.gain); getstringfield(L, index, "to_player", params.to_player); + getfloatfield(L, index, "fade", params.fade); lua_getfield(L, index, "pos"); if(!lua_isnil(L, -1)){ v3f p = read_v3f(L, -1)*BS; @@ -712,6 +713,7 @@ void read_soundspec(lua_State *L, int index, SimpleSoundSpec &spec) } else if(lua_istable(L, index)){ getstringfield(L, index, "name", spec.name); getfloatfield(L, index, "gain", spec.gain); + getfloatfield(L, index, "fade", spec.fade); } else if(lua_isstring(L, index)){ spec.name = lua_tostring(L, index); } diff --git a/src/script/common/c_converter.h b/src/script/common/c_converter.h index a5fbee765..b0f61a8ca 100644 --- a/src/script/common/c_converter.h +++ b/src/script/common/c_converter.h @@ -77,6 +77,8 @@ void setfloatfield(lua_State *L, int table, const char *fieldname, float value); void setboolfield(lua_State *L, int table, const char *fieldname, bool value); +void setstringfield(lua_State *L, int table, + const char *fieldname, const char *value); v3f checkFloatPos (lua_State *L, int index); v2f check_v2f (lua_State *L, int index); diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 7b723d14c..ea993d7b7 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -455,6 +455,16 @@ int ModApiServer::l_sound_stop(lua_State *L) return 0; } +int ModApiServer::l_sound_fade(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + s32 handle = luaL_checkinteger(L, 1); + float step = luaL_checknumber(L, 2); + float gain = luaL_checknumber(L, 3); + getServer(L)->fadeSound(handle, step, gain); + return 0; +} + // is_singleplayer() int ModApiServer::l_is_singleplayer(lua_State *L) { @@ -518,6 +528,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(show_formspec); API_FCT(sound_play); API_FCT(sound_stop); + API_FCT(sound_fade); API_FCT(get_player_information); API_FCT(get_player_privs); diff --git a/src/script/lua_api/l_server.h b/src/script/lua_api/l_server.h index 3a4a917c0..251a0ce89 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -68,6 +68,9 @@ private: // sound_stop(handle) static int l_sound_stop(lua_State *L); + // sound_fade(handle, step, gain) + static int l_sound_fade(lua_State *L); + // get_player_privs(name, text) static int l_get_player_privs(lua_State *L); diff --git a/src/server.cpp b/src/server.cpp index 9ef69cb37..190a1baf2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2100,15 +2100,23 @@ s32 Server::playSound(const SimpleSoundSpec &spec, m_playing_sounds[id] = ServerPlayingSound(); ServerPlayingSound &psound = m_playing_sounds[id]; psound.params = params; + psound.spec = spec; + float gain = params.gain * spec.gain; NetworkPacket pkt(TOCLIENT_PLAY_SOUND, 0); - pkt << id << spec.name << (float) (spec.gain * params.gain) - << (u8) params.type << pos << params.object << params.loop; + pkt << id << spec.name << gain + << (u8) params.type << pos << params.object + << params.loop << params.fade; - for(std::vector::iterator i = dst_clients.begin(); + // Backwards compability + bool play_sound = gain > 0; + + for (std::vector::iterator i = dst_clients.begin(); i != dst_clients.end(); ++i) { - psound.clients.insert(*i); - m_clients.send(*i, 0, &pkt, true); + if (play_sound || m_clients.getProtocolVersion(*i) >= 32) { + psound.clients.insert(*i); + m_clients.send(*i, 0, &pkt, true); + } } return id; } @@ -2132,6 +2140,52 @@ void Server::stopSound(s32 handle) m_playing_sounds.erase(i); } +void Server::fadeSound(s32 handle, float step, float gain) +{ + // Get sound reference + UNORDERED_MAP::iterator i = + m_playing_sounds.find(handle); + if (i == m_playing_sounds.end()) + return; + + ServerPlayingSound &psound = i->second; + psound.params.gain = gain; + + NetworkPacket pkt(TOCLIENT_FADE_SOUND, 4); + pkt << handle << step << gain; + + // Backwards compability + bool play_sound = gain > 0; + ServerPlayingSound compat_psound = psound; + compat_psound.clients.clear(); + + NetworkPacket compat_pkt(TOCLIENT_STOP_SOUND, 4); + compat_pkt << handle; + + for (UNORDERED_SET::iterator it = psound.clients.begin(); + it != psound.clients.end();) { + if (m_clients.getProtocolVersion(*it) >= 32) { + // Send as reliable + m_clients.send(*it, 0, &pkt, true); + ++it; + } else { + compat_psound.clients.insert(*it); + // Stop old sound + m_clients.send(*it, 0, &compat_pkt, true); + psound.clients.erase(it++); + } + } + + // Remove sound reference + if (!play_sound || psound.clients.size() == 0) + m_playing_sounds.erase(i); + + if (play_sound && compat_psound.clients.size() > 0) { + // Play new sound volume on older clients + playSound(compat_psound.spec, compat_psound.params); + } +} + void Server::sendRemoveNode(v3s16 p, u16 ignore_id, std::vector *far_players, float far_d_nodes) { diff --git a/src/server.h b/src/server.h index 3a082b9a4..5e6211637 100644 --- a/src/server.h +++ b/src/server.h @@ -115,6 +115,7 @@ struct ServerSoundParams u16 object; float max_hear_distance; bool loop; + float fade; ServerSoundParams(): gain(1.0), @@ -123,7 +124,8 @@ struct ServerSoundParams pos(0,0,0), object(0), max_hear_distance(32*BS), - loop(false) + loop(false), + fade(0) {} v3f getPos(ServerEnvironment *env, bool *pos_exists) const; @@ -132,6 +134,7 @@ struct ServerSoundParams struct ServerPlayingSound { ServerSoundParams params; + SimpleSoundSpec spec; UNORDERED_SET clients; // peer ids }; @@ -231,6 +234,7 @@ public: // Envlock s32 playSound(const SimpleSoundSpec &spec, const ServerSoundParams ¶ms); void stopSound(s32 handle); + void fadeSound(s32 handle, float step, float gain); // Envlock std::set getPlayerEffectivePrivs(const std::string &name); diff --git a/src/sound.h b/src/sound.h index 98f7692d5..7bdb6a26b 100644 --- a/src/sound.h +++ b/src/sound.h @@ -34,8 +34,8 @@ public: struct SimpleSoundSpec { - SimpleSoundSpec(const std::string &name = "", float gain = 1.0) - : name(name), gain(gain) + SimpleSoundSpec(const std::string &name = "", float gain = 1.0, float fade = 0.0) + : name(name), gain(gain), fade(fade) { } @@ -43,13 +43,13 @@ struct SimpleSoundSpec std::string name; float gain; + float fade; }; class ISoundManager { public: virtual ~ISoundManager() {} - // Multiple sounds can be loaded per name; when played, the sound // should be chosen randomly from alternatives // Return value determines success/failure @@ -63,16 +63,21 @@ public: // playSound functions return -1 on failure, otherwise a handle to the // sound. If name=="", call should be ignored without error. - virtual int playSound(const std::string &name, bool loop, float volume) = 0; - virtual int playSoundAt( - const std::string &name, bool loop, float volume, v3f pos) = 0; + virtual int playSound(const std::string &name, bool loop, float volume, + float fade = 0) = 0; + virtual int playSoundAt(const std::string &name, bool loop, float volume, + v3f pos) = 0; virtual void stopSound(int sound) = 0; virtual bool soundExists(int sound) = 0; virtual void updateSoundPosition(int sound, v3f pos) = 0; + virtual bool updateSoundGain(int id, float gain) = 0; + virtual float getSoundGain(int id) = 0; + virtual void step(float dtime) = 0; + virtual void fadeSound(int sound, float step, float gain) = 0; int playSound(const SimpleSoundSpec &spec, bool loop) { - return playSound(spec.name, loop, spec.gain); + return playSound(spec.name, loop, spec.gain, spec.fade); } int playSoundAt(const SimpleSoundSpec &spec, bool loop, v3f pos) { @@ -93,7 +98,10 @@ public: } void updateListener(v3f pos, v3f vel, v3f at, v3f up) {} void setListenerGain(float gain) {} - int playSound(const std::string &name, bool loop, float volume) { return 0; } + int playSound(const std::string &name, bool loop, float volume, float fade) + { + return 0; + } int playSoundAt(const std::string &name, bool loop, float volume, v3f pos) { return 0; @@ -101,6 +109,10 @@ public: void stopSound(int sound) {} bool soundExists(int sound) { return false; } void updateSoundPosition(int sound, v3f pos) {} + bool updateSoundGain(int id, float gain) { return false; } + float getSoundGain(int id) { return 0; } + void step(float dtime) { } + void fadeSound(int sound, float step, float gain) { } }; // Global DummySoundManager singleton diff --git a/src/sound_openal.cpp b/src/sound_openal.cpp index b9af9e3a9..a425af827 100644 --- a/src/sound_openal.cpp +++ b/src/sound_openal.cpp @@ -274,6 +274,19 @@ private: UNORDERED_MAP > m_buffers; UNORDERED_MAP m_sounds_playing; v3f m_listener_pos; + struct FadeState { + FadeState() {} + FadeState(float step, float current_gain, float target_gain): + step(step), + current_gain(current_gain), + target_gain(target_gain) {} + float step; + float current_gain; + float target_gain; + }; + + UNORDERED_MAP m_sounds_fading; + float m_fade_delay; public: bool m_is_initialized; OpenALSoundManager(OnDemandSoundFetcher *fetcher): @@ -281,6 +294,7 @@ public: m_device(NULL), m_context(NULL), m_next_id(1), + m_fade_delay(0), m_is_initialized(false) { ALCenum error = ALC_NO_ERROR; @@ -349,6 +363,11 @@ public: infostream<<"Audio: Deinitialized."< >::iterator i = @@ -515,6 +534,7 @@ public: addBuffer(name, buf); return false; } + bool loadSoundData(const std::string &name, const std::string &filedata) { @@ -541,7 +561,7 @@ public: alListenerf(AL_GAIN, gain); } - int playSound(const std::string &name, bool loop, float volume) + int playSound(const std::string &name, bool loop, float volume, float fade) { maintain(); if(name == "") @@ -552,8 +572,16 @@ public: < 0) { + handle = playSoundRaw(buf, loop, 0); + fadeSound(handle, fade, volume); + } else { + handle = playSoundRaw(buf, loop, volume); + } + return handle; } + int playSoundAt(const std::string &name, bool loop, float volume, v3f pos) { maintain(); @@ -567,16 +595,55 @@ public: } return playSoundRawAt(buf, loop, volume, pos); } + void stopSound(int sound) { maintain(); deleteSound(sound); } + + void fadeSound(int soundid, float step, float gain) + { + m_sounds_fading[soundid] = FadeState(step, getSoundGain(soundid), gain); + } + + void doFades(float dtime) + { + m_fade_delay += dtime; + + if (m_fade_delay < 0.1f) + return; + + float chkGain = 0; + for (UNORDERED_MAP::iterator i = m_sounds_fading.begin(); + i != m_sounds_fading.end();) { + if (i->second.step < 0.f) + chkGain = -(i->second.current_gain); + else + chkGain = i->second.current_gain; + + if (chkGain < i->second.target_gain) { + i->second.current_gain += (i->second.step * m_fade_delay); + i->second.current_gain = rangelim(i->second.current_gain, 0, 1); + + updateSoundGain(i->first, i->second.current_gain); + ++i; + } else { + if (i->second.target_gain <= 0.f) + stopSound(i->first); + + m_sounds_fading.erase(i++); + } + } + m_fade_delay = 0; + } + bool soundExists(int sound) { maintain(); return (m_sounds_playing.count(sound) != 0); } + void updateSoundPosition(int id, v3f pos) { UNORDERED_MAP::iterator i = m_sounds_playing.find(id); @@ -589,6 +656,29 @@ public: alSource3f(sound->source_id, AL_VELOCITY, 0, 0, 0); alSourcef(sound->source_id, AL_REFERENCE_DISTANCE, 30.0); } + + bool updateSoundGain(int id, float gain) + { + UNORDERED_MAP::iterator i = m_sounds_playing.find(id); + if (i == m_sounds_playing.end()) + return false; + + PlayingSound *sound = i->second; + alSourcef(sound->source_id, AL_GAIN, gain); + return true; + } + + float getSoundGain(int id) + { + UNORDERED_MAP::iterator i = m_sounds_playing.find(id); + if (i == m_sounds_playing.end()) + return 0; + + PlayingSound *sound = i->second; + ALfloat gain; + alGetSourcef(sound->source_id, AL_GAIN, &gain); + return gain; + } }; ISoundManager *createOpenALSoundManager(OnDemandSoundFetcher *fetcher) -- cgit v1.2.3 From ad9fcf859ec2347325830e09504ae96968b51ea8 Mon Sep 17 00:00:00 2001 From: paramat Date: Fri, 28 Apr 2017 03:06:49 +0100 Subject: Set sky API: Add bool for clouds in front of custom skybox Default true. Add 'm_clouds_enabled' bool to sky.h, set from new bool in 'set sky' API. Make 'getCloudsVisible()' depend on 'm_clouds_enabled' instead of 'm_visible' (whether normal sky is visible). --- doc/lua_api.txt | 8 +++++--- src/client.h | 1 + src/game.cpp | 3 +++ src/network/clientpackethandler.cpp | 6 ++++++ src/network/networkprotocol.h | 1 + src/remoteplayer.h | 8 ++++++-- src/script/lua_api/l_object.cpp | 15 ++++++++++----- src/script/lua_api/l_object.h | 4 ++-- src/server.cpp | 12 ++++++++---- src/server.h | 6 ++++-- src/sky.cpp | 2 ++ src/sky.h | 7 +++++-- 12 files changed, 53 insertions(+), 20 deletions(-) (limited to 'src/server.cpp') diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 77ffb88e2..599e02fcb 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -3077,13 +3077,15 @@ This is basically a reference to a C++ `ServerActiveObject` * `hud_set_hotbar_selected_image(texturename)` * sets image for selected item of hotbar * `hud_get_hotbar_selected_image`: returns texturename -* `set_sky(bgcolor, type, {texture names})` +* `set_sky(bgcolor, type, {texture names}, clouds)` * `bgcolor`: ColorSpec, defaults to white - * Available types: + * `type`: Available types: * `"regular"`: Uses 0 textures, `bgcolor` ignored * `"skybox"`: Uses 6 textures, `bgcolor` used * `"plain"`: Uses 0 textures, `bgcolor` used -* `get_sky()`: returns bgcolor, type and a table with the textures + * `clouds`: Boolean for whether clouds appear in front of `"skybox"` or + `"plain"` custom skyboxes (default: `true`) +* `get_sky()`: returns bgcolor, type, table of textures, clouds * `set_clouds(parameters)`: set cloud parameters * `parameters` is a table with the following optional fields: * `density`: from `0` (no clouds) to `1` (full clouds) (default `0.4`) diff --git a/src/client.h b/src/client.h index e8db7de44..0dd519308 100644 --- a/src/client.h +++ b/src/client.h @@ -174,6 +174,7 @@ struct ClientEvent video::SColor *bgcolor; std::string *type; std::vector *params; + bool clouds; } set_sky; struct{ bool do_override; diff --git a/src/game.cpp b/src/game.cpp index ba6530d80..7dd9c942d 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -3255,6 +3255,8 @@ void Game::processClientEvents(CameraOrientation *cam) 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(); @@ -3264,6 +3266,7 @@ void Game::processClientEvents(CameraOrientation *cam) // 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); diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 4316a77d4..c3626158e 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1192,11 +1192,17 @@ void Client::handleCommand_HudSetSky(NetworkPacket* pkt) for (size_t i = 0; i < count; i++) params->push_back(deSerializeString(is)); + bool clouds = true; + try { + 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; m_client_event_queue.push(event); } diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 70cad85d8..7126c237b 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -584,6 +584,7 @@ enum ToClientCommand foreach count: u8 len u8[len] param + u8 clouds (boolean) */ TOCLIENT_OVERRIDE_DAY_NIGHT_RATIO = 0x50, diff --git a/src/remoteplayer.h b/src/remoteplayer.h index b9d9c74f5..7d46205c5 100644 --- a/src/remoteplayer.h +++ b/src/remoteplayer.h @@ -85,19 +85,21 @@ public: } void setSky(const video::SColor &bgcolor, const std::string &type, - const std::vector ¶ms) + const std::vector ¶ms, bool &clouds) { m_sky_bgcolor = bgcolor; m_sky_type = type; m_sky_params = params; + m_sky_clouds = clouds; } void getSky(video::SColor *bgcolor, std::string *type, - std::vector *params) + std::vector *params, bool *clouds) { *bgcolor = m_sky_bgcolor; *type = m_sky_type; *params = m_sky_params; + *clouds = m_sky_clouds; } void setCloudParams(const CloudParams &cloud_params) @@ -165,6 +167,8 @@ private: std::string m_sky_type; video::SColor m_sky_bgcolor; std::vector m_sky_params; + bool m_sky_clouds; + CloudParams m_cloud_params; }; diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 6cd852299..6f61ab55c 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1662,7 +1662,7 @@ int ObjectRef::l_hud_get_hotbar_selected_image(lua_State *L) return 1; } -// set_sky(self, bgcolor, type, list) +// set_sky(self, bgcolor, type, list, clouds = true) int ObjectRef::l_set_sky(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -1678,9 +1678,8 @@ int ObjectRef::l_set_sky(lua_State *L) std::vector params; if (lua_istable(L, 4)) { - int table = lua_gettop(L); lua_pushnil(L); - while (lua_next(L, table) != 0) { + while (lua_next(L, 4) != 0) { // key at index -2 and value at index -1 if (lua_isstring(L, -1)) params.push_back(lua_tostring(L, -1)); @@ -1694,7 +1693,11 @@ int ObjectRef::l_set_sky(lua_State *L) if (type == "skybox" && params.size() != 6) throw LuaError("skybox expects 6 textures"); - if (!getServer(L)->setSky(player, bgcolor, type, params)) + bool clouds = true; + if (lua_isboolean(L, 5)) + clouds = lua_toboolean(L, 5); + + if (!getServer(L)->setSky(player, bgcolor, type, params, clouds)) return 0; lua_pushboolean(L, true); @@ -1712,8 +1715,9 @@ int ObjectRef::l_get_sky(lua_State *L) video::SColor bgcolor(255, 255, 255, 255); std::string type; std::vector params; + bool clouds; - player->getSky(&bgcolor, &type, ¶ms); + player->getSky(&bgcolor, &type, ¶ms, &clouds); type = type == "" ? "regular" : type; push_ARGB8(L, bgcolor); @@ -1726,6 +1730,7 @@ int ObjectRef::l_get_sky(lua_State *L) lua_rawseti(L, -2, i); i++; } + lua_pushboolean(L, clouds); return 3; } diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index 0912a1c49..9801ce02b 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -283,10 +283,10 @@ private: // hud_get_hotbar_selected_image(self) static int l_hud_get_hotbar_selected_image(lua_State *L); - // set_sky(self, type, list) + // set_sky(self, bgcolor, type, list, clouds = true) static int l_set_sky(lua_State *L); - // get_sky(self, type, list) + // get_sky(self) static int l_get_sky(lua_State *L); // set_clouds(self, {density=, color=, ambient=, height=, thickness=, speed=}) diff --git a/src/server.cpp b/src/server.cpp index 190a1baf2..bf01fb7eb 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1871,7 +1871,8 @@ void Server::SendHUDSetParam(u16 peer_id, u16 param, const std::string &value) } void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor, - const std::string &type, const std::vector ¶ms) + const std::string &type, const std::vector ¶ms, + bool &clouds) { NetworkPacket pkt(TOCLIENT_SET_SKY, 0, peer_id); pkt << bgcolor << type << (u16) params.size(); @@ -1879,6 +1880,8 @@ void Server::SendSetSky(u16 peer_id, const video::SColor &bgcolor, for(size_t i=0; i ¶ms) + const std::string &type, const std::vector ¶ms, + bool &clouds) { if (!player) return false; - player->setSky(bgcolor, type, params); - SendSetSky(player->peer_id, bgcolor, type, params); + player->setSky(bgcolor, type, params, clouds); + SendSetSky(player->peer_id, bgcolor, type, params, clouds); return true; } diff --git a/src/server.h b/src/server.h index 5e6211637..2e735e77c 100644 --- a/src/server.h +++ b/src/server.h @@ -335,7 +335,8 @@ public: bool setPlayerEyeOffset(RemotePlayer *player, v3f first, v3f third); bool setSky(RemotePlayer *player, const video::SColor &bgcolor, - const std::string &type, const std::vector ¶ms); + const std::string &type, const std::vector ¶ms, + bool &clouds); bool setClouds(RemotePlayer *player, float density, const video::SColor &color_bright, const video::SColor &color_ambient, @@ -410,7 +411,8 @@ private: void SendHUDSetFlags(u16 peer_id, u32 flags, u32 mask); void SendHUDSetParam(u16 peer_id, u16 param, const std::string &value); void SendSetSky(u16 peer_id, const video::SColor &bgcolor, - const std::string &type, const std::vector ¶ms); + const std::string &type, const std::vector ¶ms, + bool &clouds); void SendCloudParams(u16 peer_id, float density, const video::SColor &color_bright, const video::SColor &color_ambient, diff --git a/src/sky.cpp b/src/sky.cpp index 7f999feb0..5414f74bd 100644 --- a/src/sky.cpp +++ b/src/sky.cpp @@ -85,6 +85,8 @@ Sky::Sky(scene::ISceneNode* parent, scene::ISceneManager* mgr, s32 id, } m_directional_colored_fog = g_settings->getBool("directional_colored_fog"); + + m_clouds_enabled = true; } diff --git a/src/sky.h b/src/sky.h index 72cb2d581..c9678a80b 100644 --- a/src/sky.h +++ b/src/sky.h @@ -65,10 +65,12 @@ public: return m_visible ? m_skycolor : m_fallback_bg_color; } - bool getCloudsVisible() { return m_clouds_visible && m_visible; } + bool getCloudsVisible() { return m_clouds_visible && m_clouds_enabled; } const video::SColorf &getCloudColor() { return m_cloudcolor_f; } void setVisible(bool visible) { m_visible = visible; } + // Set only from set_sky API + void setCloudsEnabled(bool clouds_enabled) { m_clouds_enabled = clouds_enabled; } void setFallbackBgColor(const video::SColor &fallback_bg_color) { m_fallback_bg_color = fallback_bg_color; @@ -123,7 +125,8 @@ private: bool m_sunlight_seen; float m_brightness; float m_cloud_brightness; - bool m_clouds_visible; + bool m_clouds_visible; // Whether clouds are disabled due to player underground + bool m_clouds_enabled; // Initialised to true, reset only by set_sky API bool m_directional_colored_fog; video::SColorf m_bgcolor_bright_f; video::SColorf m_skycolor_bright_f; -- cgit v1.2.3 From 0443620c5e699b02f8521ff8da7cff2e89ce4c5a Mon Sep 17 00:00:00 2001 From: Paramat Date: Wed, 17 May 2017 09:37:28 +0100 Subject: Particles: Do not send single particles to distant clients (#5760) Previously, every individual particle on a server is sent to, and rendered by (even if not actually visible), every client regardless of distance. This significantly reduces client FPS and creates unnecessary network traffic. Maximum distance is set by 'max block send distance' as this determines how far a client is able to see. --- src/server.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'src/server.cpp') diff --git a/src/server.cpp b/src/server.cpp index bf01fb7eb..5400dd595 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1707,13 +1707,25 @@ void Server::SendSpawnParticle(u16 peer_id, u16 protocol_version, const struct TileAnimationParams &animation, u8 glow) { DSTACK(FUNCTION_NAME); + static const float radius = + g_settings->getS16("max_block_send_distance") * MAP_BLOCKSIZE * BS; + if (peer_id == PEER_ID_INEXISTENT) { - // This sucks and should be replaced by a better solution in a refactor: std::vector clients = m_clients.getClientIDs(); + for (std::vector::iterator i = clients.begin(); i != clients.end(); ++i) { RemotePlayer *player = m_env->getPlayer(*i); if (!player) continue; + + PlayerSAO *sao = player->getPlayerSAO(); + if (!sao) + continue; + + // Do not send to distant clients + if (sao->getBasePosition().getDistanceFrom(pos * BS) > radius) + continue; + SendSpawnParticle(*i, player->protocol_version, pos, velocity, acceleration, expirationtime, size, collisiondetection, -- cgit v1.2.3 From 674400523e10624ae8320b0d18a05dbfd6dcac42 Mon Sep 17 00:00:00 2001 From: SmallJoker Date: Fri, 19 May 2017 07:45:47 +0200 Subject: Mainmenu: Fix issues while trying to enable all mods (#5770) --- builtin/mainmenu/dlg_config_world.lua | 24 +++++++++++++----------- builtin/mainmenu/modmgr.lua | 4 +++- src/client.cpp | 2 +- src/server.cpp | 2 +- src/serverenvironment.cpp | 2 +- 5 files changed, 19 insertions(+), 15 deletions(-) (limited to 'src/server.cpp') diff --git a/builtin/mainmenu/dlg_config_world.lua b/builtin/mainmenu/dlg_config_world.lua index 3e5ba16eb..fcedadea8 100644 --- a/builtin/mainmenu/dlg_config_world.lua +++ b/builtin/mainmenu/dlg_config_world.lua @@ -49,7 +49,7 @@ local function get_formspec(data) "button[3.25,7;2.5,0.5;btn_config_world_save;" .. fgettext("Save") .. "]" .. "button[5.75,7;2.5,0.5;btn_config_world_cancel;" .. fgettext("Cancel") .. "]" - if mod and mod.name ~= "" and mod.typ ~= "game_mod" then + if mod and mod.name ~= "" and not mod.is_game_content then if mod.is_modpack then local rawlist = data.list:get_raw_list() @@ -97,7 +97,7 @@ end local function enable_mod(this, toset) local mod = this.data.list:get_list()[this.data.selected_mod] - if mod.typ == "game_mod" then + if mod.is_game_content then -- game mods can't be enabled or disabled elseif not mod.is_modpack then if toset == nil then @@ -162,7 +162,7 @@ local function handle_buttons(this, fields) local i,mod for i,mod in ipairs(rawlist) do if not mod.is_modpack and - mod.typ ~= "game_mod" then + not mod.is_game_content then if modname_valid(mod.name) then worldfile:set("load_mod_"..mod.name, tostring(mod.enabled)) else @@ -198,7 +198,8 @@ local function handle_buttons(this, fields) local list = this.data.list:get_raw_list() for i = 1, #list do - if list[i].typ ~= "game_mod" and not list[i].is_modpack then + if not list[i].is_game_content + and not list[i].is_modpack then list[i].enabled = true end end @@ -210,7 +211,8 @@ local function handle_buttons(this, fields) local list = this.data.list:get_raw_list() for i = 1, #list do - if list[i].typ ~= "game_mod" and not list[i].is_modpack then + if not list[i].is_game_content + and not list[i].is_modpack then list[i].enabled = false end end @@ -252,16 +254,16 @@ function create_configure_world_dlg(worldidx) return true end end, - function(element,criteria) + function(element, criteria) if criteria.hide_game and - element.typ == "game_mod" then - return false + element.is_game_content then + return false end if criteria.hide_modpackcontents and - element.modpack ~= nil then - return false - end + element.modpack ~= nil then + return false + end return true end, --filter { worldpath= dlg.data.worldspec.path, diff --git a/builtin/mainmenu/modmgr.lua b/builtin/mainmenu/modmgr.lua index 14d29272e..dee048982 100644 --- a/builtin/mainmenu/modmgr.lua +++ b/builtin/mainmenu/modmgr.lua @@ -252,7 +252,7 @@ function modmgr.render_modlist(render_list) break end end - elseif v.typ == "game_mod" or v.typ == "game" then + elseif v.is_game_content then color = mt_color_blue elseif v.enabled then color = mt_color_green @@ -417,12 +417,14 @@ function modmgr.preparemodlist(data) -- Add title retval[#retval + 1] = { typ = "game", + is_game_content = true, name = fgettext("Subgame Mods") } end for i=1,#game_mods,1 do game_mods[i].typ = "game_mod" + game_mods[i].is_game_content = true retval[#retval + 1] = game_mods[i] end diff --git a/src/client.cpp b/src/client.cpp index 6ab4002a5..5f2d2d9d2 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -171,7 +171,7 @@ void Client::initMods() if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) { throw ModError("Error loading mod \"" + mod.name + "\": Mod name does not follow naming conventions: " - "Only chararacters [a-z0-9_] are allowed."); + "Only characters [a-z0-9_] are allowed."); } std::string script_path = mod.path + DIR_DELIM + "init.lua"; infostream << " [" << padStringRight(mod.name, 12) << "] [\"" diff --git a/src/server.cpp b/src/server.cpp index 5400dd595..6889451d9 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -283,7 +283,7 @@ Server::Server( if (!string_allowed(mod.name, MODNAME_ALLOWED_CHARS)) { throw ModError("Error loading mod \"" + mod.name + "\": Mod name does not follow naming conventions: " - "Only chararacters [a-z0-9_] are allowed."); + "Only characters [a-z0-9_] are allowed."); } std::string script_path = mod.path + DIR_DELIM + "init.lua"; infostream << " [" << padStringRight(mod.name, 12) << "] [\"" diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp index 4d2c87a4d..892c6c55b 100644 --- a/src/serverenvironment.cpp +++ b/src/serverenvironment.cpp @@ -141,7 +141,7 @@ void LBMManager::addLBMDef(LoadingBlockModifierDef *lbm_def) if (!string_allowed(lbm_def->name, LBM_NAME_ALLOWED_CHARS)) { throw ModError("Error adding LBM \"" + lbm_def->name + "\": Does not follow naming conventions: " - "Only chararacters [a-z0-9_:] are allowed."); + "Only characters [a-z0-9_:] are allowed."); } m_lbm_defs[lbm_def->name] = lbm_def; -- cgit v1.2.3 From 90808a4f34dca379e872074bdfd472faf1c48cf3 Mon Sep 17 00:00:00 2001 From: Loïc Blot Date: Sat, 20 May 2017 22:29:15 +0200 Subject: Real control fix (#5787) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Allow enabling and disabling mods. * Re-fix 605599b6f150b89ba6539c4d088231b326adcb48 This breaks some chars like € in chat. Instead verify is char is a non control char -> iswcntrl --- src/guiChatConsole.cpp | 2 +- src/mods.cpp | 100 +++++++++++++++++++++++++++++-------------------- src/mods.h | 2 + src/server.cpp | 26 ------------- 4 files changed, 62 insertions(+), 68 deletions(-) (limited to 'src/server.cpp') diff --git a/src/guiChatConsole.cpp b/src/guiChatConsole.cpp index 8281da861..5bb80bbbe 100644 --- a/src/guiChatConsole.cpp +++ b/src/guiChatConsole.cpp @@ -627,7 +627,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event) bool backwards = event.KeyInput.Shift; prompt.nickCompletion(names, backwards); return true; - } else if (iswprint(event.KeyInput.Char) && !event.KeyInput.Control) { + } else if (!iswcntrl(event.KeyInput.Char) && !event.KeyInput.Control) { #if defined(__linux__) && (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 9) wchar_t wc = L'_'; mbtowc( &wc, (char *) &event.KeyInput.Char, sizeof(event.KeyInput.Char) ); diff --git a/src/mods.cpp b/src/mods.cpp index 6fce8e93d..0e583b2db 100644 --- a/src/mods.cpp +++ b/src/mods.cpp @@ -214,6 +214,55 @@ void ModConfiguration::addMods(const std::vector &new_mods) } } +void ModConfiguration::addModsFormConfig(const std::string &settings_path, const std::set &mods) +{ + Settings conf; + std::set load_mod_names; + + conf.readConfigFile(settings_path.c_str()); + std::vector names = conf.getNames(); + for (std::vector::iterator it = names.begin(); + it != names.end(); ++it) { + std::string name = *it; + if (name.compare(0,9,"load_mod_")==0 && conf.getBool(name)) + load_mod_names.insert(name.substr(9)); + } + + std::vector addon_mods; + for (std::set::const_iterator i = mods.begin(); + i != mods.end(); ++i) { + std::vector addon_mods_in_path = flattenMods(getModsInPath(*i)); + for (std::vector::const_iterator it = addon_mods_in_path.begin(); + it != addon_mods_in_path.end(); ++it) { + const ModSpec& mod = *it; + if (load_mod_names.count(mod.name) != 0) + addon_mods.push_back(mod); + else + conf.setBool("load_mod_" + mod.name, false); + } + } + conf.updateConfigFile(settings_path.c_str()); + + addMods(addon_mods); + checkConflictsAndDeps(); + + // complain about mods declared to be loaded, but not found + for (std::vector::iterator it = addon_mods.begin(); + it != addon_mods.end(); ++it) + load_mod_names.erase((*it).name); + std::vector UnsatisfiedMods = getUnsatisfiedMods(); + for (std::vector::iterator it = UnsatisfiedMods.begin(); + it != UnsatisfiedMods.end(); ++it) + load_mod_names.erase((*it).name); + if (!load_mod_names.empty()) { + errorstream << "The following mods could not be found:"; + for (std::set::iterator it = load_mod_names.begin(); + it != load_mod_names.end(); ++it) + errorstream << " \"" << (*it) << "\""; + errorstream << std::endl; + } +} + void ModConfiguration::checkConflictsAndDeps() { // report on name conflicts @@ -296,53 +345,22 @@ ServerModConfiguration::ServerModConfiguration(const std::string &worldpath): addModsInPath(gamespec.gamemods_path); addModsInPath(worldpath + DIR_DELIM + "worldmods"); - // check world.mt file for mods explicitely declared to be - // loaded or not by a load_mod_ = ... line. - std::string worldmt = worldpath+DIR_DELIM+"world.mt"; - Settings worldmt_settings; - worldmt_settings.readConfigFile(worldmt.c_str()); - std::vector names = worldmt_settings.getNames(); - std::set include_mod_names; - for (std::vector::const_iterator it = names.begin(); - it != names.end(); ++it) { - std::string name = *it; - // for backwards compatibility: exclude only mods which are - // explicitely excluded. if mod is not mentioned at all, it is - // enabled. So by default, all installed mods are enabled. - if (name.compare(0,9,"load_mod_") == 0 && - worldmt_settings.getBool(name)) { - include_mod_names.insert(name.substr(9)); - } - } - - // Collect all mods that are also in include_mod_names - std::vector addon_mods; - for (std::set::const_iterator it_path = gamespec.addon_mods_paths.begin(); - it_path != gamespec.addon_mods_paths.end(); ++it_path) { - std::vector addon_mods_in_path = flattenMods(getModsInPath(*it_path)); - for (std::vector::const_iterator it = addon_mods_in_path.begin(); - it != addon_mods_in_path.end(); ++it) { - const ModSpec& mod = *it; - if (include_mod_names.count(mod.name) != 0) - addon_mods.push_back(mod); - else - worldmt_settings.setBool("load_mod_" + mod.name, false); - } - } - worldmt_settings.updateConfigFile(worldmt.c_str()); - - addMods(addon_mods); - - checkConflictsAndDeps(); + // Load normal mods + std::string worldmt = worldpath + DIR_DELIM + "world.mt"; + addModsFormConfig(worldmt, gamespec.addon_mods_paths); } #ifndef SERVER ClientModConfiguration::ClientModConfiguration(const std::string &path): ModConfiguration(path) { - addModsInPath(path); - addModsInPath(porting::path_user + DIR_DELIM + "clientmods"); - checkConflictsAndDeps(); + std::set paths; + std::string path_user = porting::path_user + DIR_DELIM + "clientmods"; + paths.insert(path); + paths.insert(path_user); + + std::string settings_path = path_user + DIR_DELIM + "mods.conf"; + addModsFormConfig(settings_path, paths); } #endif diff --git a/src/mods.h b/src/mods.h index 1e62db54d..7455a51ea 100644 --- a/src/mods.h +++ b/src/mods.h @@ -99,6 +99,8 @@ protected: // adds all mods in the set. void addMods(const std::vector &new_mods); + void addModsFormConfig(const std::string &settings_path, const std::set &mods); + void checkConflictsAndDeps(); private: // move mods from m_unsatisfied_mods to m_sorted_mods diff --git a/src/server.cpp b/src/server.cpp index 6889451d9..1e8e6a5d2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -230,32 +230,6 @@ Server::Server( modconf.printUnsatisfiedModsError(); } - Settings worldmt_settings; - std::string worldmt = m_path_world + DIR_DELIM + "world.mt"; - worldmt_settings.readConfigFile(worldmt.c_str()); - std::vector names = worldmt_settings.getNames(); - std::set load_mod_names; - for(std::vector::iterator it = names.begin(); - it != names.end(); ++it) { - std::string name = *it; - if(name.compare(0,9,"load_mod_")==0 && worldmt_settings.getBool(name)) - load_mod_names.insert(name.substr(9)); - } - // complain about mods declared to be loaded, but not found - for(std::vector::iterator it = m_mods.begin(); - it != m_mods.end(); ++it) - load_mod_names.erase((*it).name); - for(std::vector::iterator it = unsatisfied_mods.begin(); - it != unsatisfied_mods.end(); ++it) - load_mod_names.erase((*it).name); - if(!load_mod_names.empty()) { - errorstream << "The following mods could not be found:"; - for(std::set::iterator it = load_mod_names.begin(); - it != load_mod_names.end(); ++it) - errorstream << " \"" << (*it) << "\""; - errorstream << std::endl; - } - //lock environment MutexAutoLock envlock(m_env_mutex); -- cgit v1.2.3