diff --git a/MCServer/Plugins/APIDump/APIDesc.lua b/MCServer/Plugins/APIDump/APIDesc.lua index 740168501..dbe4b911b 100644 --- a/MCServer/Plugins/APIDump/APIDesc.lua +++ b/MCServer/Plugins/APIDump/APIDesc.lua @@ -534,6 +534,7 @@ end GetUUID = { Params = "", Return = "string", Notes = "Returns the authentication-based UUID of the client. This UUID should be used to identify the player when persisting any player-related data. Returns a 32-char UUID (no dashes)" }, GetUsername = { Params = "", Return = "string", Notes = "Returns the username that the client has provided" }, GetViewDistance = { Params = "", Return = "number", Notes = "Returns the viewdistance (number of chunks loaded for the player in each direction)" }, + GetRequestedViewDistance = { Params = "", Return = "number", Notes = "Returns the view distance that the player request, not the used view distance." }, HasPluginChannel = { Params = "ChannelName", Return = "bool", Notes = "Returns true if the client has registered to receive messages on the specified plugin channel." }, IsUUIDOnline = { Params = "UUID", Return = "bool", Notes = "(STATIC) Returns true if the UUID is generated by online auth, false if it is an offline-generated UUID. We use Version-3 UUIDs for offline UUIDs, online UUIDs are Version-4, thus we can tell them apart. Accepts both 32-char and 36-char UUIDs (with and without dashes). If the string given is not a valid UUID, returns false."}, Kick = { Params = "Reason", Return = "", Notes = "Kicks the user with the specified reason" }, diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp index 94bace43a..0b9d84bf7 100644 --- a/src/ClientHandle.cpp +++ b/src/ClientHandle.cpp @@ -65,7 +65,8 @@ int cClientHandle::s_ClientCount = 0; // cClientHandle: cClientHandle::cClientHandle(const cSocket * a_Socket, int a_ViewDistance) : - m_ViewDistance(a_ViewDistance), + m_CurrentViewDistance(a_ViewDistance), + m_RequestedViewDistance(a_ViewDistance), m_IPString(a_Socket->GetIPString()), m_OutgoingData(64 KiB), m_Player(nullptr), @@ -430,7 +431,7 @@ bool cClientHandle::StreamNextChunk(void) cCSLock Lock(m_CSChunkLists); // High priority: Load the chunks that are in the view-direction of the player (with a radius of 3) - for (int Range = 0; Range < m_ViewDistance; Range++) + for (int Range = 0; Range < m_CurrentViewDistance; Range++) { Vector3d Vector = Position + LookVector * cChunkDef::Width * Range; @@ -447,7 +448,7 @@ bool cClientHandle::StreamNextChunk(void) cChunkCoords Coords(ChunkX, ChunkZ); // Checks if the chunk is in distance - if ((Diff(ChunkX, ChunkPosX) > m_ViewDistance) || (Diff(ChunkZ, ChunkPosZ) > m_ViewDistance)) + if ((Diff(ChunkX, ChunkPosX) > m_CurrentViewDistance) || (Diff(ChunkZ, ChunkPosZ) > m_CurrentViewDistance)) { continue; } @@ -470,7 +471,7 @@ bool cClientHandle::StreamNextChunk(void) } // Low priority: Add all chunks that are in range. (From the center out to the edge) - for (int d = 0; d <= m_ViewDistance; ++d) // cycle through (square) distance, from nearest to furthest + for (int d = 0; d <= m_CurrentViewDistance; ++d) // cycle through (square) distance, from nearest to furthest { // For each distance add chunks in a hollow square centered around current position: cChunkCoordsList CurcleChunks; @@ -528,7 +529,7 @@ void cClientHandle::UnloadOutOfRangeChunks(void) { int DiffX = Diff((*itr).m_ChunkX, ChunkPosX); int DiffZ = Diff((*itr).m_ChunkZ, ChunkPosZ); - if ((DiffX > m_ViewDistance) || (DiffZ > m_ViewDistance)) + if ((DiffX > m_CurrentViewDistance) || (DiffZ > m_CurrentViewDistance)) { ChunksToRemove.push_back(*itr); itr = m_LoadedChunks.erase(itr); @@ -543,7 +544,7 @@ void cClientHandle::UnloadOutOfRangeChunks(void) { int DiffX = Diff((*itr).m_ChunkX, ChunkPosX); int DiffZ = Diff((*itr).m_ChunkZ, ChunkPosZ); - if ((DiffX > m_ViewDistance) || (DiffZ > m_ViewDistance)) + if ((DiffX > m_CurrentViewDistance) || (DiffZ > m_CurrentViewDistance)) { itr = m_ChunksToSend.erase(itr); } @@ -2847,8 +2848,11 @@ void cClientHandle::SetUsername( const AString & a_Username) void cClientHandle::SetViewDistance(int a_ViewDistance) { - m_ViewDistance = Clamp(a_ViewDistance, MIN_VIEW_DISTANCE, MAX_VIEW_DISTANCE); - LOGD("Setted %s's view distance to %i", GetUsername().c_str(), m_ViewDistance); + ASSERT(m_Player->GetWorld() == NULL); + + m_RequestedViewDistance = a_ViewDistance; + m_CurrentViewDistance = Clamp(a_ViewDistance, cClientHandle::MIN_VIEW_DISTANCE, m_Player->GetWorld()->GetMaxViewDistance()); + LOGD("Setted view distance from %s to %d!", GetUsername().c_str(), m_CurrentViewDistance); } diff --git a/src/ClientHandle.h b/src/ClientHandle.h index 082ed2fcc..8d241c1e7 100644 --- a/src/ClientHandle.h +++ b/src/ClientHandle.h @@ -217,9 +217,15 @@ public: inline short GetPing(void) const { return m_Ping; } + /** Sets the maximal view distance. */ void SetViewDistance(int a_ViewDistance); - int GetViewDistance(void) const { return m_ViewDistance; } - + + /** Returns the view distance that the player currently have. */ + int GetViewDistance(void) const { return m_CurrentViewDistance; } + + /** Returns the view distance that the player request, not the used view distance. */ + int GetRequestedViewDistance(void) const { return m_RequestedViewDistance; } + void SetLocale(AString & a_Locale) { m_Locale = a_Locale; } AString GetLocale(void) const { return m_Locale; } @@ -333,12 +339,12 @@ private: /** The type used for storing the names of registered plugin channels. */ typedef std::set cChannels; - /** Number of chunks the player can see in each direction */ - int m_ViewDistance; - - /** Server generates this many chunks AHEAD of player sight. */ - static const int GENERATEDISTANCE = 2; - + /** The actual view distance used, the minimum of client's requested view distance and world's max view distance. */ + int m_CurrentViewDistance; + + /** The requested view distance from the player. It isn't clamped with 1 and the max view distance of the world. */ + int m_RequestedViewDistance; + AString m_IPString; AString m_Username; diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp index 5c18d8f96..edcdb4799 100644 --- a/src/Entities/Player.cpp +++ b/src/Entities/Player.cpp @@ -1602,6 +1602,9 @@ bool cPlayer::DoMoveToWorld(cWorld * a_World, bool a_ShouldSendRespawn) a_World->AddPlayer(this); SetWorld(a_World); // Chunks may be streamed before cWorld::AddPlayer() sets the world to the new value + // Update the view distance. + m_ClientHandle->SetViewDistance(m_ClientHandle->GetRequestedViewDistance()); + return true; } diff --git a/src/World.cpp b/src/World.cpp index 68855e617..288cf0154 100644 --- a/src/World.cpp +++ b/src/World.cpp @@ -283,6 +283,7 @@ cWorld::cWorld(const AString & a_WorldName, eDimension a_Dimension, const AStrin m_bCommandBlocksEnabled(true), m_bUseChatPrefixes(false), m_TNTShrapnelLevel(slNone), + m_MaxViewDistance(12), m_Scoreboard(this), m_MapManager(this), m_GeneratorCallbacks(*this), @@ -561,6 +562,8 @@ void cWorld::Start(void) m_BroadcastDeathMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastDeathMessages", true); m_BroadcastAchievementMessages = IniFile.GetValueSetB("Broadcasting", "BroadcastAchievementMessages", true); + SetMaxViewDistance(IniFile.GetValueSetI("SpawnPosition", "MaxViewDistance", 12)); + // Try to find the "SpawnPosition" key and coord values in the world configuration, set the flag if found int KeyNum = IniFile.FindKey("SpawnPosition"); m_IsSpawnExplicitlySet = diff --git a/src/World.h b/src/World.h index 1a9f60a5c..03d99c538 100644 --- a/src/World.h +++ b/src/World.h @@ -26,6 +26,7 @@ #include "MapManager.h" #include "Blocks/WorldInterface.h" #include "Blocks/BroadcastInterface.h" +#include "ClientHandle.h" @@ -649,6 +650,12 @@ public: eShrapnelLevel GetTNTShrapnelLevel(void) const { return m_TNTShrapnelLevel; } void SetTNTShrapnelLevel(eShrapnelLevel a_Flag) { m_TNTShrapnelLevel = a_Flag; } + int GetMaxViewDistance(void) const { return m_MaxViewDistance; } + void SetMaxViewDistance(int a_MaxViewDistance) + { + m_MaxViewDistance = Clamp(a_MaxViewDistance, cClientHandle::MIN_VIEW_DISTANCE, cClientHandle::MAX_VIEW_DISTANCE); + } + bool ShouldUseChatPrefixes(void) const { return m_bUseChatPrefixes; } void SetShouldUseChatPrefixes(bool a_Flag) { m_bUseChatPrefixes = a_Flag; } @@ -964,6 +971,9 @@ private: */ eShrapnelLevel m_TNTShrapnelLevel; + /** The maximum view distance that a player can have in this world. */ + int m_MaxViewDistance; + /** Name of the nether world */ AString m_NetherWorldName;