1
0

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:
jfhumann 2014-04-18 21:44:58 +02:00
commit 67344a3782
46 changed files with 2172 additions and 817 deletions

View File

@ -46,6 +46,10 @@ macro(set_flags)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -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") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -std=c++11")
else() 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") add_flags_cxx("-pthread")
endif() endif()
@ -56,6 +60,10 @@ macro(set_flags)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 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_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++11")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -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() endif()
# We use a signed char (fixes #640 on RasPi) # We use a signed char (fixes #640 on RasPi)

View File

@ -2197,32 +2197,38 @@ bool cConnection::HandleServerSpawnMob(void)
struct sSpawnData
{
AString m_Name;
AString m_Value;
AString m_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<sSpawnData> sSpawnDatas;
bool cConnection::HandleServerSpawnNamedEntity(void) bool cConnection::HandleServerSpawnNamedEntity(void)
{ {
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID); HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, EntityID);
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityUUID);
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName); HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, EntityName);
HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, DataCount); HANDLE_SERVER_PACKET_READ(ReadVarInt, UInt32, DataCount);
struct sData sSpawnDatas Data;
{
AString m_Name;
AString m_Value;
AString m_Signature;
sData(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;
for (UInt32 i = 0; i < DataCount; i++) for (UInt32 i = 0; i < DataCount; i++)
{ {
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Name) HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Name)
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Value) HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Value)
HANDLE_SERVER_PACKET_READ(ReadVarUTF8String, AString, Signature) 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, PosX);
HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY); HANDLE_SERVER_PACKET_READ(ReadBEInt, int, PosY);
@ -2242,7 +2248,7 @@ bool cConnection::HandleServerSpawnNamedEntity(void)
Log(" UUID = \"%s\"", EntityUUID.c_str()); Log(" UUID = \"%s\"", EntityUUID.c_str());
Log(" Name = \"%s\"", EntityName.c_str()); Log(" Name = \"%s\"", EntityName.c_str());
Log(" NumData = %u", DataCount); 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\"", Log(" Name = \"%s\", Value = \"%s\", Signature = \"%s\"",
itr->m_Name.c_str(), itr->m_Value.c_str(), itr->m_Signature.c_str() itr->m_Name.c_str(), itr->m_Value.c_str(), itr->m_Signature.c_str()

View File

@ -154,7 +154,7 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
case ';': case ';':
case '#': case '#':
{ {
if (names.size() == 0) if (names.empty())
{ {
AddHeaderComment(line.substr(pLeft + 1)); AddHeaderComment(line.substr(pLeft + 1));
} }
@ -168,8 +168,9 @@ bool cIniFile::ReadFile(const AString & a_FileName, bool a_AllowExampleRedirect)
} // while (getline()) } // while (getline())
f.close(); f.close();
if (names.size() == 0) if (keys.empty() && names.empty() && comments.empty())
{ {
// File be empty or unreadable, equivalent to nonexistant
return false; return false;
} }

View File

@ -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;
}

View File

@ -503,6 +503,10 @@ enum
E_META_PLANKS_CONIFER = 1, E_META_PLANKS_CONIFER = 1,
E_META_PLANKS_BIRCH = 2, E_META_PLANKS_BIRCH = 2,
E_META_PLANKS_JUNGLE = 3, 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_BLOCK_QUARTZ_BLOCK metas:
E_META_QUARTZ_NORMAL = 0, E_META_QUARTZ_NORMAL = 0,

View File

@ -24,13 +24,15 @@
#include "Root.h" #include "Root.h"
#include "Authenticator.h" #include "Protocol/Authenticator.h"
#include "MersenneTwister.h" #include "MersenneTwister.h"
#include "Protocol/ProtocolRecognizer.h" #include "Protocol/ProtocolRecognizer.h"
#include "CompositeChat.h" #include "CompositeChat.h"
#include "Items/ItemSword.h" #include "Items/ItemSword.h"
#include "md5/md5.h"
/** Maximum number of explosions to send this tick, server will start dropping if exceeded */ /** 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) void cClientHandle::Kick(const AString & a_Reason)
{ {
if (m_State >= csAuthenticating) // Don't log pings 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) if (m_State != csAuthenticating)
{ {
@ -197,6 +232,12 @@ void cClientHandle::Authenticate(void)
ASSERT( m_Player == NULL ); 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) // Spawn player (only serversided, so data is loaded)
m_Player = new cPlayer(this, GetUsername()); m_Player = new cPlayer(this, GetUsername());
@ -1679,13 +1720,16 @@ void cClientHandle::Tick(float a_Dt)
} }
// Send a ping packet: // Send a ping packet:
cTimer t1; if (m_State == csPlaying)
if (m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())
{ {
m_PingID++; cTimer t1;
m_PingStartTime = t1.GetNowTime(); if ((m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime()))
m_Protocol->SendKeepAlive(m_PingID); {
m_LastPingTime = m_PingStartTime; m_PingID++;
m_PingStartTime = t1.GetNowTime();
m_Protocol->SendKeepAlive(m_PingID);
m_LastPingTime = m_PingStartTime;
}
} }
// Handle block break animation: // Handle block break animation:
@ -2103,7 +2147,7 @@ void cClientHandle::SendExplosion(double a_BlockX, double a_BlockY, double a_Blo
} }
// Update the statistics: // Update the statistics:
m_NumExplosionsThisTick += 1; m_NumExplosionsThisTick++;
m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion); m_Protocol->SendExplosion(a_BlockX, a_BlockY, a_BlockZ, a_Radius, a_BlocksAffected, a_PlayerMotion);
} }

View File

@ -62,8 +62,22 @@ public:
cPlayer* GetPlayer() { return m_Player; } // tolua_export 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 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); void StreamChunks(void);
@ -326,6 +340,7 @@ private:
static int s_ClientCount; static int s_ClientCount;
int m_UniqueID; 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 */ /** Set to true when the chunk where the player is is sent to the client. Used for spawning the player */
bool m_HasSentPlayerChunk; bool m_HasSentPlayerChunk;

View File

@ -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) 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()) double r = sqrt((a_X * a_X) + (a_Z * a_Z));
{ if (r < std::numeric_limits<double>::epsilon())
a_Pan = atan2(a_Z, a_X) * 180 / PI - 90;
}
else
{ {
a_Pan = 0; 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;
} }

View File

@ -330,7 +330,7 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
AddSpeed(a_TDI.Knockback * 2); AddSpeed(a_TDI.Knockback * 2);
} }
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT); m_World->BroadcastEntityStatus(*this, esGenericHurt);
if (m_Health <= 0) if (m_Health <= 0)
{ {
@ -479,7 +479,7 @@ void cEntity::KilledBy(cEntity * a_Killer)
GetDrops(Drops, a_Killer); GetDrops(Drops, a_Killer);
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ()); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_DEAD); m_World->BroadcastEntityStatus(*this, esGenericDead);
} }
@ -519,37 +519,36 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
} }
else else
{ {
if (a_Chunk.IsValid()) if (!a_Chunk.IsValid())
{ {
cChunk * NextChunk = a_Chunk.GetNeighborChunk(POSX_TOINT, POSZ_TOINT); return;
if ((NextChunk == NULL) || !NextChunk->IsValid())
{
return;
}
TickBurning(*NextChunk);
if (GetPosY() < VOID_BOUNDARY)
{
TickInVoid(*NextChunk);
}
else
{
m_TicksSinceLastVoidDamage = 0;
}
if (IsMob() || IsPlayer())
{
// Set swimming state
SetSwimState(*NextChunk);
// Handle drowning
HandleAir();
}
HandlePhysics(a_Dt, *NextChunk);
} }
// Position changed -> super::Tick() called
GET_AND_VERIFY_CURRENT_CHUNK(NextChunk, POSX_TOINT, POSZ_TOINT)
TickBurning(*NextChunk);
if (GetPosY() < VOID_BOUNDARY)
{
TickInVoid(*NextChunk);
}
else
{
m_TicksSinceLastVoidDamage = 0;
}
if (IsMob() || IsPlayer())
{
// Set swimming state
SetSwimState(*NextChunk);
// Handle drowning
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) 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. // TODO Add collision detection with entities.
a_Dt /= 1000; // Convert from msec to sec a_Dt /= 1000; // Convert from msec to sec
Vector3d NextPos = Vector3d(GetPosX(),GetPosY(),GetPosZ()); Vector3d NextPos = Vector3d(GetPosX(), GetPosY(), GetPosZ());
Vector3d NextSpeed = Vector3d(GetSpeedX(),GetSpeedY(),GetSpeedZ()); 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)) if ((BlockY >= cChunkDef::Height) || (BlockY < 0))
{ {
// Outside of the world // Outside of the world
AddSpeedY(m_Gravity * a_Dt);
cChunk * NextChunk = a_Chunk.GetNeighborChunk(BlockX, BlockZ); AddPosition(GetSpeed() * a_Dt);
// See if we can commit our changes. If not, we will discard them.
if (NextChunk != NULL)
{
SetSpeed(NextSpeed);
NextPos += (NextSpeed * a_Dt);
SetPosition(NextPos);
}
return; return;
} }
int RelBlockX = BlockX - (a_Chunk.GetPosX() * cChunkDef::Width); int RelBlockX = BlockX - (NextChunk->GetPosX() * cChunkDef::Width);
int RelBlockZ = BlockZ - (a_Chunk.GetPosZ() * cChunkDef::Width); int RelBlockZ = BlockZ - (NextChunk->GetPosZ() * cChunkDef::Width);
BLOCKTYPE BlockIn = a_Chunk.GetBlock( RelBlockX, BlockY, RelBlockZ ); BLOCKTYPE BlockIn = NextChunk->GetBlock( RelBlockX, BlockY, RelBlockZ );
BLOCKTYPE BlockBelow = (BlockY > 0) ? a_Chunk.GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; 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 (!cBlockInfo::IsSolid(BlockIn)) // Making sure we are not inside a solid block
{ {
if (m_bOnGround) // check if it's still on the ground 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; bool IsNoAirSurrounding = true;
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) 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 // The pickup is too close to an unloaded chunk, bail out of any physics handling
return; return;
@ -764,20 +759,8 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
} }
} }
BlockX = (int) floor(NextPos.x); SetPosition(NextPos);
BlockZ = (int) floor(NextPos.z); SetSpeed(NextSpeed);
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);
}
} }
@ -806,7 +789,7 @@ void cEntity::TickBurning(cChunk & a_Chunk)
int MaxRelX = (int)floor(GetPosX() + m_Width / 2) - a_Chunk.GetPosX() * cChunkDef::Width; 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 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 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))); int MaxY = std::max(0, std::min(cChunkDef::Height - 1, (int)ceil (GetPosY() + m_Height)));
bool HasWater = false; bool HasWater = false;
bool HasLava = false; bool HasLava = false;
@ -981,13 +964,13 @@ void cEntity::HandleAir(void)
} }
else else
{ {
m_AirTickTimer -= 1; m_AirTickTimer--;
} }
} }
else else
{ {
// Reduce air supply // Reduce air supply
m_AirLevel -= 1; m_AirLevel--;
} }
} }
else else
@ -1099,15 +1082,15 @@ void cEntity::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
void cEntity::BroadcastMovementUpdate(const cClientHandle * a_Exclude) 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 // 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)) if (((m_Speed.SqrLength() > 0.0004f) || m_bDirtySpeed) && ((m_World->GetWorldAge() - m_TimeLastSpeedPacket) >= 2))
{ {
m_World->BroadcastEntityVelocity(*this,a_Exclude); m_World->BroadcastEntityVelocity(*this,a_Exclude);
m_bDirtySpeed = false; m_bDirtySpeed = false;
m_TimeLastSpeedPacket = m_World->GetWorldAge(); m_TimeLastSpeedPacket = m_World->GetWorldAge();
} }
//Have to process position related packets this every two ticks // Have to process position related packets this every two ticks
if (m_World->GetWorldAge() % 2 == 0) if (m_World->GetWorldAge() % 2 == 0)
{ {
int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0)); int DiffX = (int) (floor(GetPosX() * 32.0) - floor(m_LastPosX * 32.0));

View File

@ -32,6 +32,8 @@
#define POSZ_TOINT (int)floor(GetPosZ()) #define POSZ_TOINT (int)floor(GetPosZ())
#define POS_TOINT Vector3i(POSXTOINT, POSYTOINT, POSZTOINT) #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; }
@ -88,23 +90,42 @@ public:
} ; } ;
// tolua_end // tolua_end
enum enum eEntityStatus
{ {
ENTITY_STATUS_HURT = 2, // TODO: Investiagate 0, 1, and 5 as Wiki.vg is not certain
ENTITY_STATUS_DEAD = 3,
ENTITY_STATUS_WOLF_TAMING = 6, // Entity becomes coloured red
ENTITY_STATUS_WOLF_TAMED = 7, esGenericHurt = 2,
ENTITY_STATUS_WOLF_SHAKING = 8, // Entity plays death animation (entity falls to ground)
ENTITY_STATUS_EATING_ACCEPTED = 9, esGenericDead = 3,
ENTITY_STATUS_SHEEP_EATING = 10, // Iron Golem plays attack animation (arms lift and fall)
ENTITY_STATUS_GOLEM_ROSING = 11, esIronGolemAttacking = 4,
ENTITY_STATUS_VILLAGER_HEARTS = 12, // Wolf taming particles spawn (smoke)
ENTITY_STATUS_VILLAGER_ANGRY = 13, esWolfTaming = 6,
ENTITY_STATUS_VILLAGER_HAPPY = 14, // Wolf tamed particles spawn (hearts)
ENTITY_STATUS_WITCH_MAGICKING = 15, 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 // 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 enum
@ -118,7 +139,8 @@ public:
BURN_TICKS = 200, ///< How long to keep an entity burning after it has stood in lava / fire 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 MAX_AIR_LEVEL = 300, ///< Maximum air an entity can have
DROWNING_TICKS = 20, ///< Number of ticks per heart of damage 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); cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, double a_Width, double a_Height);

View File

@ -132,7 +132,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
return; return;
} }
int PosY = (int)floor(GetPosY()); int PosY = POSY_TOINT;
if ((PosY <= 0) || (PosY >= cChunkDef::Height)) if ((PosY <= 0) || (PosY >= cChunkDef::Height))
{ {
// Outside the world, just process normal falling physics // Outside the world, just process normal falling physics
@ -141,8 +141,8 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
return; return;
} }
int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width; int RelPosX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width; int RelPosZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ); cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
if (Chunk == NULL) if (Chunk == NULL)
{ {
@ -195,7 +195,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
super::HandlePhysics(a_Dt, *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_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
m_bIsOnDetectorRail = false; m_bIsOnDetectorRail = false;
@ -203,7 +203,7 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
else if (WasDetectorRail) else if (WasDetectorRail)
{ {
m_bIsOnDetectorRail = true; 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 // Broadcast positioning changes to client
@ -719,11 +719,11 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{ {
if (GetSpeedZ() > 0) 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)) 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 // 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()); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart)) if (bbBlock.DoesIntersect(bbMinecart))
@ -736,10 +736,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
} }
else if (GetSpeedZ() < 0) 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)) 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()); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart)) if (bbBlock.DoesIntersect(bbMinecart))
@ -756,10 +756,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
{ {
if (GetSpeedX() > 0) 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)) 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()); cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart)) if (bbBlock.DoesIntersect(bbMinecart))
@ -772,10 +772,10 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
} }
else if (GetSpeedX() < 0) 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)) 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()); cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
if (bbBlock.DoesIntersect(bbMinecart)) 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_XM:
case E_META_RAIL_CURVED_ZP_XP: case E_META_RAIL_CURVED_ZP_XP:
{ {
BLOCKTYPE BlockXM = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); BLOCKTYPE BlockXM = m_World->GetBlock(POSX_TOINT - 1, POSY_TOINT, POSZ_TOINT);
BLOCKTYPE BlockXP = m_World->GetBlock((int)floor(GetPosX()) + 1, (int)floor(GetPosY()), (int)floor(GetPosZ())); BLOCKTYPE BlockXP = m_World->GetBlock(POSX_TOINT + 1, POSY_TOINT, POSZ_TOINT);
BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1); BLOCKTYPE BlockZM = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT - 1);
BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1); BLOCKTYPE BlockZP = m_World->GetBlock(POSX_TOINT, POSY_TOINT, POSZ_TOINT + 1);
if ( if (
(!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) || (!IsBlockRail(BlockXM) && cBlockInfo::IsSolid(BlockXM)) ||
(!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) || (!IsBlockRail(BlockXP) && cBlockInfo::IsSolid(BlockXP)) ||
@ -805,7 +805,7 @@ bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
) )
{ {
SetSpeed(0, 0, 0); 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; return true;
} }
break; break;
@ -822,7 +822,7 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
{ {
cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == NULL) ? -1 : m_Attachee->GetUniqueID())); cMinecartCollisionCallback MinecartCollisionCallback(GetPosition(), GetHeight(), GetWidth(), GetUniqueID(), ((m_Attachee == NULL) ? -1 : m_Attachee->GetUniqueID()));
int ChunkX, ChunkZ; 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); m_World->ForEachEntityInChunk(ChunkX, ChunkZ, MinecartCollisionCallback);
if (!MinecartCollisionCallback.FoundIntersection()) if (!MinecartCollisionCallback.FoundIntersection())

View File

@ -98,45 +98,44 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
if (!m_bCollected) 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 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. // 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); GET_AND_VERIFY_CURRENT_CHUNK(CurrentChunk, BlockX, BlockZ)
if (CurrentChunk != NULL) // Make sure the chunk is loaded
{ int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width);
int RelBlockX = BlockX - (CurrentChunk->GetPosX() * cChunkDef::Width); int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
int RelBlockZ = BlockZ - (CurrentChunk->GetPosZ() * cChunkDef::Width);
// If the pickup is on the bottommost block position, make it think the void is made of air: (#131) // If the pickup is on the bottommost block position, make it think the void is made of air: (#131)
BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR; BLOCKTYPE BlockBelow = (BlockY > 0) ? CurrentChunk->GetBlock(RelBlockX, BlockY - 1, RelBlockZ) : E_BLOCK_AIR;
BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ); BLOCKTYPE BlockIn = CurrentChunk->GetBlock(RelBlockX, BlockY, RelBlockZ);
if ( if (
IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) || IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE) ||
IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE) IsBlockLava(BlockIn) || (BlockIn == E_BLOCK_FIRE)
) )
{
m_bCollected = true;
m_Timer = 0; // We have to reset the timer.
m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
if (m_Timer > 500.f)
{ {
m_bCollected = true; Destroy(true);
m_Timer = 0; // We have to reset the timer. return;
m_Timer += a_Dt; // In case we have to destroy the pickup in the same tick.
if (m_Timer > 500.f)
{
Destroy(true);
return;
}
} }
}
if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me if (!IsDestroyed()) // Don't try to combine if someone has tried to combine me
{
cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this);
m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
if (PickupCombiningCallback.FoundMatchingPickup())
{ {
cPickupCombiningCallback PickupCombiningCallback(GetPosition(), this); m_World->BroadcastEntityMetadata(*this);
m_World->ForEachEntity(PickupCombiningCallback); // Not ForEachEntityInChunk, otherwise pickups don't combine across chunk boundaries
if (PickupCombiningCallback.FoundMatchingPickup())
{
m_World->BroadcastEntityMetadata(*this);
}
} }
} }
} }
@ -156,7 +155,7 @@ void cPickup::Tick(float a_Dt, cChunk & a_Chunk)
return; 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); Destroy(true);
return; return;

View File

@ -49,9 +49,6 @@ public:
bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export
private: 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 */ /** The number of ticks that the entity has existed / timer between collect and destroy; in msec */
float m_Timer; float m_Timer;

View File

@ -438,7 +438,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
cWorld * World = GetWorld(); cWorld * World = GetWorld();
if ((GetPosY() >= 0) && (GetPosY() < cChunkDef::Height)) 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) if (BlockType != E_BLOCK_AIR)
{ {
m_bTouchGround = true; m_bTouchGround = true;
@ -467,7 +467,7 @@ void cPlayer::SetTouchGround(bool a_bTouchGround)
TakeDamage(dtFalling, NULL, Damage, Damage, 0); TakeDamage(dtFalling, NULL, Damage, Damage, 0);
// Fall particles // 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(); m_LastGroundHeight = (float)GetPosY();
@ -591,7 +591,7 @@ void cPlayer::FinishEating(void)
m_EatingFinishTick = -1; m_EatingFinishTick = -1;
// Send the packets: // Send the packets:
m_ClientHandle->SendEntityStatus(*this, ENTITY_STATUS_EATING_ACCEPTED); m_ClientHandle->SendEntityStatus(*this, esPlayerEatingAccepted);
m_World->BroadcastEntityAnimation(*this, 0); m_World->BroadcastEntityAnimation(*this, 0);
m_World->BroadcastEntityMetadata(*this); m_World->BroadcastEntityMetadata(*this);
@ -1520,22 +1520,16 @@ void cPlayer::LoadPermissionsFromDisk()
cIniFile IniFile; cIniFile IniFile;
if (IniFile.ReadFile("users.ini")) if (IniFile.ReadFile("users.ini"))
{ {
std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", ""); AString Groups = IniFile.GetValueSet(m_PlayerName, "Groups", "Default");
if (!Groups.empty()) AStringVector Split = StringSplitAndTrim(Groups, ",");
for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
{ {
AStringVector Split = StringSplitAndTrim(Groups, ","); if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr))
for (AStringVector::const_iterator itr = Split.begin(), end = Split.end(); itr != end; ++itr)
{ {
if (!cRoot::Get()->GetGroupManager()->ExistsGroup(*itr)) LOGWARNING("The group %s for player %s was not found!", itr->c_str(), m_PlayerName.c_str());
{
LOGWARNING("The group %s for player %s was not found!", itr->c_str(), m_PlayerName.c_str());
}
AddToGroup(*itr);
} }
} AddToGroup(*itr);
else
{
AddToGroup("Default");
} }
AString Color = IniFile.GetValue(m_PlayerName, "Color", "-"); AString Color = IniFile.GetValue(m_PlayerName, "Color", "-");
@ -1547,8 +1541,10 @@ void cPlayer::LoadPermissionsFromDisk()
else else
{ {
cGroupManager::GenerateDefaultUsersIni(IniFile); cGroupManager::GenerateDefaultUsersIni(IniFile);
IniFile.AddValue("Groups", m_PlayerName, "Default");
AddToGroup("Default"); AddToGroup("Default");
} }
IniFile.WriteFile("users.ini");
ResolvePermissions(); ResolvePermissions();
} }
@ -1900,9 +1896,9 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
void cPlayer::Detach() void cPlayer::Detach()
{ {
super::Detach(); super::Detach();
int PosX = (int)floor(GetPosX()); int PosX = POSX_TOINT;
int PosY = (int)floor(GetPosY()); int PosY = POSY_TOINT;
int PosZ = (int)floor(GetPosZ()); int PosZ = POSZ_TOINT;
// Search for a position within an area to teleport player after detachment // Search for a position within an area to teleport player after detachment
// Position must be solid land, and occupied by a nonsolid block // Position must be solid land, and occupied by a nonsolid block

View File

@ -791,7 +791,7 @@ void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks) if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
{ {
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_FIREWORK_EXPLODE); m_World->BroadcastEntityStatus(*this, esFireworkExploding);
Destroy(); Destroy();
} }

View File

@ -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: // 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) void cNetherFortGen::PiecePlaced(const cPiece & a_Piece)
{ {
UNUSED(a_Piece); UNUSED(a_Piece);

View File

@ -26,6 +26,7 @@ public:
virtual ~cNetherFortGen(); virtual ~cNetherFortGen();
protected: protected:
friend class cNetherFortPerfTest; // fwd: NetherFortGen.cpp
class cNetherFort; // fwd: NetherFortGen.cpp class cNetherFort; // fwd: NetherFortGen.cpp
typedef std::list<cNetherFort *> cNetherForts; typedef std::list<cNetherFort *> cNetherForts;
@ -77,6 +78,7 @@ protected:
// cPiecePool overrides: // cPiecePool overrides:
virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override; virtual cPieces GetPiecesWithConnector(int a_ConnectorType) override;
virtual cPieces GetStartingPieces(void) 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 PiecePlaced(const cPiece & a_Piece) override;
virtual void Reset(void) override; virtual void Reset(void) override;
} ; } ;

View File

@ -392,14 +392,17 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
Connections.reserve(AvailablePieces.size()); 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 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); AddFaceDirection(ConnPos.x, ConnPos.y, ConnPos.z, a_Connector.m_Direction);
int WeightTotal = 0;
/*
// 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());
//*/
for (cPieces::iterator itrP = AvailablePieces.begin(), endP = AvailablePieces.end(); itrP != endP; ++itrP) 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(); cPiece::cConnectors Connectors = (*itrP)->GetConnectors();
for (cPiece::cConnectors::iterator itrC = Connectors.begin(), endC = Connectors.end(); itrC != endC; ++itrC) 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 // Doesn't fit in this rotation
continue; 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 itrC - Connectors[]
} // for itrP - AvailablePieces[] } // for itrP - AvailablePieces[]
if (Connections.empty()) if (Connections.empty())
@ -427,21 +432,23 @@ bool cPieceGenerator::TryPlacePieceAtConnector(
// No available connections, bail out // No available connections, bail out
return false; return false;
} }
ASSERT(WeightTotal > 0);
// Choose a random connection from the list: // 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; int rnd = (m_Noise.IntNoise3DInt(a_Connector.m_Pos.x, a_Connector.m_Pos.y, a_Connector.m_Pos.z) / 7) % WeightTotal;
cConnection & Conn = Connections[rnd % Connections.size()]; 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: // 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); Vector3i NewPos = Conn.m_Piece->RotatePos(Conn.m_Connector.m_Pos, Conn.m_NumCCWRotations);
ConnPos -= NewPos; ConnPos -= NewPos;
cPlacedPiece * PlacedPiece = new cPlacedPiece(&a_ParentPiece, *(Conn.m_Piece), ConnPos, Conn.m_NumCCWRotations); 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: // Add the new piece's connectors to the list of free connectors:
cPiece::cConnectors Connectors = Conn.m_Piece->GetConnectors(); 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) for (cPiece::cConnectors::const_iterator itr = Connectors.begin(), end = Connectors.end(); itr != end; ++itr)
{ {
if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos)) if (itr->m_Pos.Equals(Conn.m_Connector.m_Pos))
@ -524,10 +525,11 @@ void cPieceGenerator::DebugConnectorPool(const cPieceGenerator::cFreeConnectors
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cPieceGenerator::cConnection: // 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_Piece(&a_Piece),
m_Connector(a_Connector), m_Connector(a_Connector),
m_NumCCWRotations(a_NumCCWRotations) m_NumCCWRotations(a_NumCCWRotations),
m_Weight(a_Weight)
{ {
} }

View File

@ -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 /** 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. */ placed and adjust the returned piece vectors. */
class cPiecePool class cPiecePool
@ -101,6 +108,16 @@ public:
Multiple starting points are supported, one of the returned piece will be chosen. */ Multiple starting points are supported, one of the returned piece will be chosen. */
virtual cPieces GetStartingPieces(void) = 0; 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. /** 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. */ The pool may adjust the pieces it will return the next time. */
virtual void PiecePlaced(const cPiece & a_Piece) = 0; virtual void PiecePlaced(const cPiece & a_Piece) = 0;
@ -157,8 +174,9 @@ protected:
cPiece * m_Piece; // The piece being connected cPiece * m_Piece; // The piece being connected
cPiece::cConnector m_Connector; // The piece's connector being used (relative non-rotated coords) 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_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; typedef std::vector<cConnection> cConnections;

View File

@ -91,7 +91,19 @@ static const cPrefab::sDef g_TestPrefabDef =
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotations */
// Merge strategy: // Merge strategy:
cBlockArea::msImprint cBlockArea::msImprint,
// ShouldExtendFloor:
false,
// DefaultWeight:
10,
// DepthWeight:
"",
// AddWeightIfSame:
1000,
}; };
static cPrefab g_TestPrefab(g_TestPrefabDef); 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_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_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_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); m_BlockArea[0].Create(m_Size);
CharMap cm; CharMap cm;
ParseCharMap(cm, a_Def.m_CharMap); ParseCharMap(cm, a_Def.m_CharMap);
ParseBlockImage(cm, a_Def.m_Image); ParseBlockImage(cm, a_Def.m_Image);
ParseConnectors(a_Def.m_Connectors); ParseConnectors(a_Def.m_Connectors);
ParseDepthWeight(a_Def.m_DepthWeight);
// 1 CCW rotation: // 1 CCW rotation:
if ((m_AllowedRotations & 0x01) != 0) 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 void cPrefab::Draw(cChunkDesc & a_Dest, const cPlacedPiece * a_Placement) const
{ {
// Draw the basic image:
Vector3i Placement = a_Placement->GetCoords(); Vector3i Placement = a_Placement->GetCoords();
int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width; int ChunkStartX = a_Dest.GetChunkX() * cChunkDef::Width;
int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width; int ChunkStartZ = a_Dest.GetChunkZ() * cChunkDef::Width;
Placement.Move(-ChunkStartX, 0, -ChunkStartZ); 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) void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
{ {
ASSERT(a_CharMapDef != NULL); 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 cPiece::cConnectors cPrefab::GetConnectors(void) const
{ {
return m_Connectors; return m_Connectors;

View File

@ -37,11 +37,47 @@ public:
int m_SizeX; int m_SizeX;
int m_SizeY; int m_SizeY;
int m_SizeZ; 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; 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; 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; const char * m_Connectors;
/** Bitmask specifying the allowed rotations.
N rotations CCW are allowed if bit N is set. */
int m_AllowedRotations; int m_AllowedRotations;
/** The merge strategy to use while drawing the prefab. */
cBlockArea::eMergeStrategy m_MergeStrategy; 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); cPrefab(const sDef & a_Def);
@ -51,6 +87,10 @@ public:
/** Returns true if the prefab has any connector of the specified type. */ /** Returns true if the prefab has any connector of the specified type. */
bool HasConnectorType(int a_ConnectorType) const; 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: protected:
/** Packs complete definition of a single block, for per-letter assignment. */ /** Packs complete definition of a single block, for per-letter assignment. */
@ -60,9 +100,12 @@ protected:
NIBBLETYPE m_BlockMeta; 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]; 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 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, ...). */ The index identifies the number of CCW rotations applied (0 = no rotation, 1 = 1 CCW rotation, ...). */
@ -82,6 +125,26 @@ protected:
/** The merge strategy to use when drawing the prefab into a block area */ /** The merge strategy to use when drawing the prefab into a block area */
cBlockArea::eMergeStrategy m_MergeStrategy; 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: // cPiece overrides:
@ -98,6 +161,9 @@ protected:
/** Parses the connectors definition text into m_Connectors member. */ /** Parses the connectors definition text into m_Connectors member. */
void ParseConnectors(const char * a_ConnectorsDef); void ParseConnectors(const char * a_ConnectorsDef);
/** Parses the per-depth weight into m_DepthWeight member. */
void ParseDepthWeight(const char * a_DepthWeightDef);
}; };

View File

@ -133,10 +133,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 0, 2, 2: 4\n" /* Type 1, direction X- */, "1: 0, 2, 2: 4\n" /* Type 1, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
20,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // BalconyCorridor }, // BalconyCorridor
@ -274,10 +286,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 0, 2, 4: 4\n" /* Type 1, direction X- */, "1: 0, 2, 4: 4\n" /* Type 1, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
20,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // BalconyTee2 }, // BalconyTee2
@ -378,10 +402,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 0, 1, 3: 4\n" /* Type 0, direction X- */, "0: 0, 1, 3: 4\n" /* Type 0, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // BlazePlatform }, // BlazePlatform
@ -510,10 +546,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 0, 5, 3: 4\n" /* Type 0, direction X- */, "0: 0, 5, 3: 4\n" /* Type 0, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // BlazePlatformOverhang }, // BlazePlatformOverhang
@ -694,10 +742,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 7, 5, 14: 3\n" /* Type 0, direction Z+ */, "0: 7, 5, 14: 3\n" /* Type 0, direction Z+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
5,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // BridgeCircleCrossing }, // BridgeCircleCrossing
@ -879,10 +939,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 14, 5, 7: 5\n" /* Type 0, direction X+ */, "0: 14, 5, 7: 5\n" /* Type 0, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
10,
// DepthWeight:
"1:1000",
// AddWeightIfSame:
0,
}, // BridgeCrossing }, // BridgeCrossing
@ -957,10 +1029,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 0, 5, 2: 4\n" /* Type 0, direction X- */, "0: 0, 5, 2: 4\n" /* Type 0, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"1:0",
// AddWeightIfSame:
0,
}, // BridgeCrumble1 }, // BridgeCrumble1
@ -1041,10 +1125,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 0, 5, 2: 4\n" /* Type 1, direction X- */, "1: 0, 5, 2: 4\n" /* Type 1, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"1:0",
// AddWeightIfSame:
0,
}, // BridgeCrumble2 }, // BridgeCrumble2
@ -1204,14 +1300,262 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 2, 4, 15: 3\n" /* Type 0, direction Z+ */, "0: 2, 4, 15: 3\n" /* Type 0, direction Z+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
10,
// DepthWeight:
"",
// AddWeightIfSame:
1000,
}, // BridgeDoubleCrumble }, // 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: // BridgeLevelCrossing:
// The data has been exported from the gallery Nether, area index 45, ID 304, created by Aloe_vera // 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: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // BridgeLevelCrossing }, // BridgeLevelCrossing
@ -1617,10 +1973,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 14, 5, 2: 5\n" /* Type 0, direction X+ */, "0: 14, 5, 2: 5\n" /* Type 0, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
500,
// DepthWeight:
"",
// AddWeightIfSame:
1000,
}, // BridgeSegment }, // BridgeSegment
@ -1761,10 +2129,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 14, 5, 2: 5\n" /* Type 0, direction X+ */, "0: 14, 5, 2: 5\n" /* Type 0, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
10,
// DepthWeight:
"1:500",
// AddWeightIfSame:
0,
}, // BridgeTee }, // BridgeTee
@ -1844,10 +2224,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 0, 1, 2: 4\n" /* Type 1, direction X- */, "1: 0, 1, 2: 4\n" /* Type 1, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
200,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // Corridor11 }, // Corridor11
@ -1927,10 +2319,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 0, 1, 2: 4\n" /* Type 1, direction X- */, "1: 0, 1, 2: 4\n" /* Type 1, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
200,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // Corridor13 }, // Corridor13
@ -2048,10 +2452,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 10, 1, 2: 5\n" /* Type 1, direction X+ */, "1: 10, 1, 2: 5\n" /* Type 1, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // CorridorCorner5 }, // CorridorCorner5
@ -2170,10 +2586,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */, "1: 2, 1, 10: 3\n" /* Type 1, direction Z+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // CorridorCornerChest5 }, // CorridorCornerChest5
@ -2304,10 +2732,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 8, 8, 2: 5\n" /* Type 1, direction X+ */, "1: 8, 8, 2: 5\n" /* Type 1, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // CorridorStairs }, // CorridorStairs
@ -2367,11 +2807,11 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
// Level 4 // Level 4
/* z\x* 1111 */ /* z\x* 1111 */
/* * 01234567890123 */ /* * 01234567890123 */
/* 0 */ "aaaaaaaaaaaaaa" /* 0 */ "aabaaaaaaaabaa"
/* 1 */ ".............." /* 1 */ ".............."
/* 2 */ ".............." /* 2 */ ".............."
/* 3 */ ".............." /* 3 */ ".............."
/* 4 */ "aaaaaaaaaaaaaa" /* 4 */ "aabaaaaaaaabaa"
// Level 5 // Level 5
/* z\x* 1111 */ /* z\x* 1111 */
@ -2387,10 +2827,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 13, 1, 2: 5\n" /* Type 1, direction X+ */, "1: 13, 1, 2: 5\n" /* Type 1, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // DarkCorridor }, // DarkCorridor
@ -2625,10 +3077,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 9, 1, 0: 2\n" /* Type 1, direction Z- */, "1: 9, 1, 0: 2\n" /* Type 1, direction Z- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // LavaStaircase }, // LavaStaircase
@ -2938,10 +3402,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 0, 9, 7: 4\n" /* Type 1, direction X- */, "1: 0, 9, 7: 4\n" /* Type 1, direction X- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // LavaStaircaseBig }, // LavaStaircaseBig
@ -3200,10 +3676,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"", "",
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // LavaStairsBridge }, // LavaStairsBridge
@ -3367,13 +3855,25 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
// Connectors: // Connectors:
"1: 12, 1, 6: 5\n" /* Type 1, direction X+ */ "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: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // MidStaircase }, // MidStaircase
@ -3497,10 +3997,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 3, 1, 0: 2\n" /* Type 0, direction Z- */, "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // StairsToOpen1 }, // StairsToOpen1
@ -3624,10 +4136,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 3, 1, 0: 2\n" /* Type 0, direction Z- */, "0: 3, 1, 0: 2\n" /* Type 0, direction Z- */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // StairsToOpen2 }, // StairsToOpen2
@ -3722,10 +4246,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 12, 1, 4: 5\n" /* Type 1, direction X+ */, "1: 12, 1, 4: 5\n" /* Type 1, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // Tee2x4 }, // Tee2x4
@ -3832,10 +4368,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"1: 12, 1, 6: 5\n" /* Type 1, direction X+ */, "1: 12, 1, 6: 5\n" /* Type 1, direction X+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // Tee4x4 }, // Tee4x4
@ -3921,10 +4469,22 @@ const cPrefab::sDef g_NetherFortPrefabs[] =
"0: 3, 1, 6: 3\n" /* Type 0, direction Z+ */, "0: 3, 1, 6: 3\n" /* Type 0, direction Z+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
-99,
}, // Turret }, // Turret
}; // g_NetherFortPrefabs }; // g_NetherFortPrefabs
@ -4108,10 +4668,22 @@ const cPrefab::sDef g_NetherFortStartingPrefabs[] =
"1: 6, 1, 12: 3\n" /* Type 1, direction Z+ */, "1: 6, 1, 12: 3\n" /* Type 1, direction Z+ */,
// AllowedRotations: // AllowedRotations:
7, /* 1, 2, 3 CCW rotations */ 7, /* 1, 2, 3 CCW rotation allowed */
// Merge strategy: // Merge strategy:
cBlockArea::msSpongePrint, cBlockArea::msSpongePrint,
// ShouldExtendFloor:
false,
// DefaultWeight:
100,
// DepthWeight:
"",
// AddWeightIfSame:
0,
}, // CentralRoom }, // CentralRoom
}; };

View File

@ -111,9 +111,9 @@ void cMonster::SpawnOn(cClientHandle & a_Client)
void cMonster::TickPathFinding() void cMonster::TickPathFinding()
{ {
const int PosX = (int)floor(GetPosX()); const int PosX = POSX_TOINT;
const int PosY = (int)floor(GetPosY()); const int PosY = POSY_TOINT;
const int PosZ = (int)floor(GetPosZ()); const int PosZ = POSZ_TOINT;
m_FinalDestination.y = (double)FindFirstNonAirBlockPosition(m_FinalDestination.x, m_FinalDestination.z); 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 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 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 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)); 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)); 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 */); 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 cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
{ {
int PosY = (int)floor(GetPosY()); int PosY = POSY_TOINT;
if (PosY < 0) if (PosY < 0)
PosY = 0; PosY = 0;
@ -969,15 +983,15 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk)
return; return;
} }
int RelY = (int)floor(GetPosY()); int RelY = POSY_TOINT;
if ((RelY < 0) || (RelY >= cChunkDef::Height)) if ((RelY < 0) || (RelY >= cChunkDef::Height))
{ {
// Outside the world // Outside the world
return; return;
} }
int RelX = (int)floor(GetPosX()) - GetChunkX() * cChunkDef::Width; int RelX = POSX_TOINT - GetChunkX() * cChunkDef::Width;
int RelZ = (int)floor(GetPosZ()) - GetChunkZ() * cChunkDef::Width; int RelZ = POSZ_TOINT - GetChunkZ() * cChunkDef::Width;
if (!a_Chunk.IsLightValid()) if (!a_Chunk.IsLightValid())
{ {

View File

@ -185,14 +185,14 @@ protected:
inline bool IsNextYPosReachable(int a_PosY) inline bool IsNextYPosReachable(int a_PosY)
{ {
return ( return (
(a_PosY <= (int)floor(GetPosY())) || (a_PosY <= POSY_TOINT) ||
DoesPosYRequireJump(a_PosY) DoesPosYRequireJump(a_PosY)
); );
} }
/** Returns if a monster can reach a given height by jumping */ /** Returns if a monster can reach a given height by jumping */
inline bool DoesPosYRequireJump(int a_PosY) 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 */ /** A semi-temporary list to store the traversed coordinates during active pathfinding so we don't visit them again */

View File

@ -102,7 +102,7 @@ void cSheep::Tick(float a_Dt, cChunk & a_Chunk)
{ {
if (m_World->GetBlock(PosX, PosY, PosZ) == E_BLOCK_GRASS) 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; m_TimeToStopEating = 40;
} }
} }

View File

@ -30,7 +30,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
{ {
if (m_World->GetTickRandomNumber(5) == 3) if (m_World->GetTickRandomNumber(5) == 3)
{ {
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_VILLAGER_ANGRY); m_World->BroadcastEntityStatus(*this, esVillagerAngry);
} }
} }
} }

View File

@ -75,12 +75,12 @@ void cWolf::OnRightClicked(cPlayer & a_Player)
SetMaxHealth(20); SetMaxHealth(20);
SetIsTame(true); SetIsTame(true);
SetOwner(a_Player.GetName()); 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); m_World->BroadcastParticleEffect("heart", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
} }
else 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); m_World->BroadcastParticleEffect("smoke", (float) GetPosX(), (float) GetPosY(), (float) GetPosZ(), 0, 0, 0, 0, 5);
} }
} }

View 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;
}

View File

@ -14,7 +14,7 @@
#ifndef CAUTHENTICATOR_H_INCLUDED #ifndef CAUTHENTICATOR_H_INCLUDED
#define CAUTHENTICATOR_H_INCLUDED #define CAUTHENTICATOR_H_INCLUDED
#include "OSSupport/IsThread.h" #include "../OSSupport/IsThread.h"
@ -31,23 +31,23 @@ class cAuthenticator :
public cIsThread public cIsThread
{ {
typedef cIsThread super; typedef cIsThread super;
public: public:
cAuthenticator(void); cAuthenticator(void);
~cAuthenticator(); ~cAuthenticator();
/// (Re-)read server and address from INI: /** (Re-)read server and address from INI: */
void ReadINI(cIniFile & IniFile); 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); 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); 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); void Stop(void);
private: private:
class cUser class cUser
@ -56,30 +56,30 @@ private:
int m_ClientID; int m_ClientID;
AString m_Name; AString m_Name;
AString m_ServerID; AString m_ServerID;
cUser(int a_ClientID, const AString & a_Name, const AString & a_ServerID) : cUser(int a_ClientID, const AString & a_Name, const AString & a_ServerID) :
m_ClientID(a_ClientID), m_ClientID(a_ClientID),
m_Name(a_Name), m_Name(a_Name),
m_ServerID(a_ServerID) m_ServerID(a_ServerID)
{ {
} }
} ; };
typedef std::deque<cUser> cUserList; typedef std::deque<cUser> cUserList;
cCriticalSection m_CS; cCriticalSection m_CS;
cUserList m_Queue; cUserList m_Queue;
cEvent m_QueueNonempty; cEvent m_QueueNonempty;
AString m_Server; AString m_Server;
AString m_Address; AString m_Address;
bool m_ShouldAuthenticate; bool m_ShouldAuthenticate;
// cIsThread override: /** cIsThread override: */
virtual void Execute(void) 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) /** 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); bool AuthWithYggdrasil(AString & a_UserName, const AString & a_ServerId, AString & a_UUID);
}; };

View File

@ -83,6 +83,7 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0; virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) = 0;
virtual void SendKeepAlive (int a_PingID) = 0; virtual void SendKeepAlive (int a_PingID) = 0;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) = 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 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 SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) = 0;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) = 0;

View File

@ -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) void cProtocol125::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
{ {
cCSLock Lock(m_CSPacket); 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) void cProtocol125::SendPickupSpawn(const cPickup & a_Pickup)
{ {
cCSLock Lock(m_CSPacket); 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) void cProtocol125::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
{ {
cCSLock Lock(m_CSPacket); 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) 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 // Not needed in this protocol version

View File

@ -56,19 +56,12 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override; virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) 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 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 SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) 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 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 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 virtual void SendPaintingSpawn (const cPainting & a_Painting) override;
{
UNUSED(a_Painting);
};
virtual void SendPickupSpawn (const cPickup & a_Pickup) override; virtual void SendPickupSpawn (const cPickup & a_Pickup) override;
virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message virtual void SendPlayerAbilities (void) override {} // This protocol doesn't support such message
virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override; virtual void SendEntityAnimation (const cEntity & a_Entity, char a_Animation) override;
@ -82,12 +75,7 @@ public:
virtual void SendRespawn (void) override; virtual void SendRespawn (void) override;
virtual void SendExperience (void) override; virtual void SendExperience (void) override;
virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override; virtual void SendExperienceOrb (const cExpOrb & a_ExpOrb) override;
virtual void SendScoreboardObjective (const AString & a_Name, const AString & a_DisplayName, Byte a_Mode) 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 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 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 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 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

View File

@ -88,8 +88,9 @@ cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAdd
// Create the comm log file, if so requested: // Create the comm log file, if so requested:
if (g_ShouldLogCommIn || g_ShouldLogCommOut) if (g_ShouldLogCommIn || g_ShouldLogCommOut)
{ {
static int sCounter = 0;
cFile::CreateFolder("CommLogs"); 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); 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) 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 cPacketizer Pkt(*this, 0x1b); // Attach Entity packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteInt((a_Vehicle != NULL) ? a_Vehicle->GetUniqueID() : 0); 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) 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 cPacketizer Pkt(*this, 0x24); // Block Action packet
Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockX);
Pkt.WriteShort(a_BlockY); 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) 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 cPacketizer Pkt(*this, 0x25); // Block Break Animation packet
Pkt.WriteVarInt(a_EntityID); Pkt.WriteVarInt(a_EntityID);
Pkt.WriteInt(a_BlockX); 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) 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 cPacketizer Pkt(*this, 0x23); // Block Change packet
Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockX);
Pkt.WriteByte(a_BlockY); 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) 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 cPacketizer Pkt(*this, 0x22); // Multi Block Change packet
Pkt.WriteInt(a_ChunkX); Pkt.WriteInt(a_ChunkX);
Pkt.WriteInt(a_ChunkZ); 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) void cProtocol172::SendChat(const AString & a_Message)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x02); // Chat Message packet cPacketizer Pkt(*this, 0x02); // Chat Message packet
Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Message).c_str())); 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) void cProtocol172::SendChat(const cCompositeChat & a_Message)
{ {
ASSERT(m_State == 3); // In game mode?
// Compose the complete Json string to send: // Compose the complete Json string to send:
Json::Value msg; Json::Value msg;
msg["text"] = ""; // The client crashes without this 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) 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) // Serialize first, before creating the Packetizer (the packetizer locks a CS)
// This contains the flags and bitmasks, too // This contains the flags and bitmasks, too
const AString & ChunkData = a_Serializer.Serialize(cChunkDataSerializer::RELEASE_1_3_2); 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) 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 cPacketizer Pkt(*this, 0x0d); // Collect Item packet
Pkt.WriteInt(a_Pickup.GetUniqueID()); Pkt.WriteInt(a_Pickup.GetUniqueID());
Pkt.WriteInt(a_Player.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) void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x13); // Destroy Entities packet cPacketizer Pkt(*this, 0x13); // Destroy Entities packet
Pkt.WriteByte(1); Pkt.WriteByte(1);
Pkt.WriteInt(a_Entity.GetUniqueID()); 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) 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 cPacketizer Pkt(*this, 0x36); // Sign Editor Open packet
Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockX);
Pkt.WriteInt(a_BlockY); 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) 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 cPacketizer Pkt(*this, 0x1D); // Entity Effect packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_EffectID); 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) 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 cPacketizer Pkt(*this, 0x04); // Entity Equipment packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteShort(a_SlotNum); 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) void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x19); // Entity Head Look packet cPacketizer Pkt(*this, 0x19); // Entity Head Look packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetHeadYaw()); Pkt.WriteByteAngle(a_Entity.GetHeadYaw());
@ -391,6 +420,8 @@ void cProtocol172::SendEntityHeadLook(const cEntity & a_Entity)
void cProtocol172::SendEntityLook(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 cPacketizer Pkt(*this, 0x16); // Entity Look packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByteAngle(a_Entity.GetYaw()); Pkt.WriteByteAngle(a_Entity.GetYaw());
@ -403,6 +434,8 @@ void cProtocol172::SendEntityLook(const cEntity & a_Entity)
void cProtocol172::SendEntityMetadata(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 cPacketizer Pkt(*this, 0x1c); // Entity Metadata packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteEntityMetadata(a_Entity); Pkt.WriteEntityMetadata(a_Entity);
@ -415,6 +448,8 @@ void cProtocol172::SendEntityMetadata(const cEntity & a_Entity)
void cProtocol172::SendEntityProperties(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 cPacketizer Pkt(*this, 0x20); // Entity Properties packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteEntityProperties(a_Entity); 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) 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 cPacketizer Pkt(*this, 0x15); // Entity Relative Move packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_RelX); 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) 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 cPacketizer Pkt(*this, 0x17); // Entity Look And Relative Move packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_RelX); 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) void cProtocol172::SendEntityStatus(const cEntity & a_Entity, char a_Status)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x1a); // Entity Status packet cPacketizer Pkt(*this, 0x1a); // Entity Status packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteChar(a_Status); 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) void cProtocol172::SendEntityVelocity(const cEntity & a_Entity)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x12); // Entity Velocity packet cPacketizer Pkt(*this, 0x12); // Entity Velocity packet
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
// 400 = 8000 / 20 ... Conversion from our speed in m/s to 8000 m/tick // 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) 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 cPacketizer Pkt(*this, 0x27); // Explosion packet
Pkt.WriteFloat((float)a_BlockX); Pkt.WriteFloat((float)a_BlockX);
Pkt.WriteFloat((float)a_BlockY); 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) void cProtocol172::SendGameMode(eGameMode a_GameMode)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2b); // Change Game State packet cPacketizer Pkt(*this, 0x2b); // Change Game State packet
Pkt.WriteByte(3); // Reason: Change game mode Pkt.WriteByte(3); // Reason: Change game mode
Pkt.WriteFloat((float)a_GameMode); Pkt.WriteFloat((float)a_GameMode);
@ -513,6 +560,8 @@ void cProtocol172::SendGameMode(eGameMode a_GameMode)
void cProtocol172::SendHealth(void) void cProtocol172::SendHealth(void)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x06); // Update Health packet cPacketizer Pkt(*this, 0x06); // Update Health packet
cPlayer * Player = m_Client->GetPlayer(); cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteFloat((float)Player->GetHealth()); 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) 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 cPacketizer Pkt(*this, 0x2f); // Set Slot packet
Pkt.WriteChar(a_WindowID); Pkt.WriteChar(a_WindowID);
Pkt.WriteShort(a_SlotNum); 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) 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 cPacketizer Pkt(*this, 0x00); // Keep Alive packet
Pkt.WriteInt(a_PingID); 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) void cProtocol172::SendPaintingSpawn(const cPainting & a_Painting)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x10); // Spawn Painting packet cPacketizer Pkt(*this, 0x10); // Spawn Painting packet
Pkt.WriteVarInt(a_Painting.GetUniqueID()); Pkt.WriteVarInt(a_Painting.GetUniqueID());
Pkt.WriteString(a_Painting.GetName().c_str()); 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) 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); cPacketizer Pkt(*this, 0x34);
Pkt.WriteVarInt(a_ID); Pkt.WriteVarInt(a_ID);
Pkt.WriteShort (3 + a_Length); 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) void cProtocol172::SendMapDecorators(int a_ID, const cMapDecoratorList & a_Decorators)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x34); cPacketizer Pkt(*this, 0x34);
Pkt.WriteVarInt(a_ID); Pkt.WriteVarInt(a_ID);
Pkt.WriteShort (1 + (3 * a_Decorators.size())); 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) void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x34); cPacketizer Pkt(*this, 0x34);
Pkt.WriteVarInt(a_ID); Pkt.WriteVarInt(a_ID);
Pkt.WriteShort (2); Pkt.WriteShort (2);
@ -647,6 +728,8 @@ void cProtocol172::SendMapInfo(int a_ID, unsigned int a_Scale)
void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup) void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
{ {
ASSERT(m_State == 3); // In game mode?
{ {
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
Pkt.WriteVarInt(a_Pickup.GetUniqueID()); Pkt.WriteVarInt(a_Pickup.GetUniqueID());
@ -673,6 +756,8 @@ void cProtocol172::SendPickupSpawn(const cPickup & a_Pickup)
void cProtocol172::SendPlayerAbilities(void) void cProtocol172::SendPlayerAbilities(void)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x39); // Player Abilities packet cPacketizer Pkt(*this, 0x39); // Player Abilities packet
Byte Flags = 0; Byte Flags = 0;
cPlayer * Player = m_Client->GetPlayer(); cPlayer * Player = m_Client->GetPlayer();
@ -700,6 +785,8 @@ void cProtocol172::SendPlayerAbilities(void)
void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animation) void cProtocol172::SendEntityAnimation(const cEntity & a_Entity, char a_Animation)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0b); // Animation packet cPacketizer Pkt(*this, 0x0b); // Animation packet
Pkt.WriteVarInt(a_Entity.GetUniqueID()); Pkt.WriteVarInt(a_Entity.GetUniqueID());
Pkt.WriteChar(a_Animation); 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) 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); cPacketizer Pkt(*this, 0x2A);
Pkt.WriteString(a_ParticleName); Pkt.WriteString(a_ParticleName);
Pkt.WriteFloat(a_SrcX); 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) void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x38); // Playerlist Item packet cPacketizer Pkt(*this, 0x38); // Playerlist Item packet
Pkt.WriteString(a_Player.GetName()); Pkt.WriteString(a_Player.GetName());
Pkt.WriteBool(a_IsOnline); Pkt.WriteBool(a_IsOnline);
@ -741,6 +832,8 @@ void cProtocol172::SendPlayerListItem(const cPlayer & a_Player, bool a_IsOnline)
void cProtocol172::SendPlayerMaxSpeed(void) void cProtocol172::SendPlayerMaxSpeed(void)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x20); // Entity Properties cPacketizer Pkt(*this, 0x20); // Entity Properties
cPlayer * Player = m_Client->GetPlayer(); cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteInt(Player->GetUniqueID()); Pkt.WriteInt(Player->GetUniqueID());
@ -768,6 +861,8 @@ void cProtocol172::SendPlayerMaxSpeed(void)
void cProtocol172::SendPlayerMoveLook(void) void cProtocol172::SendPlayerMoveLook(void)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x08); // Player Position And Look packet cPacketizer Pkt(*this, 0x08); // Player Position And Look packet
cPlayer * Player = m_Client->GetPlayer(); cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteDouble(Player->GetPosX()); Pkt.WriteDouble(Player->GetPosX());
@ -798,10 +893,12 @@ void cProtocol172::SendPlayerPosition(void)
void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player) void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
{ {
ASSERT(m_State == 3); // In game mode?
// Called to spawn another player for the client // Called to spawn another player for the client
cPacketizer Pkt(*this, 0x0c); // Spawn Player packet cPacketizer Pkt(*this, 0x0c); // Spawn Player packet
Pkt.WriteVarInt(a_Player.GetUniqueID()); 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.WriteString(a_Player.GetName());
Pkt.WriteFPInt(a_Player.GetPosX()); Pkt.WriteFPInt(a_Player.GetPosX());
Pkt.WriteFPInt(a_Player.GetPosY()); 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) void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3f); cPacketizer Pkt(*this, 0x3f);
Pkt.WriteString(a_Channel); Pkt.WriteString(a_Channel);
Pkt.WriteShort((short)a_Message.size()); 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) 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.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_EffectID); Pkt.WriteByte(a_EffectID);
} }
@ -858,7 +959,9 @@ void cProtocol172::SendRespawn(void)
void cProtocol172::SendExperience (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(); cPlayer * Player = m_Client->GetPlayer();
Pkt.WriteFloat(Player->GetXpPercentage()); Pkt.WriteFloat(Player->GetXpPercentage());
Pkt.WriteShort(Player->GetXpLevel()); Pkt.WriteShort(Player->GetXpLevel());
@ -871,6 +974,8 @@ void cProtocol172::SendExperience (void)
void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb) void cProtocol172::SendExperienceOrb(const cExpOrb & a_ExpOrb)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x11); cPacketizer Pkt(*this, 0x11);
Pkt.WriteVarInt(a_ExpOrb.GetUniqueID()); Pkt.WriteVarInt(a_ExpOrb.GetUniqueID());
Pkt.WriteInt((int) a_ExpOrb.GetPosX()); 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) 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_Name);
Pkt.WriteString(a_DisplayName); Pkt.WriteString(a_DisplayName);
Pkt.WriteByte(a_Mode); 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) 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.WriteString(a_Player);
Pkt.WriteByte(a_Mode); 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) 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.WriteByte((int) a_Display);
Pkt.WriteString(a_Objective); 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 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 cPacketizer Pkt(*this, 0x29); // Sound Effect packet
Pkt.WriteString(a_SoundName); Pkt.WriteString(a_SoundName);
Pkt.WriteInt(a_SrcX); 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) 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 cPacketizer Pkt(*this, 0x28); // Effect packet
Pkt.WriteInt(a_EffectID); Pkt.WriteInt(a_EffectID);
Pkt.WriteInt(a_SrcX); 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) void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0e); // Spawn Object packet cPacketizer Pkt(*this, 0x0e); // Spawn Object packet
Pkt.WriteVarInt(a_FallingBlock.GetUniqueID()); Pkt.WriteVarInt(a_FallingBlock.GetUniqueID());
Pkt.WriteByte(70); // Falling block Pkt.WriteByte(70); // Falling block
@ -975,6 +1092,8 @@ void cProtocol172::SendSpawnFallingBlock(const cFallingBlock & a_FallingBlock)
void cProtocol172::SendSpawnMob(const cMonster & a_Mob) void cProtocol172::SendSpawnMob(const cMonster & a_Mob)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet cPacketizer Pkt(*this, 0x0f); // Spawn Mob packet
Pkt.WriteVarInt(a_Mob.GetUniqueID()); Pkt.WriteVarInt(a_Mob.GetUniqueID());
Pkt.WriteByte((Byte)a_Mob.GetMobType()); 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) 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 cPacketizer Pkt(*this, 0xe); // Spawn Object packet
Pkt.WriteVarInt(a_Entity.GetUniqueID()); Pkt.WriteVarInt(a_Entity.GetUniqueID());
Pkt.WriteByte(a_ObjectType); 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) 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 cPacketizer Pkt(*this, 0xe); // Spawn Object packet
Pkt.WriteVarInt(a_Vehicle.GetUniqueID()); Pkt.WriteVarInt(a_Vehicle.GetUniqueID());
Pkt.WriteByte(a_VehicleType); 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) void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet cPacketizer Pkt(*this, 0x3a); // Tab-Complete packet
Pkt.WriteVarInt(a_Results.size()); Pkt.WriteVarInt(a_Results.size());
@ -1058,6 +1183,8 @@ void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
void cProtocol172::SendTeleportEntity(const cEntity & a_Entity) void cProtocol172::SendTeleportEntity(const cEntity & a_Entity)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x18); cPacketizer Pkt(*this, 0x18);
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteFPInt(a_Entity.GetPosX()); 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) 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 cPacketizer Pkt(*this, 0x2c); // Spawn Global Entity packet
Pkt.WriteVarInt(0); // EntityID = 0, always Pkt.WriteVarInt(0); // EntityID = 0, always
Pkt.WriteByte(1); // Type = Thunderbolt 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) void cProtocol172::SendTimeUpdate(Int64 a_WorldAge, Int64 a_TimeOfDay)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x03); cPacketizer Pkt(*this, 0x03);
Pkt.WriteInt64(a_WorldAge); Pkt.WriteInt64(a_WorldAge);
Pkt.WriteInt64(a_TimeOfDay); 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) void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x21); // Chunk Data packet cPacketizer Pkt(*this, 0x21); // Chunk Data packet
Pkt.WriteInt(a_ChunkX); Pkt.WriteInt(a_ChunkX);
Pkt.WriteInt(a_ChunkZ); Pkt.WriteInt(a_ChunkZ);
@ -1112,6 +1245,8 @@ void cProtocol172::SendUnloadChunk(int a_ChunkX, int a_ChunkZ)
void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity) void cProtocol172::SendUpdateBlockEntity(cBlockEntity & a_BlockEntity)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x35); // Update tile entity packet cPacketizer Pkt(*this, 0x35); // Update tile entity packet
Pkt.WriteInt(a_BlockEntity.GetPosX()); Pkt.WriteInt(a_BlockEntity.GetPosX());
Pkt.WriteShort(a_BlockEntity.GetPosY()); 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) 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); cPacketizer Pkt(*this, 0x33);
Pkt.WriteInt(a_BlockX); Pkt.WriteInt(a_BlockX);
Pkt.WriteShort((short)a_BlockY); 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) 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); cPacketizer Pkt(*this, 0x0a);
Pkt.WriteInt(a_Entity.GetUniqueID()); Pkt.WriteInt(a_Entity.GetUniqueID());
Pkt.WriteInt(a_BlockX); 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) void cProtocol172::SendWeather(eWeather a_Weather)
{ {
ASSERT(m_State == 3); // In game mode?
{ {
cPacketizer Pkt(*this, 0x2b); // Change Game State packet cPacketizer Pkt(*this, 0x2b); // Change Game State packet
Pkt.WriteByte((a_Weather == wSunny) ? 1 : 2); // End rain / begin rain 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) void cProtocol172::SendWholeInventory(const cWindow & a_Window)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x30); // Window Items packet cPacketizer Pkt(*this, 0x30); // Window Items packet
Pkt.WriteChar(a_Window.GetWindowID()); Pkt.WriteChar(a_Window.GetWindowID());
Pkt.WriteShort(a_Window.GetNumSlots()); Pkt.WriteShort(a_Window.GetNumSlots());
@ -1199,6 +1342,8 @@ void cProtocol172::SendWholeInventory(const cWindow & a_Window)
void cProtocol172::SendWindowClose(const cWindow & a_Window) void cProtocol172::SendWindowClose(const cWindow & a_Window)
{ {
ASSERT(m_State == 3); // In game mode?
cPacketizer Pkt(*this, 0x2e); cPacketizer Pkt(*this, 0x2e);
Pkt.WriteChar(a_Window.GetWindowID()); Pkt.WriteChar(a_Window.GetWindowID());
} }
@ -1209,6 +1354,8 @@ void cProtocol172::SendWindowClose(const cWindow & a_Window)
void cProtocol172::SendWindowOpen(const cWindow & a_Window) void cProtocol172::SendWindowOpen(const cWindow & a_Window)
{ {
ASSERT(m_State == 3); // In game mode?
if (a_Window.GetWindowType() < 0) if (a_Window.GetWindowType() < 0)
{ {
// Do not send this packet for player inventory windows // 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) 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 cPacketizer Pkt(*this, 0x31); // Window Property packet
Pkt.WriteChar(a_Window.GetWindowID()); Pkt.WriteChar(a_Window.GetWindowID());
Pkt.WriteShort(a_Property); Pkt.WriteShort(a_Property);
@ -1563,15 +1712,6 @@ void cProtocol172::HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffe
} }
StartEncryption(DecryptedKey); 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()); m_Client->HandleLogin(4, m_Client->GetUsername());
} }
@ -1605,14 +1745,6 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
return; 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); 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);
}

View File

@ -87,6 +87,7 @@ public:
virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override; virtual void SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override; virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) 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 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 SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) 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): // Packet handlers while in the Status state (m_State == 1):
void HandlePacketStatusPing (cByteBuffer & a_ByteBuffer); 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): // Packet handlers while in the Login state (m_State == 2):
void HandlePacketLoginEncryptionResponse(cByteBuffer & a_ByteBuffer); 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;
} ;

View File

@ -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_3: return "1.6.3";
case PROTO_VERSION_1_6_4: return "1.6.4"; 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_2: return "1.7.2";
case PROTO_VERSION_1_7_6: return "1.7.6";
} }
ASSERT(!"Unknown protocol version"); ASSERT(!"Unknown protocol version");
return Printf("Unknown protocol (%d)", a_ProtocolVersion); 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) void cProtocolRecognizer::SendMapColumn(int a_ID, int a_X, int a_Y, const Byte * a_Colors, unsigned int a_Length)
{ {
ASSERT(m_Protocol != NULL); ASSERT(m_Protocol != NULL);
@ -965,6 +976,18 @@ bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRema
m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState); m_Protocol = new cProtocol172(m_Client, ServerAddress, (UInt16)ServerPort, NextState);
return true; 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)", LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)",
m_Client->GetIPString().c_str(), ProtocolVersion m_Client->GetIPString().c_str(), ProtocolVersion

View File

@ -18,8 +18,8 @@
// Adjust these if a new protocol is added or an old one is removed: // 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_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" #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 // 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_2 = 4,
PROTO_VERSION_1_7_6 = 5,
} ; } ;
cProtocolRecognizer(cClientHandle * a_Client); 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 SendInventorySlot (char a_WindowID, short a_SlotNum, const cItem & a_Item) override;
virtual void SendKeepAlive (int a_PingID) override; virtual void SendKeepAlive (int a_PingID) override;
virtual void SendLogin (const cPlayer & a_Player, const cWorld & a_World) 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 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 SendMapDecorators (int a_ID, const cMapDecoratorList & a_Decorators) override;
virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override; virtual void SendMapInfo (int a_ID, unsigned int a_Scale) override;

View File

@ -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);
} }

View File

@ -1,7 +1,7 @@
#pragma once #pragma once
#include "Authenticator.h" #include "Protocol/Authenticator.h"
#include "HTTPServer/HTTPServer.h" #include "HTTPServer/HTTPServer.h"
#include "Defines.h" #include "Defines.h"
@ -89,7 +89,7 @@ public:
void KickUser(int a_ClientID, const AString & a_Reason); void KickUser(int a_ClientID, const AString & a_Reason);
/// Called by cAuthenticator to auth the specified user /// 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 /// Executes commands queued in the command queue
void TickCommands(void); void TickCommands(void);

View File

@ -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); cCSLock Lock(m_CSClients);
for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr) for (ClientList::iterator itr = m_Clients.begin(); itr != m_Clients.end(); ++itr)
{ {
if ((*itr)->GetUniqueID() == a_ClientID) if ((*itr)->GetUniqueID() == a_ClientID)
{ {
(*itr)->Authenticate(); (*itr)->Authenticate(a_Name, a_UUID);
return; return;
} }
} // for itr - m_Clients[] } // for itr - m_Clients[]

View File

@ -83,7 +83,7 @@ public: // tolua_export
void Shutdown(void); void Shutdown(void);
void KickUser(int a_ClientID, const AString & a_Reason); 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 const AString & GetServerID(void) const { return m_ServerID; } // tolua_export

View File

@ -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 // Checking only when a block is changed, as opposed to every tick, also improves performance
PoweredBlocksList * PoweredBlocks = a_Chunk->GetRedstoneSimulatorPoweredBlocksList(); 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))) if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{ {
++itr;
continue; continue;
} }
if (!IsPotentialSource(Block)) 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); 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); itr = PoweredBlocks->erase(itr);
break; continue;
} }
else if ( else if (
// Changeable sources // 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); 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); itr = PoweredBlocks->erase(itr);
break; continue;
} }
++itr;
} }
LinkedBlocksList * LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList(); LinkedBlocksList * LinkedPoweredBlocks = a_Chunk->GetRedstoneSimulatorLinkedBlocksList();
@ -532,128 +534,96 @@ void cIncrementalRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_Block
}; };
// Check to see if directly beside a power source // 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); return;
NIBBLETYPE MetaToSet = MyMeta; }
int TimesMetaSmaller = 0, TimesFoundAWire = 0;
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power MyPower--;
for (size_t i = 0; i < ARRAYCOUNT(gCrossCoords); i++) // Loop through all directions to transfer or receive power
{
if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above...
{ {
if ((i >= 4) && (i <= 7)) // If we are currently checking for wire surrounding ourself one block above... if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) // If there is something solid above us (wire cut off)...
{ {
if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ))) // If there is something solid above us (wire cut off)... continue; // We don't receive power from that wire
{
continue; // We don't receive power from that wire
}
} }
else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us }
else if ((i >= 8) && (i <= 11)) // See above, but this is for wire below us
{
if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)))
{ {
if (cBlockInfo::IsSolid(m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y + 1, a_BlockZ + gCrossCoords[i].z))) continue;
{
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)
{
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
}
}
if (SurroundMeta < MyMeta) // Go through all surroundings to see if self power is larger than everyone else's
{
TimesMetaSmaller++;
}
}
} }
if ((TimesMetaSmaller == TimesFoundAWire) && (MyMeta != 0)) if (m_World.GetBlock(a_BlockX + gCrossCoords[i].x, a_BlockY + gCrossCoords[i].y, a_BlockZ + gCrossCoords[i].z) == E_BLOCK_REDSTONE_WIRE)
{ {
// All surrounding metas were smaller - self must have been a wire that was 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);
// 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
{ {
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)
{ {
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, MyPower);
{
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);
}
} }
}
// Wire still powered, power blocks beneath // Wire still powered, power blocks beneath
SetBlockPowered(a_BlockX, a_BlockY - 1, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ, 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); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_YM, E_BLOCK_REDSTONE_WIRE, MyPower);
switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ)) switch (GetWireDirection(a_BlockX, a_BlockY, a_BlockZ))
{
case REDSTONE_NONE:
{ {
case REDSTONE_NONE: 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 - 1, 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, MyPower);
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, MyPower);
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);
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, 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); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower);
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, MyPower);
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, MyPower);
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE); break;
break; }
} case REDSTONE_X_POS:
case REDSTONE_X_POS: {
{ 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); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE, MyPower);
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XP, E_BLOCK_REDSTONE_WIRE); break;
break; }
} case REDSTONE_X_NEG:
case REDSTONE_X_NEG: {
{ 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); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE, MyPower);
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_XM, E_BLOCK_REDSTONE_WIRE); break;
break; }
} case REDSTONE_Z_POS:
case REDSTONE_Z_POS: {
{ 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); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE, MyPower);
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZP, E_BLOCK_REDSTONE_WIRE); break;
break; }
} case REDSTONE_Z_NEG:
case REDSTONE_Z_NEG: {
{ 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); SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE, MyPower);
SetDirectionLinkedPowered(a_BlockX, a_BlockY, a_BlockZ, BLOCK_FACE_ZM, E_BLOCK_REDSTONE_WIRE); break;
break;
}
} }
} }
} }
@ -1046,16 +1016,13 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
break; break;
} }
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_WOODEN_PRESSURE_PLATE:
{ {
class cPressurePlateCallback : class cPressurePlateCallback :
public cEntityCallback public cEntityCallback
{ {
public: public:
cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) : cPressurePlateCallback(int a_BlockX, int a_BlockY, int a_BlockZ) :
m_Entity(NULL), m_NumberOfEntities(0),
m_World(a_World),
m_X(a_BlockX), m_X(a_BlockX),
m_Y(a_BlockY), m_Y(a_BlockY),
m_Z(a_BlockZ) m_Z(a_BlockZ)
@ -1070,7 +1037,140 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
if (Distance <= 0.7) 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 true; // Break out, we only need to know for plates that at least one entity is on top
} }
return false; return false;
@ -1078,45 +1178,46 @@ void cIncrementalRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_Bloc
bool FoundEntity(void) const bool FoundEntity(void) const
{ {
return m_Entity != NULL; return m_FoundEntity;
} }
protected: protected:
cEntity * m_Entity; bool m_FoundEntity;
cWorld * m_World;
int m_X; int m_X;
int m_Y; int m_Y;
int m_Z; 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); m_World.ForEachEntity(PressurePlateCallback);
NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ); NIBBLETYPE Meta = m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
if (PressurePlateCallback.FoundEntity()) 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.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); SetAllDirsAsPowered(a_BlockX, a_BlockY, a_BlockZ, a_MyType);
} }
else 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.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); m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
} }
break; break;
} }
default: default:
{
LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str()); LOGD("Unimplemented pressure plate type %s in cRedstoneSimulator", ItemToFullString(a_MyType).c_str());
break; 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) a_PowerLevel = 0;
{
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
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
{
if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{ {
return true; 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)))
if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
{ {
return true; continue;
} }
a_PowerLevel = std::max(a_PowerLevel, itr->a_PowerLevel);
} }
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) 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); 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 - 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); 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); 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); 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); 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; break;
} }
@ -1394,11 +1496,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
{ {
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX + 1, a_BlockY, a_BlockZ); 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 + 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); 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); 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); 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); 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; break;
} }
@ -1406,11 +1508,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
{ {
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ); 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, 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); 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); 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); 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); 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; break;
} }
@ -1418,11 +1520,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
{ {
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); 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, 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); 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); 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); 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); 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; break;
} }
@ -1430,11 +1532,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
{ {
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ - 1); 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, 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); 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); 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); 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); 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; break;
} }
@ -1442,11 +1544,11 @@ void cIncrementalRedstoneSimulator::SetDirectionLinkedPowered(int a_BlockX, int
{ {
BLOCKTYPE MiddleBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ + 1); 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, 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); 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); 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); 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); 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; 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 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 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); BLOCKTYPE Block = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
if (Block == E_BLOCK_AIR) 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(); PoweredBlocksList * Powered = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorPoweredBlocksList();
for (PoweredBlocksList::iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
for (PoweredBlocksList::const_iterator itr = Powered->begin(); itr != Powered->end(); ++itr) // Check powered list
{ {
if ( if (
itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) 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; return;
} }
} }
@ -1513,6 +1631,7 @@ void cIncrementalRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY,
sPoweredBlocks RC; sPoweredBlocks RC;
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
RC.a_PowerLevel = a_PowerLevel;
Powered->push_back(RC); Powered->push_back(RC);
} }
@ -1524,7 +1643,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
int a_BlockX, int a_BlockY, int a_BlockZ, int a_BlockX, int a_BlockY, int a_BlockZ,
int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ,
int a_SourceX, int a_SourceY, int a_SourceZ, 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); BLOCKTYPE DestBlock = m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ);
@ -1539,16 +1658,19 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
} }
LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList(); LinkedBlocksList * Linked = m_Chunk->GetNeighborChunk(a_BlockX, a_BlockZ)->GetRedstoneSimulatorLinkedBlocksList();
for (LinkedBlocksList::iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
for (LinkedBlocksList::const_iterator itr = Linked->begin(); itr != Linked->end(); ++itr) // Check linked powered list
{ {
if ( if (
itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) && itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)) &&
itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) && itr->a_MiddlePos.Equals(Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ)) &&
itr->a_SourcePos.Equals(Vector3i(a_SourceX, a_SourceY, a_SourceZ)) 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; return;
} }
} }
@ -1557,6 +1679,7 @@ void cIncrementalRedstoneSimulator::SetBlockLinkedPowered(
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ); RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ); RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ);
RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ); RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
RC.a_PowerLevel = a_PowerLevel;
Linked->push_back(RC); 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); 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.) // 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_DelayTicks = (((a_Meta & 0xC) >> 0x2) + 1) * 2;
RC.a_ElapsedTicks = 0; RC.a_ElapsedTicks = 0;
@ -1697,12 +1820,3 @@ bool cIncrementalRedstoneSimulator::IsLeverOn(NIBBLETYPE a_BlockMeta)
bool cIncrementalRedstoneSimulator::IsButtonOn(NIBBLETYPE a_BlockMeta)
{
return IsLeverOn(a_BlockMeta);
}

View File

@ -36,31 +36,35 @@ public:
private: private:
#define MAX_POWER_LEVEL 15
struct sPoweredBlocks // Define structure of the directly powered blocks list struct sPoweredBlocks // Define structure of the directly powered blocks list
{ {
Vector3i a_BlockPos; // Position of powered block Vector3i a_BlockPos; // Position of powered block
Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos 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) 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_BlockPos;
Vector3i a_MiddlePos; Vector3i a_MiddlePos; // Position of block that is betwixt a source and the destination
Vector3i a_SourcePos; 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; 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; Vector3i a_BlockPos;
unsigned char a_DelayTicks; unsigned char a_DelayTicks; // For how many ticks should the repeater delay
unsigned char a_ElapsedTicks; unsigned char a_ElapsedTicks; // How much of the previous has been elapsed?
bool ShouldPowerOn; bool ShouldPowerOn; // What happens when the delay time is fulfilled?
}; };
public: public:
@ -132,15 +136,15 @@ private:
/* ====== Helper functions ====== */ /* ====== Helper functions ====== */
/** Marks a block as powered */ /** 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 */ /** 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 */ /** 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); void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered);
/** Marks the second block in a direction as linked powered */ /** 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 */ /** 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 */ /** Queues a repeater to be powered or unpowered */
void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, bool ShouldPowerOn); 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 */ /** Returns if a piston is powered */
bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta); bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
/** Returns if a wire is powered /** 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 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);
bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ);
/** Returns if lever metadata marks it as emitting power */ /** Returns if lever metadata marks it as emitting power */
bool IsLeverOn(NIBBLETYPE a_BlockMeta); bool IsLeverOn(NIBBLETYPE a_BlockMeta);
/** Returns if button metadata marks it as emitting power */ /** 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 ====== */ /* ====== Misc Functions ====== */

View File

@ -108,6 +108,11 @@ public:
return x == a_Rhs.x && y == a_Rhs.y && z == a_Rhs.z; 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) inline bool operator < (const Vector3<T> & a_Rhs)
{ {
// return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ? // return (x < a_Rhs.x) && (y < a_Rhs.y) && (z < a_Rhs.z); ?

View File

@ -574,7 +574,7 @@ void cWorld::Start(void)
m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false); m_IsSugarcaneBonemealable = IniFile.GetValueSetB("Plants", "IsSugarcaneBonemealable", false);
m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true); m_IsDeepSnowEnabled = IniFile.GetValueSetB("Physics", "DeepSnow", true);
m_ShouldLavaSpawnFire = IniFile.GetValueSetB("Physics", "ShouldLavaSpawnFire", 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_bCommandBlocksEnabled = IniFile.GetValueSetB("Mechanics", "CommandBlocksEnabled", false);
m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true); m_bEnabledPVP = IniFile.GetValueSetB("Mechanics", "PVPEnabled", true);
m_bUseChatPrefixes = IniFile.GetValueSetB("Mechanics", "UseChatPrefixes", 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) 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 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) 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; continue;
} }
float SpeedX = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5)); float SpeedX = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
float SpeedY = (float)(a_FlyAwaySpeed * r1.randInt(50)); float SpeedY = (float)(a_FlyAwaySpeed * GetTickRandomNumber(50));
float SpeedZ = (float)(a_FlyAwaySpeed * (r1.randInt(10) - 5)); float SpeedZ = (float)(a_FlyAwaySpeed * (GetTickRandomNumber(10) - 5));
cPickup * Pickup = new cPickup( cPickup * Pickup = new cPickup(
a_BlockX, a_BlockY, a_BlockZ, a_BlockX, a_BlockY, a_BlockZ,

View File

@ -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 Colours are supposed to be calculated via: R << 16 + G << 8 + B

View File

@ -81,7 +81,7 @@ public:
static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem); static void FadeColoursFromString(const AString & a_String, cFireworkItem & a_FireworkItem);
/** Returns a colour code for fireworks used by the network code */ /** 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_HasFlicker;
bool m_HasTrail; bool m_HasTrail;