Merge remote-tracking branch 'origin/master' into fixes
Conflicts: src/Authenticator.cpp src/ClientHandle.cpp src/Entities/Minecart.cpp src/Protocol/Protocol17x.cpp
This commit is contained in:
commit
67344a3782
@ -46,6 +46,10 @@ macro(set_flags)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
|
||||
|
||||
add_flags_cxx("-pthread")
|
||||
endif()
|
||||
|
||||
@ -56,6 +60,10 @@ macro(set_flags)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++0x")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++0x")
|
||||
endif()
|
||||
|
||||
# We use a signed char (fixes #640 on RasPi)
|
||||
|
@ -2197,32 +2197,38 @@ bool cConnection::HandleServerSpawnMob(void)
|
||||
|
||||
|
||||
|
||||
bool cConnection::HandleServerSpawnNamedEntity(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID);
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName);
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, DataCount);
|
||||
struct sData
|
||||
struct sSpawnData
|
||||
{
|
||||
AString m_Name;
|
||||
AString m_Value;
|
||||
AString m_Signature;
|
||||
sData(const AString & a_Name, const AString & a_Value, const AString & a_Signature) :
|
||||
sSpawnData(const AString & a_Name, const AString & a_Value, const AString & a_Signature) :
|
||||
m_Name(a_Name),
|
||||
m_Value(a_Value),
|
||||
m_Signature(a_Signature)
|
||||
{
|
||||
}
|
||||
};
|
||||
typedef std::vector<sData> sDataVec;
|
||||
sDataVec Data;
|
||||
|
||||
typedef std::vector<sSpawnData> sSpawnDatas;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cConnection::HandleServerSpawnNamedEntity(void)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID);
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName);
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, DataCount);
|
||||
sSpawnDatas Data;
|
||||
for (UInt32 i = 0; i < DataCount; i++)
|
||||
{
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Name)
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Value)
|
||||
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Signature)
|
||||
Data.push_back(sData(Name, Value, Signature));
|
||||
Data.push_back(sSpawnData(Name, Value, Signature));
|
||||
}
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosX);
|
||||
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
|
||||
@ -2242,7 +2248,7 @@ bool cConnection::HandleServerSpawnNamedEntity(void)
|
||||
Log(" UUID = \"%s\"", EntityUUID.c_str());
|
||||
Log(" Name = \"%s\"", EntityName.c_str());
|
||||
Log(" NumData = %u", DataCount);
|
||||
for (sDataVec::const_iterator itr = Data.begin(), end = Data.end(); itr != end; ++itr)
|
||||
for (sSpawnDatas::const_iterator itr = Data.begin(), end = Data.end(); itr != end; ++itr)
|
||||
{
|
||||
Log(" Name = \"%s\", Value = \"%s\", Signature = \"%s\"",
|
||||
itr->m_Name.c_str(), itr->m_Value.c_str(), itr->m_Signature.c_str()
|
||||
|
@ -154,7 +154,7 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
|
||||
case ';':
|
||||
case '#':
|
||||
{
|
||||
if (names.size() == 0)
|
||||
if (names.empty())
|
||||
{
|
||||
AddHeaderComment(line.substr(pLeft + 1));
|
||||
}
|
||||
@ -168,8 +168,9 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
|
||||
} // while (getline())
|
||||
|
||||
f.close();
|
||||
if (names.size() == 0)
|
||||
if (keys.empty() && names.empty() && comments.empty())
|
||||
{
|
||||
// File be empty or unreadable, equivalent to nonexistant
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1,268 +0,0 @@
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Authenticator.h"
|
||||
#include "OSSupport/BlockingTCPLink.h"
|
||||
#include "Root.h"
|
||||
#include "Server.h"
|
||||
|
||||
#include "inifile/iniFile.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define DEFAULT_AUTH_SERVER "session.minecraft.net"
|
||||
#define DEFAULT_AUTH_ADDRESS "/game/checkserver.jsp?user=%USERNAME%&serverId=%SERVERID%"
|
||||
#define MAX_REDIRECTS 10
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAuthenticator::cAuthenticator(void) :
|
||||
super("cAuthenticator"),
|
||||
m_Server(DEFAULT_AUTH_SERVER),
|
||||
m_Address(DEFAULT_AUTH_ADDRESS),
|
||||
m_ShouldAuthenticate(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAuthenticator::~cAuthenticator()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::ReadINI(cIniFile & IniFile)
|
||||
{
|
||||
m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER);
|
||||
m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS);
|
||||
m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash)
|
||||
{
|
||||
if (!m_ShouldAuthenticate)
|
||||
{
|
||||
cRoot::Get()->AuthenticateUser(a_ClientID);
|
||||
return;
|
||||
}
|
||||
|
||||
cCSLock Lock(m_CS);
|
||||
m_Queue.push_back(cUser(a_ClientID, a_UserName, a_ServerHash));
|
||||
m_QueueNonempty.Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Start(cIniFile & IniFile)
|
||||
{
|
||||
ReadINI(IniFile);
|
||||
m_ShouldTerminate = false;
|
||||
super::Start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Stop(void)
|
||||
{
|
||||
m_ShouldTerminate = true;
|
||||
m_QueueNonempty.Set();
|
||||
Wait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Execute(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
while (!m_ShouldTerminate && (m_Queue.size() == 0))
|
||||
{
|
||||
cCSUnlock Unlock(Lock);
|
||||
m_QueueNonempty.Wait();
|
||||
}
|
||||
if (m_ShouldTerminate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ASSERT(!m_Queue.empty());
|
||||
|
||||
cAuthenticator::cUser & User = m_Queue.front();
|
||||
int ClientID = User.m_ClientID;
|
||||
AString UserName = User.m_Name;
|
||||
AString ActualAddress = m_Address;
|
||||
ReplaceString(ActualAddress, "%USERNAME%", UserName);
|
||||
ReplaceString(ActualAddress, "%SERVERID%", User.m_ServerID);
|
||||
m_Queue.pop_front();
|
||||
Lock.Unlock();
|
||||
|
||||
if (!AuthFromAddress(m_Server, ActualAddress, UserName))
|
||||
{
|
||||
cRoot::Get()->KickUser(ClientID, "Failed to authenticate account!");
|
||||
}
|
||||
else
|
||||
{
|
||||
cRoot::Get()->AuthenticateUser(ClientID);
|
||||
}
|
||||
} // for (-ever)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cAuthenticator::AuthFromAddress(const AString & a_Server, const AString & a_Address, const AString & a_UserName, int a_Level /* = 1 */)
|
||||
{
|
||||
// Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep)
|
||||
|
||||
cBlockingTCPLink Link;
|
||||
if (!Link.Connect(a_Server.c_str(), 80))
|
||||
{
|
||||
LOGWARNING("%s: cannot connect to auth server \"%s\", kicking user \"%s\"",
|
||||
__FUNCTION__, a_Server.c_str(), a_UserName.c_str()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
Link.SendMessage( AString( "GET " + a_Address + " HTTP/1.1\r\n" ).c_str());
|
||||
Link.SendMessage( AString( "User-Agent: MCServer\r\n" ).c_str());
|
||||
Link.SendMessage( AString( "Host: " + a_Server + "\r\n" ).c_str());
|
||||
//Link.SendMessage( AString( "Host: session.minecraft.net\r\n" ).c_str());
|
||||
Link.SendMessage( AString( "Accept: */*\r\n" ).c_str());
|
||||
Link.SendMessage( AString( "Connection: close\r\n" ).c_str()); //Close so we don´t have to mess with the Content-Length :)
|
||||
Link.SendMessage( AString( "\r\n" ).c_str());
|
||||
AString DataRecvd;
|
||||
Link.ReceiveData(DataRecvd);
|
||||
Link.CloseSocket();
|
||||
|
||||
std::stringstream ss(DataRecvd);
|
||||
|
||||
// Parse the data received:
|
||||
std::string temp;
|
||||
ss >> temp;
|
||||
bool bRedirect = false;
|
||||
bool bOK = false;
|
||||
if ((temp.compare("HTTP/1.1") == 0) || (temp.compare("HTTP/1.0") == 0))
|
||||
{
|
||||
int code;
|
||||
ss >> code;
|
||||
if (code == 302)
|
||||
{
|
||||
// redirect blabla
|
||||
LOGD("%s: Need to redirect, current level %d!", __FUNCTION__, a_Level);
|
||||
if (a_Level > MAX_REDIRECTS)
|
||||
{
|
||||
LOGERROR("cAuthenticator: received too many levels of redirection from auth server \"%s\" for user \"%s\", bailing out and kicking the user", a_Server.c_str(), a_UserName.c_str());
|
||||
return false;
|
||||
}
|
||||
bRedirect = true;
|
||||
}
|
||||
else if (code == 200)
|
||||
{
|
||||
LOGD("cAuthenticator: Received status 200 OK! :D");
|
||||
bOK = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("cAuthenticator: cannot parse auth reply from server \"%s\" for user \"%s\", kicking the user.", a_Server.c_str(), a_UserName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if( bRedirect )
|
||||
{
|
||||
AString Location;
|
||||
// Search for "Location:"
|
||||
bool bFoundLocation = false;
|
||||
while( !bFoundLocation && ss.good() )
|
||||
{
|
||||
char c = 0;
|
||||
while( c != '\n' )
|
||||
{
|
||||
ss.get( c );
|
||||
}
|
||||
AString Name;
|
||||
ss >> Name;
|
||||
if (Name.compare("Location:") == 0)
|
||||
{
|
||||
bFoundLocation = true;
|
||||
ss >> Location;
|
||||
}
|
||||
}
|
||||
if (!bFoundLocation)
|
||||
{
|
||||
LOGERROR("cAuthenticator: received invalid redirection from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
Location = Location.substr(strlen("http://"), std::string::npos); // Strip http://
|
||||
std::string Server = Location.substr( 0, Location.find( "/" ) ); // Only leave server address
|
||||
Location = Location.substr( Server.length(), std::string::npos);
|
||||
return AuthFromAddress(Server, Location, a_UserName, a_Level + 1);
|
||||
}
|
||||
|
||||
if (!bOK)
|
||||
{
|
||||
LOGERROR("cAuthenticator: received an error from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Header says OK, so receive the rest.
|
||||
// Go past header, double \n means end of headers
|
||||
char c = 0;
|
||||
while (ss.good())
|
||||
{
|
||||
while (c != '\n')
|
||||
{
|
||||
ss.get(c);
|
||||
}
|
||||
ss.get(c);
|
||||
if( c == '\n' || c == '\r' || ss.peek() == '\r' || ss.peek() == '\n' )
|
||||
break;
|
||||
}
|
||||
if (!ss.good())
|
||||
{
|
||||
LOGERROR("cAuthenticator: error while parsing response body from auth server \"%s\" for user \"%s\", kicking user.", a_Server.c_str(), a_UserName.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string Result;
|
||||
ss >> Result;
|
||||
LOGD("cAuthenticator: Authentication result was %s", Result.c_str());
|
||||
|
||||
if (Result.compare("YES") == 0) //Works well
|
||||
{
|
||||
LOGINFO("Authentication result \"YES\", player authentication success!");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
LOGINFO("Authentication result was \"%s\", player authentication failure!", Result.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -504,6 +504,10 @@ enum
|
||||
E_META_PLANKS_BIRCH = 2,
|
||||
E_META_PLANKS_JUNGLE = 3,
|
||||
|
||||
// E_BLOCK_(XXX_WEIGHTED)_PRESSURE_PLATE metas:
|
||||
E_META_PRESSURE_PLATE_RAISED = 0,
|
||||
E_META_PRESSURE_PLATE_DEPRESSED = 1,
|
||||
|
||||
// E_BLOCK_QUARTZ_BLOCK metas:
|
||||
E_META_QUARTZ_NORMAL = 0,
|
||||
E_META_QUARTZ_CHISELLED = 1,
|
||||
|
@ -24,13 +24,15 @@
|
||||
|
||||
#include "Root.h"
|
||||
|
||||
#include "Authenticator.h"
|
||||
#include "Protocol/Authenticator.h"
|
||||
#include "MersenneTwister.h"
|
||||
|
||||
#include "Protocol/ProtocolRecognizer.h"
|
||||
#include "CompositeChat.h"
|
||||
#include "Items/ItemSword.h"
|
||||
|
||||
#include "md5/md5.h"
|
||||
|
||||
|
||||
|
||||
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */
|
||||
@ -175,6 +177,39 @@ void cClientHandle::Destroy(void)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::GenerateOfflineUUID(void)
|
||||
{
|
||||
m_UUID = GenerateOfflineUUID(m_Username);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
AString cClientHandle::GenerateOfflineUUID(const AString & a_Username)
|
||||
{
|
||||
// Proper format for a version 3 UUID is:
|
||||
// xxxxxxxx-xxxx-3xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y is one of 8, 9, A, or B
|
||||
|
||||
// Generate an md5 checksum, and use it as base for the ID:
|
||||
MD5 Checksum(a_Username);
|
||||
AString UUID = Checksum.hexdigest();
|
||||
UUID[12] = '3'; // Version 3 UUID
|
||||
UUID[16] = '8'; // Variant 1 UUID
|
||||
|
||||
// Now the digest doesn't have the UUID slashes, but the client requires them, so add them into the appropriate positions:
|
||||
UUID.insert(8, "-");
|
||||
UUID.insert(13, "-");
|
||||
UUID.insert(18, "-");
|
||||
UUID.insert(23, "-");
|
||||
|
||||
return UUID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::Kick(const AString & a_Reason)
|
||||
{
|
||||
if (m_State >= csAuthenticating) // Don't log pings
|
||||
@ -188,7 +223,7 @@ void cClientHandle::Kick(const AString & a_Reason)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::Authenticate(void)
|
||||
void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID)
|
||||
{
|
||||
if (m_State != csAuthenticating)
|
||||
{
|
||||
@ -197,6 +232,12 @@ void cClientHandle::Authenticate(void)
|
||||
|
||||
ASSERT( m_Player == NULL );
|
||||
|
||||
m_Username = a_Name;
|
||||
m_UUID = a_UUID;
|
||||
|
||||
// Send login success (if the protocol supports it):
|
||||
m_Protocol->SendLoginSuccess();
|
||||
|
||||
// Spawn player (only serversided, so data is loaded)
|
||||
m_Player = new cPlayer(this, GetUsername());
|
||||
|
||||
@ -1679,14 +1720,17 @@ void cClientHandle::Tick(float a_Dt)
|
||||
}
|
||||
|
||||
// Send a ping packet:
|
||||
if (m_State == csPlaying)
|
||||
{
|
||||
cTimer t1;
|
||||
if (m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())
|
||||
if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()))
|
||||
{
|
||||
m_PingID++;
|
||||
m_PingStartTime = t1.GetNowTime();
|
||||
m_Protocol->SendKeepAlive(m_PingID);
|
||||
m_LastPingTime = m_PingStartTime;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle block break animation:
|
||||
if (m_BlockDigAnimStage > -1)
|
||||
@ -2103,7 +2147,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo
|
||||
}
|
||||
|
||||
// Update the statistics:
|
||||
m_NumExplosionsThisTick += 1;
|
||||
m_NumExplosionsThisTick++;
|
||||
|
||||
m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion);
|
||||
}
|
||||
|
@ -62,8 +62,22 @@ public:
|
||||
|
||||
cPlayer* GetPlayer() { return m_Player; } // tolua_export
|
||||
|
||||
const AString & GetUUID(void) const { return m_UUID; } // tolua_export
|
||||
void SetUUID(const AString & a_UUID) { m_UUID = a_UUID; }
|
||||
|
||||
/** Generates an UUID based on the username stored for this client, and stores it in the m_UUID member.
|
||||
This is used for the offline (non-auth) mode, when there's no UUID source.
|
||||
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same.
|
||||
Internally calls the GenerateOfflineUUID static function. */
|
||||
void GenerateOfflineUUID(void);
|
||||
|
||||
/** Generates an UUID based on the player name provided.
|
||||
This is used for the offline (non-auth) mode, when there's no UUID source.
|
||||
Each username generates a unique and constant UUID, so that when the player reconnects with the same name, their UUID is the same. */
|
||||
static AString GenerateOfflineUUID(const AString & a_Username); // tolua_export
|
||||
|
||||
void Kick(const AString & a_Reason); // tolua_export
|
||||
void Authenticate(void); // Called by cAuthenticator when the user passes authentication
|
||||
void Authenticate(const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator when the user passes authentication
|
||||
|
||||
void StreamChunks(void);
|
||||
|
||||
@ -326,6 +340,7 @@ private:
|
||||
|
||||
static int s_ClientCount;
|
||||
int m_UniqueID;
|
||||
AString m_UUID;
|
||||
|
||||
/** Set to true when the chunk where the player is is sent to the client. Used for spawning the player */
|
||||
bool m_HasSentPlayerChunk;
|
||||
|
@ -493,15 +493,17 @@ inline void EulerToVector(double a_Pan, double a_Pitch, double & a_X, double & a
|
||||
|
||||
inline void VectorToEuler(double a_X, double a_Y, double a_Z, double & a_Pan, double & a_Pitch)
|
||||
{
|
||||
if (fabs(a_X) < std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
|
||||
}
|
||||
else
|
||||
double r = sqrt((a_X * a_X) + (a_Z * a_Z));
|
||||
if (r < std::numeric_limits<double>::epsilon())
|
||||
{
|
||||
a_Pan = 0;
|
||||
}
|
||||
a_Pitch = atan2(a_Y, sqrt((a_X * a_X) + (a_Z * a_Z))) * 180 / PI;
|
||||
else
|
||||
{
|
||||
a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
|
||||
}
|
||||
|
||||
a_Pitch = atan2(a_Y, r) * 180 / PI;
|
||||
}
|
||||
|
||||
|
||||
|
@ -330,7 +330,7 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
AddSpeed(a_TDI.Knockback * 2);
|
||||
}
|
||||
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
|
||||
m_World->BroadcastEntityStatus(*this, esGenericHurt);
|
||||
|
||||
if (m_Health <= 0)
|
||||
{
|
||||
@ -479,7 +479,7 @@ void cEntity::KilledBy(cEntity * a_Killer)
|
||||
GetDrops(Drops, a_Killer);
|
||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
|
||||
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD);
|
||||
m_World->BroadcastEntityStatus(*this, esGenericDead);
|
||||
}
|
||||
|
||||
|
||||
@ -519,15 +519,14 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a_Chunk.IsValid())
|
||||
{
|
||||
cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT);
|
||||
|
||||
if ((NextChunk == NULL) || !NextChunk->IsValid())
|
||||
if (!a_Chunk.IsValid())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Position changed -> super::Tick() called
|
||||
GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, POSX_TOINT, POSZ_TOINT)
|
||||
|
||||
TickBurning(*NextChunk);
|
||||
|
||||
if (GetPosY() < VOID_BOUNDARY)
|
||||
@ -548,10 +547,10 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
HandleAir();
|
||||
}
|
||||
|
||||
// None of the above functions change position, we remain in the chunk of NextChunk
|
||||
HandlePhysics(a_Dt, *NextChunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -559,34 +558,30 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
|
||||
void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
int BlockX = POSX_TOINT;
|
||||
int BlockY = POSY_TOINT;
|
||||
int BlockZ = POSZ_TOINT;
|
||||
|
||||
// Position changed -> super::HandlePhysics() called
|
||||
GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, BlockX, BlockZ)
|
||||
|
||||
// TODO Add collision detection with entities.
|
||||
a_Dt /= 1000; // Convert from msec to sec
|
||||
Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ());
|
||||
Vector3d NextSpeed = Vector3d(GetSpeedX(), GetSpeedY(), GetSpeedZ());
|
||||
int BlockX = (int) floor(NextPos.x);
|
||||
int BlockY = (int) floor(NextPos.y);
|
||||
int BlockZ = (int) floor(NextPos.z);
|
||||
|
||||
if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
|
||||
{
|
||||
// Outside of the world
|
||||
|
||||
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
|
||||
// See if we can commit our changes. If not, we will discard them.
|
||||
if (NextChunk != NULL)
|
||||
{
|
||||
SetSpeed(NextSpeed);
|
||||
NextPos += (NextSpeed * a_Dt);
|
||||
SetPosition(NextPos);
|
||||
}
|
||||
|
||||
AddSpeedY(m_Gravity * a_Dt);
|
||||
AddPosition(GetSpeed() * a_Dt);
|
||||
return;
|
||||
}
|
||||
|
||||
int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width);
|
||||
int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width);
|
||||
BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ );
|
||||
BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
|
||||
int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
|
||||
int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
|
||||
BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
|
||||
BLOCKTYPE BlockBelow = (BlockY > 0) ? NextChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
|
||||
if (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
|
||||
{
|
||||
if (m_bOnGround) // check if it's still on the ground
|
||||
@ -616,7 +611,7 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
bool IsNoAirSurrounding = true;
|
||||
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++)
|
||||
{
|
||||
if (!a_Chunk.UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
|
||||
if (!NextChunk->UnboundedRelGetBlockType(RelBlockX + gCrossCoords[i].x, BlockY, RelBlockZ + gCrossCoords[i].z, GotBlock))
|
||||
{
|
||||
// The pickup is too close to an unloaded chunk, bail out of any physics handling
|
||||
return;
|
||||
@ -764,20 +759,8 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
}
|
||||
|
||||
BlockX = (int) floor(NextPos.x);
|
||||
BlockZ = (int) floor(NextPos.z);
|
||||
|
||||
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
|
||||
// See if we can commit our changes. If not, we will discard them.
|
||||
if (NextChunk != NULL)
|
||||
{
|
||||
if (NextPos.x != GetPosX()) SetPosX(NextPos.x);
|
||||
if (NextPos.y != GetPosY()) SetPosY(NextPos.y);
|
||||
if (NextPos.z != GetPosZ()) SetPosZ(NextPos.z);
|
||||
if (NextSpeed.x != GetSpeedX()) SetSpeedX(NextSpeed.x);
|
||||
if (NextSpeed.y != GetSpeedY()) SetSpeedY(NextSpeed.y);
|
||||
if (NextSpeed.z != GetSpeedZ()) SetSpeedZ(NextSpeed.z);
|
||||
}
|
||||
SetPosition(NextPos);
|
||||
SetSpeed(NextSpeed);
|
||||
}
|
||||
|
||||
|
||||
@ -806,7 +789,7 @@ void cEntity::TickBurning(cChunk & a_Chunk)
|
||||
int MaxRelX = (int)floor(GetPosX() + m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int MinRelZ = (int)floor(GetPosZ() - m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
int MaxRelZ = (int)floor(GetPosZ() + m_Width / 2) - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
int MinY = std::max(0, std::min(cChunkDef::Height - 1, (int)floor(GetPosY())));
|
||||
int MinY = std::max(0, std::min(cChunkDef::Height - 1, POSY_TOINT));
|
||||
int MaxY = std::max(0, std::min(cChunkDef::Height - 1, (int)ceil (GetPosY() + m_Height)));
|
||||
bool HasWater = false;
|
||||
bool HasLava = false;
|
||||
@ -981,13 +964,13 @@ void cEntity::HandleAir(void)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_AirTickTimer -= 1;
|
||||
m_AirTickTimer--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reduce air supply
|
||||
m_AirLevel -= 1;
|
||||
m_AirLevel--;
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1099,8 +1082,8 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
|
||||
|
||||
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude)
|
||||
{
|
||||
//We need to keep updating the clients when there is movement or if there was a change in speed and after 2 ticks
|
||||
if( (m_Speed.SqrLength() > 0.0004f || m_bDirtySpeed) && (m_World->GetWorldAge() - m_TimeLastSpeedPacket >= 2))
|
||||
// Send velocity packet every two ticks if: speed is not negligible or speed was set (as indicated by the DirtySpeed flag)
|
||||
if (((m_Speed.SqrLength() > 0.0004f) || m_bDirtySpeed) && ((m_World->GetWorldAge() - m_TimeLastSpeedPacket) >= 2))
|
||||
{
|
||||
m_World->BroadcastEntityVelocity(*this,a_Exclude);
|
||||
m_bDirtySpeed = false;
|
||||
|
@ -32,6 +32,8 @@
|
||||
#define POSZ_TOINT (int)floor(GetPosZ())
|
||||
#define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT)
|
||||
|
||||
#define GET_AND_VERIFY_CURRENT_CHUNK(ChunkVarName, X, Z) cChunk * ChunkVarName = a_Chunk.GetNeighborChunk(X, Z); if ((ChunkVarName == NULL) || !ChunkVarName->IsValid()) { return; }
|
||||
|
||||
|
||||
|
||||
|
||||
@ -89,22 +91,41 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
enum
|
||||
enum eEntityStatus
|
||||
{
|
||||
ENTITY_STATUS_HURT = 2,
|
||||
ENTITY_STATUS_DEAD = 3,
|
||||
ENTITY_STATUS_WOLF_TAMING = 6,
|
||||
ENTITY_STATUS_WOLF_TAMED = 7,
|
||||
ENTITY_STATUS_WOLF_SHAKING = 8,
|
||||
ENTITY_STATUS_EATING_ACCEPTED = 9,
|
||||
ENTITY_STATUS_SHEEP_EATING = 10,
|
||||
ENTITY_STATUS_GOLEM_ROSING = 11,
|
||||
ENTITY_STATUS_VILLAGER_HEARTS = 12,
|
||||
ENTITY_STATUS_VILLAGER_ANGRY = 13,
|
||||
ENTITY_STATUS_VILLAGER_HAPPY = 14,
|
||||
ENTITY_STATUS_WITCH_MAGICKING = 15,
|
||||
// TODO: Investiagate 0, 1, and 5 as Wiki.vg is not certain
|
||||
|
||||
// Entity becomes coloured red
|
||||
esGenericHurt = 2,
|
||||
// Entity plays death animation (entity falls to ground)
|
||||
esGenericDead = 3,
|
||||
// Iron Golem plays attack animation (arms lift and fall)
|
||||
esIronGolemAttacking = 4,
|
||||
// Wolf taming particles spawn (smoke)
|
||||
esWolfTaming = 6,
|
||||
// Wolf tamed particles spawn (hearts)
|
||||
esWolfTamed = 7,
|
||||
// Wolf plays water removal animation (shaking and water particles)
|
||||
esWolfDryingWater = 8,
|
||||
// Informs client that eating was accepted
|
||||
esPlayerEatingAccepted = 9,
|
||||
// Sheep plays eating animation (head lowers to ground)
|
||||
esSheepEating = 10,
|
||||
// Iron Golem holds gift to villager children
|
||||
esIronGolemGivingPlant = 11,
|
||||
// Villager spawns heart particles
|
||||
esVillagerBreeding = 12,
|
||||
// Villager spawns thunderclound particles
|
||||
esVillagerAngry = 13,
|
||||
// Villager spawns green crosses
|
||||
esVillagerHappy = 14,
|
||||
// Witch spawns magic particle (TODO: investigation into what this is)
|
||||
esWitchMagicking = 15,
|
||||
|
||||
// It seems 16 (zombie conversion) is now done with metadata
|
||||
ENTITY_STATUS_FIREWORK_EXPLODE= 17,
|
||||
|
||||
// Informs client to explode a firework based on its metadata
|
||||
esFireworkExploding = 17,
|
||||
} ;
|
||||
|
||||
enum
|
||||
@ -118,7 +139,8 @@ public:
|
||||
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire
|
||||
MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have
|
||||
DROWNING_TICKS = 20, ///< Number of ticks per heart of damage
|
||||
VOID_BOUNDARY = -46 ///< At what position Y to begin applying void damage
|
||||
VOID_BOUNDARY = -46, ///< At what position Y to begin applying void damage
|
||||
FALL_DAMAGE_HEIGHT = 4 ///< At what position Y fall damage is applied
|
||||
} ;
|
||||
|
||||
cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);
|
||||
|
@ -132,7 +132,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
int PosY = (int)floor(GetPosY());
|
||||
int PosY = POSY_TOINT;
|
||||
if ((PosY <= 0) || (PosY >= cChunkDef::Height))
|
||||
{
|
||||
// Outside the world, just process normal falling physics
|
||||
@ -141,8 +141,8 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
int RelPosX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||
int RelPosZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
|
||||
if (Chunk == NULL)
|
||||
{
|
||||
@ -195,7 +195,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
super::HandlePhysics(a_Dt, *Chunk);
|
||||
}
|
||||
|
||||
if (m_bIsOnDetectorRail && !Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())).Equals(m_DetectorRailPosition))
|
||||
if (m_bIsOnDetectorRail && !Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT).Equals(m_DetectorRailPosition))
|
||||
{
|
||||
m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
|
||||
m_bIsOnDetectorRail = false;
|
||||
@ -203,7 +203,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||
else if (WasDetectorRail)
|
||||
{
|
||||
m_bIsOnDetectorRail = true;
|
||||
m_DetectorRailPosition = Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
|
||||
m_DetectorRailPosition = Vector3i(POSX_TOINT, POSY_TOINT, POSZ_TOINT);
|
||||
}
|
||||
|
||||
// Broadcast positioning changes to client
|
||||
@ -719,11 +719,11 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
|
||||
{
|
||||
if (GetSpeedZ() > 0)
|
||||
{
|
||||
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ()));
|
||||
BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ()));
|
||||
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
|
||||
{
|
||||
// We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
|
||||
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1);
|
||||
cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, (int)ceil(GetPosZ())), 0.5, 1);
|
||||
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
|
||||
|
||||
if (bbBlock.DoesIntersect(bbMinecart))
|
||||
@ -736,10 +736,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
|
||||
}
|
||||
else if (GetSpeedZ() < 0)
|
||||
{
|
||||
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1);
|
||||
BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
|
||||
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
|
||||
{
|
||||
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1);
|
||||
cBoundingBox bbBlock(Vector3d(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1), 0.5, 1);
|
||||
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
|
||||
|
||||
if (bbBlock.DoesIntersect(bbMinecart))
|
||||
@ -756,10 +756,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
|
||||
{
|
||||
if (GetSpeedX() > 0)
|
||||
{
|
||||
BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
|
||||
BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT);
|
||||
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
|
||||
{
|
||||
cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
|
||||
cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), POSY_TOINT, POSZ_TOINT), 0.5, 1);
|
||||
cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
|
||||
|
||||
if (bbBlock.DoesIntersect(bbMinecart))
|
||||
@ -772,10 +772,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
|
||||
}
|
||||
else if (GetSpeedX() < 0)
|
||||
{
|
||||
BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
|
||||
BLOCKTYPE Block = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
|
||||
if (!IsBlockRail(Block) && cBlockInfo::IsSolid(Block))
|
||||
{
|
||||
cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
|
||||
cBoundingBox bbBlock(Vector3d(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT), 0.5, 1);
|
||||
cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
|
||||
|
||||
if (bbBlock.DoesIntersect(bbMinecart))
|
||||
@ -793,10 +793,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
|
||||
case E_META_RAIL_CURVED_ZP_XM:
|
||||
case E_META_RAIL_CURVED_ZP_XP:
|
||||
{
|
||||
BLOCKTYPE BlockXM = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
|
||||
BLOCKTYPE BlockXP = m_World->GetBlock((int)floor(GetPosX()) + 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
|
||||
BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1);
|
||||
BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
|
||||
BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
|
||||
BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT);
|
||||
BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
|
||||
BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1);
|
||||
if (
|
||||
(!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) ||
|
||||
(!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) ||
|
||||
@ -805,7 +805,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
|
||||
)
|
||||
{
|
||||
SetSpeed(0, 0, 0);
|
||||
SetPosition((int)floor(GetPosX()) + 0.5, GetPosY(), (int)floor(GetPosZ()) + 0.5);
|
||||
SetPosition(POSX_TOINT + 0.5, GetPosY(), POSZ_TOINT + 0.5);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
@ -822,7 +822,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
|
||||
{
|
||||
cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == NULL) ? -1 : m_Attachee->GetUniqueID()));
|
||||
int ChunkX, ChunkZ;
|
||||
cChunkDef::BlockToChunk((int)floor(GetPosX()), (int)floor(GetPosZ()), ChunkX, ChunkZ);
|
||||
cChunkDef::BlockToChunk(POSX_TOINT, POSZ_TOINT, ChunkX, ChunkZ);
|
||||
m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback);
|
||||
|
||||
if (!MinecartCollisionCallback.FoundIntersection())
|
||||
|
@ -98,15 +98,15 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
|
||||
if (!m_bCollected)
|
||||
{
|
||||
int BlockY = (int) floor(GetPosY());
|
||||
int BlockY = POSY_TOINT;
|
||||
int BlockX = POSX_TOINT;
|
||||
int BlockZ = POSZ_TOINT;
|
||||
|
||||
if ((BlockY >= 0) && (BlockY < cChunkDef::Height)) // Don't do anything except for falling when outside the world
|
||||
{
|
||||
int BlockX = (int) floor(GetPosX());
|
||||
int BlockZ = (int) floor(GetPosZ());
|
||||
// Position might have changed due to physics. So we have to make sure we have the correct chunk.
|
||||
cChunk * CurrentChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ);
|
||||
if (CurrentChunk != NULL) // Make sure the chunk is loaded
|
||||
{
|
||||
GET_AND_VERIFY_CURRENT_CHUNK(CurrentChunk, BlockX, BlockZ)
|
||||
|
||||
int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
|
||||
int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
|
||||
|
||||
@ -140,7 +140,6 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_Timer > 500.f) // 0.5 second
|
||||
@ -156,7 +155,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
if (GetPosY() < -8) // Out of this world and no more visible!
|
||||
if (GetPosY() < VOID_BOUNDARY) // Out of this world and no more visible!
|
||||
{
|
||||
Destroy(true);
|
||||
return;
|
||||
|
@ -49,9 +49,6 @@ public:
|
||||
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
|
||||
|
||||
private:
|
||||
Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
|
||||
|
||||
Vector3d m_WaterSpeed;
|
||||
|
||||
/** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
|
||||
float m_Timer;
|
||||
|
@ -438,7 +438,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||
cWorld * World = GetWorld();
|
||||
if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height))
|
||||
{
|
||||
BLOCKTYPE BlockType = World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
|
||||
BLOCKTYPE BlockType = World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT);
|
||||
if (BlockType != E_BLOCK_AIR)
|
||||
{
|
||||
m_bTouchGround = true;
|
||||
@ -467,7 +467,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
|
||||
TakeDamage(dtFalling, NULL, Damage, Damage, 0);
|
||||
|
||||
// Fall particles
|
||||
GetWorld()->BroadcastSoundParticleEffect(2006, (int)floor(GetPosX()), (int)GetPosY() - 1, (int)floor(GetPosZ()), Damage /* Used as particle effect speed modifier */);
|
||||
GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, (int)GetPosY() - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
|
||||
}
|
||||
|
||||
m_LastGroundHeight = (float)GetPosY();
|
||||
@ -591,7 +591,7 @@ void cPlayer::FinishEating(void)
|
||||
m_EatingFinishTick = -1;
|
||||
|
||||
// Send the packets:
|
||||
m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED);
|
||||
m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
|
||||
m_World->BroadcastEntityAnimation(*this, 0);
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
|
||||
@ -1520,10 +1520,9 @@ void cPlayer::LoadPermissionsFromDisk()
|
||||
cIniFile IniFile;
|
||||
if (IniFile.ReadFile("users.ini"))
|
||||
{
|
||||
std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", "");
|
||||
if (!Groups.empty())
|
||||
{
|
||||
AString Groups = IniFile.GetValueSet(m_PlayerName, "Groups", "Default");
|
||||
AStringVector Split = StringSplitAndTrim(Groups, ",");
|
||||
|
||||
for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
|
||||
{
|
||||
if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr))
|
||||
@ -1532,11 +1531,6 @@ void cPlayer::LoadPermissionsFromDisk()
|
||||
}
|
||||
AddToGroup(*itr);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddToGroup("Default");
|
||||
}
|
||||
|
||||
AString Color = IniFile.GetValue(m_PlayerName, "Color", "-");
|
||||
if (!Color.empty())
|
||||
@ -1547,8 +1541,10 @@ void cPlayer::LoadPermissionsFromDisk()
|
||||
else
|
||||
{
|
||||
cGroupManager::GenerateDefaultUsersIni(IniFile);
|
||||
IniFile.AddValue("Groups", m_PlayerName, "Default");
|
||||
AddToGroup("Default");
|
||||
}
|
||||
IniFile.WriteFile("users.ini");
|
||||
ResolvePermissions();
|
||||
}
|
||||
|
||||
@ -1900,9 +1896,9 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
|
||||
void cPlayer::Detach()
|
||||
{
|
||||
super::Detach();
|
||||
int PosX = (int)floor(GetPosX());
|
||||
int PosY = (int)floor(GetPosY());
|
||||
int PosZ = (int)floor(GetPosZ());
|
||||
int PosX = POSX_TOINT;
|
||||
int PosY = POSY_TOINT;
|
||||
int PosZ = POSZ_TOINT;
|
||||
|
||||
// Search for a position within an area to teleport player after detachment
|
||||
// Position must be solid land, and occupied by a nonsolid block
|
||||
|
@ -791,7 +791,7 @@ void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
|
||||
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE);
|
||||
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
@ -70,6 +70,40 @@ public:
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Performance test of the NetherFort generator:
|
||||
|
||||
/*
|
||||
#include "OSSupport/Timer.h"
|
||||
static class cNetherFortPerfTest
|
||||
{
|
||||
public:
|
||||
cNetherFortPerfTest(void)
|
||||
{
|
||||
cTimer Timer;
|
||||
long long StartTime = Timer.GetNowTime();
|
||||
|
||||
const int GridSize = 512;
|
||||
const int MaxDepth = 12;
|
||||
const int NumIterations = 100;
|
||||
for (int i = 0; i < NumIterations; i++)
|
||||
{
|
||||
cNetherFortGen FortGen(i, GridSize, MaxDepth);
|
||||
delete new cNetherFortGen::cNetherFort(FortGen, 0, 0, GridSize, MaxDepth, i);
|
||||
}
|
||||
|
||||
long long EndTime = Timer.GetNowTime();
|
||||
printf("%d forts took %lld msec (%f sec) to generate\n", NumIterations, EndTime - StartTime, ((double)(EndTime - StartTime)) / 1000);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
} g_PerfTest;
|
||||
//*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cNetherFortGen:
|
||||
|
||||
@ -258,6 +292,15 @@ cPieces cNetherFortGen::GetStartingPieces(void)
|
||||
|
||||
|
||||
|
||||
int cNetherFortGen::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece)
|
||||
{
|
||||
return ((const cPrefab &)a_NewPiece).GetPieceWeight(a_PlacedPiece, a_ExistingConnector);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cNetherFortGen::PiecePlaced(const cPiece & a_Piece)
|
||||
{
|
||||
UNUSED(a_Piece);
|
||||
|
@ -26,6 +26,7 @@ public:
|
||||
virtual ~cNetherFortGen();
|
||||
|
||||
protected:
|
||||
friend class cNetherFortPerfTest; // fwd: NetherFortGen.cpp
|
||||
class cNetherFort; // fwd: NetherFortGen.cpp
|
||||
typedef std::list<cNetherFort *> cNetherForts;
|
||||
|
||||
@ -77,6 +78,7 @@ protected:
|
||||
// cPiecePool overrides:
|
||||
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
|
||||
virtual cPieces GetStartingPieces(void) override;
|
||||
virtual int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector, const cPiece & a_NewPiece) override;
|
||||
virtual void PiecePlaced(const cPiece & a_Piece) override;
|
||||
virtual void Reset(void) override;
|
||||
} ;
|
||||
|
@ -392,14 +392,17 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
|
||||
Connections.reserve(AvailablePieces.size());
|
||||
Vector3i ConnPos = a_Connector.m_Pos; // The position at which the new connector should be placed - 1 block away from the connector
|
||||
AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
|
||||
|
||||
/*
|
||||
// DEBUG:
|
||||
printf("Placing piece at connector pos {%d, %d, %d}, direction %s\n", ConnPos.x, ConnPos.y, ConnPos.z, BlockFaceToString(a_Connector.m_Direction).c_str());
|
||||
//*/
|
||||
|
||||
int WeightTotal = 0;
|
||||
for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP)
|
||||
{
|
||||
// Get the relative chance of this piece being generated in this path:
|
||||
int Weight = m_PiecePool.GetPieceWeight(a_ParentPiece, a_Connector, **itrP);
|
||||
if (Weight <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try fitting each of the piece's connector:
|
||||
cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
|
||||
for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC)
|
||||
{
|
||||
@ -419,7 +422,9 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
|
||||
// Doesn't fit in this rotation
|
||||
continue;
|
||||
}
|
||||
Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations));
|
||||
// Fits, add it to list of possibile connections:
|
||||
Connections.push_back(cConnection(**itrP, *itrC, NumCCWRotations, Weight));
|
||||
WeightTotal += Weight;
|
||||
} // for itrC - Connectors[]
|
||||
} // for itrP - AvailablePieces[]
|
||||
if (Connections.empty())
|
||||
@ -427,21 +432,23 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
|
||||
// No available connections, bail out
|
||||
return false;
|
||||
}
|
||||
ASSERT(WeightTotal > 0);
|
||||
|
||||
// Choose a random connection from the list:
|
||||
int rnd = m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7;
|
||||
cConnection & Conn = Connections[rnd % Connections.size()];
|
||||
// Choose a random connection from the list, based on the weights:
|
||||
int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal;
|
||||
size_t ChosenIndex = 0;
|
||||
for (cConnections::const_iterator itr = Connections.begin(), end = Connections.end(); itr != end; ++itr, ++ChosenIndex)
|
||||
{
|
||||
rnd -= itr->m_Weight;
|
||||
if (rnd <= 0)
|
||||
{
|
||||
// This is the piece to choose
|
||||
break;
|
||||
}
|
||||
}
|
||||
cConnection & Conn = Connections[ChosenIndex];
|
||||
|
||||
// Place the piece:
|
||||
/*
|
||||
// DEBUG
|
||||
printf("Chosen connector at {%d, %d, %d}, direction %s, needs %d rotations\n",
|
||||
Conn.m_Connector.m_Pos.x, Conn.m_Connector.m_Pos.y, Conn.m_Connector.m_Pos.z,
|
||||
BlockFaceToString(Conn.m_Connector.m_Direction).c_str(),
|
||||
Conn.m_NumCCWRotations
|
||||
);
|
||||
//*/
|
||||
|
||||
Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
|
||||
ConnPos -= NewPos;
|
||||
cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations);
|
||||
@ -449,12 +456,6 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
|
||||
|
||||
// Add the new piece's connectors to the list of free connectors:
|
||||
cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors();
|
||||
|
||||
/*
|
||||
// DEBUG:
|
||||
printf("Adding %u connectors to the pool\n", Connectors.size() - 1);
|
||||
//*/
|
||||
|
||||
for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
|
||||
{
|
||||
if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
|
||||
@ -524,10 +525,11 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cPieceGenerator::cConnection:
|
||||
|
||||
cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations) :
|
||||
cPieceGenerator::cConnection::cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight) :
|
||||
m_Piece(&a_Piece),
|
||||
m_Connector(a_Connector),
|
||||
m_NumCCWRotations(a_NumCCWRotations)
|
||||
m_NumCCWRotations(a_NumCCWRotations),
|
||||
m_Weight(a_Weight)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -85,6 +85,13 @@ typedef std::vector<cPiece *> cPieces;
|
||||
|
||||
|
||||
|
||||
// fwd:
|
||||
class cPlacedPiece;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** This class is an interface that provides pieces for the generator. It can keep track of what pieces were
|
||||
placed and adjust the returned piece vectors. */
|
||||
class cPiecePool
|
||||
@ -101,6 +108,16 @@ public:
|
||||
Multiple starting points are supported, one of the returned piece will be chosen. */
|
||||
virtual cPieces GetStartingPieces(void) = 0;
|
||||
|
||||
/** Returns the relative weight with which the a_NewPiece is to be selected for placing under a_PlacedPiece through a_ExistingConnector.
|
||||
This allows the pool to tweak the piece's chances, based on the previous pieces in the tree and the connector used.
|
||||
The higher the number returned, the higher the chance the piece will be chosen. 0 means the piece will never be chosen.
|
||||
*/
|
||||
virtual int GetPieceWeight(
|
||||
const cPlacedPiece & a_PlacedPiece,
|
||||
const cPiece::cConnector & a_ExistingConnector,
|
||||
const cPiece & a_NewPiece
|
||||
) { return 1; }
|
||||
|
||||
/** Called after a piece is placed, to notify the pool that it has been used.
|
||||
The pool may adjust the pieces it will return the next time. */
|
||||
virtual void PiecePlaced(const cPiece & a_Piece) = 0;
|
||||
@ -157,8 +174,9 @@ protected:
|
||||
cPiece * m_Piece; // The piece being connected
|
||||
cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords)
|
||||
int m_NumCCWRotations; // Number of rotations necessary to match the two connectors
|
||||
int m_Weight; // Relative chance that this connection will be chosen
|
||||
|
||||
cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations);
|
||||
cConnection(cPiece & a_Piece, cPiece::cConnector & a_Connector, int a_NumCCWRotations, int a_Weight);
|
||||
};
|
||||
typedef std::vector<cConnection> cConnections;
|
||||
|
||||
|
@ -91,7 +91,19 @@ static const cPrefab::sDef g_TestPrefabDef =
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msImprint
|
||||
cBlockArea::msImprint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
10,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
1000,
|
||||
};
|
||||
|
||||
static cPrefab g_TestPrefab(g_TestPrefabDef);
|
||||
@ -105,13 +117,17 @@ cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
|
||||
m_Size(a_Def.m_SizeX, a_Def.m_SizeY, a_Def.m_SizeZ),
|
||||
m_HitBox(0, 0, 0, a_Def.m_SizeX - 1, a_Def.m_SizeY - 1, a_Def.m_SizeZ - 1),
|
||||
m_AllowedRotations(a_Def.m_AllowedRotations),
|
||||
m_MergeStrategy(a_Def.m_MergeStrategy)
|
||||
m_MergeStrategy(a_Def.m_MergeStrategy),
|
||||
m_ShouldExtendFloor(a_Def.m_ShouldExtendFloor),
|
||||
m_DefaultWeight(a_Def.m_DefaultWeight),
|
||||
m_AddWeightIfSame(a_Def.m_AddWeightIfSame)
|
||||
{
|
||||
m_BlockArea[0].Create(m_Size);
|
||||
CharMap cm;
|
||||
ParseCharMap(cm, a_Def.m_CharMap);
|
||||
ParseBlockImage(cm, a_Def.m_Image);
|
||||
ParseConnectors(a_Def.m_Connectors);
|
||||
ParseDepthWeight(a_Def.m_DepthWeight);
|
||||
|
||||
// 1 CCW rotation:
|
||||
if ((m_AllowedRotations & 0x01) != 0)
|
||||
@ -142,12 +158,53 @@ cPrefab::cPrefab(const cPrefab::sDef & a_Def) :
|
||||
|
||||
void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
|
||||
{
|
||||
// Draw the basic image:
|
||||
Vector3i Placement = a_Placement->GetCoords();
|
||||
int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
|
||||
int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
|
||||
Placement.Move(-ChunkStartX, 0, -ChunkStartZ);
|
||||
a_Dest.WriteBlockArea(m_BlockArea[a_Placement->GetNumCCWRotations()], Placement.x, Placement.y, Placement.z, m_MergeStrategy);
|
||||
const cBlockArea & Image = m_BlockArea[a_Placement->GetNumCCWRotations()];
|
||||
a_Dest.WriteBlockArea(Image, Placement.x, Placement.y, Placement.z, m_MergeStrategy);
|
||||
|
||||
// If requested, draw the floor (from the bottom of the prefab down to the nearest non-air)
|
||||
int MaxX = Image.GetSizeX();
|
||||
int MaxZ = Image.GetSizeZ();
|
||||
for (int z = 0; z < MaxZ; z++)
|
||||
{
|
||||
int RelZ = Placement.z + z;
|
||||
if ((RelZ < 0) || (RelZ >= cChunkDef::Width))
|
||||
{
|
||||
// Z coord outside the chunk
|
||||
continue;
|
||||
}
|
||||
for (int x = 0; x < MaxX; x++)
|
||||
{
|
||||
int RelX = Placement.x + x;
|
||||
if ((RelX < 0) || (RelX >= cChunkDef::Width))
|
||||
{
|
||||
// X coord outside the chunk
|
||||
continue;
|
||||
}
|
||||
BLOCKTYPE BlockType;
|
||||
NIBBLETYPE BlockMeta;
|
||||
Image.GetRelBlockTypeMeta(x, 0, z, BlockType, BlockMeta);
|
||||
if ((BlockType == E_BLOCK_AIR) || (BlockType == E_BLOCK_SPONGE))
|
||||
{
|
||||
// Do not expand air nor sponge blocks
|
||||
continue;
|
||||
}
|
||||
for (int y = Placement.y - 1; y >= 0; y--)
|
||||
{
|
||||
BLOCKTYPE ExistingBlock = a_Dest.GetBlockType(RelX, y, RelZ);
|
||||
if (ExistingBlock != E_BLOCK_AIR)
|
||||
{
|
||||
// End the expansion for this column, reached the end
|
||||
break;
|
||||
}
|
||||
a_Dest.SetBlockTypeMeta(RelX, y, RelZ, BlockType, BlockMeta);
|
||||
} // for y
|
||||
} // for x
|
||||
} // for z
|
||||
}
|
||||
|
||||
|
||||
@ -170,6 +227,26 @@ bool cPrefab::HasConnectorType(int a_ConnectorType) const
|
||||
|
||||
|
||||
|
||||
int cPrefab::GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector) const
|
||||
{
|
||||
// Use the default or per-depth weight:
|
||||
cDepthWeight::const_iterator itr = m_DepthWeight.find(a_PlacedPiece.GetDepth() + 1);
|
||||
int res = (itr == m_DepthWeight.end()) ? m_DefaultWeight : itr->second;
|
||||
|
||||
// If the piece is the same as the parent, apply the m_AddWeightIfSame modifier:
|
||||
const cPiece * ParentPiece = &a_PlacedPiece.GetPiece();
|
||||
const cPiece * ThisPiece = this;
|
||||
if (ThisPiece == ParentPiece)
|
||||
{
|
||||
res += m_AddWeightIfSame;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
|
||||
{
|
||||
ASSERT(a_CharMapDef != NULL);
|
||||
@ -277,6 +354,54 @@ void cPrefab::ParseConnectors(const char * a_ConnectorsDef)
|
||||
|
||||
|
||||
|
||||
void cPrefab::ParseDepthWeight(const char * a_DepthWeightDef)
|
||||
{
|
||||
// The member needn't be defined at all, if so, skip:
|
||||
if (a_DepthWeightDef == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Split into individual records: "Record | Record | Record"
|
||||
AStringVector Defs = StringSplitAndTrim(a_DepthWeightDef, "|");
|
||||
|
||||
// Add each record's contents:
|
||||
for (AStringVector::const_iterator itr = Defs.begin(), end = Defs.end(); itr != end; ++itr)
|
||||
{
|
||||
// Split into components: "Depth : Weight"
|
||||
AStringVector Components = StringSplitAndTrim(*itr, ":");
|
||||
if (Components.size() != 2)
|
||||
{
|
||||
LOGWARNING("Bad prefab DepthWeight record: \"%s\", skipping.", itr->c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse depth:
|
||||
int Depth = atoi(Components[0].c_str());
|
||||
if ((Depth == 0) && (Components[0] != "0"))
|
||||
{
|
||||
LOGWARNING("Bad prefab DepthWeight record, cannot parse depth \"%s\", skipping.", Components[0].c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Parse weight:
|
||||
int Weight = atoi(Components[1].c_str());
|
||||
if ((Weight == 0) && (Components[1] != "0"))
|
||||
{
|
||||
LOGWARNING("Bad prefab DepthWeight record, cannot parse weight \"%s\", skipping.", Components[1].c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
// Save to map:
|
||||
ASSERT(m_DepthWeight.find(Depth) == m_DepthWeight.end()); // Not a duplicate
|
||||
m_DepthWeight[Depth] = Weight;
|
||||
} // for itr - Defs[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPiece::cConnectors cPrefab::GetConnectors(void) const
|
||||
{
|
||||
return m_Connectors;
|
||||
|
@ -37,11 +37,47 @@ public:
|
||||
int m_SizeX;
|
||||
int m_SizeY;
|
||||
int m_SizeZ;
|
||||
|
||||
/** The mapping between characters in m_Image and the blocktype / blockmeta.
|
||||
Format: "Char: BlockType: BlockMeta \n Char: BlockType : BlockMeta \n ..." */
|
||||
const char * m_CharMap;
|
||||
|
||||
/** The actual image to be used for the prefab. Organized YZX (Y changes the least often).
|
||||
Each character represents a single block, the type is mapped through m_CharMap. */
|
||||
const char * m_Image;
|
||||
|
||||
/** List of connectors.
|
||||
Format: "Type: X, Y, Z : Direction \n Type : X, Y, Z : Direction \n ...".
|
||||
Type is an arbitrary number, Direction is the BlockFace constant value (0 .. 5). */
|
||||
const char * m_Connectors;
|
||||
|
||||
/** Bitmask specifying the allowed rotations.
|
||||
N rotations CCW are allowed if bit N is set. */
|
||||
int m_AllowedRotations;
|
||||
|
||||
/** The merge strategy to use while drawing the prefab. */
|
||||
cBlockArea::eMergeStrategy m_MergeStrategy;
|
||||
|
||||
/** If set to true, the prefab will extend its lowermost blocks until a solid block is found,
|
||||
thus creating a foundation for the prefab. This is used for houses to be "on the ground", as well as
|
||||
nether fortresses not to float. */
|
||||
bool m_ShouldExtendFloor;
|
||||
|
||||
/** Chance of this piece being used, if no other modifier is active. */
|
||||
int m_DefaultWeight;
|
||||
|
||||
/** Chances of this piece being used, per depth of the generated piece tree.
|
||||
The starting piece has a depth of 0, the pieces connected to it are depth 1, etc.
|
||||
The specified depth stands for the depth of the new piece (not the existing already-placed piece),
|
||||
so valid depths start at 1.
|
||||
Format: "Depth : Weight | Depth : Weight | Depth : Weight ..."
|
||||
Depths that are not specified will use the m_DefaultWeight value. */
|
||||
const char * m_DepthWeight;
|
||||
|
||||
/** The weight to add to this piece's base per-depth chance if the previous piece is the same.
|
||||
Can be positive or negative.
|
||||
This is used e. g. to make nether bridges prefer spanning multiple segments or to penalize turrets next to each other. */
|
||||
int m_AddWeightIfSame;
|
||||
};
|
||||
|
||||
cPrefab(const sDef & a_Def);
|
||||
@ -52,6 +88,10 @@ public:
|
||||
/** Returns true if the prefab has any connector of the specified type. */
|
||||
bool HasConnectorType(int a_ConnectorType) const;
|
||||
|
||||
/** Returns the weight (chance) of this prefab generating as the next piece after the specified placed piece.
|
||||
PiecePool implementations can use this for their GetPieceWeight() implementations. */
|
||||
int GetPieceWeight(const cPlacedPiece & a_PlacedPiece, const cPiece::cConnector & a_ExistingConnector) const;
|
||||
|
||||
protected:
|
||||
/** Packs complete definition of a single block, for per-letter assignment. */
|
||||
struct sBlockTypeDef
|
||||
@ -60,9 +100,12 @@ protected:
|
||||
NIBBLETYPE m_BlockMeta;
|
||||
};
|
||||
|
||||
/** Maps letters in the sDef::m_Image onto a number, BlockType * 16 | BlockMeta */
|
||||
/** Maps letters in the sDef::m_Image onto a sBlockTypeDef block type definition. */
|
||||
typedef sBlockTypeDef CharMap[256];
|
||||
|
||||
/** Maps generator tree depth to weight. */
|
||||
typedef std::map<int, int> cDepthWeight;
|
||||
|
||||
|
||||
/** The cBlockArea that contains the block definitions for the prefab.
|
||||
The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */
|
||||
@ -83,6 +126,26 @@ protected:
|
||||
/** The merge strategy to use when drawing the prefab into a block area */
|
||||
cBlockArea::eMergeStrategy m_MergeStrategy;
|
||||
|
||||
/** If set to true, the prefab will extend its lowermost blocks until a solid block is found,
|
||||
thus creating a foundation for the prefab. This is used for houses to be "on the ground", as well as
|
||||
nether fortresses not to float. */
|
||||
bool m_ShouldExtendFloor;
|
||||
|
||||
/** Chance of this piece being used, if no other modifier is active. */
|
||||
int m_DefaultWeight;
|
||||
|
||||
/** Chances of this piece being used, per depth of the generated piece tree.
|
||||
The starting piece has a depth of 0, the pieces connected to it are depth 1, etc.
|
||||
The specified depth stands for the depth of the new piece (not the existing already-placed piece),
|
||||
so valid depths start at 1.
|
||||
Depths that are not specified will use the m_DefaultWeight value. */
|
||||
cDepthWeight m_DepthWeight;
|
||||
|
||||
/** The weight to add to this piece's base per-depth chance if the previous piece is the same.
|
||||
Can be positive or negative.
|
||||
This is used e. g. to make nether bridges prefer spanning multiple segments or to penalize turrets next to each other. */
|
||||
int m_AddWeightIfSame;
|
||||
|
||||
|
||||
// cPiece overrides:
|
||||
virtual cConnectors GetConnectors(void) const override;
|
||||
@ -98,6 +161,9 @@ protected:
|
||||
|
||||
/** Parses the connectors definition text into m_Connectors member. */
|
||||
void ParseConnectors(const char * a_ConnectorsDef);
|
||||
|
||||
/** Parses the per-depth weight into m_DepthWeight member. */
|
||||
void ParseDepthWeight(const char * a_DepthWeightDef);
|
||||
};
|
||||
|
||||
|
||||
|
@ -133,10 +133,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 0, 2, 2: 4\n" /* Type 1, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
20,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BalconyCorridor
|
||||
|
||||
|
||||
@ -274,10 +286,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 0, 2, 4: 4\n" /* Type 1, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
20,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BalconyTee2
|
||||
|
||||
|
||||
@ -378,10 +402,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 0, 1, 3: 4\n" /* Type 0, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BlazePlatform
|
||||
|
||||
|
||||
@ -510,10 +546,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 0, 5, 3: 4\n" /* Type 0, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BlazePlatformOverhang
|
||||
|
||||
|
||||
@ -694,10 +742,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 7, 5, 14: 3\n" /* Type 0, direction Z+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
5,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BridgeCircleCrossing
|
||||
|
||||
|
||||
@ -879,10 +939,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 14, 5, 7: 5\n" /* Type 0, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
10,
|
||||
|
||||
// DepthWeight:
|
||||
"1:1000",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BridgeCrossing
|
||||
|
||||
|
||||
@ -957,10 +1029,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 0, 5, 2: 4\n" /* Type 0, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"1:0",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BridgeCrumble1
|
||||
|
||||
|
||||
@ -1041,10 +1125,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 0, 5, 2: 4\n" /* Type 1, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"1:0",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BridgeCrumble2
|
||||
|
||||
|
||||
@ -1204,14 +1300,262 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 2, 4, 15: 3\n" /* Type 0, direction Z+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
10,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
1000,
|
||||
}, // BridgeDoubleCrumble
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BridgeFunnelDown:
|
||||
// The data has been exported from the gallery Nether, area index 0, ID 2, created by Aloe_vera
|
||||
{
|
||||
// Size:
|
||||
15, 12, 12, // SizeX = 15, SizeY = 12, SizeZ = 12
|
||||
|
||||
// Block definitions:
|
||||
".: 0: 0\n" /* air */
|
||||
"a:112: 0\n" /* netherbrick */
|
||||
"b:114: 6\n" /* netherbrickstairs */
|
||||
"c:114: 4\n" /* netherbrickstairs */
|
||||
"d:114: 5\n" /* netherbrickstairs */
|
||||
"e: 44:14\n" /* step */
|
||||
"f:114: 7\n" /* netherbrickstairs */
|
||||
"m: 19: 0\n" /* sponge */,
|
||||
|
||||
// Block data:
|
||||
// Level 0
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "aammmmmmmmmmmaa"
|
||||
/* 2 */ "aammmmmmmmmmmaa"
|
||||
/* 3 */ "aammmmmmmmmmmaa"
|
||||
/* 4 */ "mmmmmmmmmmmmmmm"
|
||||
/* 5 */ "mmmmmmmmmmmmmmm"
|
||||
/* 6 */ "mmmmmmmmmmmmmmm"
|
||||
/* 7 */ "mmmmmmmmmmmmmmm"
|
||||
/* 8 */ "mmmmmmmmmmmmmmm"
|
||||
/* 9 */ "mmmmmmaaammmmmm"
|
||||
/* 10 */ "mmmmmmaaammmmmm"
|
||||
/* 11 */ "mmmmmmaaammmmmm"
|
||||
|
||||
// Level 1
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "aammmmmmmmmmmaa"
|
||||
/* 2 */ "aammmmmmmmmmmaa"
|
||||
/* 3 */ "aammmmmmmmmmmaa"
|
||||
/* 4 */ "mmmmmmmmmmmmmmm"
|
||||
/* 5 */ "mmmmmmmmmmmmmmm"
|
||||
/* 6 */ "mmmmmmmmmmmmmmm"
|
||||
/* 7 */ "mmmmmmmmmmmmmmm"
|
||||
/* 8 */ "mmmmmmbbbmmmmmm"
|
||||
/* 9 */ "mmmmmmaaammmmmm"
|
||||
/* 10 */ "mmmmmmaaammmmmm"
|
||||
/* 11 */ "mmmmmmaaammmmmm"
|
||||
|
||||
// Level 2
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "aammmmmmmmmmmaa"
|
||||
/* 2 */ "aammmmmmmmmmmaa"
|
||||
/* 3 */ "aammmmmmmmmmmaa"
|
||||
/* 4 */ "mmmmmmmmmmmmmmm"
|
||||
/* 5 */ "mmmmmmmmmmmmmmm"
|
||||
/* 6 */ "mmmmmmmmmmmmmmm"
|
||||
/* 7 */ "mmmmmcbbbdmmmmm"
|
||||
/* 8 */ "mmmmmcaaadmmmmm"
|
||||
/* 9 */ "mmmmmcaaadmmmmm"
|
||||
/* 10 */ "mmmmmcaaadmmmmm"
|
||||
/* 11 */ "mmmmmcaaadmmmmm"
|
||||
|
||||
// Level 3
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "aammmmmmmmmmmaa"
|
||||
/* 2 */ "aammmmmmmmmmmaa"
|
||||
/* 3 */ "aammmmmmmmmmmaa"
|
||||
/* 4 */ "mmmmmmmmmmmmmmm"
|
||||
/* 5 */ "mmmmmmmmmmmmmmm"
|
||||
/* 6 */ "mmmmmmmmmmmmmmm"
|
||||
/* 7 */ "mmmmmaaaaammmmm"
|
||||
/* 8 */ "mmmmmaaaaammmmm"
|
||||
/* 9 */ "mmmmmaaaaammmmm"
|
||||
/* 10 */ "mmmmmaaaaammmmm"
|
||||
/* 11 */ "mmmmmaaaaammmmm"
|
||||
|
||||
// Level 4
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "aammmmmmmmmmmaa"
|
||||
/* 2 */ "aammmmmmmmmmmaa"
|
||||
/* 3 */ "aammmmmmmmmmmaa"
|
||||
/* 4 */ "mmmmmmmmmmmmmmm"
|
||||
/* 5 */ "mmmmmmmmmmmmmmm"
|
||||
/* 6 */ "mmmmcbbbbbdmmmm"
|
||||
/* 7 */ "mmmmaaaaaaammmm"
|
||||
/* 8 */ "mmmma.....ammmm"
|
||||
/* 9 */ "mmmmaa...aammmm"
|
||||
/* 10 */ "mmmmma...ammmmm"
|
||||
/* 11 */ "mmmmma...ammmmm"
|
||||
|
||||
// Level 5
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "aadmmmmmmmmmcaa"
|
||||
/* 2 */ "aadmmmmmmmmmcaa"
|
||||
/* 3 */ "aadmmmmmmmmmcaa"
|
||||
/* 4 */ "mmmmmmmmmmmmmmm"
|
||||
/* 5 */ "mmmcbbbbbbbdmmm"
|
||||
/* 6 */ "mmmaaaaaaaaaamm"
|
||||
/* 7 */ "mmma.......ammm"
|
||||
/* 8 */ "mmmaa.....aammm"
|
||||
/* 9 */ "mmmmam...mammmm"
|
||||
/* 10 */ "mmmmmm...mmmmmm"
|
||||
/* 11 */ "mmmmmm...mmmmmm"
|
||||
|
||||
// Level 6
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "aaademmmmmecaaa"
|
||||
/* 2 */ "aaademmmmmecaaa"
|
||||
/* 3 */ "aaademmmmmecaaa"
|
||||
/* 4 */ "mmaaabbbbbaaaam"
|
||||
/* 5 */ "mmaaaaaaaaaaaam"
|
||||
/* 6 */ "mma.........amm"
|
||||
/* 7 */ "mmaa.......aamm"
|
||||
/* 8 */ "mmmam.....mammm"
|
||||
/* 9 */ "mmmmmm...mmmmmm"
|
||||
/* 10 */ "mmmmmm...mmmmmm"
|
||||
/* 11 */ "mmmmmm...mmmmmm"
|
||||
|
||||
// Level 7
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "bbbbbbbbbbbbbbb"
|
||||
/* 1 */ "aaaaaaaaaaaaaaa"
|
||||
/* 2 */ "aaaaaaaaaaaaaaa"
|
||||
/* 3 */ "aaaaaaaaaaaaaaa"
|
||||
/* 4 */ "faaaaaaaaaaaaaa"
|
||||
/* 5 */ "ma...........am"
|
||||
/* 6 */ "maa.........aam"
|
||||
/* 7 */ "mmam.......mamm"
|
||||
/* 8 */ "mmmmm.....mmmmm"
|
||||
/* 9 */ "mmmmmmmmmmmmmmm"
|
||||
/* 10 */ "mmmmmmmmmmmmmmm"
|
||||
/* 11 */ "mmmmmmmmmmmmmmm"
|
||||
|
||||
// Level 8
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "aaaaaaaaaaaaaaa"
|
||||
/* 1 */ "aaaaaaaaaaaaaaa"
|
||||
/* 2 */ "aaaaaaaaaaaaaaa"
|
||||
/* 3 */ "aaaaaaaaaaaaaaa"
|
||||
/* 4 */ "a.............a"
|
||||
/* 5 */ "aa...........aa"
|
||||
/* 6 */ "mam.........mam"
|
||||
/* 7 */ "mmmm.......mmmm"
|
||||
/* 8 */ "mmmmmmmmmmmmmmm"
|
||||
/* 9 */ "mmmmmmmmmmmmmmm"
|
||||
/* 10 */ "mmmmmmmmmmmmmmm"
|
||||
/* 11 */ "mmmmmmmmmmmmmmm"
|
||||
|
||||
// Level 9
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "aaaaaaaaaaaaaaa"
|
||||
/* 1 */ "..............."
|
||||
/* 2 */ "..............."
|
||||
/* 3 */ "..............."
|
||||
/* 4 */ "a.............a"
|
||||
/* 5 */ "am............a"
|
||||
/* 6 */ "mmm.........mmm"
|
||||
/* 7 */ "mmmmmmmmmmmmmmm"
|
||||
/* 8 */ "mmmmmmmmmmmmmmm"
|
||||
/* 9 */ "mmmmmmmmmmmmmmm"
|
||||
/* 10 */ "mmmmmmmmmmmmmmm"
|
||||
/* 11 */ "mmmmmmmmmmmmmmm"
|
||||
|
||||
// Level 10
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "..............."
|
||||
/* 2 */ "..............."
|
||||
/* 3 */ "..............."
|
||||
/* 4 */ "m.............m"
|
||||
/* 5 */ "mm............m"
|
||||
/* 6 */ "mmmmmmmmmmmmmmm"
|
||||
/* 7 */ "mmmmmmmmmmmmmmm"
|
||||
/* 8 */ "mmmmmmmmmmmmmmm"
|
||||
/* 9 */ "mmmmmmmmmmmmmmm"
|
||||
/* 10 */ "mmmmmmmmmmmmmmm"
|
||||
/* 11 */ "mmmmmmmmmmmmmmm"
|
||||
|
||||
// Level 11
|
||||
/* z\x* 11111 */
|
||||
/* * 012345678901234 */
|
||||
/* 0 */ "mmmmmmmmmmmmmmm"
|
||||
/* 1 */ "..............."
|
||||
/* 2 */ "..............."
|
||||
/* 3 */ "..............."
|
||||
/* 4 */ "m.............m"
|
||||
/* 5 */ "mmmmmmmmmmmmmmm"
|
||||
/* 6 */ "mmmmmmmmmmmmmmm"
|
||||
/* 7 */ "mmmmmmmmmmmmmmm"
|
||||
/* 8 */ "mmmmmmmmmmmmmmm"
|
||||
/* 9 */ "mmmmmmmmmmmmmmm"
|
||||
/* 10 */ "mmmmmmmmmmmmmmm"
|
||||
/* 11 */ "mmmmmmmmmmmmmmm",
|
||||
|
||||
// Connectors:
|
||||
"0: 7, 4, 11: 3\n" /* Type 0, direction Z+ */
|
||||
"0: 0, 9, 2: 4\n" /* Type 0, direction X- */
|
||||
"0: 14, 9, 2: 5\n" /* Type 0, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
5,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BridgeFunnelDown
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// BridgeLevelCrossing:
|
||||
// The data has been exported from the gallery Nether, area index 45, ID 304, created by Aloe_vera
|
||||
@ -1514,10 +1858,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"",
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BridgeLevelCrossing
|
||||
|
||||
|
||||
@ -1617,10 +1973,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 14, 5, 2: 5\n" /* Type 0, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
500,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
1000,
|
||||
}, // BridgeSegment
|
||||
|
||||
|
||||
@ -1761,10 +2129,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 14, 5, 2: 5\n" /* Type 0, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
10,
|
||||
|
||||
// DepthWeight:
|
||||
"1:500",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // BridgeTee
|
||||
|
||||
|
||||
@ -1844,10 +2224,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 0, 1, 2: 4\n" /* Type 1, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
200,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // Corridor11
|
||||
|
||||
|
||||
@ -1927,10 +2319,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 0, 1, 2: 4\n" /* Type 1, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
200,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // Corridor13
|
||||
|
||||
|
||||
@ -2048,10 +2452,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 10, 1, 2: 5\n" /* Type 1, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // CorridorCorner5
|
||||
|
||||
|
||||
@ -2170,10 +2586,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // CorridorCornerChest5
|
||||
|
||||
|
||||
@ -2304,10 +2732,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 8, 8, 2: 5\n" /* Type 1, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // CorridorStairs
|
||||
|
||||
|
||||
@ -2367,11 +2807,11 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
// Level 4
|
||||
/* z\x* 1111 */
|
||||
/* * 01234567890123 */
|
||||
/* 0 */ "aaaaaaaaaaaaaa"
|
||||
/* 0 */ "aabaaaaaaaabaa"
|
||||
/* 1 */ ".............."
|
||||
/* 2 */ ".............."
|
||||
/* 3 */ ".............."
|
||||
/* 4 */ "aaaaaaaaaaaaaa"
|
||||
/* 4 */ "aabaaaaaaaabaa"
|
||||
|
||||
// Level 5
|
||||
/* z\x* 1111 */
|
||||
@ -2387,10 +2827,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 13, 1, 2: 5\n" /* Type 1, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // DarkCorridor
|
||||
|
||||
|
||||
@ -2625,10 +3077,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 9, 1, 0: 2\n" /* Type 1, direction Z- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // LavaStaircase
|
||||
|
||||
|
||||
@ -2938,10 +3402,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 0, 9, 7: 4\n" /* Type 1, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // LavaStaircaseBig
|
||||
|
||||
|
||||
@ -3200,10 +3676,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"",
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // LavaStairsBridge
|
||||
|
||||
|
||||
@ -3367,13 +3855,25 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
|
||||
// Connectors:
|
||||
"1: 12, 1, 6: 5\n" /* Type 1, direction X+ */
|
||||
"1: -1, 1, 6: 4\n" /* Type 1, direction X- */,
|
||||
"1: 0, 1, 6: 4\n" /* Type 1, direction X- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // MidStaircase
|
||||
|
||||
|
||||
@ -3497,10 +3997,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 3, 1, 0: 2\n" /* Type 0, direction Z- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // StairsToOpen1
|
||||
|
||||
|
||||
@ -3624,10 +4136,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 3, 1, 0: 2\n" /* Type 0, direction Z- */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // StairsToOpen2
|
||||
|
||||
|
||||
@ -3722,10 +4246,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 12, 1, 4: 5\n" /* Type 1, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // Tee2x4
|
||||
|
||||
|
||||
@ -3832,10 +4368,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"1: 12, 1, 6: 5\n" /* Type 1, direction X+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // Tee4x4
|
||||
|
||||
|
||||
@ -3921,10 +4469,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
|
||||
"0: 3, 1, 6: 3\n" /* Type 0, direction Z+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
-99,
|
||||
}, // Turret
|
||||
}; // g_NetherFortPrefabs
|
||||
|
||||
@ -4108,10 +4668,22 @@ const cPrefab::sDef g_NetherFortStartingPrefabs[] =
|
||||
"1: 6, 1, 12: 3\n" /* Type 1, direction Z+ */,
|
||||
|
||||
// AllowedRotations:
|
||||
7, /* 1, 2, 3 CCW rotations */
|
||||
7, /* 1, 2, 3 CCW rotation allowed */
|
||||
|
||||
// Merge strategy:
|
||||
cBlockArea::msSpongePrint,
|
||||
|
||||
// ShouldExtendFloor:
|
||||
false,
|
||||
|
||||
// DefaultWeight:
|
||||
100,
|
||||
|
||||
// DepthWeight:
|
||||
"",
|
||||
|
||||
// AddWeightIfSame:
|
||||
0,
|
||||
}, // CentralRoom
|
||||
};
|
||||
|
||||
|
@ -111,9 +111,9 @@ void cMonster::SpawnOn(cClientHandle & a_Client)
|
||||
|
||||
void cMonster::TickPathFinding()
|
||||
{
|
||||
const int PosX = (int)floor(GetPosX());
|
||||
const int PosY = (int)floor(GetPosY());
|
||||
const int PosZ = (int)floor(GetPosZ());
|
||||
const int PosX = POSX_TOINT;
|
||||
const int PosY = POSY_TOINT;
|
||||
const int PosZ = POSZ_TOINT;
|
||||
|
||||
m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z);
|
||||
|
||||
@ -148,13 +148,27 @@ void cMonster::TickPathFinding()
|
||||
BLOCKTYPE BlockAtY = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY, gCrossCoords[i].z + PosZ);
|
||||
BLOCKTYPE BlockAtYP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 1, gCrossCoords[i].z + PosZ);
|
||||
BLOCKTYPE BlockAtYPP = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY + 2, gCrossCoords[i].z + PosZ);
|
||||
BLOCKTYPE BlockAtYM = m_World->GetBlock(gCrossCoords[i].x + PosX, PosY - 1, gCrossCoords[i].z + PosZ);
|
||||
int LowestY = FindFirstNonAirBlockPosition(gCrossCoords[i].x + PosX, gCrossCoords[i].z + PosZ);
|
||||
BLOCKTYPE BlockAtLowestY = m_World->GetBlock(gCrossCoords[i].x + PosX, LowestY, gCrossCoords[i].z + PosZ);
|
||||
|
||||
if ((!cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
|
||||
if (
|
||||
(!cBlockInfo::IsSolid(BlockAtY)) &&
|
||||
(!cBlockInfo::IsSolid(BlockAtYP)) &&
|
||||
(!IsBlockLava(BlockAtLowestY)) &&
|
||||
(BlockAtLowestY != E_BLOCK_CACTUS) &&
|
||||
(PosY - LowestY < FALL_DAMAGE_HEIGHT)
|
||||
)
|
||||
{
|
||||
m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY, gCrossCoords[i].z + PosZ));
|
||||
}
|
||||
else if ((cBlockInfo::IsSolid(BlockAtY)) && (!cBlockInfo::IsSolid(BlockAtYP)) && (!cBlockInfo::IsSolid(BlockAtYPP)) && (!IsBlockLava(BlockAtYM)) && (BlockAtY != E_BLOCK_FENCE) && (BlockAtY != E_BLOCK_FENCE_GATE))
|
||||
else if (
|
||||
(cBlockInfo::IsSolid(BlockAtY)) &&
|
||||
(BlockAtY != E_BLOCK_CACTUS) &&
|
||||
(!cBlockInfo::IsSolid(BlockAtYP)) &&
|
||||
(!cBlockInfo::IsSolid(BlockAtYPP)) &&
|
||||
(BlockAtY != E_BLOCK_FENCE) &&
|
||||
(BlockAtY != E_BLOCK_FENCE_GATE)
|
||||
)
|
||||
{
|
||||
m_PotentialCoordinates.push_back(Vector3d((gCrossCoords[i].x + PosX), PosY + 1, gCrossCoords[i].z + PosZ));
|
||||
}
|
||||
@ -402,7 +416,7 @@ void cMonster::HandleFalling()
|
||||
GetWorld()->BroadcastSoundParticleEffect(2006, POSX_TOINT, POSY_TOINT - 1, POSZ_TOINT, Damage /* Used as particle effect speed modifier */);
|
||||
}
|
||||
|
||||
m_LastGroundHeight = (int)floor(GetPosY());
|
||||
m_LastGroundHeight = POSY_TOINT;
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,7 +425,7 @@ void cMonster::HandleFalling()
|
||||
|
||||
int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
|
||||
{
|
||||
int PosY = (int)floor(GetPosY());
|
||||
int PosY = POSY_TOINT;
|
||||
|
||||
if (PosY < 0)
|
||||
PosY = 0;
|
||||
@ -969,15 +983,15 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
|
||||
return;
|
||||
}
|
||||
|
||||
int RelY = (int)floor(GetPosY());
|
||||
int RelY = POSY_TOINT;
|
||||
if ((RelY < 0) || (RelY >= cChunkDef::Height))
|
||||
{
|
||||
// Outside the world
|
||||
return;
|
||||
}
|
||||
|
||||
int RelX = (int)floor(GetPosX()) - GetChunkX() * cChunkDef::Width;
|
||||
int RelZ = (int)floor(GetPosZ()) - GetChunkZ() * cChunkDef::Width;
|
||||
int RelX = POSX_TOINT - GetChunkX() * cChunkDef::Width;
|
||||
int RelZ = POSZ_TOINT - GetChunkZ() * cChunkDef::Width;
|
||||
|
||||
if (!a_Chunk.IsLightValid())
|
||||
{
|
||||
|
@ -185,14 +185,14 @@ protected:
|
||||
inline bool IsNextYPosReachable(int a_PosY)
|
||||
{
|
||||
return (
|
||||
(a_PosY <= (int)floor(GetPosY())) ||
|
||||
(a_PosY <= POSY_TOINT) ||
|
||||
DoesPosYRequireJump(a_PosY)
|
||||
);
|
||||
}
|
||||
/** Returns if a monster can reach a given height by jumping */
|
||||
inline bool DoesPosYRequireJump(int a_PosY)
|
||||
{
|
||||
return ((a_PosY > (int)floor(GetPosY())) && (a_PosY == (int)floor(GetPosY()) + 1));
|
||||
return ((a_PosY > POSY_TOINT) && (a_PosY == POSY_TOINT + 1));
|
||||
}
|
||||
|
||||
/** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */
|
||||
|
@ -102,7 +102,7 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
|
||||
{
|
||||
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_SHEEP_EATING);
|
||||
m_World->BroadcastEntityStatus(*this, esSheepEating);
|
||||
m_TimeToStopEating = 40;
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
{
|
||||
if (m_World->GetTickRandomNumber(5) == 3)
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_VILLAGER_ANGRY);
|
||||
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,12 +75,12 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
|
||||
SetMaxHealth(20);
|
||||
SetIsTame(true);
|
||||
SetOwner(a_Player.GetName());
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMED);
|
||||
m_World->BroadcastEntityStatus(*this, esWolfTamed);
|
||||
m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_WOLF_TAMING);
|
||||
m_World->BroadcastEntityStatus(*this, esWolfTaming);
|
||||
m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
|
||||
}
|
||||
}
|
||||
|
314
src/Protocol/Authenticator.cpp
Normal file
314
src/Protocol/Authenticator.cpp
Normal file
@ -0,0 +1,314 @@
|
||||
|
||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||
|
||||
#include "Authenticator.h"
|
||||
#include "../OSSupport/BlockingTCPLink.h"
|
||||
#include "../Root.h"
|
||||
#include "../Server.h"
|
||||
#include "../ClientHandle.h"
|
||||
|
||||
#include "inifile/iniFile.h"
|
||||
#include "json/json.h"
|
||||
|
||||
#include "polarssl/config.h"
|
||||
#include "polarssl/net.h"
|
||||
#include "polarssl/ssl.h"
|
||||
#include "polarssl/entropy.h"
|
||||
#include "polarssl/ctr_drbg.h"
|
||||
#include "polarssl/error.h"
|
||||
#include "polarssl/certs.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define DEFAULT_AUTH_SERVER "sessionserver.mojang.com"
|
||||
#define DEFAULT_AUTH_ADDRESS "/session/minecraft/hasJoined?username=%USERNAME%&serverId=%SERVERID%"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAuthenticator::cAuthenticator(void) :
|
||||
super("cAuthenticator"),
|
||||
m_Server(DEFAULT_AUTH_SERVER),
|
||||
m_Address(DEFAULT_AUTH_ADDRESS),
|
||||
m_ShouldAuthenticate(true)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cAuthenticator::~cAuthenticator()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::ReadINI(cIniFile & IniFile)
|
||||
{
|
||||
m_Server = IniFile.GetValueSet("Authentication", "Server", DEFAULT_AUTH_SERVER);
|
||||
m_Address = IniFile.GetValueSet("Authentication", "Address", DEFAULT_AUTH_ADDRESS);
|
||||
m_ShouldAuthenticate = IniFile.GetValueSetB("Authentication", "Authenticate", true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash)
|
||||
{
|
||||
if (!m_ShouldAuthenticate)
|
||||
{
|
||||
cRoot::Get()->AuthenticateUser(a_ClientID, a_UserName, cClientHandle::GenerateOfflineUUID(a_UserName));
|
||||
return;
|
||||
}
|
||||
|
||||
cCSLock LOCK(m_CS);
|
||||
m_Queue.push_back(cUser(a_ClientID, a_UserName, a_ServerHash));
|
||||
m_QueueNonempty.Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Start(cIniFile & IniFile)
|
||||
{
|
||||
ReadINI(IniFile);
|
||||
m_ShouldTerminate = false;
|
||||
super::Start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Stop(void)
|
||||
{
|
||||
m_ShouldTerminate = true;
|
||||
m_QueueNonempty.Set();
|
||||
Wait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cAuthenticator::Execute(void)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
while (!m_ShouldTerminate && (m_Queue.size() == 0))
|
||||
{
|
||||
cCSUnlock Unlock(Lock);
|
||||
m_QueueNonempty.Wait();
|
||||
}
|
||||
if (m_ShouldTerminate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ASSERT(!m_Queue.empty());
|
||||
|
||||
cAuthenticator::cUser & User = m_Queue.front();
|
||||
int ClientID = User.m_ClientID;
|
||||
AString UserName = User.m_Name;
|
||||
AString ServerID = User.m_ServerID;
|
||||
m_Queue.pop_front();
|
||||
Lock.Unlock();
|
||||
|
||||
AString NewUserName = UserName;
|
||||
AString UUID;
|
||||
if (AuthWithYggdrasil(NewUserName, ServerID, UUID))
|
||||
{
|
||||
LOGINFO("User %s authenticated with UUID '%s'", NewUserName.c_str(), UUID.c_str());
|
||||
cRoot::Get()->AuthenticateUser(ClientID, NewUserName, UUID);
|
||||
}
|
||||
else
|
||||
{
|
||||
cRoot::Get()->KickUser(ClientID, "Failed to authenticate account!");
|
||||
}
|
||||
} // for (-ever)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cAuthenticator::AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID)
|
||||
{
|
||||
LOGD("Trying to auth user %s", a_UserName.c_str());
|
||||
|
||||
int ret, server_fd = -1;
|
||||
unsigned char buf[1024];
|
||||
const char *pers = "cAuthenticator";
|
||||
|
||||
entropy_context entropy;
|
||||
ctr_drbg_context ctr_drbg;
|
||||
ssl_context ssl;
|
||||
x509_crt cacert;
|
||||
|
||||
/* Initialize the RNG and the session data */
|
||||
memset(&ssl, 0, sizeof(ssl_context));
|
||||
x509_crt_init(&cacert);
|
||||
|
||||
entropy_init(&entropy);
|
||||
if ((ret = ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ctr_drbg_init returned %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Initialize certificates */
|
||||
// TODO: Grab the sessionserver's root CA and any intermediates and hard-code them here, instead of test_ca_list
|
||||
ret = x509_crt_parse(&cacert, (const unsigned char *)test_ca_list, strlen(test_ca_list));
|
||||
|
||||
if (ret < 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: x509_crt_parse returned -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Connect */
|
||||
if ((ret = net_connect(&server_fd, m_Server.c_str(), 443)) != 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: Can't connect to %s: %d", m_Server.c_str(), ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Setup */
|
||||
if ((ret = ssl_init(&ssl)) != 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_init returned %d", ret);
|
||||
return false;
|
||||
}
|
||||
ssl_set_endpoint(&ssl, SSL_IS_CLIENT);
|
||||
ssl_set_authmode(&ssl, SSL_VERIFY_OPTIONAL);
|
||||
ssl_set_ca_chain(&ssl, &cacert, NULL, "PolarSSL Server 1");
|
||||
ssl_set_rng(&ssl, ctr_drbg_random, &ctr_drbg);
|
||||
ssl_set_bio(&ssl, net_recv, &server_fd, net_send, &server_fd);
|
||||
|
||||
/* Handshake */
|
||||
while ((ret = ssl_handshake(&ssl)) != 0)
|
||||
{
|
||||
if ((ret != POLARSSL_ERR_NET_WANT_READ) && (ret != POLARSSL_ERR_NET_WANT_WRITE))
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_handshake returned -0x%x", -ret);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write the GET request */
|
||||
AString ActualAddress = m_Address;
|
||||
ReplaceString(ActualAddress, "%USERNAME%", a_UserName);
|
||||
ReplaceString(ActualAddress, "%SERVERID%", a_ServerId);
|
||||
|
||||
AString Request;
|
||||
Request += "GET " + ActualAddress + " HTTP/1.1\r\n";
|
||||
Request += "Host: " + m_Server + "\r\n";
|
||||
Request += "User-Agent: MCServer\r\n";
|
||||
Request += "Connection: close\r\n";
|
||||
Request += "\r\n";
|
||||
|
||||
ret = ssl_write(&ssl, (const unsigned char *)Request.c_str(), Request.size());
|
||||
if (ret <= 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_write returned %d", ret);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read the HTTP response */
|
||||
std::string Response;
|
||||
for (;;)
|
||||
{
|
||||
memset(buf, 0, sizeof(buf));
|
||||
ret = ssl_read(&ssl, buf, sizeof(buf));
|
||||
|
||||
if ((ret == POLARSSL_ERR_NET_WANT_READ) || (ret == POLARSSL_ERR_NET_WANT_WRITE))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (ret < 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: ssl_read returned %d", ret);
|
||||
break;
|
||||
}
|
||||
if (ret == 0)
|
||||
{
|
||||
LOGWARNING("cAuthenticator: EOF");
|
||||
break;
|
||||
}
|
||||
|
||||
Response.append((const char *)buf, ret);
|
||||
}
|
||||
|
||||
ssl_close_notify(&ssl);
|
||||
x509_crt_free(&cacert);
|
||||
net_close(server_fd);
|
||||
ssl_free(&ssl);
|
||||
entropy_free(&entropy);
|
||||
memset(&ssl, 0, sizeof(ssl));
|
||||
|
||||
// Check the HTTP status line:
|
||||
AString prefix("HTTP/1.1 200 OK");
|
||||
AString HexDump;
|
||||
if (Response.compare(0, prefix.size(), prefix))
|
||||
{
|
||||
LOGINFO("User \"%s\" failed to auth, bad http status line received", a_UserName.c_str());
|
||||
LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Erase the HTTP headers from the response:
|
||||
size_t idxHeadersEnd = Response.find("\r\n\r\n");
|
||||
if (idxHeadersEnd == AString::npos)
|
||||
{
|
||||
LOGINFO("User \"%s\" failed to authenticate, bad http response header received", a_UserName.c_str());
|
||||
LOG("Response: \n%s", CreateHexDump(HexDump, Response.data(), Response.size(), 16).c_str());
|
||||
return false;
|
||||
}
|
||||
Response.erase(0, idxHeadersEnd + 4);
|
||||
|
||||
// Parse the Json response:
|
||||
if (Response.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Json::Value root;
|
||||
Json::Reader reader;
|
||||
if (!reader.parse(Response, root, false))
|
||||
{
|
||||
LOGWARNING("cAuthenticator: Cannot parse Received Data to json!");
|
||||
return false;
|
||||
}
|
||||
a_UserName = root.get("name", "Unknown").asString();
|
||||
a_UUID = root.get("id", "").asString();
|
||||
|
||||
// If the UUID doesn't contain the hashes, insert them at the proper places:
|
||||
if (a_UUID.size() == 32)
|
||||
{
|
||||
a_UUID.insert(8, "-");
|
||||
a_UUID.insert(13, "-");
|
||||
a_UUID.insert(18, "-");
|
||||
a_UUID.insert(23, "-");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#ifndef CAUTHENTICATOR_H_INCLUDED
|
||||
#define CAUTHENTICATOR_H_INCLUDED
|
||||
|
||||
#include "OSSupport/IsThread.h"
|
||||
#include "../OSSupport/IsThread.h"
|
||||
|
||||
|
||||
|
||||
@ -36,16 +36,16 @@ public:
|
||||
cAuthenticator(void);
|
||||
~cAuthenticator();
|
||||
|
||||
/// (Re-)read server and address from INI:
|
||||
/** (Re-)read server and address from INI: */
|
||||
void ReadINI(cIniFile & IniFile);
|
||||
|
||||
/// Queues a request for authenticating a user. If the auth fails, the user is kicked
|
||||
/** Queues a request for authenticating a user. If the auth fails, the user will be kicked */
|
||||
void Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash);
|
||||
|
||||
/// Starts the authenticator thread. The thread may be started and stopped repeatedly
|
||||
/** Starts the authenticator thread. The thread may be started and stopped repeatedly */
|
||||
void Start(cIniFile & IniFile);
|
||||
|
||||
/// Stops the authenticator thread. The thread may be started and stopped repeatedly
|
||||
/** Stops the authenticator thread. The thread may be started and stopped repeatedly */
|
||||
void Stop(void);
|
||||
|
||||
private:
|
||||
@ -75,11 +75,11 @@ private:
|
||||
AString m_Address;
|
||||
bool m_ShouldAuthenticate;
|
||||
|
||||
// cIsThread override:
|
||||
/** cIsThread override: */
|
||||
virtual void Execute(void) override;
|
||||
|
||||
// Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep)
|
||||
bool AuthFromAddress(const AString & a_Server, const AString & a_Address, const AString & a_UserName, int a_Level = 1);
|
||||
/** Returns true if the user authenticated okay, false on error; iLevel is the recursion deptht (bails out if too deep) */
|
||||
bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID);
|
||||
};
|
||||
|
||||
|
@ -83,6 +83,7 @@ public:
|
||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
|
||||
virtual void SendKeepAlive (int a_PingID) = 0;
|
||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 0;
|
||||
virtual void SendLoginSuccess (void) = 0;
|
||||
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) = 0;
|
||||
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) = 0;
|
||||
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0;
|
||||
|
@ -595,6 +595,15 @@ void cProtocol125::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendLoginSuccess(void)
|
||||
{
|
||||
// Not supported in this protocol version
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
@ -643,6 +652,17 @@ void cProtocol125::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendMapInfo(int a_ID, unsigned int a_Scale)
|
||||
{
|
||||
// This protocol doesn't support such message
|
||||
UNUSED(a_ID);
|
||||
UNUSED(a_Scale);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
@ -685,6 +705,16 @@ void cProtocol125::SendParticleEffect(const AString & a_ParticleName, float a_Sr
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendPaintingSpawn(const cPainting & a_Painting)
|
||||
{
|
||||
// Not implemented in this protocol version
|
||||
UNUSED(a_Painting);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
|
||||
{
|
||||
cCSLock Lock(m_CSPacket);
|
||||
@ -846,6 +876,18 @@ void cProtocol125::SendExperienceOrb(const cExpOrb & a_ExpOrb)
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
|
||||
{
|
||||
// This protocol version doesn't support such message
|
||||
UNUSED(a_Name);
|
||||
UNUSED(a_DisplayName);
|
||||
UNUSED(a_Mode);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol125::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch)
|
||||
{
|
||||
// Not needed in this protocol version
|
||||
|
@ -56,19 +56,12 @@ public:
|
||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||
virtual void SendKeepAlive (int a_PingID) override;
|
||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||
virtual void SendLoginSuccess (void) override;
|
||||
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
|
||||
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
|
||||
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override
|
||||
{
|
||||
// This protocol doesn't support such message
|
||||
UNUSED(a_ID);
|
||||
UNUSED(a_Scale);
|
||||
}
|
||||
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
|
||||
virtual void SendParticleEffect (const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount) override;
|
||||
virtual void SendPaintingSpawn (const cPainting & a_Painting) override
|
||||
{
|
||||
UNUSED(a_Painting);
|
||||
};
|
||||
virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
|
||||
virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
|
||||
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
|
||||
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
|
||||
@ -82,12 +75,7 @@ public:
|
||||
virtual void SendRespawn (void) override;
|
||||
virtual void SendExperience (void) override;
|
||||
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
|
||||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override
|
||||
{
|
||||
UNUSED(a_Name);
|
||||
UNUSED(a_DisplayName);
|
||||
UNUSED(a_Mode);
|
||||
} // This protocol doesn't support such message
|
||||
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) override;
|
||||
virtual void SendScoreUpdate (const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode) override {} // This protocol doesn't support such message
|
||||
virtual void SendDisplayObjective (const AString & a_Objective, cScoreboard::eDisplaySlot a_Display) override {} // This protocol doesn't support such message
|
||||
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
|
||||
|
@ -88,8 +88,9 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
|
||||
// Create the comm log file, if so requested:
|
||||
if (g_ShouldLogCommIn || g_ShouldLogCommOut)
|
||||
{
|
||||
static int sCounter = 0;
|
||||
cFile::CreateFolder("CommLogs");
|
||||
AString FileName = Printf("CommLogs/%x__%s.log", (unsigned)time(NULL), a_Client->GetIPString().c_str());
|
||||
AString FileName = Printf("CommLogs/%x_%d__%s.log", (unsigned)time(NULL), sCounter++, a_Client->GetIPString().c_str());
|
||||
m_CommLogFile.Open(FileName, cFile::fmWrite);
|
||||
}
|
||||
}
|
||||
@ -124,6 +125,8 @@ void cProtocol172::DataReceived(const char * a_Data, size_t a_Size)
|
||||
|
||||
void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_Vehicle)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x1b); // Attach Entity packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteInt((a_Vehicle != NULL) ? a_Vehicle->GetUniqueID() : 0);
|
||||
@ -136,6 +139,8 @@ void cProtocol172::SendAttachEntity(const cEntity & a_Entity, const cEntity * a_
|
||||
|
||||
void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Byte1, char a_Byte2, BLOCKTYPE a_BlockType)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x24); // Block Action packet
|
||||
Pkt.WriteInt(a_BlockX);
|
||||
Pkt.WriteShort(a_BlockY);
|
||||
@ -151,6 +156,8 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
|
||||
|
||||
void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x25); // Block Break Animation packet
|
||||
Pkt.WriteVarInt(a_EntityID);
|
||||
Pkt.WriteInt(a_BlockX);
|
||||
@ -165,6 +172,8 @@ void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY
|
||||
|
||||
void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x23); // Block Change packet
|
||||
Pkt.WriteInt(a_BlockX);
|
||||
Pkt.WriteByte(a_BlockY);
|
||||
@ -179,6 +188,8 @@ void cProtocol172::SendBlockChange(int a_BlockX, int a_BlockY, int a_BlockZ, BLO
|
||||
|
||||
void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockVector & a_Changes)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x22); // Multi Block Change packet
|
||||
Pkt.WriteInt(a_ChunkX);
|
||||
Pkt.WriteInt(a_ChunkZ);
|
||||
@ -198,6 +209,8 @@ void cProtocol172::SendBlockChanges(int a_ChunkX, int a_ChunkZ, const sSetBlockV
|
||||
|
||||
void cProtocol172::SendChat(const AString & a_Message)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x02); // Chat Message packet
|
||||
Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str()));
|
||||
}
|
||||
@ -208,6 +221,8 @@ void cProtocol172::SendChat(const AString & a_Message)
|
||||
|
||||
void cProtocol172::SendChat(const cCompositeChat & a_Message)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
// Compose the complete Json string to send:
|
||||
Json::Value msg;
|
||||
msg["text"] = ""; // The client crashes without this
|
||||
@ -280,6 +295,8 @@ void cProtocol172::SendChat(const cCompositeChat & a_Message)
|
||||
|
||||
void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerializer & a_Serializer)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
// Serialize first, before creating the Packetizer (the packetizer locks a CS)
|
||||
// This contains the flags and bitmasks, too
|
||||
const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2);
|
||||
@ -296,6 +313,8 @@ void cProtocol172::SendChunkData(int a_ChunkX, int a_ChunkZ, cChunkDataSerialize
|
||||
|
||||
void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a_Player)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x0d); // Collect Item packet
|
||||
Pkt.WriteInt(a_Pickup.GetUniqueID());
|
||||
Pkt.WriteInt(a_Player.GetUniqueID());
|
||||
@ -307,6 +326,8 @@ void cProtocol172::SendCollectPickup(const cPickup & a_Pickup, const cPlayer & a
|
||||
|
||||
void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x13); // Destroy Entities packet
|
||||
Pkt.WriteByte(1);
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
@ -343,6 +364,8 @@ void cProtocol172::SendDisconnect(const AString & a_Reason)
|
||||
|
||||
void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet
|
||||
Pkt.WriteInt(a_BlockX);
|
||||
Pkt.WriteInt(a_BlockY);
|
||||
@ -355,6 +378,8 @@ void cProtocol172::SendEditSign(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
|
||||
void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, int a_Amplifier, short a_Duration)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x1D); // Entity Effect packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteByte(a_EffectID);
|
||||
@ -368,6 +393,8 @@ void cProtocol172::SendEntityEffect(const cEntity & a_Entity, int a_EffectID, in
|
||||
|
||||
void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum, const cItem & a_Item)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x04); // Entity Equipment packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteShort(a_SlotNum);
|
||||
@ -380,6 +407,8 @@ void cProtocol172::SendEntityEquipment(const cEntity & a_Entity, short a_SlotNum
|
||||
|
||||
void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x19); // Entity Head Look packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
|
||||
@ -391,6 +420,8 @@ void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
|
||||
|
||||
void cProtocol172::SendEntityLook(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x16); // Entity Look packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteByteAngle(a_Entity.GetYaw());
|
||||
@ -403,6 +434,8 @@ void cProtocol172::SendEntityLook(const cEntity & a_Entity)
|
||||
|
||||
void cProtocol172::SendEntityMetadata(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteEntityMetadata(a_Entity);
|
||||
@ -415,6 +448,8 @@ void cProtocol172::SendEntityMetadata(const cEntity & a_Entity)
|
||||
|
||||
void cProtocol172::SendEntityProperties(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x20); // Entity Properties packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteEntityProperties(a_Entity);
|
||||
@ -426,6 +461,8 @@ void cProtocol172::SendEntityProperties(const cEntity & a_Entity)
|
||||
|
||||
void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteByte(a_RelX);
|
||||
@ -439,6 +476,8 @@ void cProtocol172::SendEntityRelMove(const cEntity & a_Entity, char a_RelX, char
|
||||
|
||||
void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX, char a_RelY, char a_RelZ)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteByte(a_RelX);
|
||||
@ -454,6 +493,8 @@ void cProtocol172::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
|
||||
|
||||
void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x1a); // Entity Status packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteChar(a_Status);
|
||||
@ -465,6 +506,8 @@ void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status)
|
||||
|
||||
void cProtocol172::SendEntityVelocity(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x12); // Entity Velocity packet
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
// 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick
|
||||
@ -479,6 +522,8 @@ void cProtocol172::SendEntityVelocity(const cEntity & a_Entity)
|
||||
|
||||
void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_BlockZ, float a_Radius, const cVector3iArray & a_BlocksAffected, const Vector3d & a_PlayerMotion)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x27); // Explosion packet
|
||||
Pkt.WriteFloat((float)a_BlockX);
|
||||
Pkt.WriteFloat((float)a_BlockY);
|
||||
@ -502,6 +547,8 @@ void cProtocol172::SendExplosion(double a_BlockX, double a_BlockY, double a_Bloc
|
||||
|
||||
void cProtocol172::SendGameMode(eGameMode a_GameMode)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
|
||||
Pkt.WriteByte(3); // Reason: Change game mode
|
||||
Pkt.WriteFloat((float)a_GameMode);
|
||||
@ -513,6 +560,8 @@ void cProtocol172::SendGameMode(eGameMode a_GameMode)
|
||||
|
||||
void cProtocol172::SendHealth(void)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x06); // Update Health packet
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
Pkt.WriteFloat((float)Player->GetHealth());
|
||||
@ -526,6 +575,8 @@ void cProtocol172::SendHealth(void)
|
||||
|
||||
void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cItem & a_Item)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x2f); // Set Slot packet
|
||||
Pkt.WriteChar(a_WindowID);
|
||||
Pkt.WriteShort(a_SlotNum);
|
||||
@ -538,6 +589,13 @@ void cProtocol172::SendInventorySlot(char a_WindowID, short a_SlotNum, const cIt
|
||||
|
||||
void cProtocol172::SendKeepAlive(int a_PingID)
|
||||
{
|
||||
// Drop the packet if the protocol is not in the Game state yet (caused a client crash):
|
||||
if (m_State != 3)
|
||||
{
|
||||
LOGWARNING("Trying to send a KeepAlive packet to a player who's not yet fully logged in (%d). The protocol class prevented the packet.", m_State);
|
||||
return;
|
||||
}
|
||||
|
||||
cPacketizer Pkt(*this, 0x00); // Keep Alive packet
|
||||
Pkt.WriteInt(a_PingID);
|
||||
}
|
||||
@ -575,8 +633,25 @@ void cProtocol172::SendLogin(const cPlayer & a_Player, const cWorld & a_World)
|
||||
|
||||
|
||||
|
||||
void cProtocol172::SendLoginSuccess(void)
|
||||
{
|
||||
ASSERT(m_State == 2); // State: login?
|
||||
|
||||
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||
Pkt.WriteString(m_Client->GetUUID());
|
||||
Pkt.WriteString(m_Client->GetUsername());
|
||||
|
||||
m_State = 3; // State = Game
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x10); // Spawn Painting packet
|
||||
Pkt.WriteVarInt(a_Painting.GetUniqueID());
|
||||
Pkt.WriteString(a_Painting.GetName().c_str());
|
||||
@ -592,6 +667,8 @@ void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
|
||||
|
||||
void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x34);
|
||||
Pkt.WriteVarInt(a_ID);
|
||||
Pkt.WriteShort (3 + a_Length);
|
||||
@ -612,6 +689,8 @@ void cProtocol172::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colo
|
||||
|
||||
void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x34);
|
||||
Pkt.WriteVarInt(a_ID);
|
||||
Pkt.WriteShort (1 + (3 * a_Decorators.size()));
|
||||
@ -632,6 +711,8 @@ void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decor
|
||||
|
||||
void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x34);
|
||||
Pkt.WriteVarInt(a_ID);
|
||||
Pkt.WriteShort (2);
|
||||
@ -647,6 +728,8 @@ void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
|
||||
|
||||
void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
|
||||
Pkt.WriteVarInt(a_Pickup.GetUniqueID());
|
||||
@ -673,6 +756,8 @@ void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
|
||||
|
||||
void cProtocol172::SendPlayerAbilities(void)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x39); // Player Abilities packet
|
||||
Byte Flags = 0;
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
@ -700,6 +785,8 @@ void cProtocol172::SendPlayerAbilities(void)
|
||||
|
||||
void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x0b); // Animation packet
|
||||
Pkt.WriteVarInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteChar(a_Animation);
|
||||
@ -711,6 +798,8 @@ void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animatio
|
||||
|
||||
void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_SrcX, float a_SrcY, float a_SrcZ, float a_OffsetX, float a_OffsetY, float a_OffsetZ, float a_ParticleData, int a_ParticleAmmount)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x2A);
|
||||
Pkt.WriteString(a_ParticleName);
|
||||
Pkt.WriteFloat(a_SrcX);
|
||||
@ -729,6 +818,8 @@ void cProtocol172::SendParticleEffect(const AString & a_ParticleName, float a_Sr
|
||||
|
||||
void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
|
||||
Pkt.WriteString(a_Player.GetName());
|
||||
Pkt.WriteBool(a_IsOnline);
|
||||
@ -741,6 +832,8 @@ void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
|
||||
|
||||
void cProtocol172::SendPlayerMaxSpeed(void)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x20); // Entity Properties
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
Pkt.WriteInt(Player->GetUniqueID());
|
||||
@ -768,6 +861,8 @@ void cProtocol172::SendPlayerMaxSpeed(void)
|
||||
|
||||
void cProtocol172::SendPlayerMoveLook(void)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x08); // Player Position And Look packet
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
Pkt.WriteDouble(Player->GetPosX());
|
||||
@ -798,10 +893,12 @@ void cProtocol172::SendPlayerPosition(void)
|
||||
|
||||
void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
// Called to spawn another player for the client
|
||||
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
|
||||
Pkt.WriteVarInt(a_Player.GetUniqueID());
|
||||
Pkt.WriteString(Printf("%d", a_Player.GetUniqueID())); // TODO: Proper UUID
|
||||
Pkt.WriteString(a_Player.GetClientHandle()->GetUUID());
|
||||
Pkt.WriteString(a_Player.GetName());
|
||||
Pkt.WriteFPInt(a_Player.GetPosX());
|
||||
Pkt.WriteFPInt(a_Player.GetPosY());
|
||||
@ -821,6 +918,8 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
|
||||
|
||||
void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x3f);
|
||||
Pkt.WriteString(a_Channel);
|
||||
Pkt.WriteShort((short)a_Message.size());
|
||||
@ -833,7 +932,9 @@ void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString &
|
||||
|
||||
void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x1E);
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x1e);
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteByte(a_EffectID);
|
||||
}
|
||||
@ -858,7 +959,9 @@ void cProtocol172::SendRespawn(void)
|
||||
|
||||
void cProtocol172::SendExperience (void)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x1F); //Experience Packet
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x1f); // Experience Packet
|
||||
cPlayer * Player = m_Client->GetPlayer();
|
||||
Pkt.WriteFloat(Player->GetXpPercentage());
|
||||
Pkt.WriteShort(Player->GetXpLevel());
|
||||
@ -871,6 +974,8 @@ void cProtocol172::SendExperience (void)
|
||||
|
||||
void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x11);
|
||||
Pkt.WriteVarInt(a_ExpOrb.GetUniqueID());
|
||||
Pkt.WriteInt((int) a_ExpOrb.GetPosX());
|
||||
@ -885,7 +990,9 @@ void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
|
||||
|
||||
void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString & a_DisplayName, Byte a_Mode)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x3B);
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x3b);
|
||||
Pkt.WriteString(a_Name);
|
||||
Pkt.WriteString(a_DisplayName);
|
||||
Pkt.WriteByte(a_Mode);
|
||||
@ -897,7 +1004,9 @@ void cProtocol172::SendScoreboardObjective(const AString & a_Name, const AString
|
||||
|
||||
void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString & a_Player, cObjective::Score a_Score, Byte a_Mode)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x3C);
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x3c);
|
||||
Pkt.WriteString(a_Player);
|
||||
Pkt.WriteByte(a_Mode);
|
||||
|
||||
@ -914,7 +1023,9 @@ void cProtocol172::SendScoreUpdate(const AString & a_Objective, const AString &
|
||||
|
||||
void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard::eDisplaySlot a_Display)
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x3D);
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x3d);
|
||||
Pkt.WriteByte((int) a_Display);
|
||||
Pkt.WriteString(a_Objective);
|
||||
}
|
||||
@ -925,6 +1036,8 @@ void cProtocol172::SendDisplayObjective(const AString & a_Objective, cScoreboard
|
||||
|
||||
void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) // a_Src coords are Block * 8
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x29); // Sound Effect packet
|
||||
Pkt.WriteString(a_SoundName);
|
||||
Pkt.WriteInt(a_SrcX);
|
||||
@ -940,6 +1053,8 @@ void cProtocol172::SendSoundEffect(const AString & a_SoundName, int a_SrcX, int
|
||||
|
||||
void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_SrcY, int a_SrcZ, int a_Data)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x28); // Effect packet
|
||||
Pkt.WriteInt(a_EffectID);
|
||||
Pkt.WriteInt(a_SrcX);
|
||||
@ -955,6 +1070,8 @@ void cProtocol172::SendSoundParticleEffect(int a_EffectID, int a_SrcX, int a_Src
|
||||
|
||||
void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
|
||||
Pkt.WriteVarInt(a_FallingBlock.GetUniqueID());
|
||||
Pkt.WriteByte(70); // Falling block
|
||||
@ -975,6 +1092,8 @@ void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
|
||||
|
||||
void cProtocol172::SendSpawnMob(const cMonster & a_Mob)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet
|
||||
Pkt.WriteVarInt(a_Mob.GetUniqueID());
|
||||
Pkt.WriteByte((Byte)a_Mob.GetMobType());
|
||||
@ -997,6 +1116,8 @@ void cProtocol172::SendSpawnMob(const cMonster & a_Mob)
|
||||
|
||||
void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
|
||||
Pkt.WriteVarInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteByte(a_ObjectType);
|
||||
@ -1020,6 +1141,8 @@ void cProtocol172::SendSpawnObject(const cEntity & a_Entity, char a_ObjectType,
|
||||
|
||||
void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0xe); // Spawn Object packet
|
||||
Pkt.WriteVarInt(a_Vehicle.GetUniqueID());
|
||||
Pkt.WriteByte(a_VehicleType);
|
||||
@ -1043,6 +1166,8 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
|
||||
|
||||
void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet
|
||||
Pkt.WriteVarInt(a_Results.size());
|
||||
|
||||
@ -1058,6 +1183,8 @@ void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
|
||||
|
||||
void cProtocol172::SendTeleportEntity(const cEntity & a_Entity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x18);
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteFPInt(a_Entity.GetPosX());
|
||||
@ -1073,6 +1200,8 @@ void cProtocol172::SendTeleportEntity(const cEntity & a_Entity)
|
||||
|
||||
void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet
|
||||
Pkt.WriteVarInt(0); // EntityID = 0, always
|
||||
Pkt.WriteByte(1); // Type = Thunderbolt
|
||||
@ -1087,6 +1216,8 @@ void cProtocol172::SendThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
|
||||
void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x03);
|
||||
Pkt.WriteInt64(a_WorldAge);
|
||||
Pkt.WriteInt64(a_TimeOfDay);
|
||||
@ -1098,6 +1229,8 @@ void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
|
||||
|
||||
void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x21); // Chunk Data packet
|
||||
Pkt.WriteInt(a_ChunkX);
|
||||
Pkt.WriteInt(a_ChunkZ);
|
||||
@ -1112,6 +1245,8 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
|
||||
|
||||
void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x35); // Update tile entity packet
|
||||
Pkt.WriteInt(a_BlockEntity.GetPosX());
|
||||
Pkt.WriteShort(a_BlockEntity.GetPosY());
|
||||
@ -1137,6 +1272,8 @@ void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
|
||||
|
||||
void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x33);
|
||||
Pkt.WriteInt(a_BlockX);
|
||||
Pkt.WriteShort((short)a_BlockY);
|
||||
@ -1154,6 +1291,8 @@ void cProtocol172::SendUpdateSign(int a_BlockX, int a_BlockY, int a_BlockZ, cons
|
||||
|
||||
void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x0a);
|
||||
Pkt.WriteInt(a_Entity.GetUniqueID());
|
||||
Pkt.WriteInt(a_BlockX);
|
||||
@ -1167,6 +1306,8 @@ void cProtocol172::SendUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bloc
|
||||
|
||||
void cProtocol172::SendWeather(eWeather a_Weather)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x2b); // Change Game State packet
|
||||
Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain
|
||||
@ -1182,6 +1323,8 @@ void cProtocol172::SendWeather(eWeather a_Weather)
|
||||
|
||||
void cProtocol172::SendWholeInventory(const cWindow & a_Window)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x30); // Window Items packet
|
||||
Pkt.WriteChar(a_Window.GetWindowID());
|
||||
Pkt.WriteShort(a_Window.GetNumSlots());
|
||||
@ -1199,6 +1342,8 @@ void cProtocol172::SendWholeInventory(const cWindow & a_Window)
|
||||
|
||||
void cProtocol172::SendWindowClose(const cWindow & a_Window)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x2e);
|
||||
Pkt.WriteChar(a_Window.GetWindowID());
|
||||
}
|
||||
@ -1209,6 +1354,8 @@ void cProtocol172::SendWindowClose(const cWindow & a_Window)
|
||||
|
||||
void cProtocol172::SendWindowOpen(const cWindow & a_Window)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
if (a_Window.GetWindowType() < 0)
|
||||
{
|
||||
// Do not send this packet for player inventory windows
|
||||
@ -1233,6 +1380,8 @@ void cProtocol172::SendWindowOpen(const cWindow & a_Window)
|
||||
|
||||
void cProtocol172::SendWindowProperty(const cWindow & a_Window, short a_Property, short a_Value)
|
||||
{
|
||||
ASSERT(m_State == 3); // In game mode?
|
||||
|
||||
cPacketizer Pkt(*this, 0x31); // Window Property packet
|
||||
Pkt.WriteChar(a_Window.GetWindowID());
|
||||
Pkt.WriteShort(a_Property);
|
||||
@ -1563,15 +1712,6 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
|
||||
}
|
||||
|
||||
StartEncryption(DecryptedKey);
|
||||
|
||||
// Send login success:
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||
Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID
|
||||
Pkt.WriteString(m_Client->GetUsername());
|
||||
}
|
||||
|
||||
m_State = 3; // State = Game
|
||||
m_Client->HandleLogin(4, m_Client->GetUsername());
|
||||
}
|
||||
|
||||
@ -1605,14 +1745,6 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
|
||||
return;
|
||||
}
|
||||
|
||||
// Send login success:
|
||||
{
|
||||
cPacketizer Pkt(*this, 0x02); // Login success packet
|
||||
Pkt.WriteString(Printf("%d", m_Client->GetUniqueID())); // TODO: proper UUID
|
||||
Pkt.WriteString(Username);
|
||||
}
|
||||
|
||||
m_State = 3; // State = Game
|
||||
m_Client->HandleLogin(4, Username);
|
||||
}
|
||||
|
||||
@ -2766,3 +2898,64 @@ void cProtocol172::cPacketizer::WriteEntityProperties(const cEntity & a_Entity)
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cProtocol176:
|
||||
|
||||
cProtocol176::cProtocol176(cClientHandle * a_Client, const AString &a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) :
|
||||
super(a_Client, a_ServerAddress, a_ServerPort, a_State)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol176::SendPlayerSpawn(const cPlayer & a_Player)
|
||||
{
|
||||
// Called to spawn another player for the client
|
||||
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
|
||||
Pkt.WriteVarInt(a_Player.GetUniqueID());
|
||||
Pkt.WriteString(a_Player.GetClientHandle()->GetUUID());
|
||||
Pkt.WriteString(a_Player.GetName());
|
||||
Pkt.WriteVarInt(0); // We have no data to send here
|
||||
Pkt.WriteFPInt(a_Player.GetPosX());
|
||||
Pkt.WriteFPInt(a_Player.GetPosY());
|
||||
Pkt.WriteFPInt(a_Player.GetPosZ());
|
||||
Pkt.WriteByteAngle(a_Player.GetYaw());
|
||||
Pkt.WriteByteAngle(a_Player.GetPitch());
|
||||
short ItemType = a_Player.GetEquippedItem().IsEmpty() ? 0 : a_Player.GetEquippedItem().m_ItemType;
|
||||
Pkt.WriteShort(ItemType);
|
||||
Pkt.WriteByte((3 << 5) | 6); // Metadata: float + index 6
|
||||
Pkt.WriteFloat((float)a_Player.GetHealth());
|
||||
Pkt.WriteByte(0x7f); // Metadata: end
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocol176::HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer)
|
||||
{
|
||||
// Send the response:
|
||||
AString Response = "{\"version\":{\"name\":\"1.7.6\",\"protocol\":5},\"players\":{";
|
||||
AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},",
|
||||
cRoot::Get()->GetServer()->GetMaxPlayers(),
|
||||
cRoot::Get()->GetServer()->GetNumPlayers()
|
||||
);
|
||||
AppendPrintf(Response, "\"description\":{\"text\":\"%s\"},",
|
||||
cRoot::Get()->GetServer()->GetDescription().c_str()
|
||||
);
|
||||
AppendPrintf(Response, "\"favicon\":\"data:image/png;base64,%s\"",
|
||||
cRoot::Get()->GetServer()->GetFaviconData().c_str()
|
||||
);
|
||||
Response.append("}");
|
||||
|
||||
cPacketizer Pkt(*this, 0x00); // Response packet
|
||||
Pkt.WriteString(Response);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -87,6 +87,7 @@ public:
|
||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||
virtual void SendKeepAlive (int a_PingID) override;
|
||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||
virtual void SendLoginSuccess (void) override;
|
||||
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
|
||||
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
|
||||
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
|
||||
@ -252,7 +253,7 @@ protected:
|
||||
|
||||
// Packet handlers while in the Status state (m_State == 1):
|
||||
void HandlePacketStatusPing (cByteBuffer & a_ByteBuffer);
|
||||
void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer);
|
||||
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer);
|
||||
|
||||
// Packet handlers while in the Login state (m_State == 2):
|
||||
void HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer);
|
||||
@ -306,3 +307,22 @@ protected:
|
||||
|
||||
|
||||
|
||||
|
||||
/** The version 5 lengthed protocol, used by 1.7.6 through 1.7.9. */
|
||||
class cProtocol176 :
|
||||
public cProtocol172
|
||||
{
|
||||
typedef cProtocol172 super;
|
||||
|
||||
public:
|
||||
cProtocol176(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State);
|
||||
|
||||
// cProtocol172 overrides:
|
||||
virtual void SendPlayerSpawn(const cPlayer & a_Player) override;
|
||||
virtual void HandlePacketStatusRequest(cByteBuffer & a_ByteBuffer) override;
|
||||
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -59,6 +59,7 @@ AString cProtocolRecognizer::GetVersionTextFromInt(int a_ProtocolVersion)
|
||||
case PROTO_VERSION_1_6_3: return "1.6.3";
|
||||
case PROTO_VERSION_1_6_4: return "1.6.4";
|
||||
case PROTO_VERSION_1_7_2: return "1.7.2";
|
||||
case PROTO_VERSION_1_7_6: return "1.7.6";
|
||||
}
|
||||
ASSERT(!"Unknown protocol version");
|
||||
return Printf("Unknown protocol (%d)", a_ProtocolVersion);
|
||||
@ -396,6 +397,16 @@ void cProtocolRecognizer::SendLogin(const cPlayer & a_Player, const cWorld & a_W
|
||||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendLoginSuccess(void)
|
||||
{
|
||||
ASSERT(m_Protocol != NULL);
|
||||
m_Protocol->SendLoginSuccess();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
|
||||
{
|
||||
ASSERT(m_Protocol != NULL);
|
||||
@ -965,6 +976,18 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
|
||||
m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
|
||||
return true;
|
||||
}
|
||||
case PROTO_VERSION_1_7_6:
|
||||
{
|
||||
AString ServerAddress;
|
||||
short ServerPort;
|
||||
UInt32 NextState;
|
||||
m_Buffer.ReadVarUTF8String(ServerAddress);
|
||||
m_Buffer.ReadBEShort(ServerPort);
|
||||
m_Buffer.ReadVarInt(NextState);
|
||||
m_Buffer.CommitRead();
|
||||
m_Protocol = new cProtocol176(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)",
|
||||
m_Client->GetIPString().c_str(), ProtocolVersion
|
||||
|
@ -18,8 +18,8 @@
|
||||
|
||||
|
||||
// Adjust these if a new protocol is added or an old one is removed:
|
||||
#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4"
|
||||
#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4"
|
||||
#define MCS_CLIENT_VERSIONS "1.2.4, 1.2.5, 1.3.1, 1.3.2, 1.4.2, 1.4.4, 1.4.5, 1.4.6, 1.4.7, 1.5, 1.5.1, 1.5.2, 1.6.1, 1.6.2, 1.6.3, 1.6.4, 1.7.2, 1.7.4, 1.7.5, 1.7.6, 1.7.7, 1.7.8, 1.7.9"
|
||||
#define MCS_PROTOCOL_VERSIONS "29, 39, 47, 49, 51, 60, 61, 73, 74, 77, 78, 4, 5"
|
||||
|
||||
|
||||
|
||||
@ -50,6 +50,7 @@ public:
|
||||
|
||||
// These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols
|
||||
PROTO_VERSION_1_7_2 = 4,
|
||||
PROTO_VERSION_1_7_6 = 5,
|
||||
} ;
|
||||
|
||||
cProtocolRecognizer(cClientHandle * a_Client);
|
||||
@ -90,6 +91,7 @@ public:
|
||||
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
|
||||
virtual void SendKeepAlive (int a_PingID) override;
|
||||
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) override;
|
||||
virtual void SendLoginSuccess (void) override;
|
||||
virtual void SendMapColumn (int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length) override;
|
||||
virtual void SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
|
||||
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;
|
||||
|
@ -499,9 +499,9 @@ void cRoot::KickUser(int a_ClientID, const AString & a_Reason)
|
||||
|
||||
|
||||
|
||||
void cRoot::AuthenticateUser(int a_ClientID)
|
||||
void cRoot::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID)
|
||||
{
|
||||
m_Server->AuthenticateUser(a_ClientID);
|
||||
m_Server->AuthenticateUser(a_ClientID, a_Name, a_UUID);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Authenticator.h"
|
||||
#include "Protocol/Authenticator.h"
|
||||
#include "HTTPServer/HTTPServer.h"
|
||||
#include "Defines.h"
|
||||
|
||||
@ -89,7 +89,7 @@ public:
|
||||
void KickUser(int a_ClientID, const AString & a_Reason);
|
||||
|
||||
/// Called by cAuthenticator to auth the specified user
|
||||
void AuthenticateUser(int a_ClientID);
|
||||
void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID);
|
||||
|
||||
/// Executes commands queued in the command queue
|
||||
void TickCommands(void);
|
||||
|
@ -615,14 +615,14 @@ void cServer::KickUser(int a_ClientID, const AString & a_Reason)
|
||||
|
||||
|
||||
|
||||
void cServer::AuthenticateUser(int a_ClientID)
|
||||
void cServer::AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID)
|
||||
{
|
||||
cCSLock Lock(m_CSClients);
|
||||
for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetUniqueID() == a_ClientID)
|
||||
{
|
||||
(*itr)->Authenticate();
|
||||
(*itr)->Authenticate(a_Name, a_UUID);
|
||||
return;
|
||||
}
|
||||
} // for itr - m_Clients[]
|
||||
|
@ -83,7 +83,7 @@ public: // tolua_export
|
||||
void Shutdown(void);
|
||||
|
||||
void KickUser(int a_ClientID, const AString & a_Reason);
|
||||
void AuthenticateUser(int a_ClientID); // Called by cAuthenticator to auth the specified user
|
||||
void AuthenticateUser(int a_ClientID, const AString & a_Name, const AString & a_UUID); // Called by cAuthenticator to auth the specified user
|
||||
|
||||
const AString & GetServerID(void) const { return m_ServerID; } // tolua_export
|
||||
|
||||
|
@ -69,18 +69,19 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
|
||||
// Checking only when a block is changed, as opposed to every tick, also improves performance
|
||||
|
||||
PoweredBlocksList * PoweredBlocks = a_Chunk->GetRedstoneSimulatorPoweredBlocksList();
|
||||
for (PoweredBlocksList::iterator itr = PoweredBlocks->begin(); itr != PoweredBlocks->end(); ++itr)
|
||||
for (PoweredBlocksList::iterator itr = PoweredBlocks->begin(); itr != PoweredBlocks->end();)
|
||||
{
|
||||
if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IsPotentialSource(Block))
|
||||
{
|
||||
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
|
||||
PoweredBlocks->erase(itr);
|
||||
break;
|
||||
itr = PoweredBlocks->erase(itr);
|
||||
continue;
|
||||
}
|
||||
else if (
|
||||
// Changeable sources
|
||||
@ -93,9 +94,10 @@ void cIncrementalRedstoneSimulator::RedstoneAddBlock(int a_BlockX, int a_BlockY,
|
||||
)
|
||||
{
|
||||
LOGD("cIncrementalRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
|
||||
PoweredBlocks->erase(itr);
|
||||
break;
|
||||
itr = PoweredBlocks->erase(itr);
|
||||
continue;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
|
||||
LinkedBlocksList * LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList();
|
||||
@ -532,15 +534,22 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block
|
||||
};
|
||||
|
||||
// Check to see if directly beside a power source
|
||||
if (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ))
|
||||
unsigned char MyPower;
|
||||
if (!IsWirePowered(a_BlockX, a_BlockY, a_BlockZ, MyPower))
|
||||
{
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0);
|
||||
m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MyPower);
|
||||
|
||||
if (MyPower < 1)
|
||||
{
|
||||
NIBBLETYPE MyMeta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||
NIBBLETYPE MetaToSet = MyMeta;
|
||||
int TimesMetaSmaller = 0, TimesFoundAWire = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
MyPower--;
|
||||
|
||||
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
|
||||
{
|
||||
@ -553,110 +562,71 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block
|
||||
}
|
||||
else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
|
||||
{
|
||||
if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z)))
|
||||
if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
BLOCKTYPE SurroundType;
|
||||
NIBBLETYPE SurroundMeta;
|
||||
m_World.GetBlockTypeMeta(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, SurroundType, SurroundMeta);
|
||||
|
||||
if (SurroundType == E_BLOCK_REDSTONE_WIRE)
|
||||
if (m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z) == E_BLOCK_REDSTONE_WIRE)
|
||||
{
|
||||
TimesFoundAWire++;
|
||||
|
||||
if (SurroundMeta > 1) // Wires of power 1 or 0 cannot transfer power TO ME, don't bother checking
|
||||
{
|
||||
// Does surrounding wire have a higher power level than the highest so far (MetaToSet)?
|
||||
// >= to fix a bug where wires bordering each other with the same power level will appear (in terms of meta) to power each other, when they aren't actually in the powered list
|
||||
if (SurroundMeta >= MetaToSet)
|
||||
{
|
||||
MetaToSet = SurroundMeta - 1; // To improve performance
|
||||
SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
}
|
||||
}
|
||||
|
||||
if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's
|
||||
{
|
||||
TimesMetaSmaller++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((TimesMetaSmaller == TimesFoundAWire) && (MyMeta != 0))
|
||||
{
|
||||
// All surrounding metas were smaller - self must have been a wire that was
|
||||
// transferring power to other wires around.
|
||||
// However, self not directly powered anymore, so source must have been removed,
|
||||
// therefore, self must be set to meta zero
|
||||
m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock
|
||||
return; // No need to process block power sets because self not powered
|
||||
}
|
||||
else if (MyMeta != MetaToSet)
|
||||
{
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, MetaToSet);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) != 0) // A powered wire
|
||||
{
|
||||
for (size_t i = 0; i < ARRAYCOUNT(gSideCoords); i++) // Look for repeaters immediately surrounding self and try to power them
|
||||
{
|
||||
if (m_World.GetBlock(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z) == E_BLOCK_REDSTONE_REPEATER_OFF)
|
||||
{
|
||||
SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX + gSideCoords[i].x, a_BlockY + gSideCoords[i].y, a_BlockZ + gSideCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
}
|
||||
}
|
||||
|
||||
// Wire still powered, power blocks beneath
|
||||
SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
|
||||
switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ))
|
||||
{
|
||||
case REDSTONE_NONE:
|
||||
{
|
||||
SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
break;
|
||||
}
|
||||
case REDSTONE_X_POS:
|
||||
{
|
||||
SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
break;
|
||||
}
|
||||
case REDSTONE_X_NEG:
|
||||
{
|
||||
SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
break;
|
||||
}
|
||||
case REDSTONE_Z_POS:
|
||||
{
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
break;
|
||||
}
|
||||
case REDSTONE_Z_NEG:
|
||||
{
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE);
|
||||
SetBlockPowered(a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE, MyPower);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1046,16 +1016,13 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
|
||||
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
|
||||
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||
{
|
||||
class cPressurePlateCallback :
|
||||
public cEntityCallback
|
||||
{
|
||||
public:
|
||||
cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
|
||||
m_Entity(NULL),
|
||||
m_World(a_World),
|
||||
cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
|
||||
m_NumberOfEntities(0),
|
||||
m_X(a_BlockX),
|
||||
m_Y(a_BlockY),
|
||||
m_Z(a_BlockZ)
|
||||
@ -1070,7 +1037,140 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
|
||||
|
||||
if (Distance <= 0.7)
|
||||
{
|
||||
m_Entity = a_Entity;
|
||||
m_NumberOfEntities++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetPowerLevel(unsigned char & a_PowerLevel) const
|
||||
{
|
||||
a_PowerLevel = std::min(m_NumberOfEntities, MAX_POWER_LEVEL);
|
||||
return (a_PowerLevel > 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
int m_NumberOfEntities;
|
||||
|
||||
int m_X;
|
||||
int m_Y;
|
||||
int m_Z;
|
||||
};
|
||||
|
||||
cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ);
|
||||
m_World.ForEachEntity(PressurePlateCallback);
|
||||
|
||||
unsigned char Power;
|
||||
NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||
if (PressurePlateCallback.GetPowerLevel(Power))
|
||||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_RAISED)
|
||||
{
|
||||
m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
|
||||
}
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
|
||||
SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
|
||||
{
|
||||
m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
|
||||
}
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED);
|
||||
m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
|
||||
{class cPressurePlateCallback :
|
||||
public cEntityCallback
|
||||
{
|
||||
public:
|
||||
cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
|
||||
m_NumberOfEntities(0),
|
||||
m_X(a_BlockX),
|
||||
m_Y(a_BlockY),
|
||||
m_Z(a_BlockZ)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Item(cEntity * a_Entity) override
|
||||
{
|
||||
Vector3f EntityPos = a_Entity->GetPosition();
|
||||
Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
|
||||
double Distance = (EntityPos - BlockPos).Length();
|
||||
|
||||
if (Distance <= 0.7)
|
||||
{
|
||||
m_NumberOfEntities++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetPowerLevel(unsigned char & a_PowerLevel) const
|
||||
{
|
||||
a_PowerLevel = std::min((int)ceil(m_NumberOfEntities / (float)10), MAX_POWER_LEVEL);
|
||||
return (a_PowerLevel > 0);
|
||||
}
|
||||
|
||||
protected:
|
||||
int m_NumberOfEntities;
|
||||
|
||||
int m_X;
|
||||
int m_Y;
|
||||
int m_Z;
|
||||
};
|
||||
|
||||
cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ);
|
||||
m_World.ForEachEntity(PressurePlateCallback);
|
||||
|
||||
unsigned char Power;
|
||||
NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||
if (PressurePlateCallback.GetPowerLevel(Power))
|
||||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_RAISED)
|
||||
{
|
||||
m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
|
||||
}
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
|
||||
SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType, Power);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
|
||||
{
|
||||
m_World.BroadcastSoundEffect("random.click", (int)((a_BlockX + 0.5) * 8.0), (int)((a_BlockY + 0.1) * 8.0), (int)((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
|
||||
}
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED);
|
||||
m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case E_BLOCK_WOODEN_PRESSURE_PLATE:
|
||||
{
|
||||
class cPressurePlateCallback :
|
||||
public cEntityCallback
|
||||
{
|
||||
public:
|
||||
cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
|
||||
m_FoundEntity(false),
|
||||
m_X(a_BlockX),
|
||||
m_Y(a_BlockY),
|
||||
m_Z(a_BlockZ)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool Item(cEntity * a_Entity) override
|
||||
{
|
||||
Vector3f EntityPos = a_Entity->GetPosition();
|
||||
Vector3f BlockPos(m_X + 0.5f, (float)m_Y, m_Z + 0.5f);
|
||||
double Distance = (EntityPos - BlockPos).Length();
|
||||
|
||||
if (Distance <= 0.7)
|
||||
{
|
||||
m_FoundEntity = true;
|
||||
return true; // Break out, we only need to know for plates that at least one entity is on top
|
||||
}
|
||||
return false;
|
||||
@ -1078,47 +1178,48 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
|
||||
|
||||
bool FoundEntity(void) const
|
||||
{
|
||||
return m_Entity != NULL;
|
||||
return m_FoundEntity;
|
||||
}
|
||||
|
||||
protected:
|
||||
cEntity * m_Entity;
|
||||
cWorld * m_World;
|
||||
bool m_FoundEntity;
|
||||
|
||||
int m_X;
|
||||
int m_Y;
|
||||
int m_Z;
|
||||
} ;
|
||||
|
||||
cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ, &m_World);
|
||||
cPressurePlateCallback PressurePlateCallback(a_BlockX, a_BlockY, a_BlockZ);
|
||||
m_World.ForEachEntity(PressurePlateCallback);
|
||||
|
||||
NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||
if (PressurePlateCallback.FoundEntity())
|
||||
{
|
||||
if (Meta == 0x0)
|
||||
if (Meta == E_META_PRESSURE_PLATE_RAISED)
|
||||
{
|
||||
m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.5F);
|
||||
}
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x1);
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_DEPRESSED);
|
||||
SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Meta == 0x1)
|
||||
if (Meta == E_META_PRESSURE_PLATE_DEPRESSED)
|
||||
{
|
||||
m_World.BroadcastSoundEffect("random.click", (int) ((a_BlockX + 0.5) * 8.0), (int) ((a_BlockY + 0.1) * 8.0), (int) ((a_BlockZ + 0.5) * 8.0), 0.3F, 0.6F);
|
||||
}
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
|
||||
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, E_META_PRESSURE_PLATE_RAISED);
|
||||
m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -1323,28 +1424,29 @@ bool cIncrementalRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY,
|
||||
|
||||
|
||||
|
||||
bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||
bool cIncrementalRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ, unsigned char & a_PowerLevel)
|
||||
{
|
||||
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr)
|
||||
{
|
||||
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
|
||||
a_PowerLevel = 0;
|
||||
|
||||
if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
|
||||
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks->begin(); itr != m_PoweredBlocks->end(); ++itr) // Check powered list
|
||||
{
|
||||
return true;
|
||||
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
a_PowerLevel = std::max(a_PowerLevel, itr->a_PowerLevel);
|
||||
}
|
||||
|
||||
for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr)
|
||||
for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks->begin(); itr != m_LinkedPoweredBlocks->end(); ++itr) // Check linked powered list
|
||||
{
|
||||
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
|
||||
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
a_PowerLevel = std::max(a_PowerLevel, itr->a_PowerLevel);
|
||||
}
|
||||
|
||||
if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // Source was in front of the piston's front face
|
||||
return (a_PowerLevel != 0); // Source was in front of the piston's front face
|
||||
}
|
||||
|
||||
|
||||
@ -1374,7 +1476,7 @@ bool cIncrementalRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_Block
|
||||
|
||||
|
||||
|
||||
void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType)
|
||||
void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceType, unsigned char a_PowerLevel)
|
||||
{
|
||||
switch (a_Direction)
|
||||
{
|
||||
@ -1382,11 +1484,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
|
||||
{
|
||||
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX - 1, a_BlockY, a_BlockZ);
|
||||
|
||||
SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 2, a_BlockY, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX - 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1394,11 +1496,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
|
||||
{
|
||||
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ);
|
||||
|
||||
SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 2, a_BlockY, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX + 1, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1406,11 +1508,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
|
||||
{
|
||||
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ);
|
||||
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 2, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1418,11 +1520,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
|
||||
{
|
||||
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ);
|
||||
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 2, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY + 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1430,11 +1532,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
|
||||
{
|
||||
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1);
|
||||
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ - 2, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ - 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1442,11 +1544,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
|
||||
{
|
||||
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1);
|
||||
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY, a_BlockZ + 2, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX + 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX - 1, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY + 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
SetBlockLinkedPowered(a_BlockX, a_BlockY - 1, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ + 1, a_BlockX, a_BlockY, a_BlockZ, a_SourceType, MiddleBlock, a_PowerLevel);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1462,7 +1564,7 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
|
||||
|
||||
|
||||
|
||||
void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock)
|
||||
void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel)
|
||||
{
|
||||
static const struct
|
||||
{
|
||||
@ -1479,7 +1581,7 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc
|
||||
|
||||
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through struct to power all directions
|
||||
{
|
||||
SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock);
|
||||
SetBlockPowered(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z, a_BlockX, a_BlockY, a_BlockZ, a_SourceBlock, a_PowerLevel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1487,7 +1589,7 @@ void cIncrementalRedstoneSimulator::SetAllDirsAsPowered(int a_BlockX, int a_Bloc
|
||||
|
||||
|
||||
|
||||
void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock)
|
||||
void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel)
|
||||
{
|
||||
BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
if (Block == E_BLOCK_AIR)
|
||||
@ -1497,15 +1599,31 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY,
|
||||
}
|
||||
|
||||
PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList();
|
||||
|
||||
for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
|
||||
for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
|
||||
{
|
||||
if (
|
||||
itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
|
||||
itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
|
||||
)
|
||||
{
|
||||
// Check for duplicates
|
||||
// Check for duplicates, update power level if everything else the same but either way, don't add a new listing
|
||||
if (itr->a_PowerLevel != a_PowerLevel)
|
||||
{
|
||||
itr->a_PowerLevel = a_PowerLevel;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
PoweredBlocksList * OtherPowered = m_Chunk->GetNeighborChunk(a_SourceX, a_SourceZ)->GetRedstoneSimulatorPoweredBlocksList();
|
||||
for (PoweredBlocksList::const_iterator itr = OtherPowered->begin(); itr != OtherPowered->end(); ++itr) // Check powered list
|
||||
{
|
||||
if (
|
||||
itr->a_BlockPos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) &&
|
||||
itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))
|
||||
)
|
||||
{
|
||||
// Powered wires try to power their source - don't let them!
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1513,6 +1631,7 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY,
|
||||
sPoweredBlocks RC;
|
||||
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
|
||||
RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
|
||||
RC.a_PowerLevel = a_PowerLevel;
|
||||
Powered->push_back(RC);
|
||||
}
|
||||
|
||||
@ -1524,7 +1643,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
|
||||
int a_BlockX, int a_BlockY, int a_BlockZ,
|
||||
int a_MiddleX, int a_MiddleY, int a_MiddleZ,
|
||||
int a_SourceX, int a_SourceY, int a_SourceZ,
|
||||
BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock
|
||||
BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddleBlock, unsigned char a_PowerLevel
|
||||
)
|
||||
{
|
||||
BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
|
||||
@ -1539,8 +1658,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
|
||||
}
|
||||
|
||||
LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList();
|
||||
|
||||
for (LinkedBlocksList::const_iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
|
||||
for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
|
||||
{
|
||||
if (
|
||||
itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
|
||||
@ -1548,7 +1666,11 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
|
||||
itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ))
|
||||
)
|
||||
{
|
||||
// Check for duplicates
|
||||
// Check for duplicates, update power level if everything else the same but either way, don't add a new listing
|
||||
if (itr->a_PowerLevel != a_PowerLevel)
|
||||
{
|
||||
itr->a_PowerLevel = a_PowerLevel;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1557,6 +1679,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
|
||||
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
|
||||
RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ);
|
||||
RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
|
||||
RC.a_PowerLevel = a_PowerLevel;
|
||||
Linked->push_back(RC);
|
||||
}
|
||||
|
||||
@ -1621,7 +1744,7 @@ void cIncrementalRedstoneSimulator::QueueRepeaterPowerChange(int a_BlockX, int a
|
||||
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
|
||||
|
||||
// Gets the top two bits (delay time), shifts them into the lower two bits, and adds one (meta 0 = 1 tick; 1 = 2 etc.)
|
||||
// * 2 because apparently, MCS ticks are way faster than vanilla ticks, so repeater aren't noticeably delayed
|
||||
// * 2 because in MCS, 1 redstone tick = 1 world tick, but in Vanilla, 1 redstone tick = 2 world ticks, and we need to maintain compatibility
|
||||
RC.a_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2;
|
||||
|
||||
RC.a_ElapsedTicks = 0;
|
||||
@ -1697,12 +1820,3 @@ bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
|
||||
|
||||
|
||||
|
||||
|
||||
bool cIncrementalRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta)
|
||||
{
|
||||
return IsLeverOn(a_BlockMeta);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -36,31 +36,35 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
#define MAX_POWER_LEVEL 15
|
||||
|
||||
struct sPoweredBlocks // Define structure of the directly powered blocks list
|
||||
{
|
||||
Vector3i a_BlockPos; // Position of powered block
|
||||
Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos
|
||||
unsigned char a_PowerLevel;
|
||||
};
|
||||
|
||||
struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side)
|
||||
{
|
||||
Vector3i a_BlockPos;
|
||||
Vector3i a_MiddlePos;
|
||||
Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination
|
||||
Vector3i a_SourcePos;
|
||||
unsigned char a_PowerLevel;
|
||||
};
|
||||
|
||||
struct sSimulatedPlayerToggleableList
|
||||
struct sSimulatedPlayerToggleableList // Define structure of the list containing simulate-on-update blocks (such as trapdoors that respond once to a block update, and can be toggled by a player)
|
||||
{
|
||||
Vector3i a_BlockPos;
|
||||
bool WasLastStatePowered;
|
||||
bool WasLastStatePowered; // Was the last state powered or not? Determines whether a source update has happened and if I should resimulate
|
||||
};
|
||||
|
||||
struct sRepeatersDelayList
|
||||
struct sRepeatersDelayList // Define structure of list containing repeaters' delay states
|
||||
{
|
||||
Vector3i a_BlockPos;
|
||||
unsigned char a_DelayTicks;
|
||||
unsigned char a_ElapsedTicks;
|
||||
bool ShouldPowerOn;
|
||||
unsigned char a_DelayTicks; // For how many ticks should the repeater delay
|
||||
unsigned char a_ElapsedTicks; // How much of the previous has been elapsed?
|
||||
bool ShouldPowerOn; // What happens when the delay time is fulfilled?
|
||||
};
|
||||
|
||||
public:
|
||||
@ -132,15 +136,15 @@ private:
|
||||
|
||||
/* ====== Helper functions ====== */
|
||||
/** Marks a block as powered */
|
||||
void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock);
|
||||
void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
|
||||
/** Marks a block as being powered through another block */
|
||||
void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock);
|
||||
void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
|
||||
/** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
|
||||
void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered);
|
||||
/** Marks the second block in a direction as linked powered */
|
||||
void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock);
|
||||
void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
|
||||
/** Marks all blocks immediately surrounding a coordinate as powered */
|
||||
void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock);
|
||||
void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock, unsigned char a_PowerLevel = MAX_POWER_LEVEL);
|
||||
/** Queues a repeater to be powered or unpowered */
|
||||
void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn);
|
||||
|
||||
@ -159,15 +163,14 @@ private:
|
||||
/** Returns if a piston is powered */
|
||||
bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
|
||||
/** Returns if a wire is powered
|
||||
The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire
|
||||
*/
|
||||
bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||
The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire */
|
||||
bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ, unsigned char & a_PowerLevel);
|
||||
|
||||
|
||||
/** Returns if lever metadata marks it as emitting power */
|
||||
bool IsLeverOn(NIBBLETYPE a_BlockMeta);
|
||||
/** Returns if button metadata marks it as emitting power */
|
||||
bool IsButtonOn(NIBBLETYPE a_BlockMeta);
|
||||
bool IsButtonOn(NIBBLETYPE a_BlockMeta) { return IsLeverOn(a_BlockMeta); }
|
||||
/* ============================== */
|
||||
|
||||
/* ====== Misc Functions ====== */
|
||||
|
@ -108,6 +108,11 @@ public:
|
||||
return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z;
|
||||
}
|
||||
|
||||
inline bool operator == (const Vector3<T> & a_Rhs) const
|
||||
{
|
||||
return Equals(a_Rhs);
|
||||
}
|
||||
|
||||
inline bool operator < (const Vector3<T> & a_Rhs)
|
||||
{
|
||||
// return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ?
|
||||
|
@ -574,7 +574,7 @@ void cWorld::Start(void)
|
||||
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
|
||||
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
|
||||
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", true);
|
||||
int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slNone);
|
||||
int TNTShrapnelLevel = IniFile.GetValueSetI("Physics", "TNTShrapnelLevel", (int)slAll);
|
||||
m_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
|
||||
m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
|
||||
m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", true);
|
||||
@ -1632,7 +1632,6 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock
|
||||
|
||||
void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed, bool IsPlayerCreated)
|
||||
{
|
||||
MTRand r1;
|
||||
a_FlyAwaySpeed /= 100; // Pre-divide, so that we don't have to divide each time inside the loop
|
||||
for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr)
|
||||
{
|
||||
@ -1642,9 +1641,9 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double
|
||||
continue;
|
||||
}
|
||||
|
||||
float SpeedX = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5));
|
||||
float SpeedY = (float)(a_FlyAwaySpeed * r1.randInt(50));
|
||||
float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5));
|
||||
float SpeedX = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
|
||||
float SpeedY = (float)(a_FlyAwaySpeed * GetTickRandomNumber(50));
|
||||
float SpeedZ = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
|
||||
|
||||
cPickup * Pickup = new cPickup(
|
||||
a_BlockX, a_BlockY, a_BlockZ,
|
||||
|
@ -231,7 +231,7 @@ void cFireworkItem::FadeColoursFromString(const AString & a_String, cFireworkIte
|
||||
|
||||
|
||||
|
||||
int cFireworkItem::GetVanillaColourCodeFromDye(short a_DyeMeta)
|
||||
int cFireworkItem::GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta)
|
||||
{
|
||||
/*
|
||||
Colours are supposed to be calculated via: R << 16 + G << 8 + B
|
||||
|
@ -81,7 +81,7 @@ public:
|
||||
static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
|
||||
|
||||
/** Returns a colour code for fireworks used by the network code */
|
||||
static int GetVanillaColourCodeFromDye(short a_DyeMeta);
|
||||
static int GetVanillaColourCodeFromDye(NIBBLETYPE a_DyeMeta);
|
||||
|
||||
bool m_HasFlicker;
|
||||
bool m_HasTrail;
|
||||
|
Loading…
Reference in New Issue
Block a user