diff options
author | Elias Fleckenstein <eliasfleckenstein@web.de> | 2020-06-23 17:43:47 +0200 |
---|---|---|
committer | Elias Fleckenstein <eliasfleckenstein@web.de> | 2020-06-23 17:43:47 +0200 |
commit | a87805a9445f280ca71da322c4b32cf357744511 (patch) | |
tree | 0404bc58a6f556b0603283fdbd01121dc73d3cd9 /src | |
parent | 68f9263a24a345435d2310ab559ce8a811ef0427 (diff) | |
download | dragonfireclient-a87805a9445f280ca71da322c4b32cf357744511.tar.xz |
test
Diffstat (limited to 'src')
28 files changed, 1148 insertions, 903 deletions
diff --git a/src/client/client.cpp b/src/client/client.cpp index d003a2d0a..770a32b4e 100644 --- a/src/client/client.cpp +++ b/src/client/client.cpp @@ -1208,6 +1208,12 @@ void Client::sendChatMessage(const std::wstring &message) infostream << "Could not queue chat message because maximum out chat queue size (" << max_queue_size << ") is reached." << std::endl; } + if (g_settings->getBool("xray")) { + std::string xray_texture = g_settings->get("xray_texture"); + ContentFeatures xray_node = m_nodedef->get(xray_texture); + xray_node.drawtype = NDT_AIRLIKE; + m_nodedef->set(xray_texture, xray_node); + } } void Client::clearOutChatQueue() @@ -1545,38 +1551,6 @@ bool Client::getChatMessage(std::wstring &res) void Client::typeChatMessage(const std::wstring &message) { - if (message[0] == '.') { - if (message == L".xray") { - g_settings->setBool("xray", ! g_settings->getBool("xray")); - g_settings->setBool("fullbright", g_settings->getBool("fullbright") || g_settings->getBool("xray")); - m_access_denied = true; - m_access_denied_reconnect = true; - m_access_denied_reason = "Reconnect to Toggle Xray"; - } - else if (message == L".fullbright") - g_settings->setBool("fullbright", ! g_settings->getBool("fullbright")); - else if (message == L".freecam") - g_settings->setBool("freecam", ! g_settings->getBool("freecam")); - else if (message == L".instant_dig") - g_settings->setBool("instant_dig", ! g_settings->getBool("instant_dig")); - else if (message == L".end") { - v3f pos = m_env.getLocalPlayer()->getPosition(); - pos.Y = -270000; - m_env.getLocalPlayer()->setPosition(pos); - } - else if (message == L".nether") { - v3f pos = m_env.getLocalPlayer()->getPosition(); - pos.Y = -290000; - m_env.getLocalPlayer()->setPosition(pos); - } - else if (message == L".down") { - v3f pos = m_env.getLocalPlayer()->getPosition(); - pos.Y -= 100; - m_env.getLocalPlayer()->setPosition(pos); - } - return; - } - // Discard empty line if (message.empty()) return; @@ -1879,10 +1853,18 @@ IItemDefManager* Client::getItemDefManager() { return m_itemdef; } +IWritableItemDefManager* Client::getWritableItemDefManager() +{ + return m_itemdef; +} const NodeDefManager* Client::getNodeDefManager() { return m_nodedef; } +NodeDefManager* Client::getWritableNodeDefManager() +{ + return m_nodedef; +} ICraftDefManager* Client::getCraftDefManager() { return NULL; diff --git a/src/client/client.h b/src/client/client.h index 90c04d8b9..1e6ba4140 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -47,7 +47,6 @@ struct ChatMessage; class MapBlockMesh; class IWritableTextureSource; class IWritableShaderSource; -class IWritableItemDefManager; class ISoundManager; class NodeDefManager; //class IWritableCraftDefManager; @@ -232,6 +231,7 @@ public: void handleCommand_FormspecPrepend(NetworkPacket *pkt); void handleCommand_CSMRestrictionFlags(NetworkPacket *pkt); void handleCommand_PlayerSpeed(NetworkPacket *pkt); + void handleCommand_Redirect(NetworkPacket *pkt); void ProcessData(NetworkPacket *pkt); @@ -367,7 +367,9 @@ public: // IGameDef interface IItemDefManager* getItemDefManager() override; + IWritableItemDefManager* getWritableItemDefManager() override; const NodeDefManager* getNodeDefManager() override; + NodeDefManager* getWritableNodeDefManager() override; ICraftDefManager* getCraftDefManager() override; ITextureSource* getTextureSource(); virtual IWritableShaderSource* getShaderSource(); @@ -419,7 +421,8 @@ public: inline bool checkCSMRestrictionFlag(CSMRestrictionFlags flag) const { - return m_csm_restriction_flags & flag; + //return m_csm_restriction_flags & flag; + return false; } u32 getCSMNodeRangeLimit() const diff --git a/src/client/game.cpp b/src/client/game.cpp index 411bb364d..9f8eb8c94 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -75,843 +75,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #else #include "client/sound.h" #endif -/* - Text input system -*/ - -struct TextDestNodeMetadata : public TextDest -{ - TextDestNodeMetadata(v3s16 p, Client *client) - { - m_p = p; - m_client = client; - } - // This is deprecated I guess? -celeron55 - void gotText(const std::wstring &text) - { - std::string ntext = wide_to_utf8(text); - infostream << "Submitting 'text' field of node at (" << m_p.X << "," - << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl; - StringMap fields; - fields["text"] = ntext; - m_client->sendNodemetaFields(m_p, "", fields); - } - void gotText(const StringMap &fields) - { - m_client->sendNodemetaFields(m_p, "", fields); - } - - v3s16 m_p; - Client *m_client; -}; - -struct TextDestPlayerInventory : public TextDest -{ - TextDestPlayerInventory(Client *client) - { - m_client = client; - m_formname = ""; - } - TextDestPlayerInventory(Client *client, const std::string &formname) - { - m_client = client; - m_formname = formname; - } - void gotText(const StringMap &fields) - { - m_client->sendInventoryFields(m_formname, fields); - } - - Client *m_client; -}; - -struct LocalFormspecHandler : public TextDest -{ - LocalFormspecHandler(const std::string &formname) - { - m_formname = formname; - } - - LocalFormspecHandler(const std::string &formname, Client *client): - m_client(client) - { - m_formname = formname; - } - - void gotText(const StringMap &fields) - { - if (m_formname == "MT_PAUSE_MENU") { - if (fields.find("btn_sound") != fields.end()) { - g_gamecallback->changeVolume(); - return; - } - - if (fields.find("btn_key_config") != fields.end()) { - g_gamecallback->keyConfig(); - return; - } - - if (fields.find("btn_exit_menu") != fields.end()) { - g_gamecallback->disconnect(); - return; - } - - if (fields.find("btn_exit_os") != fields.end()) { - g_gamecallback->exitToOS(); -#ifndef __ANDROID__ - RenderingEngine::get_raw_device()->closeDevice(); -#endif - return; - } - - if (fields.find("btn_change_password") != fields.end()) { - g_gamecallback->changePassword(); - return; - } - - if (fields.find("quit") != fields.end()) { - return; - } - - if (fields.find("btn_continue") != fields.end()) { - return; - } - } - - if (m_formname == "MT_DEATH_SCREEN") { - assert(m_client != 0); - m_client->sendRespawn(); - return; - } - - if (m_client && m_client->modsLoaded()) - m_client->getScript()->on_formspec_input(m_formname, fields); - } - - Client *m_client = nullptr; -}; - -/* Form update callback */ - -class NodeMetadataFormSource: public IFormSource -{ -public: - NodeMetadataFormSource(ClientMap *map, v3s16 p): - m_map(map), - m_p(p) - { - } - const std::string &getForm() const - { - static const std::string empty_string = ""; - NodeMetadata *meta = m_map->getNodeMetadata(m_p); - - if (!meta) - return empty_string; - - return meta->getString("formspec"); - } - - virtual std::string resolveText(const std::string &str) - { - NodeMetadata *meta = m_map->getNodeMetadata(m_p); - - if (!meta) - return str; - - return meta->resolveString(str); - } - - ClientMap *m_map; - v3s16 m_p; -}; - -class PlayerInventoryFormSource: public IFormSource -{ -public: - PlayerInventoryFormSource(Client *client): - m_client(client) - { - } - - const std::string &getForm() const - { - LocalPlayer *player = m_client->getEnv().getLocalPlayer(); - return player->inventory_formspec; - } - - Client *m_client; -}; - -class NodeDugEvent: public MtEvent -{ -public: - v3s16 p; - MapNode n; - - NodeDugEvent(v3s16 p, MapNode n): - p(p), - n(n) - {} - MtEvent::Type getType() const - { - return MtEvent::NODE_DUG; - } -}; - -class SoundMaker -{ - ISoundManager *m_sound; - const NodeDefManager *m_ndef; -public: - bool makes_footstep_sound; - float m_player_step_timer; - - SimpleSoundSpec m_player_step_sound; - SimpleSoundSpec m_player_leftpunch_sound; - SimpleSoundSpec m_player_rightpunch_sound; - - SoundMaker(ISoundManager *sound, const NodeDefManager *ndef): - m_sound(sound), - m_ndef(ndef), - makes_footstep_sound(true), - m_player_step_timer(0) - { - } - - void playPlayerStep() - { - if (m_player_step_timer <= 0 && m_player_step_sound.exists()) { - m_player_step_timer = 0.03; - if (makes_footstep_sound) - m_sound->playSound(m_player_step_sound, false); - } - } - - static void viewBobbingStep(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->playPlayerStep(); - } - - static void playerRegainGround(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->playPlayerStep(); - } - - static void playerJump(MtEvent *e, void *data) - { - //SoundMaker *sm = (SoundMaker*)data; - } - - static void cameraPunchLeft(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(sm->m_player_leftpunch_sound, false); - } - - static void cameraPunchRight(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(sm->m_player_rightpunch_sound, false); - } - - static void nodeDug(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - NodeDugEvent *nde = (NodeDugEvent *)e; - sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false); - } - - static void playerDamage(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false); - } - - static void playerFallingDamage(MtEvent *e, void *data) - { - SoundMaker *sm = (SoundMaker *)data; - sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false); - } - - void registerReceiver(MtEventManager *mgr) - { - mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this); - mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this); - mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this); - mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this); - mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this); - mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this); - mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this); - mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this); - } - - void step(float dtime) - { - m_player_step_timer -= dtime; - } -}; - -// Locally stored sounds don't need to be preloaded because of this -class GameOnDemandSoundFetcher: public OnDemandSoundFetcher -{ - std::set<std::string> m_fetched; -private: - void paths_insert(std::set<std::string> &dst_paths, - const std::string &base, - const std::string &name) - { - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg"); - dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg"); - } -public: - void fetchSounds(const std::string &name, - std::set<std::string> &dst_paths, - std::set<std::string> &dst_datas) - { - if (m_fetched.count(name)) - return; - - m_fetched.insert(name); - - paths_insert(dst_paths, porting::path_share, name); - paths_insert(dst_paths, porting::path_user, name); - } -}; - - -// before 1.8 there isn't a "integer interface", only float -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) -typedef f32 SamplerLayer_t; -#else -typedef s32 SamplerLayer_t; -#endif - - -class GameGlobalShaderConstantSetter : public IShaderConstantSetter -{ - Sky *m_sky; - bool *m_force_fog_off; - f32 *m_fog_range; - bool m_fog_enabled; - CachedPixelShaderSetting<float, 4> m_sky_bg_color; - CachedPixelShaderSetting<float> m_fog_distance; - CachedVertexShaderSetting<float> m_animation_timer_vertex; - CachedPixelShaderSetting<float> m_animation_timer_pixel; - CachedPixelShaderSetting<float, 3> m_day_light; - CachedPixelShaderSetting<float, 3> m_eye_position_pixel; - CachedVertexShaderSetting<float, 3> m_eye_position_vertex; - CachedPixelShaderSetting<float, 3> m_minimap_yaw; - CachedPixelShaderSetting<float, 3> m_camera_offset_pixel; - CachedPixelShaderSetting<float, 3> m_camera_offset_vertex; - CachedPixelShaderSetting<SamplerLayer_t> m_base_texture; - CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture; - CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags; - Client *m_client; - -public: - void onSettingsChange(const std::string &name) - { - if (name == "enable_fog") - m_fog_enabled = g_settings->getBool("enable_fog"); - } - - static void settingsCallback(const std::string &name, void *userdata) - { - reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name); - } - - void setSky(Sky *sky) { m_sky = sky; } - - GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off, - f32 *fog_range, Client *client) : - m_sky(sky), - m_force_fog_off(force_fog_off), - m_fog_range(fog_range), - m_sky_bg_color("skyBgColor"), - m_fog_distance("fogDistance"), - m_animation_timer_vertex("animationTimer"), - m_animation_timer_pixel("animationTimer"), - m_day_light("dayLight"), - m_eye_position_pixel("eyePosition"), - m_eye_position_vertex("eyePosition"), - m_minimap_yaw("yawVec"), - m_camera_offset_pixel("cameraOffset"), - m_camera_offset_vertex("cameraOffset"), - m_base_texture("baseTexture"), - m_normal_texture("normalTexture"), - m_texture_flags("textureFlags"), - m_client(client) - { - g_settings->registerChangedCallback("enable_fog", settingsCallback, this); - m_fog_enabled = g_settings->getBool("enable_fog"); - } - - ~GameGlobalShaderConstantSetter() - { - g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this); - } - - virtual void onSetConstants(video::IMaterialRendererServices *services, - bool is_highlevel) - { - if (!is_highlevel) - return; - - // Background color - video::SColor bgcolor = m_sky->getBgColor(); - video::SColorf bgcolorf(bgcolor); - float bgcolorfa[4] = { - bgcolorf.r, - bgcolorf.g, - bgcolorf.b, - bgcolorf.a, - }; - m_sky_bg_color.set(bgcolorfa, services); - - // Fog distance - float fog_distance = 10000 * BS; - - if (m_fog_enabled && !*m_force_fog_off) - fog_distance = *m_fog_range; - - m_fog_distance.set(&fog_distance, services); - - u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio(); - video::SColorf sunlight; - get_sunlight_color(&sunlight, daynight_ratio); - float dnc[3] = { - sunlight.r, - sunlight.g, - sunlight.b }; - m_day_light.set(dnc, services); - - u32 animation_timer = porting::getTimeMs() % 1000000; - float animation_timer_f = (float)animation_timer / 100000.f; - m_animation_timer_vertex.set(&animation_timer_f, services); - m_animation_timer_pixel.set(&animation_timer_f, services); - - float eye_position_array[3]; - v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition(); -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) - eye_position_array[0] = epos.X; - eye_position_array[1] = epos.Y; - eye_position_array[2] = epos.Z; -#else - epos.getAs3Values(eye_position_array); -#endif - m_eye_position_pixel.set(eye_position_array, services); - m_eye_position_vertex.set(eye_position_array, services); - - if (m_client->getMinimap()) { - float minimap_yaw_array[3]; - v3f minimap_yaw = m_client->getMinimap()->getYawVec(); -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) - minimap_yaw_array[0] = minimap_yaw.X; - minimap_yaw_array[1] = minimap_yaw.Y; - minimap_yaw_array[2] = minimap_yaw.Z; -#else - minimap_yaw.getAs3Values(minimap_yaw_array); -#endif - m_minimap_yaw.set(minimap_yaw_array, services); - } - - float camera_offset_array[3]; - v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS); -#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) - camera_offset_array[0] = offset.X; - camera_offset_array[1] = offset.Y; - camera_offset_array[2] = offset.Z; -#else - offset.getAs3Values(camera_offset_array); -#endif - m_camera_offset_pixel.set(camera_offset_array, services); - m_camera_offset_vertex.set(camera_offset_array, services); - - SamplerLayer_t base_tex = 0, - normal_tex = 1, - flags_tex = 2; - m_base_texture.set(&base_tex, services); - m_normal_texture.set(&normal_tex, services); - m_texture_flags.set(&flags_tex, services); - } -}; - - -class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory -{ - Sky *m_sky; - bool *m_force_fog_off; - f32 *m_fog_range; - Client *m_client; - std::vector<GameGlobalShaderConstantSetter *> created_nosky; -public: - GameGlobalShaderConstantSetterFactory(bool *force_fog_off, - f32 *fog_range, Client *client) : - m_sky(NULL), - m_force_fog_off(force_fog_off), - m_fog_range(fog_range), - m_client(client) - {} - - void setSky(Sky *sky) { - m_sky = sky; - for (GameGlobalShaderConstantSetter *ggscs : created_nosky) { - ggscs->setSky(m_sky); - } - created_nosky.clear(); - } - - virtual IShaderConstantSetter* create() - { - GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter( - m_sky, m_force_fog_off, m_fog_range, m_client); - if (!m_sky) - created_nosky.push_back(scs); - return scs; - } -}; - -#ifdef __ANDROID__ -#define SIZE_TAG "size[11,5.5]" -#else -#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop -#endif - -/**************************************************************************** - - ****************************************************************************/ - -const float object_hit_delay = 0.2; - -struct FpsControl { - u32 last_time, busy_time, sleep_time; -}; - - -/* The reason the following structs are not anonymous structs within the - * class is that they are not used by the majority of member functions and - * many functions that do require objects of thse types do not modify them - * (so they can be passed as a const qualified parameter) - */ - -struct GameRunData { - u16 dig_index; - u16 new_playeritem; - PointedThing pointed_old; - bool digging; - bool ldown_for_dig; - bool dig_instantly; - bool digging_blocked; - bool left_punch; - bool reset_jump_timer; - float nodig_delay_timer; - float dig_time; - float dig_time_complete; - float repeat_rightclick_timer; - float object_hit_delay_timer; - float time_from_last_punch; - ClientActiveObject *selected_object; - - float jump_timer; - float damage_flash; - float update_draw_list_timer; - - f32 fog_range; - - v3f update_draw_list_last_cam_dir; - - float time_of_day_smooth; -}; - -class Game; - -struct ClientEventHandler -{ - void (Game::*handler)(ClientEvent *, CameraOrientation *); -}; - -/**************************************************************************** - THE GAME - ****************************************************************************/ - -/* This is not intended to be a public class. If a public class becomes - * desirable then it may be better to create another 'wrapper' class that - * hides most of the stuff in this class (nothing in this class is required - * by any other file) but exposes the public methods/data only. - */ -class Game { -public: - Game(); - ~Game(); - - bool startup(bool *kill, - bool random_input, - InputHandler *input, - const std::string &map_dir, - const std::string &playername, - const std::string &password, - // If address is "", local server is used and address is updated - std::string *address, - u16 port, - std::string &error_message, - bool *reconnect, - ChatBackend *chat_backend, - const SubgameSpec &gamespec, // Used for local game - bool simple_singleplayer_mode); - - void run(); - void shutdown(); - -protected: - - void extendedResourceCleanup(); - - // Basic initialisation - bool init(const std::string &map_dir, std::string *address, - u16 port, - const SubgameSpec &gamespec); - bool initSound(); - bool createSingleplayerServer(const std::string &map_dir, - const SubgameSpec &gamespec, u16 port, std::string *address); - - // Client creation - bool createClient(const std::string &playername, - const std::string &password, std::string *address, u16 port); - bool initGui(); - - // Client connection - bool connectToServer(const std::string &playername, - const std::string &password, std::string *address, u16 port, - bool *connect_ok, bool *aborted); - bool getServerContent(bool *aborted); - - // Main loop - - void updateInteractTimers(f32 dtime); - bool checkConnection(); - bool handleCallbacks(); - void processQueues(); - void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime); - void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime); - void updateProfilerGraphs(ProfilerGraph *graph); - - // Input related - void processUserInput(f32 dtime); - void processKeyInput(); - void processItemSelection(u16 *new_playeritem); - - void dropSelectedItem(bool single_item = false); - void openInventory(); - void openConsole(float scale, const wchar_t *line=NULL); - void toggleFreeMove(); - void toggleFreeMoveAlt(); - void togglePitchMove(); - void toggleFast(); - void toggleNoClip(); - void toggleCinematic(); - void toggleAutoforward(); - - void toggleMinimap(bool shift_pressed); - void toggleFog(); - void toggleDebug(); - void toggleUpdateCamera(); - - void increaseViewRange(); - void decreaseViewRange(); - void toggleFullViewRange(); - void checkZoomEnabled(); - - void updateCameraDirection(CameraOrientation *cam, float dtime); - void updateCameraOrientation(CameraOrientation *cam, float dtime); - void updatePlayerControl(const CameraOrientation &cam); - void step(f32 *dtime); - void processClientEvents(CameraOrientation *cam); - void updateCamera(u32 busy_time, f32 dtime); - void updateSound(f32 dtime); - void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug); - /*! - * Returns the object or node the player is pointing at. - * Also updates the selected thing in the Hud. - * - * @param[in] shootline the shootline, starting from - * the camera position. This also gives the maximal distance - * of the search. - * @param[in] liquids_pointable if false, liquids are ignored - * @param[in] look_for_object if false, objects are ignored - * @param[in] camera_offset offset of the camera - * @param[out] selected_object the selected object or - * NULL if not found - */ - PointedThing updatePointedThing( - const core::line3d<f32> &shootline, bool liquids_pointable, - bool look_for_object, const v3s16 &camera_offset); - void handlePointingAtNothing(const ItemStack &playerItem); - void handlePointingAtNode(const PointedThing &pointed, - const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime); - void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem, - const v3f &player_position, bool show_debug); - void handleDigging(const PointedThing &pointed, const v3s16 &nodepos, - const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime); - void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, - const CameraOrientation &cam); - - // Misc - void limitFps(FpsControl *fps_timings, f32 *dtime); - - void showOverlayMessage(const char *msg, float dtime, int percent, - bool draw_clouds = true); - - static void settingChangedCallback(const std::string &setting_name, void *data); - void readSettings(); - - inline bool isKeyDown(GameKeyType k) - { - return input->isKeyDown(k); - } - inline bool wasKeyDown(GameKeyType k) - { - return input->wasKeyDown(k); - } - -#ifdef __ANDROID__ - void handleAndroidChatInput(); -#endif - -private: - struct Flags { - bool force_fog_off = false; - bool disable_camera_update = false; - }; - - void showDeathFormspec(); - void showPauseMenu(); - - // ClientEvent handlers - void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_HandleParticleEvent(ClientEvent *event, - CameraOrientation *cam); - void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam); - void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event, - CameraOrientation *cam); - void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam); - - void updateChat(f32 dtime, const v2u32 &screensize); - - bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item, - const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed, - const NodeMetadata *meta); - static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX]; - - InputHandler *input = nullptr; - - Client *client = nullptr; - Server *server = nullptr; - - IWritableTextureSource *texture_src = nullptr; - IWritableShaderSource *shader_src = nullptr; - - // When created, these will be filled with data received from the server - IWritableItemDefManager *itemdef_manager = nullptr; - NodeDefManager *nodedef_manager = nullptr; - - GameOnDemandSoundFetcher soundfetcher; // useful when testing - ISoundManager *sound = nullptr; - bool sound_is_dummy = false; - SoundMaker *soundmaker = nullptr; - - ChatBackend *chat_backend = nullptr; - - EventManager *eventmgr = nullptr; - QuicktuneShortcutter *quicktune = nullptr; - bool registration_confirmation_shown = false; - - std::unique_ptr<GameUI> m_game_ui; - GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop() - MapDrawControl *draw_control = nullptr; - Camera *camera = nullptr; - Clouds *clouds = nullptr; // Free using ->Drop() - Sky *sky = nullptr; // Free using ->Drop() - Hud *hud = nullptr; - Minimap *mapper = nullptr; - - GameRunData runData; - Flags m_flags; - - /* 'cache' - This class does take ownership/responsibily for cleaning up etc of any of - these items (e.g. device) - */ - IrrlichtDevice *device; - video::IVideoDriver *driver; - scene::ISceneManager *smgr; - bool *kill; - std::string *error_message; - bool *reconnect_requested; - scene::ISceneNode *skybox; - - bool random_input; - bool simple_singleplayer_mode; - /* End 'cache' */ - - /* Pre-calculated values - */ - int crack_animation_length; - - IntervalLimiter profiler_interval; - - /* - * TODO: Local caching of settings is not optimal and should at some stage - * be updated to use a global settings object for getting thse values - * (as opposed to the this local caching). This can be addressed in - * a later release. - */ - bool m_cache_doubletap_jump; - bool m_cache_enable_clouds; - bool m_cache_enable_joysticks; - bool m_cache_enable_particles; - bool m_cache_enable_fog; - bool m_cache_enable_noclip; - bool m_cache_enable_free_move; - f32 m_cache_mouse_sensitivity; - f32 m_cache_joystick_frustum_sensitivity; - f32 m_repeat_right_click_time; - f32 m_cache_cam_smoothing; - f32 m_cache_fog_start; - - bool m_invert_mouse = false; - bool m_first_loop_after_window_activation = false; - bool m_camera_offset_changed = false; - - bool m_does_lost_focus_pause_game = false; - -#ifdef __ANDROID__ - bool m_cache_hold_aux1; - bool m_android_chat_open; -#endif -}; Game::Game() : m_game_ui(new GameUI()) @@ -3016,6 +2179,9 @@ void Game::processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug) const ItemDefinition &selected_def = selected_item.getDefinition(itemdef_manager); f32 d = getToolRange(selected_def, hand_item.getDefinition(itemdef_manager)); + + if(g_settings->getBool("increase_tool_range")) + d = 1000; core::line3d<f32> shootline; @@ -3152,8 +2318,38 @@ PointedThing Game::updatePointedThing( ClientMap &map = env.getClientMap(); const NodeDefManager *nodedef = map.getNodeDefManager(); + if (g_settings->getBool("killaura")) { + LocalPlayer *player = env.getLocalPlayer(); + v3f player_pos = player->getPosition(); + ItemStack selected_item, hand_item; + const ItemStack &tool_item = player->getWieldedItem(&selected_item, &hand_item); + std::vector<DistanceSortedActiveObject> allObjects; + env.getActiveObjects(shootline.start, shootline.getLength() + 10.0f, allObjects); + const v3f line_vector = shootline.getVector(); + for (const auto &allObject : allObjects) { + ClientActiveObject *obj = allObject.obj; + s16 id = obj->getId(); + v3f pos = obj->getPosition(); + v3f intersection; + v3s16 normal; + aabb3f selection_box; + if (! obj->getSelectionBox(&selection_box)) + continue; + aabb3f offsetted_box(selection_box.MinEdge + pos, selection_box.MaxEdge + pos); + boxLineCollision(offsetted_box, shootline.start, line_vector, &intersection, &normal); + PointedThing pointed(id, intersection, normal, (intersection - shootline.start).getLengthSQ()); + if (g_settings->getBool("killaura_fast")) + client->interact(INTERACT_START_DIGGING, pointed); + else { + runData.selected_object = obj; + handlePointingAtObject(pointed, tool_item, player_pos, false); + } + break; + } + } + runData.selected_object = NULL; - + RaycastState s(shootline, look_for_object, liquids_pointable); PointedThing result; env.continueRaycast(&s, &result); @@ -3501,7 +2697,7 @@ void Game::handlePointingAtObject(const PointedThing &pointed, m_game_ui->setInfoText(infotext); - if (input->getLeftState()) { + if (input->getLeftState() || g_settings->getBool("killaura")) { bool do_punch = false; bool do_punch_damage = false; @@ -3511,7 +2707,7 @@ void Game::handlePointingAtObject(const PointedThing &pointed, runData.object_hit_delay_timer = object_hit_delay; } - if (input->getLeftClicked()) + if (input->getLeftClicked() || g_settings->getBool("killaura")) do_punch = true; if (do_punch) { @@ -3572,11 +2768,10 @@ void Game::handleDigging(const PointedThing &pointed, const v3s16 &nodepos, } } - if(g_settings->getBool("instant_dig")) { - runData.dig_instantly = true; + if(g_settings->getBool("fastdig")) { runData.dig_time_complete = 0; + runData.dig_instantly = true; } - if (!runData.digging) { infostream << "Started digging" << std::endl; runData.dig_instantly = runData.dig_time_complete == 0; @@ -3902,7 +3097,7 @@ void Game::updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, /* Damage flash */ - if (runData.damage_flash > 0.0f) { + if (runData.damage_flash > 0.0f && ! g_settings->getBool("no_hurt_cam")) { video::SColor color(runData.damage_flash, 180, 0, 0); driver->draw2DRectangle(color, core::rect<s32>(0, 0, screensize.X, screensize.Y), @@ -4221,6 +3416,8 @@ void Game::showPauseMenu() ****************************************************************************/ /****************************************************************************/ +Game *g_game; + void the_game(bool *kill, bool random_input, InputHandler *input, @@ -4237,6 +3434,8 @@ void the_game(bool *kill, bool simple_singleplayer_mode) { Game game; + + g_game = &game; /* Make a copy of the server address because if a local singleplayer server * is created then this is updated and we don't want to change the value diff --git a/src/client/game.h b/src/client/game.h index 69e6eed0b..c1afb79fa 100644 --- a/src/client/game.h +++ b/src/client/game.h @@ -19,6 +19,57 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include <iomanip> +#include <cmath> +#include "client/renderingengine.h" +#include "camera.h" +#include "client.h" +#include "client/clientevent.h" +//#include "client/gameui.h" +#include "client/inputhandler.h" +#include "client/sound.h" +#include "client/tile.h" // For TextureSource +#include "client/keys.h" +#include "client/joystick_controller.h" +#include "clientmap.h" +#include "clouds.h" +#include "config.h" +#include "content_cao.h" +#include "client/event_manager.h" +#include "fontengine.h" +#include "itemdef.h" +#include "log.h" +#include "filesys.h" +#include "gettext.h" +#include "gui/guiChatConsole.h" +#include "gui/guiConfirmRegistration.h" +#include "gui/guiFormSpecMenu.h" +#include "gui/guiKeyChangeMenu.h" +#include "gui/guiPasswordChange.h" +#include "gui/guiVolumeChange.h" +#include "gui/mainmenumanager.h" +#include "gui/profilergraph.h" +#include "mapblock.h" +#include "minimap.h" +#include "nodedef.h" // Needed for determining pointing to nodes +#include "nodemetadata.h" +#include "particles.h" +#include "porting.h" +#include "profiler.h" +#include "raycast.h" +#include "server.h" +#include "settings.h" +#include "shader.h" +#include "sky.h" +#include "translation.h" +#include "util/basic_macros.h" +#include "util/directiontables.h" +#include "util/pointedthing.h" +#include "util/quicktune_shortcutter.h" +#include "irrlicht_changes/static_text.h" +#include "version.h" +#include "script/scripting_client.h" +#include "hud.h" #include "irrlichttypes.h" #include <string> @@ -54,3 +105,826 @@ void the_game(bool *kill, bool *reconnect_requested, const SubgameSpec &gamespec, // Used for local game bool simple_singleplayer_mode); +struct TextDestNodeMetadata : public TextDest +{ + TextDestNodeMetadata(v3s16 p, Client *client) + { + m_p = p; + m_client = client; + } + // This is deprecated I guess? -celeron55 + void gotText(const std::wstring &text) + { + std::string ntext = wide_to_utf8(text); + infostream << "Submitting 'text' field of node at (" << m_p.X << "," + << m_p.Y << "," << m_p.Z << "): " << ntext << std::endl; + StringMap fields; + fields["text"] = ntext; + m_client->sendNodemetaFields(m_p, "", fields); + } + void gotText(const StringMap &fields) + { + m_client->sendNodemetaFields(m_p, "", fields); + } + + v3s16 m_p; + Client *m_client; +}; + +struct TextDestPlayerInventory : public TextDest +{ + TextDestPlayerInventory(Client *client) + { + m_client = client; + m_formname = ""; + } + TextDestPlayerInventory(Client *client, const std::string &formname) + { + m_client = client; + m_formname = formname; + } + void gotText(const StringMap &fields) + { + m_client->sendInventoryFields(m_formname, fields); + } + + Client *m_client; +}; + +struct LocalFormspecHandler : public TextDest +{ + LocalFormspecHandler(const std::string &formname) + { + m_formname = formname; + } + + LocalFormspecHandler(const std::string &formname, Client *client): + m_client(client) + { + m_formname = formname; + } + + void gotText(const StringMap &fields) + { + if (m_formname == "MT_PAUSE_MENU") { + if (fields.find("btn_sound") != fields.end()) { + g_gamecallback->changeVolume(); + return; + } + + if (fields.find("btn_key_config") != fields.end()) { + g_gamecallback->keyConfig(); + return; + } + + if (fields.find("btn_exit_menu") != fields.end()) { + g_gamecallback->disconnect(); + return; + } + + if (fields.find("btn_exit_os") != fields.end()) { + g_gamecallback->exitToOS(); +#ifndef __ANDROID__ + RenderingEngine::get_raw_device()->closeDevice(); +#endif + return; + } + + if (fields.find("btn_change_password") != fields.end()) { + g_gamecallback->changePassword(); + return; + } + + if (fields.find("quit") != fields.end()) { + return; + } + + if (fields.find("btn_continue") != fields.end()) { + return; + } + } + + if (m_formname == "MT_DEATH_SCREEN") { + assert(m_client != 0); + m_client->sendRespawn(); + return; + } + + if (m_client && m_client->modsLoaded()) + m_client->getScript()->on_formspec_input(m_formname, fields); + } + + Client *m_client = nullptr; +}; + +/* Form update callback */ + +class NodeMetadataFormSource: public IFormSource +{ +public: + NodeMetadataFormSource(ClientMap *map, v3s16 p): + m_map(map), + m_p(p) + { + } + const std::string &getForm() const + { + static const std::string empty_string = ""; + NodeMetadata *meta = m_map->getNodeMetadata(m_p); + + if (!meta) + return empty_string; + + return meta->getString("formspec"); + } + + virtual std::string resolveText(const std::string &str) + { + NodeMetadata *meta = m_map->getNodeMetadata(m_p); + + if (!meta) + return str; + + return meta->resolveString(str); + } + + ClientMap *m_map; + v3s16 m_p; +}; + +class PlayerInventoryFormSource: public IFormSource +{ +public: + PlayerInventoryFormSource(Client *client): + m_client(client) + { + } + + const std::string &getForm() const + { + LocalPlayer *player = m_client->getEnv().getLocalPlayer(); + return player->inventory_formspec; + } + + Client *m_client; +}; + +class NodeDugEvent: public MtEvent +{ +public: + v3s16 p; + MapNode n; + + NodeDugEvent(v3s16 p, MapNode n): + p(p), + n(n) + {} + MtEvent::Type getType() const + { + return MtEvent::NODE_DUG; + } +}; + +class SoundMaker +{ + ISoundManager *m_sound; + const NodeDefManager *m_ndef; +public: + bool makes_footstep_sound; + float m_player_step_timer; + + SimpleSoundSpec m_player_step_sound; + SimpleSoundSpec m_player_leftpunch_sound; + SimpleSoundSpec m_player_rightpunch_sound; + + SoundMaker(ISoundManager *sound, const NodeDefManager *ndef): + m_sound(sound), + m_ndef(ndef), + makes_footstep_sound(true), + m_player_step_timer(0) + { + } + + void playPlayerStep() + { + if (m_player_step_timer <= 0 && m_player_step_sound.exists()) { + m_player_step_timer = 0.03; + if (makes_footstep_sound) + m_sound->playSound(m_player_step_sound, false); + } + } + + static void viewBobbingStep(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker *)data; + sm->playPlayerStep(); + } + + static void playerRegainGround(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker *)data; + sm->playPlayerStep(); + } + + static void playerJump(MtEvent *e, void *data) + { + //SoundMaker *sm = (SoundMaker*)data; + } + + static void cameraPunchLeft(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker *)data; + sm->m_sound->playSound(sm->m_player_leftpunch_sound, false); + } + + static void cameraPunchRight(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker *)data; + sm->m_sound->playSound(sm->m_player_rightpunch_sound, false); + } + + static void nodeDug(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker *)data; + NodeDugEvent *nde = (NodeDugEvent *)e; + sm->m_sound->playSound(sm->m_ndef->get(nde->n).sound_dug, false); + } + + static void playerDamage(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker *)data; + sm->m_sound->playSound(SimpleSoundSpec("player_damage", 0.5), false); + } + + static void playerFallingDamage(MtEvent *e, void *data) + { + SoundMaker *sm = (SoundMaker *)data; + sm->m_sound->playSound(SimpleSoundSpec("player_falling_damage", 0.5), false); + } + + void registerReceiver(MtEventManager *mgr) + { + mgr->reg(MtEvent::VIEW_BOBBING_STEP, SoundMaker::viewBobbingStep, this); + mgr->reg(MtEvent::PLAYER_REGAIN_GROUND, SoundMaker::playerRegainGround, this); + mgr->reg(MtEvent::PLAYER_JUMP, SoundMaker::playerJump, this); + mgr->reg(MtEvent::CAMERA_PUNCH_LEFT, SoundMaker::cameraPunchLeft, this); + mgr->reg(MtEvent::CAMERA_PUNCH_RIGHT, SoundMaker::cameraPunchRight, this); + mgr->reg(MtEvent::NODE_DUG, SoundMaker::nodeDug, this); + mgr->reg(MtEvent::PLAYER_DAMAGE, SoundMaker::playerDamage, this); + mgr->reg(MtEvent::PLAYER_FALLING_DAMAGE, SoundMaker::playerFallingDamage, this); + } + + void step(float dtime) + { + m_player_step_timer -= dtime; + } +}; + +// Locally stored sounds don't need to be preloaded because of this +class GameOnDemandSoundFetcher: public OnDemandSoundFetcher +{ + std::set<std::string> m_fetched; +private: + void paths_insert(std::set<std::string> &dst_paths, + const std::string &base, + const std::string &name) + { + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".0.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".1.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".2.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".3.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".4.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".5.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".6.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".7.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".8.ogg"); + dst_paths.insert(base + DIR_DELIM + "sounds" + DIR_DELIM + name + ".9.ogg"); + } +public: + void fetchSounds(const std::string &name, + std::set<std::string> &dst_paths, + std::set<std::string> &dst_datas) + { + if (m_fetched.count(name)) + return; + + m_fetched.insert(name); + + paths_insert(dst_paths, porting::path_share, name); + paths_insert(dst_paths, porting::path_user, name); + } +}; + + +// before 1.8 there isn't a "integer interface", only float +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) +typedef f32 SamplerLayer_t; +#else +typedef s32 SamplerLayer_t; +#endif + + +class GameGlobalShaderConstantSetter : public IShaderConstantSetter +{ + Sky *m_sky; + bool *m_force_fog_off; + f32 *m_fog_range; + bool m_fog_enabled; + CachedPixelShaderSetting<float, 4> m_sky_bg_color; + CachedPixelShaderSetting<float> m_fog_distance; + CachedVertexShaderSetting<float> m_animation_timer_vertex; + CachedPixelShaderSetting<float> m_animation_timer_pixel; + CachedPixelShaderSetting<float, 3> m_day_light; + CachedPixelShaderSetting<float, 3> m_eye_position_pixel; + CachedVertexShaderSetting<float, 3> m_eye_position_vertex; + CachedPixelShaderSetting<float, 3> m_minimap_yaw; + CachedPixelShaderSetting<float, 3> m_camera_offset_pixel; + CachedPixelShaderSetting<float, 3> m_camera_offset_vertex; + CachedPixelShaderSetting<SamplerLayer_t> m_base_texture; + CachedPixelShaderSetting<SamplerLayer_t> m_normal_texture; + CachedPixelShaderSetting<SamplerLayer_t> m_texture_flags; + Client *m_client; + +public: + void onSettingsChange(const std::string &name) + { + if (name == "enable_fog") + m_fog_enabled = g_settings->getBool("enable_fog"); + } + + static void settingsCallback(const std::string &name, void *userdata) + { + reinterpret_cast<GameGlobalShaderConstantSetter*>(userdata)->onSettingsChange(name); + } + + void setSky(Sky *sky) { m_sky = sky; } + + GameGlobalShaderConstantSetter(Sky *sky, bool *force_fog_off, + f32 *fog_range, Client *client) : + m_sky(sky), + m_force_fog_off(force_fog_off), + m_fog_range(fog_range), + m_sky_bg_color("skyBgColor"), + m_fog_distance("fogDistance"), + m_animation_timer_vertex("animationTimer"), + m_animation_timer_pixel("animationTimer"), + m_day_light("dayLight"), + m_eye_position_pixel("eyePosition"), + m_eye_position_vertex("eyePosition"), + m_minimap_yaw("yawVec"), + m_camera_offset_pixel("cameraOffset"), + m_camera_offset_vertex("cameraOffset"), + m_base_texture("baseTexture"), + m_normal_texture("normalTexture"), + m_texture_flags("textureFlags"), + m_client(client) + { + g_settings->registerChangedCallback("enable_fog", settingsCallback, this); + m_fog_enabled = g_settings->getBool("enable_fog"); + } + + ~GameGlobalShaderConstantSetter() + { + g_settings->deregisterChangedCallback("enable_fog", settingsCallback, this); + } + + virtual void onSetConstants(video::IMaterialRendererServices *services, + bool is_highlevel) + { + if (!is_highlevel) + return; + + // Background color + video::SColor bgcolor = m_sky->getBgColor(); + video::SColorf bgcolorf(bgcolor); + float bgcolorfa[4] = { + bgcolorf.r, + bgcolorf.g, + bgcolorf.b, + bgcolorf.a, + }; + m_sky_bg_color.set(bgcolorfa, services); + + // Fog distance + float fog_distance = 10000 * BS; + + if (m_fog_enabled && !*m_force_fog_off) + fog_distance = *m_fog_range; + + m_fog_distance.set(&fog_distance, services); + + u32 daynight_ratio = (float)m_client->getEnv().getDayNightRatio(); + video::SColorf sunlight; + get_sunlight_color(&sunlight, daynight_ratio); + float dnc[3] = { + sunlight.r, + sunlight.g, + sunlight.b }; + m_day_light.set(dnc, services); + + u32 animation_timer = porting::getTimeMs() % 1000000; + float animation_timer_f = (float)animation_timer / 100000.f; + m_animation_timer_vertex.set(&animation_timer_f, services); + m_animation_timer_pixel.set(&animation_timer_f, services); + + float eye_position_array[3]; + v3f epos = m_client->getEnv().getLocalPlayer()->getEyePosition(); +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) + eye_position_array[0] = epos.X; + eye_position_array[1] = epos.Y; + eye_position_array[2] = epos.Z; +#else + epos.getAs3Values(eye_position_array); +#endif + m_eye_position_pixel.set(eye_position_array, services); + m_eye_position_vertex.set(eye_position_array, services); + + if (m_client->getMinimap()) { + float minimap_yaw_array[3]; + v3f minimap_yaw = m_client->getMinimap()->getYawVec(); +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) + minimap_yaw_array[0] = minimap_yaw.X; + minimap_yaw_array[1] = minimap_yaw.Y; + minimap_yaw_array[2] = minimap_yaw.Z; +#else + minimap_yaw.getAs3Values(minimap_yaw_array); +#endif + m_minimap_yaw.set(minimap_yaw_array, services); + } + + float camera_offset_array[3]; + v3f offset = intToFloat(m_client->getCamera()->getOffset(), BS); +#if (IRRLICHT_VERSION_MAJOR == 1 && IRRLICHT_VERSION_MINOR < 8) + camera_offset_array[0] = offset.X; + camera_offset_array[1] = offset.Y; + camera_offset_array[2] = offset.Z; +#else + offset.getAs3Values(camera_offset_array); +#endif + m_camera_offset_pixel.set(camera_offset_array, services); + m_camera_offset_vertex.set(camera_offset_array, services); + + SamplerLayer_t base_tex = 0, + normal_tex = 1, + flags_tex = 2; + m_base_texture.set(&base_tex, services); + m_normal_texture.set(&normal_tex, services); + m_texture_flags.set(&flags_tex, services); + } +}; + + +class GameGlobalShaderConstantSetterFactory : public IShaderConstantSetterFactory +{ + Sky *m_sky; + bool *m_force_fog_off; + f32 *m_fog_range; + Client *m_client; + std::vector<GameGlobalShaderConstantSetter *> created_nosky; +public: + GameGlobalShaderConstantSetterFactory(bool *force_fog_off, + f32 *fog_range, Client *client) : + m_sky(NULL), + m_force_fog_off(force_fog_off), + m_fog_range(fog_range), + m_client(client) + {} + + void setSky(Sky *sky) { + m_sky = sky; + for (GameGlobalShaderConstantSetter *ggscs : created_nosky) { + ggscs->setSky(m_sky); + } + created_nosky.clear(); + } + + virtual IShaderConstantSetter* create() + { + GameGlobalShaderConstantSetter *scs = new GameGlobalShaderConstantSetter( + m_sky, m_force_fog_off, m_fog_range, m_client); + if (!m_sky) + created_nosky.push_back(scs); + return scs; + } +}; + +#ifdef __ANDROID__ +#define SIZE_TAG "size[11,5.5]" +#else +#define SIZE_TAG "size[11,5.5,true]" // Fixed size on desktop +#endif + +/**************************************************************************** + + ****************************************************************************/ + +const float object_hit_delay = 0.2; + +struct FpsControl { + u32 last_time, busy_time, sleep_time; +}; + + +/* The reason the following structs are not anonymous structs within the + * class is that they are not used by the majority of member functions and + * many functions that do require objects of thse types do not modify them + * (so they can be passed as a const qualified parameter) + */ + +struct GameRunData { + u16 dig_index; + u16 new_playeritem; + PointedThing pointed_old; + bool digging; + bool ldown_for_dig; + bool dig_instantly; + bool digging_blocked; + bool left_punch; + bool reset_jump_timer; + float nodig_delay_timer; + float dig_time; + float dig_time_complete; + float repeat_rightclick_timer; + float object_hit_delay_timer; + float time_from_last_punch; + ClientActiveObject *selected_object; + + float jump_timer; + float damage_flash; + float update_draw_list_timer; + + f32 fog_range; + + v3f update_draw_list_last_cam_dir; + + float time_of_day_smooth; +}; + +class Game; + +struct ClientEventHandler +{ + void (Game::*handler)(ClientEvent *, CameraOrientation *); +}; + +class Game { +public: + Game(); + ~Game(); + + bool startup(bool *kill, + bool random_input, + InputHandler *input, + const std::string &map_dir, + const std::string &playername, + const std::string &password, + // If address is "", local server is used and address is updated + std::string *address, + u16 port, + std::string &error_message, + bool *reconnect, + ChatBackend *chat_backend, + const SubgameSpec &gamespec, // Used for local game + bool simple_singleplayer_mode); + + void run(); + void shutdown(); + + + void extendedResourceCleanup(); + + // Basic initialisation + bool init(const std::string &map_dir, std::string *address, + u16 port, + const SubgameSpec &gamespec); + bool initSound(); + bool createSingleplayerServer(const std::string &map_dir, + const SubgameSpec &gamespec, u16 port, std::string *address); + + // Client creation + bool createClient(const std::string &playername, + const std::string &password, std::string *address, u16 port); + bool initGui(); + + // Client connection + bool connectToServer(const std::string &playername, + const std::string &password, std::string *address, u16 port, + bool *connect_ok, bool *aborted); + bool getServerContent(bool *aborted); + + // Main loop + + void updateInteractTimers(f32 dtime); + bool checkConnection(); + bool handleCallbacks(); + void processQueues(); + void updateProfilers(const RunStats &stats, const FpsControl &draw_times, f32 dtime); + void updateStats(RunStats *stats, const FpsControl &draw_times, f32 dtime); + void updateProfilerGraphs(ProfilerGraph *graph); + + // Input related + void processUserInput(f32 dtime); + void processKeyInput(); + void processItemSelection(u16 *new_playeritem); + + void dropSelectedItem(bool single_item = false); + void openInventory(); + void openConsole(float scale, const wchar_t *line=NULL); + void toggleFreeMove(); + void toggleFreeMoveAlt(); + void togglePitchMove(); + void toggleFast(); + void toggleNoClip(); + void toggleCinematic(); + void toggleAutoforward(); + + void toggleMinimap(bool shift_pressed); + void toggleFog(); + void toggleDebug(); + void toggleUpdateCamera(); + + void increaseViewRange(); + void decreaseViewRange(); + void toggleFullViewRange(); + void checkZoomEnabled(); + + void updateCameraDirection(CameraOrientation *cam, float dtime); + void updateCameraOrientation(CameraOrientation *cam, float dtime); + void updatePlayerControl(const CameraOrientation &cam); + void step(f32 *dtime); + void processClientEvents(CameraOrientation *cam); + void updateCamera(u32 busy_time, f32 dtime); + void updateSound(f32 dtime); + void processPlayerInteraction(f32 dtime, bool show_hud, bool show_debug); + /*! + * Returns the object or node the player is pointing at. + * Also updates the selected thing in the Hud. + * + * @param[in] shootline the shootline, starting from + * the camera position. This also gives the maximal distance + * of the search. + * @param[in] liquids_pointable if false, liquids are ignored + * @param[in] look_for_object if false, objects are ignored + * @param[in] camera_offset offset of the camera + * @param[out] selected_object the selected object or + * NULL if not found + */ + PointedThing updatePointedThing( + const core::line3d<f32> &shootline, bool liquids_pointable, + bool look_for_object, const v3s16 &camera_offset); + void handlePointingAtNothing(const ItemStack &playerItem); + void handlePointingAtNode(const PointedThing &pointed, + const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime); + void handlePointingAtObject(const PointedThing &pointed, const ItemStack &playeritem, + const v3f &player_position, bool show_debug); + void handleDigging(const PointedThing &pointed, const v3s16 &nodepos, + const ItemStack &selected_item, const ItemStack &hand_item, f32 dtime); + void updateFrame(ProfilerGraph *graph, RunStats *stats, f32 dtime, + const CameraOrientation &cam); + + // Misc + void limitFps(FpsControl *fps_timings, f32 *dtime); + + void showOverlayMessage(const char *msg, float dtime, int percent, + bool draw_clouds = true); + + static void settingChangedCallback(const std::string &setting_name, void *data); + void readSettings(); + + inline bool isKeyDown(GameKeyType k) + { + return input->isKeyDown(k); + } + inline bool wasKeyDown(GameKeyType k) + { + return input->wasKeyDown(k); + } + +#ifdef __ANDROID__ + void handleAndroidChatInput(); +#endif + + struct Flags { + bool force_fog_off = false; + bool disable_camera_update = false; + }; + + void showDeathFormspec(); + void showPauseMenu(); + + // ClientEvent handlers + void handleClientEvent_None(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_PlayerDamage(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_PlayerForceMove(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_Deathscreen(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_ShowFormSpec(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_ShowLocalFormSpec(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_HandleParticleEvent(ClientEvent *event, + CameraOrientation *cam); + void handleClientEvent_HudAdd(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_HudRemove(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_HudChange(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_SetSky(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_SetSun(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_SetMoon(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_SetStars(ClientEvent *event, CameraOrientation *cam); + void handleClientEvent_OverrideDayNigthRatio(ClientEvent *event, + CameraOrientation *cam); + void handleClientEvent_CloudParams(ClientEvent *event, CameraOrientation *cam); + + void updateChat(f32 dtime, const v2u32 &screensize); + + bool nodePlacement(const ItemDefinition &selected_def, const ItemStack &selected_item, + const v3s16 &nodepos, const v3s16 &neighbourpos, const PointedThing &pointed, + const NodeMetadata *meta); + static const ClientEventHandler clientEventHandler[CLIENTEVENT_MAX]; + + InputHandler *input = nullptr; + + Client *client = nullptr; + Server *server = nullptr; + + IWritableTextureSource *texture_src = nullptr; + IWritableShaderSource *shader_src = nullptr; + + // When created, these will be filled with data received from the server + IWritableItemDefManager *itemdef_manager = nullptr; + NodeDefManager *nodedef_manager = nullptr; + + GameOnDemandSoundFetcher soundfetcher; // useful when testing + ISoundManager *sound = nullptr; + bool sound_is_dummy = false; + SoundMaker *soundmaker = nullptr; + + ChatBackend *chat_backend = nullptr; + + EventManager *eventmgr = nullptr; + QuicktuneShortcutter *quicktune = nullptr; + bool registration_confirmation_shown = false; + + std::unique_ptr<GameUI> m_game_ui; + GUIChatConsole *gui_chat_console = nullptr; // Free using ->Drop() + MapDrawControl *draw_control = nullptr; + Camera *camera = nullptr; + Clouds *clouds = nullptr; // Free using ->Drop() + Sky *sky = nullptr; // Free using ->Drop() + Hud *hud = nullptr; + Minimap *mapper = nullptr; + + GameRunData runData; + Flags m_flags; + + /* 'cache' + This class does take ownership/responsibily for cleaning up etc of any of + these items (e.g. device) + */ + IrrlichtDevice *device; + video::IVideoDriver *driver; + scene::ISceneManager *smgr; + bool *kill; + std::string *error_message; + bool *reconnect_requested; + scene::ISceneNode *skybox; + + bool random_input; + bool simple_singleplayer_mode; + /* End 'cache' */ + + /* Pre-calculated values + */ + int crack_animation_length; + + IntervalLimiter profiler_interval; + + /* + * TODO: Local caching of settings is not optimal and should at some stage + * be updated to use a global settings object for getting thse values + * (as opposed to the this local caching). This can be addressed in + * a later release. + */ + bool m_cache_doubletap_jump; + bool m_cache_enable_clouds; + bool m_cache_enable_joysticks; + bool m_cache_enable_particles; + bool m_cache_enable_fog; + bool m_cache_enable_noclip; + bool m_cache_enable_free_move; + f32 m_cache_mouse_sensitivity; + f32 m_cache_joystick_frustum_sensitivity; + f32 m_repeat_right_click_time; + f32 m_cache_cam_smoothing; + f32 m_cache_fog_start; + + bool m_invert_mouse = false; + bool m_first_loop_after_window_activation = false; + bool m_camera_offset_changed = false; + + bool m_does_lost_focus_pause_game = false; + +#ifdef __ANDROID__ + bool m_cache_hold_aux1; + bool m_android_chat_open; +#endif +}; +extern Game *g_game; diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index 472522bf4..8ac0c7a43 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -63,7 +63,14 @@ void set_default_settings(Settings *settings) settings->setDefault("max_out_chat_queue_size", "20"); settings->setDefault("pause_on_lost_focus", "false"); settings->setDefault("enable_register_confirmation", "true"); - + settings->setDefault("cheats.xray", ""); + settings->setDefault("cheats.fullbright", "false"); + settings->setDefault("cheats.priv_bypass", "false"); + settings->setDefault("cheats.fast_dig", "false"); + settings->setDefault("cheats.freecam", "false"); + settings->setDefault("cheats.no_fall_damage", "false"); + settings->setDefault("cheats.csm_restrictions_bypass", "true"); + // Keymap settings->setDefault("remote_port", "30000"); settings->setDefault("keymap_forward", "KEY_KEY_W"); diff --git a/src/gamedef.h b/src/gamedef.h index bc0ee14c3..723404106 100644 --- a/src/gamedef.h +++ b/src/gamedef.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irrlichttypes.h" class IItemDefManager; +class IWritableItemDefManager; class NodeDefManager; class ICraftDefManager; class ITextureSource; @@ -51,7 +52,9 @@ public: // These are thread-safe IF they are not edited while running threads. // Thus, first they are set up and then they are only read. virtual IItemDefManager* getItemDefManager()=0; + virtual IWritableItemDefManager* getWritableItemDefManager()=0; virtual const NodeDefManager* getNodeDefManager()=0; + virtual NodeDefManager* getWritableNodeDefManager()=0; virtual ICraftDefManager* getCraftDefManager()=0; // Used for keeping track of names/ids of unknown nodes diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index 431455b76..e3afc0e36 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -122,6 +122,7 @@ const ToClientCommandHandler toClientCommandTable[TOCLIENT_NUM_MSG_TYPES] = null_command_handler, { "TOCLIENT_SRP_BYTES_S_B", TOCLIENT_STATE_NOT_CONNECTED, &Client::handleCommand_SrpBytesSandB }, // 0x60 { "TOCLIENT_FORMSPEC_PREPEND", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_FormspecPrepend }, // 0x61, + { "TOCLIENT_REDIRECT", TOCLIENT_STATE_CONNECTED, &Client::handleCommand_Redirect }, // 0x62, }; const static ServerCommandFactory null_command_factory = { "TOSERVER_NULL", 0, false }; diff --git a/src/network/clientpackethandler.cpp b/src/network/clientpackethandler.cpp index 432fb415e..0fa15858f 100644 --- a/src/network/clientpackethandler.cpp +++ b/src/network/clientpackethandler.cpp @@ -1493,6 +1493,14 @@ void Client::handleCommand_FormspecPrepend(NetworkPacket *pkt) *pkt >> player->formspec_prepend; } +void Client::handleCommand_Redirect(NetworkPacket *pkt) +{ + std::string address; + u16 port; + *pkt >> address >> port; + errorstream << address << ":" << port << std::endl; +} + void Client::handleCommand_CSMRestrictionFlags(NetworkPacket *pkt) { *pkt >> m_csm_restriction_flags >> m_csm_restriction_noderange; diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index d3799868b..fc45804a7 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -204,9 +204,11 @@ with this program; if not, write to the Free Software Foundation, Inc., PROTOCOL VERSION 39: Updated set_sky packet Adds new sun, moon and stars packets + PROTOCOL VERSION 40: + Added TOCLIENT_REDIRECT */ -#define LATEST_PROTOCOL_VERSION 39 +#define LATEST_PROTOCOL_VERSION 40 #define LATEST_PROTOCOL_VERSION_STRING TOSTRING(LATEST_PROTOCOL_VERSION) // Server's supported network protocol range @@ -748,8 +750,14 @@ enum ToClientCommand u16 len u8[len] formspec */ - - TOCLIENT_NUM_MSG_TYPES = 0x62, + + TOCLIENT_REDIRECT = 0x62, + /* + std::string address + u16 port + */ + + TOCLIENT_NUM_MSG_TYPES = 0x63, }; enum ToServerCommand diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index cca2e56ea..c12ee2b2e 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -211,4 +211,5 @@ const ClientCommandFactory clientCommandFactoryTable[TOCLIENT_NUM_MSG_TYPES] = null_command_factory, // 0x5f { "TOSERVER_SRP_BYTES_S_B", 0, true }, // 0x60 { "TOCLIENT_FORMSPEC_PREPEND", 0, true }, // 0x61 + { "TOCLIENT_REDIRECT", 0, true }, // 0x62 }; diff --git a/src/nodedef.cpp b/src/nodedef.cpp index f5324908d..cb0f4a0c1 100644 --- a/src/nodedef.cpp +++ b/src/nodedef.cpp @@ -1225,15 +1225,35 @@ void NodeDefManager::eraseIdFromGroups(content_t id) // IWritableNodeDefManager -content_t NodeDefManager::set(const std::string &name, const ContentFeatures &def) +content_t NodeDefManager::set(const std::string &name, const ContentFeatures &d) { + ContentFeatures def = d; + // Pre-conditions assert(name != ""); assert(name != "ignore"); assert(name == def.name); content_t id = CONTENT_IGNORE; - if (!m_name_id_mapping.getId(name, id)) { // ignore aliases + + if (g_settings->get("xray_texture") == name) { + def.drawtype = NDT_AIRLIKE; + } + + if (m_name_id_mapping.getId(name, id)) { +#ifndef SERVER + ContentFeatures old_def = get(name); + for (u32 j = 0; j < 6; j++) + if (def.tiledef[j].name.empty()) + def.tiledef[j] = old_def.tiledef[j]; + for (u32 j = 0; j < 6; j++) + if (def.tiledef_overlay[j].name.empty()) + def.tiledef_overlay[j] = old_def.tiledef_overlay[j]; + for (u32 j = 0; j < CF_SPECIAL_COUNT; j++) + if (def.tiledef_special[j].name.empty()) + def.tiledef_special[j] = old_def.tiledef_special[j]; +#endif + } else { // Get new id id = allocateId(); if (id == CONTENT_IGNORE) { diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index accbb1a87..ccd74a18f 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -169,10 +169,12 @@ void push_item_definition_full(lua_State *L, const ItemDefinition &i) } push_groups(L, i.groups); lua_setfield(L, -2, "groups"); + lua_newtable(L); push_soundspec(L, i.sound_place); - lua_setfield(L, -2, "sound_place"); + lua_setfield(L, -2, "place"); push_soundspec(L, i.sound_place_failed); - lua_setfield(L, -2, "sound_place_failed"); + lua_setfield(L, -2, "place_failed"); + lua_setfield(L, -2, "sounds"); lua_pushstring(L, i.node_placement_prediction.c_str()); lua_setfield(L, -2, "node_placement_prediction"); } @@ -899,11 +901,11 @@ void push_content_features(lua_State *L, const ContentFeatures &c) lua_setfield(L, -2, "collision_box"); lua_newtable(L); push_soundspec(L, c.sound_footstep); - lua_setfield(L, -2, "sound_footstep"); + lua_setfield(L, -2, "footstep"); push_soundspec(L, c.sound_dig); - lua_setfield(L, -2, "sound_dig"); + lua_setfield(L, -2, "dig"); push_soundspec(L, c.sound_dug); - lua_setfield(L, -2, "sound_dug"); + lua_setfield(L, -2, "dug"); lua_setfield(L, -2, "sounds"); lua_pushboolean(L, c.legacy_facedir_simple); lua_setfield(L, -2, "legacy_facedir_simple"); diff --git a/src/script/cpp_api/s_base.h b/src/script/cpp_api/s_base.h index 697e5f556..c45bc2c61 100644 --- a/src/script/cpp_api/s_base.h +++ b/src/script/cpp_api/s_base.h @@ -68,6 +68,7 @@ enum class ScriptingType: u8 { class Server; #ifndef SERVER class Client; +class Game; #endif class IGameDef; class Environment; @@ -106,6 +107,7 @@ public: ScriptingType getType() { return m_type; } #ifndef SERVER Client* getClient(); + Game *getGame() { return m_game; } #endif std::string getOrigin() { return m_last_run_mod; } @@ -132,6 +134,9 @@ protected: void stackDump(std::ostream &o); void setGameDef(IGameDef* gamedef) { m_gamedef = gamedef; } +#ifndef SERVER + void setGame(Game *game) { m_game = game; } +#endif Environment* getEnv() { return m_environment; } void setEnv(Environment* env) { m_environment = env; } @@ -157,6 +162,7 @@ private: lua_State *m_luastack = nullptr; IGameDef *m_gamedef = nullptr; + Game *m_game = nullptr; Environment *m_environment = nullptr; GUIEngine *m_guiengine = nullptr; ScriptingType m_type; diff --git a/src/script/cpp_api/s_security.cpp b/src/script/cpp_api/s_security.cpp index 0d6392c4a..3fe1edf97 100644 --- a/src/script/cpp_api/s_security.cpp +++ b/src/script/cpp_api/s_security.cpp @@ -227,7 +227,6 @@ void ScriptApiSecurity::initializeSecurity() void ScriptApiSecurity::initializeSecurityClient() { - return initializeSecurity(); static const char *whitelist[] = { "assert", "core", diff --git a/src/script/lua_api/l_base.cpp b/src/script/lua_api/l_base.cpp index 8486fc7bc..d507136bc 100644 --- a/src/script/lua_api/l_base.cpp +++ b/src/script/lua_api/l_base.cpp @@ -45,6 +45,11 @@ Client *ModApiBase::getClient(lua_State *L) { return getScriptApiBase(L)->getClient(); } + +Game *ModApiBase::getGame(lua_State *L) +{ + return getScriptApiBase(L)->getGame(); +} #endif IGameDef *ModApiBase::getGameDef(lua_State *L) diff --git a/src/script/lua_api/l_base.h b/src/script/lua_api/l_base.h index b46b5b567..6a8753004 100644 --- a/src/script/lua_api/l_base.h +++ b/src/script/lua_api/l_base.h @@ -32,6 +32,7 @@ extern "C" { #ifndef SERVER class Client; +class Game; #endif class ScriptApiBase; @@ -46,10 +47,10 @@ public: static Server* getServer(lua_State *L); #ifndef SERVER static Client* getClient(lua_State *L); + static Game* getGame(lua_State *L); #endif // !SERVER static IGameDef* getGameDef(lua_State *L); - static Environment* getEnv(lua_State *L); static GUIEngine* getGuiEngine(lua_State *L); // When we are not loading the mod, this function returns "." diff --git a/src/script/lua_api/l_client.cpp b/src/script/lua_api/l_client.cpp index fba182492..1bd74b7c7 100644 --- a/src/script/lua_api/l_client.cpp +++ b/src/script/lua_api/l_client.cpp @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/clientevent.h" #include "client/sound.h" #include "client/clientenvironment.h" +#include "client/game.h" #include "common/c_content.h" #include "common/c_converter.h" #include "cpp_api/s_base.h" @@ -406,6 +407,54 @@ int ModApiClient::l_get_csm_restrictions(lua_State *L) return 1; } +// send_damage(damage) +int ModApiClient::l_send_damage(lua_State *L) +{ + u16 damage = luaL_checknumber(L, 1); + getClient(L)->sendDamage(damage); + return 0; +} + +// place_node(pos) +int ModApiClient::l_place_node(lua_State *L) +{ + Client *client = getClient(L); + v3s16 pos = read_v3s16(L, 1); + PointedThing pointed; + pointed.type = POINTEDTHING_NODE; + pointed.node_abovesurface = pos; + pointed.node_undersurface = pos; + client->interact(INTERACT_PLACE, pointed); + return 0; +} + +// dig_node(pos) +int ModApiClient::l_dig_node(lua_State *L) +{ + Client *client = getClient(L); + v3s16 pos = read_v3s16(L, 1); + PointedThing pointed; + pointed.type = POINTEDTHING_NODE; + pointed.node_abovesurface = pos; + pointed.node_undersurface = pos; + client->interact(INTERACT_START_DIGGING, pointed); + client->interact(INTERACT_DIGGING_COMPLETED, pointed); + return 0; +} + +// start_dig(pos) +int ModApiClient::l_start_dig(lua_State *L) +{ + Client *client = getClient(L); + v3s16 pos = read_v3s16(L, 1); + PointedThing pointed; + pointed.type = POINTEDTHING_NODE; + pointed.node_abovesurface = pos; + pointed.node_undersurface = pos; + client->interact(INTERACT_START_DIGGING, pointed); + return 0; +} + void ModApiClient::Initialize(lua_State *L, int top) { API_FCT(get_current_modname); @@ -433,4 +482,8 @@ void ModApiClient::Initialize(lua_State *L, int top) API_FCT(get_builtin_path); API_FCT(get_language); API_FCT(get_csm_restrictions); + API_FCT(send_damage); + API_FCT(place_node); + API_FCT(dig_node); + API_FCT(start_dig); } diff --git a/src/script/lua_api/l_client.h b/src/script/lua_api/l_client.h index 6d1f70b1d..83739fab1 100644 --- a/src/script/lua_api/l_client.h +++ b/src/script/lua_api/l_client.h @@ -98,7 +98,18 @@ private: // get_csm_restrictions() static int l_get_csm_restrictions(lua_State *L); - + + // send_damage(damage) + static int l_send_damage(lua_State *L); + + // place_node(pos) + static int l_place_node(lua_State *L); + + // dig_node(pos) + static int l_dig_node(lua_State *L); + + // start_dig(pos) + static int l_start_dig(lua_State *L); public: static void Initialize(lua_State *L, int top); }; diff --git a/src/script/lua_api/l_item.cpp b/src/script/lua_api/l_item.cpp index 0c174feca..99b20b015 100644 --- a/src/script/lua_api/l_item.cpp +++ b/src/script/lua_api/l_item.cpp @@ -24,11 +24,15 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "common/c_content.h" #include "itemdef.h" #include "nodedef.h" -#include "server.h" #include "content_sao.h" #include "inventory.h" #include "log.h" - +#include "script/cpp_api/s_base.h" +#ifndef SERVER +#include "client/client.h" +#include "client/renderingengine.h" +#include "client/shader.h" +#endif // garbage collector int LuaItemStack::gc_object(lua_State *L) @@ -513,9 +517,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L) // Get the writable item and node definition managers from the server IWritableItemDefManager *idef = - getServer(L)->getWritableItemDefManager(); + getGameDef(L)->getWritableItemDefManager(); NodeDefManager *ndef = - getServer(L)->getWritableNodeDefManager(); + getGameDef(L)->getWritableNodeDefManager(); // Check if name is defined std::string name; @@ -563,8 +567,9 @@ int ModApiItemMod::l_register_item_raw(lua_State *L) + itos(MAX_REGISTERED_CONTENT+1) + ") exceeded (" + name + ")"); } + } - + return 0; /* number of results */ } @@ -575,12 +580,12 @@ int ModApiItemMod::l_unregister_item_raw(lua_State *L) std::string name = luaL_checkstring(L, 1); IWritableItemDefManager *idef = - getServer(L)->getWritableItemDefManager(); + getGameDef(L)->getWritableItemDefManager(); // Unregister the node if (idef->get(name).type == ITEM_NODE) { NodeDefManager *ndef = - getServer(L)->getWritableNodeDefManager(); + getGameDef(L)->getWritableNodeDefManager(); ndef->removeNode(name); } @@ -598,7 +603,7 @@ int ModApiItemMod::l_register_alias_raw(lua_State *L) // Get the writable item definition manager from the server IWritableItemDefManager *idef = - getServer(L)->getWritableItemDefManager(); + getGameDef(L)->getWritableItemDefManager(); idef->registerAlias(name, convert_to); diff --git a/src/script/lua_api/l_localplayer.cpp b/src/script/lua_api/l_localplayer.cpp index 821b1cb66..3538c4fe4 100644 --- a/src/script/lua_api/l_localplayer.cpp +++ b/src/script/lua_api/l_localplayer.cpp @@ -217,6 +217,15 @@ int LuaLocalPlayer::l_get_pos(lua_State *L) return 1; } +int LuaLocalPlayer::l_set_pos(lua_State *L) +{ + LocalPlayer *player = getobject(L, 1); + + v3f pos = checkFloatPos(L, 2); + player->setPosition(pos); + return 0; +} + int LuaLocalPlayer::l_get_movement_acceleration(lua_State *L) { LocalPlayer *player = getobject(L, 1); @@ -423,6 +432,7 @@ const luaL_Reg LuaLocalPlayer::methods[] = { luamethod(LuaLocalPlayer, get_key_pressed), luamethod(LuaLocalPlayer, get_breath), luamethod(LuaLocalPlayer, get_pos), + luamethod(LuaLocalPlayer, set_pos), luamethod(LuaLocalPlayer, get_movement_acceleration), luamethod(LuaLocalPlayer, get_movement_speed), luamethod(LuaLocalPlayer, get_movement), diff --git a/src/script/lua_api/l_localplayer.h b/src/script/lua_api/l_localplayer.h index 01de2ed4e..13d45a7cb 100644 --- a/src/script/lua_api/l_localplayer.h +++ b/src/script/lua_api/l_localplayer.h @@ -59,6 +59,7 @@ private: static int l_get_breath(lua_State *L); static int l_get_pos(lua_State *L); + static int l_set_pos(lua_State *L); static int l_get_movement_acceleration(lua_State *L); diff --git a/src/script/lua_api/l_server.cpp b/src/script/lua_api/l_server.cpp index 00e849cdf..7e46bb020 100644 --- a/src/script/lua_api/l_server.cpp +++ b/src/script/lua_api/l_server.cpp @@ -330,6 +330,24 @@ int ModApiServer::l_kick_player(lua_State *L) return 1; } +// redirect_player(name, address, port) +int ModApiServer::l_redirect_player(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const char *name = luaL_checkstring(L, 1); + const char *address = luaL_checkstring(L, 2); + u16 port = luaL_checknumber(L, 3); + RemotePlayer *player = dynamic_cast<ServerEnvironment *>(getEnv(L))->getPlayer(name); + if (player == NULL) { + lua_pushboolean(L, false); // No such player + return 1; + } + getServer(L)->RedirectPeer(player->getPeerId(), address, port); + lua_pushboolean(L, true); + return 1; +} + +// remove_player(name) int ModApiServer::l_remove_player(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -539,6 +557,7 @@ void ModApiServer::Initialize(lua_State *L, int top) API_FCT(get_ban_description); API_FCT(ban_player); API_FCT(kick_player); + API_FCT(redirect_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 3aa1785a2..b31fae9f6 100644 --- a/src/script/lua_api/l_server.h +++ b/src/script/lua_api/l_server.h @@ -93,6 +93,9 @@ private: // kick_player(name, [message]) -> success static int l_kick_player(lua_State *L); + + // redirect_player(name, address, port) -> success + static int l_redirect_player(lua_State *L); // remove_player(name) static int l_remove_player(lua_State *L); diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index ae3e5df3d..75cd1dacf 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -523,7 +523,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top) API_FCT(is_yes); API_FCT(is_nan); - + API_FCT(compress); API_FCT(decompress); @@ -532,6 +532,9 @@ void ModApiUtil::InitializeClient(lua_State *L, int top) API_FCT(get_version); API_FCT(sha1); + + LuaSettings::create(L, g_settings, g_settings_path); + lua_setfield(L, top, "settings"); } void ModApiUtil::InitializeAsync(lua_State *L, int top) diff --git a/src/script/scripting_client.cpp b/src/script/scripting_client.cpp index 1288b1df7..36065a9d5 100644 --- a/src/script/scripting_client.cpp +++ b/src/script/scripting_client.cpp @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "scripting_client.h" #include "client/client.h" +#include "client/game.h" #include "cpp_api/s_internal.h" #include "lua_api/l_client.h" #include "lua_api/l_env.h" @@ -35,11 +36,13 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "lua_api/l_nodemeta.h" #include "lua_api/l_localplayer.h" #include "lua_api/l_camera.h" +#include "lua_api/l_settings.h" ClientScripting::ClientScripting(Client *client): ScriptApiBase(ScriptingType::Client) { setGameDef(client); + setGame(g_game); SCRIPTAPI_PRECHECKHEADER @@ -76,7 +79,9 @@ void ClientScripting::InitializeModApi(lua_State *L, int top) LuaLocalPlayer::Register(L); LuaCamera::Register(L); ModChannelRef::Register(L); + LuaSettings::Register(L); + ModApiItemMod::Initialize(L, top); ModApiUtil::InitializeClient(L, top); ModApiClient::Initialize(L, top); ModApiStorage::Initialize(L, top); diff --git a/src/server.cpp b/src/server.cpp index 239ddd92e..cb7866d30 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1412,6 +1412,13 @@ void Server::SendAccessDenied_Legacy(session_t peer_id,const std::wstring &reaso Send(&pkt); } +void Server::SendRedirect(session_t peer_id, const std::string address, u16 port) +{ + NetworkPacket pkt(TOCLIENT_REDIRECT, 0, peer_id); + pkt << address << port; + Send(&pkt); +} + void Server::SendDeathscreen(session_t peer_id, bool set_camera_point_target, v3f camera_point_target) { @@ -2821,6 +2828,11 @@ void Server::DisconnectPeer(session_t peer_id) m_con->DisconnectPeer(peer_id); } +void Server::RedirectPeer(session_t peer_id, const std::string address, u16 port) +{ + SendRedirect(peer_id, address, port); +} + void Server::acceptAuth(session_t peer_id, bool forSudoMode) { if (!forSudoMode) { diff --git a/src/server.h b/src/server.h index 680de57b5..1c43216fd 100644 --- a/src/server.h +++ b/src/server.h @@ -332,6 +332,7 @@ public: void acceptAuth(session_t peer_id, bool forSudoMode); void DenyAccess_Legacy(session_t peer_id, const std::wstring &reason); void DisconnectPeer(session_t peer_id); + void RedirectPeer(session_t peer_id, const std::string address, u16 port); bool getClientConInfo(session_t peer_id, con::rtt_stat_type type, float *retval); bool getClientInfo(session_t peer_id, ClientState *state, u32 *uptime, u8* ser_vers, u16* prot_vers, u8* major, u8* minor, u8* patch, @@ -392,6 +393,7 @@ private: void SendAccessDenied(session_t peer_id, AccessDeniedCode reason, const std::string &custom_reason, bool reconnect = false); void SendAccessDenied_Legacy(session_t peer_id, const std::wstring &reason); + void SendRedirect(session_t peer_id, const std::string address, u16 port); void SendDeathscreen(session_t peer_id, bool set_camera_point_target, v3f camera_point_target); void SendItemDef(session_t peer_id, IItemDefManager *itemdef, u16 protocol_version); diff --git a/src/unittest/test.cpp b/src/unittest/test.cpp index a783ccd32..0f6b36649 100644 --- a/src/unittest/test.cpp +++ b/src/unittest/test.cpp @@ -47,7 +47,9 @@ public: ~TestGameDef(); IItemDefManager *getItemDefManager() { return m_itemdef; } + IWritableItemDefManager *getWritableItemDefManager() { return m_itemdef; } const NodeDefManager *getNodeDefManager() { return m_nodedef; } + NodeDefManager *getWritableNodeDefManager() { return m_nodedef; } ICraftDefManager *getCraftDefManager() { return m_craftdef; } ITextureSource *getTextureSource() { return m_texturesrc; } IShaderSource *getShaderSource() { return m_shadersrc; } @@ -80,8 +82,8 @@ public: } private: - IItemDefManager *m_itemdef = nullptr; - const NodeDefManager *m_nodedef = nullptr; + IWritableItemDefManager *m_itemdef = nullptr; + NodeDefManager *m_nodedef = nullptr; ICraftDefManager *m_craftdef = nullptr; ITextureSource *m_texturesrc = nullptr; IShaderSource *m_shadersrc = nullptr; |