Merged branch 'master' into VillageGen.
This commit is contained in:
commit
e69a11012f
@ -27,7 +27,7 @@ Code Stuff
|
|||||||
- The only exception: a `switch` statement with all `case` statements being a single short statement is allowed to use the short brace-less form.
|
- The only exception: a `switch` statement with all `case` statements being a single short statement is allowed to use the short brace-less form.
|
||||||
- These two rules really mean that indent is governed by braces
|
- These two rules really mean that indent is governed by braces
|
||||||
* Add an empty last line in all source files (GCC and GIT can complain otherwise)
|
* Add an empty last line in all source files (GCC and GIT can complain otherwise)
|
||||||
* Use doxy-comments for functions in the header file, format as `/** Description */`
|
* All new public functions in all classes need documenting comments on what they do and what behavior they follow, use doxy-comments formatted as `/** Description */`. Do not use asterisks on additional lines in multi-line comments.
|
||||||
* Use spaces after the comment markers: `// Comment` instead of `//Comment`
|
* Use spaces after the comment markers: `// Comment` instead of `//Comment`
|
||||||
|
|
||||||
|
|
||||||
|
4
MCServer/.gitignore
vendored
4
MCServer/.gitignore
vendored
@ -30,3 +30,7 @@ motd.txt
|
|||||||
*.xml
|
*.xml
|
||||||
mcserver_api.lua
|
mcserver_api.lua
|
||||||
|
|
||||||
|
# Ignore the webadmin certs / privkey, so that no-one commits theirs by accident:
|
||||||
|
webadmin/httpscert.crt
|
||||||
|
webadmin/httpskey.pem
|
||||||
|
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
echo This script generates the certificate and private key for the https webadmin
|
||||||
|
echo Note that the generated certificate is self-signed, and therefore not trusted by browsers
|
||||||
|
echo Note that this script requires openssl to be installed and in PATH
|
||||||
|
echo.
|
||||||
|
echo When OpenSSL asks you for Common Name, you need to enter the fully qualified domain name of the server, that is, e. g. gallery.xoft.cz
|
||||||
|
echo.
|
||||||
|
echo If OpenSSL fails with an error, "WARNING: can't open config file: /usr/local/ssl/openssl.cnf", you need to run this script as an administrator
|
||||||
|
echo.
|
||||||
|
|
||||||
|
openssl req -x509 -newkey rsa:2048 -keyout httpskey.pem -out httpscert.crt -days 3650 -nodes
|
||||||
|
pause
|
10
MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh
Executable file
10
MCServer/webadmin/GenerateSelfSignedHTTPSCertUsingOpenssl.sh
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "This script generates the certificate and private key for the https webadmin"
|
||||||
|
echo "Note that the generated certificate is self-signed, and therefore not trusted by browsers"
|
||||||
|
echo "Note that this script requires openssl to be installed and in PATH"
|
||||||
|
echo ""
|
||||||
|
echo "When OpenSSL asks you for Common Name, you need to enter the fully qualified domain name of the server, that is, e. g. gallery.xoft.cz"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
openssl req -x509 -newkey rsa:2048 -keyout httpskey.pem -out httpscert.crt -days 3650 -nodes
|
@ -38,9 +38,9 @@ set(SHARED_SRC
|
|||||||
../../src/MCLogger.cpp
|
../../src/MCLogger.cpp
|
||||||
../../src/PolarSSL++/AesCfb128Decryptor.cpp
|
../../src/PolarSSL++/AesCfb128Decryptor.cpp
|
||||||
../../src/PolarSSL++/AesCfb128Encryptor.cpp
|
../../src/PolarSSL++/AesCfb128Encryptor.cpp
|
||||||
|
../../src/PolarSSL++/CryptoKey.cpp
|
||||||
../../src/PolarSSL++/CtrDrbgContext.cpp
|
../../src/PolarSSL++/CtrDrbgContext.cpp
|
||||||
../../src/PolarSSL++/EntropyContext.cpp
|
../../src/PolarSSL++/EntropyContext.cpp
|
||||||
../../src/PolarSSL++/PublicKey.cpp
|
|
||||||
../../src/PolarSSL++/RsaPrivateKey.cpp
|
../../src/PolarSSL++/RsaPrivateKey.cpp
|
||||||
)
|
)
|
||||||
set(SHARED_HDR
|
set(SHARED_HDR
|
||||||
@ -50,9 +50,9 @@ set(SHARED_HDR
|
|||||||
../../src/MCLogger.h
|
../../src/MCLogger.h
|
||||||
../../src/PolarSSL++/AesCfb128Decryptor.h
|
../../src/PolarSSL++/AesCfb128Decryptor.h
|
||||||
../../src/PolarSSL++/AesCfb128Encryptor.h
|
../../src/PolarSSL++/AesCfb128Encryptor.h
|
||||||
|
../../src/PolarSSL++/CryptoKey.h
|
||||||
../../src/PolarSSL++/CtrDrbgContext.h
|
../../src/PolarSSL++/CtrDrbgContext.h
|
||||||
../../src/PolarSSL++/EntropyContext.h
|
../../src/PolarSSL++/EntropyContext.h
|
||||||
../../src/PolarSSL++/PublicKey.h
|
|
||||||
../../src/PolarSSL++/RsaPrivateKey.h
|
../../src/PolarSSL++/RsaPrivateKey.h
|
||||||
)
|
)
|
||||||
set(SHARED_OSS_SRC
|
set(SHARED_OSS_SRC
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
#include "Connection.h"
|
#include "Connection.h"
|
||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "PolarSSL++/PublicKey.h"
|
#include "PolarSSL++/CryptoKey.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <direct.h> // For _mkdir()
|
#include <direct.h> // For _mkdir()
|
||||||
@ -2900,7 +2900,7 @@ void cConnection::SendEncryptionKeyResponse(const AString & a_ServerPublicKey, c
|
|||||||
Byte SharedSecret[16];
|
Byte SharedSecret[16];
|
||||||
Byte EncryptedSecret[128];
|
Byte EncryptedSecret[128];
|
||||||
memset(SharedSecret, 0, sizeof(SharedSecret)); // Use all zeroes for the initial secret
|
memset(SharedSecret, 0, sizeof(SharedSecret)); // Use all zeroes for the initial secret
|
||||||
cPublicKey PubKey(a_ServerPublicKey);
|
cCryptoKey PubKey(a_ServerPublicKey);
|
||||||
int res = PubKey.Encrypt(SharedSecret, sizeof(SharedSecret), EncryptedSecret, sizeof(EncryptedSecret));
|
int res = PubKey.Encrypt(SharedSecret, sizeof(SharedSecret), EncryptedSecret, sizeof(EncryptedSecret));
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
|
@ -76,6 +76,7 @@ $cfile "../CompositeChat.h"
|
|||||||
$cfile "../Map.h"
|
$cfile "../Map.h"
|
||||||
$cfile "../MapManager.h"
|
$cfile "../MapManager.h"
|
||||||
$cfile "../Scoreboard.h"
|
$cfile "../Scoreboard.h"
|
||||||
|
$cfile "../Statistics.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -2123,7 +2123,7 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel
|
|||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
m_Size.x, m_Size.y, m_Size.z
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
} // case msOverwrite
|
} // case msOverwrite
|
||||||
|
|
||||||
case cBlockArea::msFillAir:
|
case cBlockArea::msFillAir:
|
||||||
@ -2137,7 +2137,7 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel
|
|||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
m_Size.x, m_Size.y, m_Size.z
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
} // case msFillAir
|
} // case msFillAir
|
||||||
|
|
||||||
case cBlockArea::msImprint:
|
case cBlockArea::msImprint:
|
||||||
@ -2151,7 +2151,7 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel
|
|||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
m_Size.x, m_Size.y, m_Size.z
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
} // case msImprint
|
} // case msImprint
|
||||||
|
|
||||||
case cBlockArea::msLake:
|
case cBlockArea::msLake:
|
||||||
@ -2165,7 +2165,7 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel
|
|||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
m_Size.x, m_Size.y, m_Size.z
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
} // case msLake
|
} // case msLake
|
||||||
|
|
||||||
case cBlockArea::msSpongePrint:
|
case cBlockArea::msSpongePrint:
|
||||||
@ -2179,7 +2179,7 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel
|
|||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
m_Size.x, m_Size.y, m_Size.z
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
} // case msSpongePrint
|
} // case msSpongePrint
|
||||||
|
|
||||||
case cBlockArea::msDifference:
|
case cBlockArea::msDifference:
|
||||||
@ -2193,7 +2193,7 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel
|
|||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
m_Size.x, m_Size.y, m_Size.z
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
} // case msDifference
|
} // case msDifference
|
||||||
|
|
||||||
case cBlockArea::msMask:
|
case cBlockArea::msMask:
|
||||||
@ -2207,16 +2207,13 @@ void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_Rel
|
|||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
m_Size.x, m_Size.y, m_Size.z
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
);
|
);
|
||||||
break;
|
return;
|
||||||
} // case msMask
|
} // case msMask
|
||||||
|
} // switch (a_Strategy)
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
|
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
|
||||||
ASSERT(!"Unknown block area merge strategy");
|
ASSERT(!"Unknown block area merge strategy");
|
||||||
break;
|
return;
|
||||||
}
|
|
||||||
} // switch (a_Strategy)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,25 +30,25 @@ public:
|
|||||||
cByteBuffer(size_t a_BufferSize);
|
cByteBuffer(size_t a_BufferSize);
|
||||||
~cByteBuffer();
|
~cByteBuffer();
|
||||||
|
|
||||||
/// Writes the bytes specified to the ringbuffer. Returns true if successful, false if not
|
/** Writes the bytes specified to the ringbuffer. Returns true if successful, false if not */
|
||||||
bool Write(const void * a_Bytes, size_t a_Count);
|
bool Write(const void * a_Bytes, size_t a_Count);
|
||||||
|
|
||||||
/// Returns the number of bytes that can be successfully written to the ringbuffer
|
/** Returns the number of bytes that can be successfully written to the ringbuffer */
|
||||||
size_t GetFreeSpace(void) const;
|
size_t GetFreeSpace(void) const;
|
||||||
|
|
||||||
/// Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes()
|
/** Returns the number of bytes that are currently in the ringbuffer. Note GetReadableBytes() */
|
||||||
size_t GetUsedSpace(void) const;
|
size_t GetUsedSpace(void) const;
|
||||||
|
|
||||||
/// Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already)
|
/** Returns the number of bytes that are currently available for reading (may be less than UsedSpace due to some data having been read already) */
|
||||||
size_t GetReadableSpace(void) const;
|
size_t GetReadableSpace(void) const;
|
||||||
|
|
||||||
/// Returns the current data start index. For debugging purposes.
|
/** Returns the current data start index. For debugging purposes. */
|
||||||
size_t GetDataStart(void) const { return m_DataStart; }
|
size_t GetDataStart(void) const { return m_DataStart; }
|
||||||
|
|
||||||
/// Returns true if the specified amount of bytes are available for reading
|
/** Returns true if the specified amount of bytes are available for reading */
|
||||||
bool CanReadBytes(size_t a_Count) const;
|
bool CanReadBytes(size_t a_Count) const;
|
||||||
|
|
||||||
/// Returns true if the specified amount of bytes are available for writing
|
/** Returns true if the specified amount of bytes are available for writing */
|
||||||
bool CanWriteBytes(size_t a_Count) const;
|
bool CanWriteBytes(size_t a_Count) const;
|
||||||
|
|
||||||
// Read the specified datatype and advance the read pointer; return true if successfully read:
|
// Read the specified datatype and advance the read pointer; return true if successfully read:
|
||||||
@ -65,7 +65,7 @@ public:
|
|||||||
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
|
bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8
|
||||||
bool ReadLEInt (int & a_Value);
|
bool ReadLEInt (int & a_Value);
|
||||||
|
|
||||||
/// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...)
|
/** Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) */
|
||||||
template <typename T> bool ReadVarInt(T & a_Value)
|
template <typename T> bool ReadVarInt(T & a_Value)
|
||||||
{
|
{
|
||||||
UInt32 v;
|
UInt32 v;
|
||||||
@ -91,37 +91,37 @@ public:
|
|||||||
bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
|
bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8
|
||||||
bool WriteLEInt (int a_Value);
|
bool WriteLEInt (int a_Value);
|
||||||
|
|
||||||
/// Reads a_Count bytes into a_Buffer; returns true if successful
|
/** Reads a_Count bytes into a_Buffer; returns true if successful */
|
||||||
bool ReadBuf(void * a_Buffer, size_t a_Count);
|
bool ReadBuf(void * a_Buffer, size_t a_Count);
|
||||||
|
|
||||||
/// Writes a_Count bytes into a_Buffer; returns true if successful
|
/** Writes a_Count bytes into a_Buffer; returns true if successful */
|
||||||
bool WriteBuf(const void * a_Buffer, size_t a_Count);
|
bool WriteBuf(const void * a_Buffer, size_t a_Count);
|
||||||
|
|
||||||
/// Reads a_Count bytes into a_String; returns true if successful
|
/** Reads a_Count bytes into a_String; returns true if successful */
|
||||||
bool ReadString(AString & a_String, size_t a_Count);
|
bool ReadString(AString & a_String, size_t a_Count);
|
||||||
|
|
||||||
/// Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String
|
/** Reads 2 * a_NumChars bytes and interprets it as a UTF16-BE string, converting it into UTF8 string a_String */
|
||||||
bool ReadUTF16String(AString & a_String, size_t a_NumChars);
|
bool ReadUTF16String(AString & a_String, size_t a_NumChars);
|
||||||
|
|
||||||
/// Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer
|
/** Skips reading by a_Count bytes; returns false if not enough bytes in the ringbuffer */
|
||||||
bool SkipRead(size_t a_Count);
|
bool SkipRead(size_t a_Count);
|
||||||
|
|
||||||
/// Reads all available data into a_Data
|
/** Reads all available data into a_Data */
|
||||||
void ReadAll(AString & a_Data);
|
void ReadAll(AString & a_Data);
|
||||||
|
|
||||||
/// Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success.
|
/** Reads the specified number of bytes and writes it into the destinatio bytebuffer. Returns true on success. */
|
||||||
bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes);
|
bool ReadToByteBuffer(cByteBuffer & a_Dst, size_t a_NumBytes);
|
||||||
|
|
||||||
/// Removes the bytes that have been read from the ringbuffer
|
/** Removes the bytes that have been read from the ringbuffer */
|
||||||
void CommitRead(void);
|
void CommitRead(void);
|
||||||
|
|
||||||
/// Restarts next reading operation at the start of the ringbuffer
|
/** Restarts next reading operation at the start of the ringbuffer */
|
||||||
void ResetRead(void);
|
void ResetRead(void);
|
||||||
|
|
||||||
/// Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication
|
/** Re-reads the data that has been read since the last commit to the current readpos. Used by ProtoProxy to duplicate communication */
|
||||||
void ReadAgain(AString & a_Out);
|
void ReadAgain(AString & a_Out);
|
||||||
|
|
||||||
/// Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs
|
/** Checks if the internal state is valid (read and write positions in the correct bounds) using ASSERTs */
|
||||||
void CheckValid(void) const;
|
void CheckValid(void) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -136,7 +136,7 @@ protected:
|
|||||||
size_t m_WritePos; // Where the data ends in the ringbuffer
|
size_t m_WritePos; // Where the data ends in the ringbuffer
|
||||||
size_t m_ReadPos; // Where the next read will start in the ringbuffer
|
size_t m_ReadPos; // Where the next read will start in the ringbuffer
|
||||||
|
|
||||||
/// Advances the m_ReadPos by a_Count bytes
|
/** Advances the m_ReadPos by a_Count bytes */
|
||||||
void AdvanceReadPos(size_t a_Count);
|
void AdvanceReadPos(size_t a_Count);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -815,6 +815,16 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
(Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) ||
|
||||||
|
(Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) ||
|
||||||
|
(Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
|
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
|
||||||
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
|
if (PlgMgr->CallHookPlayerLeftClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_Status))
|
||||||
{
|
{
|
||||||
@ -878,6 +888,7 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, eB
|
|||||||
case DIG_STATUS_CANCELLED:
|
case DIG_STATUS_CANCELLED:
|
||||||
{
|
{
|
||||||
// Block breaking cancelled by player
|
// Block breaking cancelled by player
|
||||||
|
FinishDigAnimation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -926,9 +937,12 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta))
|
if (
|
||||||
|
(Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) ||
|
||||||
|
(Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) ||
|
||||||
|
(Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows:
|
|
||||||
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1004,24 +1018,24 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_HasStartedDigging = false;
|
FinishDigAnimation();
|
||||||
if (m_BlockDigAnimStage != -1)
|
|
||||||
{
|
|
||||||
// End dig animation
|
|
||||||
m_BlockDigAnimStage = -1;
|
|
||||||
// It seems that 10 ends block animation
|
|
||||||
m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_BlockDigAnimX, m_BlockDigAnimY, m_BlockDigAnimZ, 10, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
cWorld * World = m_Player->GetWorld();
|
||||||
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
|
cItemHandler * ItemHandler = cItemHandler::GetItemHandler(m_Player->GetEquippedItem());
|
||||||
|
|
||||||
|
if (cRoot::Get()->GetPluginManager()->CallHookPlayerBreakingBlock(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_OldBlock, a_OldMeta))
|
||||||
|
{
|
||||||
|
// A plugin doesn't agree with the breaking. Bail out. Send the block back to the client, so that it knows:
|
||||||
|
m_Player->GetWorld()->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (a_OldBlock == E_BLOCK_AIR)
|
if (a_OldBlock == E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
LOGD("Dug air - what the function?");
|
LOGD("Dug air - what the function?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cWorld * World = m_Player->GetWorld();
|
|
||||||
ItemHandler->OnBlockDestroyed(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ);
|
ItemHandler->OnBlockDestroyed(World, m_Player, m_Player->GetEquippedItem(), a_BlockX, a_BlockY, a_BlockZ);
|
||||||
// The ItemHandler is also responsible for spawning the pickups
|
// The ItemHandler is also responsible for spawning the pickups
|
||||||
cChunkInterface ChunkInterface(World->GetChunkMap());
|
cChunkInterface ChunkInterface(World->GetChunkMap());
|
||||||
@ -1036,6 +1050,36 @@ void cClientHandle::HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_Blo
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cClientHandle::FinishDigAnimation()
|
||||||
|
{
|
||||||
|
if (
|
||||||
|
!m_HasStartedDigging || // Hasn't received the DIG_STARTED packet
|
||||||
|
(m_LastDigBlockX == -1) ||
|
||||||
|
(m_LastDigBlockY == -1) ||
|
||||||
|
(m_LastDigBlockZ == -1)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_HasStartedDigging = false;
|
||||||
|
if (m_BlockDigAnimStage != -1)
|
||||||
|
{
|
||||||
|
// End dig animation
|
||||||
|
m_BlockDigAnimStage = -1;
|
||||||
|
// It seems that 10 ends block animation
|
||||||
|
m_Player->GetWorld()->BroadcastBlockBreakAnimation(m_UniqueID, m_LastDigBlockX, m_LastDigBlockY, m_LastDigBlockZ, 10, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_BlockDigAnimX = -1;
|
||||||
|
m_BlockDigAnimY = -1;
|
||||||
|
m_BlockDigAnimZ = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem)
|
void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ, const cItem & a_HeldItem)
|
||||||
{
|
{
|
||||||
LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s",
|
LOGD("HandleRightClick: {%d, %d, %d}, face %d, HeldItem: %s",
|
||||||
@ -1044,6 +1088,22 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
|||||||
|
|
||||||
cWorld * World = m_Player->GetWorld();
|
cWorld * World = m_Player->GetWorld();
|
||||||
|
|
||||||
|
if (
|
||||||
|
(Diff(m_Player->GetPosX(), (double)a_BlockX) > 6) ||
|
||||||
|
(Diff(m_Player->GetPosY(), (double)a_BlockY) > 6) ||
|
||||||
|
(Diff(m_Player->GetPosZ(), (double)a_BlockZ) > 6)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (a_BlockFace != BLOCK_FACE_NONE)
|
||||||
|
{
|
||||||
|
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||||
|
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||||
|
World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things
|
||||||
|
m_Player->GetInventory().SendEquippedSlot();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
|
cPluginManager * PlgMgr = cRoot::Get()->GetPluginManager();
|
||||||
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
|
if (PlgMgr->CallHookPlayerRightClick(*m_Player, a_BlockX, a_BlockY, a_BlockZ, a_BlockFace, a_CursorX, a_CursorY, a_CursorZ))
|
||||||
{
|
{
|
||||||
@ -1058,6 +1118,7 @@ void cClientHandle::HandleRightClick(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
|||||||
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
AddFaceDirection(a_BlockX, a_BlockY, a_BlockZ, a_BlockFace);
|
||||||
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||||
World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things
|
World->SendBlockTo(a_BlockX, a_BlockY + 1, a_BlockZ, m_Player); // 2 block high things
|
||||||
|
m_Player->GetInventory().SendEquippedSlot();
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1246,6 +1307,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
|||||||
{
|
{
|
||||||
// Handler refused the placement, send that information back to the client:
|
// Handler refused the placement, send that information back to the client:
|
||||||
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockY, m_Player);
|
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockY, m_Player);
|
||||||
|
m_Player->GetInventory().SendEquippedSlot();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1255,6 +1317,7 @@ void cClientHandle::HandlePlaceBlock(int a_BlockX, int a_BlockY, int a_BlockZ, e
|
|||||||
{
|
{
|
||||||
// A plugin doesn't agree with placing the block, revert the block on the client:
|
// A plugin doesn't agree with placing the block, revert the block on the client:
|
||||||
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
World->SendBlockTo(a_BlockX, a_BlockY, a_BlockZ, m_Player);
|
||||||
|
m_Player->GetInventory().SendEquippedSlot();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2437,6 +2500,15 @@ void cClientHandle::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTy
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cClientHandle::SendStatistics(const cStatManager & a_Manager)
|
||||||
|
{
|
||||||
|
m_Protocol->SendStatistics(a_Manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::SendTabCompletionResults(const AStringVector & a_Results)
|
void cClientHandle::SendTabCompletionResults(const AStringVector & a_Results)
|
||||||
{
|
{
|
||||||
m_Protocol->SendTabCompletionResults(a_Results);
|
m_Protocol->SendTabCompletionResults(a_Results);
|
||||||
@ -2676,12 +2748,13 @@ void cClientHandle::PacketError(unsigned char a_PacketType)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::DataReceived(const char * a_Data, size_t a_Size)
|
bool cClientHandle::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
{
|
{
|
||||||
// Data is received from the client, store it in the buffer to be processed by the Tick thread:
|
// Data is received from the client, store it in the buffer to be processed by the Tick thread:
|
||||||
m_TimeSinceLastPacket = 0;
|
m_TimeSinceLastPacket = 0;
|
||||||
cCSLock Lock(m_CSIncomingData);
|
cCSLock Lock(m_CSIncomingData);
|
||||||
m_IncomingData.append(a_Data, a_Size);
|
m_IncomingData.append(a_Data, a_Size);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ class cFallingBlock;
|
|||||||
class cItemHandler;
|
class cItemHandler;
|
||||||
class cWorld;
|
class cWorld;
|
||||||
class cCompositeChat;
|
class cCompositeChat;
|
||||||
|
class cStatManager;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -160,6 +161,7 @@ public:
|
|||||||
void SendSpawnMob (const cMonster & a_Mob);
|
void SendSpawnMob (const cMonster & a_Mob);
|
||||||
void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch);
|
void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch);
|
||||||
void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType = 0);
|
void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType = 0);
|
||||||
|
void SendStatistics (const cStatManager & a_Manager);
|
||||||
void SendTabCompletionResults(const AStringVector & a_Results);
|
void SendTabCompletionResults(const AStringVector & a_Results);
|
||||||
void SendTeleportEntity (const cEntity & a_Entity);
|
void SendTeleportEntity (const cEntity & a_Entity);
|
||||||
void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ);
|
void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
@ -374,6 +376,9 @@ private:
|
|||||||
/** Handles the DIG_FINISHED dig packet: */
|
/** Handles the DIG_FINISHED dig packet: */
|
||||||
void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta);
|
void HandleBlockDigFinished(int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, BLOCKTYPE a_OldBlock, NIBBLETYPE a_OldMeta);
|
||||||
|
|
||||||
|
/** The clients will receive a finished dig animation */
|
||||||
|
void FinishDigAnimation();
|
||||||
|
|
||||||
/** Converts the protocol-formatted channel list (NUL-separated) into a proper string vector. */
|
/** Converts the protocol-formatted channel list (NUL-separated) into a proper string vector. */
|
||||||
AStringVector BreakApartPluginChannels(const AString & a_PluginChannels);
|
AStringVector BreakApartPluginChannels(const AString & a_PluginChannels);
|
||||||
|
|
||||||
@ -390,7 +395,7 @@ private:
|
|||||||
void HandleAnvilItemName(const char * a_Data, size_t a_Length);
|
void HandleAnvilItemName(const char * a_Data, size_t a_Length);
|
||||||
|
|
||||||
// cSocketThreads::cCallback overrides:
|
// cSocketThreads::cCallback overrides:
|
||||||
virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
||||||
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
||||||
virtual void SocketClosed (void) override; // The socket has been closed for any reason
|
virtual void SocketClosed (void) override; // The socket has been closed for any reason
|
||||||
}; // tolua_export
|
}; // tolua_export
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "ChatColor.h"
|
#include "ChatColor.h"
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -528,6 +529,15 @@ inline float GetSpecialSignf( float a_Val )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<class T> inline T Diff(T a_Val1, T a_Val2)
|
||||||
|
{
|
||||||
|
return std::abs(a_Val1 - a_Val2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
||||||
enum eMessageType
|
enum eMessageType
|
||||||
|
@ -10,3 +10,5 @@ file(GLOB SOURCE
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_library(Entities ${SOURCE})
|
add_library(Entities ${SOURCE})
|
||||||
|
|
||||||
|
target_link_libraries(Entities WorldStorage)
|
||||||
|
@ -312,12 +312,16 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
|
|
||||||
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
|
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
|
||||||
{
|
{
|
||||||
|
cPlayer * Player = (cPlayer *)a_TDI.Attacker;
|
||||||
|
|
||||||
// IsOnGround() only is false if the player is moving downwards
|
// IsOnGround() only is false if the player is moving downwards
|
||||||
if (!((cPlayer *)a_TDI.Attacker)->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
|
if (!Player->IsOnGround()) // TODO: Better damage increase, and check for enchantments (and use magic critical instead of plain)
|
||||||
{
|
{
|
||||||
a_TDI.FinalDamage += 2;
|
a_TDI.FinalDamage += 2;
|
||||||
m_World->BroadcastEntityAnimation(*this, 4); // Critical hit
|
m_World->BroadcastEntityAnimation(*this, 4); // Critical hit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Player->GetStatManager().AddValue(statDamageDealt, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Health -= (short)a_TDI.FinalDamage;
|
m_Health -= (short)a_TDI.FinalDamage;
|
||||||
@ -370,6 +374,11 @@ bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
if (m_Health <= 0)
|
if (m_Health <= 0)
|
||||||
{
|
{
|
||||||
KilledBy(a_TDI.Attacker);
|
KilledBy(a_TDI.Attacker);
|
||||||
|
|
||||||
|
if (a_TDI.Attacker != NULL)
|
||||||
|
{
|
||||||
|
a_TDI.Attacker->Killed(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -575,9 +584,16 @@ void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
|
|
||||||
if (m_AttachedTo != NULL)
|
if (m_AttachedTo != NULL)
|
||||||
{
|
{
|
||||||
if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5)
|
Vector3d DeltaPos = m_Pos - m_AttachedTo->GetPosition();
|
||||||
|
if (DeltaPos.Length() > 0.5)
|
||||||
{
|
{
|
||||||
SetPosition(m_AttachedTo->GetPosition());
|
SetPosition(m_AttachedTo->GetPosition());
|
||||||
|
|
||||||
|
if (IsPlayer())
|
||||||
|
{
|
||||||
|
cPlayer * Player = (cPlayer *)this;
|
||||||
|
Player->UpdateMovementStats(DeltaPos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -299,6 +299,9 @@ public:
|
|||||||
/// Called when the health drops below zero. a_Killer may be NULL (environmental damage)
|
/// Called when the health drops below zero. a_Killer may be NULL (environmental damage)
|
||||||
virtual void KilledBy(cEntity * a_Killer);
|
virtual void KilledBy(cEntity * a_Killer);
|
||||||
|
|
||||||
|
/// Called when the entity kills another entity
|
||||||
|
virtual void Killed(cEntity * a_Victim) {}
|
||||||
|
|
||||||
/// Heals the specified amount of HPs
|
/// Heals the specified amount of HPs
|
||||||
void Heal(int a_HitPoints);
|
void Heal(int a_HitPoints);
|
||||||
|
|
||||||
|
@ -192,6 +192,16 @@ bool cPickup::CollectedBy(cPlayer * a_Dest)
|
|||||||
int NumAdded = a_Dest->GetInventory().AddItem(m_Item);
|
int NumAdded = a_Dest->GetInventory().AddItem(m_Item);
|
||||||
if (NumAdded > 0)
|
if (NumAdded > 0)
|
||||||
{
|
{
|
||||||
|
// Check achievements
|
||||||
|
switch (m_Item.m_ItemType)
|
||||||
|
{
|
||||||
|
case E_BLOCK_LOG: a_Dest->AwardAchievement(achMineWood); break;
|
||||||
|
case E_ITEM_LEATHER: a_Dest->AwardAchievement(achKillCow); break;
|
||||||
|
case E_ITEM_DIAMOND: a_Dest->AwardAchievement(achDiamonds); break;
|
||||||
|
case E_ITEM_BLAZE_ROD: a_Dest->AwardAchievement(achBlazeRod); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
m_Item.m_ItemCount -= NumAdded;
|
m_Item.m_ItemCount -= NumAdded;
|
||||||
m_World->BroadcastCollectPickup(*this, *a_Dest);
|
m_World->BroadcastCollectPickup(*this, *a_Dest);
|
||||||
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
||||||
|
@ -16,6 +16,9 @@
|
|||||||
#include "../Items/ItemHandler.h"
|
#include "../Items/ItemHandler.h"
|
||||||
#include "../Vector3.h"
|
#include "../Vector3.h"
|
||||||
|
|
||||||
|
#include "../WorldStorage/StatSerializer.h"
|
||||||
|
#include "../CompositeChat.h"
|
||||||
|
|
||||||
#include "inifile/iniFile.h"
|
#include "inifile/iniFile.h"
|
||||||
#include "json/json.h"
|
#include "json/json.h"
|
||||||
|
|
||||||
@ -192,6 +195,8 @@ void cPlayer::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_Stats.AddValue(statMinutesPlayed, 1);
|
||||||
|
|
||||||
if (!a_Chunk.IsValid())
|
if (!a_Chunk.IsValid())
|
||||||
{
|
{
|
||||||
// This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
|
// This may happen if the cPlayer is created before the chunks have the chance of being loaded / generated (#83)
|
||||||
@ -832,6 +837,8 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
// Any kind of damage adds food exhaustion
|
// Any kind of damage adds food exhaustion
|
||||||
AddFoodExhaustion(0.3f);
|
AddFoodExhaustion(0.3f);
|
||||||
SendHealth();
|
SendHealth();
|
||||||
|
|
||||||
|
m_Stats.AddValue(statDamageTaken, (StatValue)floor(a_TDI.FinalDamage * 10 + 0.5));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -862,6 +869,8 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
|||||||
Pickups.Add(cItem(E_ITEM_RED_APPLE));
|
Pickups.Add(cItem(E_ITEM_RED_APPLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_Stats.AddValue(statItemsDropped, Pickups.Size());
|
||||||
|
|
||||||
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
|
m_World->SpawnItemPickups(Pickups, GetPosX(), GetPosY(), GetPosZ(), 10);
|
||||||
SaveToDisk(); // Save it, yeah the world is a tough place !
|
SaveToDisk(); // Save it, yeah the world is a tough place !
|
||||||
|
|
||||||
@ -871,9 +880,9 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
|||||||
}
|
}
|
||||||
else if (a_Killer->IsPlayer())
|
else if (a_Killer->IsPlayer())
|
||||||
{
|
{
|
||||||
GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), ((cPlayer *)a_Killer)->GetName().c_str()));
|
cPlayer * Killer = (cPlayer *)a_Killer;
|
||||||
|
|
||||||
m_World->GetScoreBoard().AddPlayerScore(((cPlayer *)a_Killer)->GetName(), cObjective::otPlayerKillCount, 1);
|
GetWorld()->BroadcastChatDeath(Printf("%s was killed by %s", GetName().c_str(), Killer->GetName().c_str()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -883,6 +892,8 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
|||||||
GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
|
GetWorld()->BroadcastChatDeath(Printf("%s was killed by a %s", GetName().c_str(), KillerClass.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_Stats.AddValue(statDeaths);
|
||||||
|
|
||||||
m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1);
|
m_World->GetScoreBoard().AddPlayerScore(GetName(), cObjective::otDeathCount, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -890,6 +901,33 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPlayer::Killed(cEntity * a_Victim)
|
||||||
|
{
|
||||||
|
cScoreboard & ScoreBoard = m_World->GetScoreBoard();
|
||||||
|
|
||||||
|
if (a_Victim->IsPlayer())
|
||||||
|
{
|
||||||
|
m_Stats.AddValue(statPlayerKills);
|
||||||
|
|
||||||
|
ScoreBoard.AddPlayerScore(GetName(), cObjective::otPlayerKillCount, 1);
|
||||||
|
}
|
||||||
|
else if (a_Victim->IsMob())
|
||||||
|
{
|
||||||
|
if (((cMonster *)a_Victim)->GetMobFamily() == cMonster::mfHostile)
|
||||||
|
{
|
||||||
|
AwardAchievement(achKillMonster);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Stats.AddValue(statMobKills);
|
||||||
|
}
|
||||||
|
|
||||||
|
ScoreBoard.AddPlayerScore(GetName(), cObjective::otTotalKillCount, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::Respawn(void)
|
void cPlayer::Respawn(void)
|
||||||
{
|
{
|
||||||
m_Health = GetMaxHealth();
|
m_Health = GetMaxHealth();
|
||||||
@ -1108,6 +1146,47 @@ void cPlayer::SetIP(const AString & a_IP)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int cPlayer::AwardAchievement(const eStatistic a_Ach)
|
||||||
|
{
|
||||||
|
eStatistic Prerequisite = cStatInfo::GetPrerequisite(a_Ach);
|
||||||
|
|
||||||
|
// Check if the prerequisites are met
|
||||||
|
if (Prerequisite != statInvalid)
|
||||||
|
{
|
||||||
|
if (m_Stats.GetValue(Prerequisite) == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StatValue Old = m_Stats.GetValue(a_Ach);
|
||||||
|
|
||||||
|
if (Old > 0)
|
||||||
|
{
|
||||||
|
return m_Stats.AddValue(a_Ach);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// First time, announce it
|
||||||
|
cCompositeChat Msg;
|
||||||
|
Msg.AddTextPart(m_PlayerName + " has just earned the achievement ");
|
||||||
|
Msg.AddTextPart(cStatInfo::GetName(a_Ach)); // TODO 2014-05-12 xdot: Use the proper cCompositeChat part (cAchievement)
|
||||||
|
m_World->BroadcastChat(Msg);
|
||||||
|
|
||||||
|
// Increment the statistic
|
||||||
|
StatValue New = m_Stats.AddValue(a_Ach);
|
||||||
|
|
||||||
|
// Achievement Get!
|
||||||
|
m_ClientHandle->SendStatistics(m_Stats);
|
||||||
|
|
||||||
|
return New;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
|
void cPlayer::TeleportToCoords(double a_PosX, double a_PosY, double a_PosZ)
|
||||||
{
|
{
|
||||||
SetPosition(a_PosX, a_PosY, a_PosZ);
|
SetPosition(a_PosX, a_PosY, a_PosZ);
|
||||||
@ -1193,6 +1272,9 @@ void cPlayer::MoveTo( const Vector3d & a_NewPos )
|
|||||||
// TODO: should do some checks to see if player is not moving through terrain
|
// TODO: should do some checks to see if player is not moving through terrain
|
||||||
// TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
|
// TODO: Official server refuses position packets too far away from each other, kicking "hacked" clients; we should, too
|
||||||
|
|
||||||
|
Vector3d DeltaPos = a_NewPos - GetPosition();
|
||||||
|
UpdateMovementStats(DeltaPos);
|
||||||
|
|
||||||
SetPosition( a_NewPos );
|
SetPosition( a_NewPos );
|
||||||
SetStance(a_NewPos.y + 1.62);
|
SetStance(a_NewPos.y + 1.62);
|
||||||
}
|
}
|
||||||
@ -1422,10 +1504,7 @@ void cPlayer::TossEquippedItem(char a_Amount)
|
|||||||
Drops.push_back(DroppedItem);
|
Drops.push_back(DroppedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
double vX = 0, vY = 0, vZ = 0;
|
TossItems(Drops);
|
||||||
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
|
|
||||||
vY = -vY * 2 + 1.f;
|
|
||||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1441,6 +1520,7 @@ void cPlayer::TossHeldItem(char a_Amount)
|
|||||||
char OriginalItemAmount = Item.m_ItemCount;
|
char OriginalItemAmount = Item.m_ItemCount;
|
||||||
Item.m_ItemCount = std::min(OriginalItemAmount, a_Amount);
|
Item.m_ItemCount = std::min(OriginalItemAmount, a_Amount);
|
||||||
Drops.push_back(Item);
|
Drops.push_back(Item);
|
||||||
|
|
||||||
if (OriginalItemAmount > a_Amount)
|
if (OriginalItemAmount > a_Amount)
|
||||||
{
|
{
|
||||||
Item.m_ItemCount = OriginalItemAmount - a_Amount;
|
Item.m_ItemCount = OriginalItemAmount - a_Amount;
|
||||||
@ -1451,10 +1531,7 @@ void cPlayer::TossHeldItem(char a_Amount)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
double vX = 0, vY = 0, vZ = 0;
|
TossItems(Drops);
|
||||||
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
|
|
||||||
vY = -vY * 2 + 1.f;
|
|
||||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1466,10 +1543,21 @@ void cPlayer::TossPickup(const cItem & a_Item)
|
|||||||
cItems Drops;
|
cItems Drops;
|
||||||
Drops.push_back(a_Item);
|
Drops.push_back(a_Item);
|
||||||
|
|
||||||
|
TossItems(Drops);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPlayer::TossItems(const cItems & a_Items)
|
||||||
|
{
|
||||||
|
m_Stats.AddValue(statItemsDropped, a_Items.Size());
|
||||||
|
|
||||||
double vX = 0, vY = 0, vZ = 0;
|
double vX = 0, vY = 0, vZ = 0;
|
||||||
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
|
EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
|
||||||
vY = -vY * 2 + 1.f;
|
vY = -vY * 2 + 1.f;
|
||||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
|
m_World->SpawnItemPickups(a_Items, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1622,6 +1710,11 @@ bool cPlayer::LoadFromDisk()
|
|||||||
|
|
||||||
m_LoadedWorldName = root.get("world", "world").asString();
|
m_LoadedWorldName = root.get("world", "world").asString();
|
||||||
|
|
||||||
|
// Load the player stats.
|
||||||
|
// We use the default world name (like bukkit) because stats are shared between dimensions/worlds.
|
||||||
|
cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), GetName(), &m_Stats);
|
||||||
|
StatSerializer.Load();
|
||||||
|
|
||||||
LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
|
LOGD("Player \"%s\" was read from file, spawning at {%.2f, %.2f, %.2f} in world \"%s\"",
|
||||||
m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
|
m_PlayerName.c_str(), GetPosX(), GetPosY(), GetPosZ(), m_LoadedWorldName.c_str()
|
||||||
);
|
);
|
||||||
@ -1692,6 +1785,16 @@ bool cPlayer::SaveToDisk()
|
|||||||
LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str());
|
LOGERROR("ERROR WRITING PLAYER JSON TO FILE \"%s\"", SourceFile.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Save the player stats.
|
||||||
|
// We use the default world name (like bukkit) because stats are shared between dimensions/worlds.
|
||||||
|
cStatSerializer StatSerializer(cRoot::Get()->GetDefaultWorld()->GetName(), m_PlayerName, &m_Stats);
|
||||||
|
if (!StatSerializer.Save())
|
||||||
|
{
|
||||||
|
LOGERROR("Could not save stats for player %s", m_PlayerName.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1706,7 +1809,10 @@ cPlayer::StringList cPlayer::GetResolvedPermissions()
|
|||||||
const PermissionMap& ResolvedPermissions = m_ResolvedPermissions;
|
const PermissionMap& ResolvedPermissions = m_ResolvedPermissions;
|
||||||
for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr )
|
for( PermissionMap::const_iterator itr = ResolvedPermissions.begin(); itr != ResolvedPermissions.end(); ++itr )
|
||||||
{
|
{
|
||||||
if( itr->second ) Permissions.push_back( itr->first );
|
if (itr->second)
|
||||||
|
{
|
||||||
|
Permissions.push_back( itr->first );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Permissions;
|
return Permissions;
|
||||||
@ -1845,6 +1951,59 @@ void cPlayer::HandleFloater()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPlayer::UpdateMovementStats(const Vector3d & a_DeltaPos)
|
||||||
|
{
|
||||||
|
StatValue Value = (StatValue)floor(a_DeltaPos.Length() * 100 + 0.5);
|
||||||
|
|
||||||
|
if (m_AttachedTo == NULL)
|
||||||
|
{
|
||||||
|
int PosX = POSX_TOINT;
|
||||||
|
int PosY = POSY_TOINT;
|
||||||
|
int PosZ = POSZ_TOINT;
|
||||||
|
|
||||||
|
BLOCKTYPE Block;
|
||||||
|
NIBBLETYPE Meta;
|
||||||
|
if (!m_World->GetBlockTypeMeta(PosX, PosY, PosZ, Block, Meta))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((Block == E_BLOCK_LADDER) && (a_DeltaPos.y > 0.0)) // Going up
|
||||||
|
{
|
||||||
|
m_Stats.AddValue(statDistClimbed, (StatValue)floor(a_DeltaPos.y * 100 + 0.5));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO 2014-05-12 xdot: Other types
|
||||||
|
m_Stats.AddValue(statDistWalked, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
switch (m_AttachedTo->GetEntityType())
|
||||||
|
{
|
||||||
|
case cEntity::etMinecart: m_Stats.AddValue(statDistMinecart, Value); break;
|
||||||
|
case cEntity::etBoat: m_Stats.AddValue(statDistBoat, Value); break;
|
||||||
|
case cEntity::etMonster:
|
||||||
|
{
|
||||||
|
cMonster * Monster = (cMonster *)m_AttachedTo;
|
||||||
|
switch (Monster->GetMobType())
|
||||||
|
{
|
||||||
|
case cMonster::mtPig: m_Stats.AddValue(statDistPig, Value); break;
|
||||||
|
case cMonster::mtHorse: m_Stats.AddValue(statDistHorse, Value); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::ApplyFoodExhaustionFromMovement()
|
void cPlayer::ApplyFoodExhaustionFromMovement()
|
||||||
{
|
{
|
||||||
if (IsGameModeCreative())
|
if (IsGameModeCreative())
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
#include "../ClientHandle.h"
|
#include "../ClientHandle.h"
|
||||||
|
|
||||||
|
#include "../Statistics.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -175,6 +177,15 @@ public:
|
|||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
|
/** Return the associated statistic and achievement manager. */
|
||||||
|
cStatManager & GetStatManager() { return m_Stats; }
|
||||||
|
|
||||||
|
/** Awards the player an achievement.
|
||||||
|
If all prerequisites are met, this method will award the achievement and will broadcast a chat message.
|
||||||
|
If the achievement has been already awarded to the player, this method will just increment the stat counter.
|
||||||
|
Returns the _new_ stat value. (0 = Could not award achievement) */
|
||||||
|
unsigned int AwardAchievement(const eStatistic a_Ach);
|
||||||
|
|
||||||
void SetIP(const AString & a_IP);
|
void SetIP(const AString & a_IP);
|
||||||
|
|
||||||
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
|
// Sets the current gamemode, doesn't check validity, doesn't send update packets to client
|
||||||
@ -307,6 +318,8 @@ public:
|
|||||||
|
|
||||||
virtual void KilledBy(cEntity * a_Killer) override;
|
virtual void KilledBy(cEntity * a_Killer) override;
|
||||||
|
|
||||||
|
virtual void Killed(cEntity * a_Victim) override;
|
||||||
|
|
||||||
void Respawn(void); // tolua_export
|
void Respawn(void); // tolua_export
|
||||||
|
|
||||||
void SetVisible( bool a_bVisible ); // tolua_export
|
void SetVisible( bool a_bVisible ); // tolua_export
|
||||||
@ -375,6 +388,9 @@ public:
|
|||||||
/** If true the player can fly even when he's not in creative. */
|
/** If true the player can fly even when he's not in creative. */
|
||||||
void SetCanFly(bool a_CanFly);
|
void SetCanFly(bool a_CanFly);
|
||||||
|
|
||||||
|
/** Update movement-related statistics. */
|
||||||
|
void UpdateMovementStats(const Vector3d & a_DeltaPos);
|
||||||
|
|
||||||
/** Returns wheter the player can fly or not. */
|
/** Returns wheter the player can fly or not. */
|
||||||
virtual bool CanFly(void) const { return m_CanFly; }
|
virtual bool CanFly(void) const { return m_CanFly; }
|
||||||
// tolua_end
|
// tolua_end
|
||||||
@ -487,6 +503,8 @@ protected:
|
|||||||
|
|
||||||
cTeam * m_Team;
|
cTeam * m_Team;
|
||||||
|
|
||||||
|
cStatManager m_Stats;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ResolvePermissions(void);
|
void ResolvePermissions(void);
|
||||||
@ -506,6 +524,9 @@ protected:
|
|||||||
/** Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. */
|
/** Called in each tick if the player is fishing to make sure the floater dissapears when the player doesn't have a fishing rod as equipped item. */
|
||||||
void HandleFloater(void);
|
void HandleFloater(void);
|
||||||
|
|
||||||
|
/** Tosses a list of items. */
|
||||||
|
void TossItems(const cItems & a_Items);
|
||||||
|
|
||||||
/** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */
|
/** Adds food exhaustion based on the difference between Pos and LastPos, sprinting status and swimming (in water block) */
|
||||||
void ApplyFoodExhaustionFromMovement();
|
void ApplyFoodExhaustionFromMovement();
|
||||||
|
|
||||||
|
@ -596,10 +596,9 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
|
|||||||
// Interpolate between FloorLo and FloorHi:
|
// Interpolate between FloorLo and FloorHi:
|
||||||
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
|
for (int z = 0; z < 16; z++) for (int x = 0; x < 16; x++)
|
||||||
{
|
{
|
||||||
switch (a_ChunkDesc.GetBiome(x, z))
|
EMCSBiome biome = a_ChunkDesc.GetBiome(x, z);
|
||||||
{
|
|
||||||
case biExtremeHills:
|
if ((biome == biExtremeHills) || (biome == biExtremeHillsEdge))
|
||||||
case biExtremeHillsEdge:
|
|
||||||
{
|
{
|
||||||
int Lo = FloorLo[x + 17 * z] / 256;
|
int Lo = FloorLo[x + 17 * z] / 256;
|
||||||
int Hi = FloorHi[x + 17 * z] / 256;
|
int Hi = FloorHi[x + 17 * z] / 256;
|
||||||
@ -612,8 +611,7 @@ void cStructGenDirectOverhangs::GenFinish(cChunkDesc & a_ChunkDesc)
|
|||||||
}
|
}
|
||||||
} // for y
|
} // for y
|
||||||
break;
|
break;
|
||||||
}
|
} // if (biome)
|
||||||
} // switch (biome)
|
|
||||||
} // for z, x
|
} // for z, x
|
||||||
|
|
||||||
// Swap the floors:
|
// Swap the floors:
|
||||||
|
@ -174,7 +174,7 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
|
|||||||
{
|
{
|
||||||
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case biTaiga:
|
case biTaiga:
|
||||||
@ -184,14 +184,14 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
|
|||||||
{
|
{
|
||||||
// Conifers
|
// Conifers
|
||||||
GetConiferTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetConiferTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case biSwampland:
|
case biSwampland:
|
||||||
{
|
{
|
||||||
// Swamp trees:
|
// Swamp trees:
|
||||||
GetSwampTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetSwampTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case biJungle:
|
case biJungle:
|
||||||
@ -207,21 +207,21 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
|
|||||||
{
|
{
|
||||||
GetJungleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetJungleTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
}
|
}
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case biBirchForest:
|
case biBirchForest:
|
||||||
case biBirchForestHills:
|
case biBirchForestHills:
|
||||||
{
|
{
|
||||||
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case biBirchForestM:
|
case biBirchForestM:
|
||||||
case biBirchForestHillsM:
|
case biBirchForestHillsM:
|
||||||
{
|
{
|
||||||
GetTallBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetTallBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
case biRoofedForest:
|
case biRoofedForest:
|
||||||
@ -257,9 +257,29 @@ void GetTreeImageByBiome(int a_BlockX, int a_BlockY, int a_BlockZ, cNoise & a_No
|
|||||||
{
|
{
|
||||||
// TODO: These need their special trees
|
// TODO: These need their special trees
|
||||||
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
GetBirchTreeImage(a_BlockX, a_BlockY, a_BlockZ, a_Noise, a_Seq, a_LogBlocks, a_OtherBlocks);
|
||||||
break;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
case biDesert:
|
||||||
|
case biDesertHills:
|
||||||
|
case biRiver:
|
||||||
|
case biBeach:
|
||||||
|
case biHell:
|
||||||
|
case biSky:
|
||||||
|
case biOcean:
|
||||||
|
case biFrozenOcean:
|
||||||
|
case biFrozenRiver:
|
||||||
|
case biVariant:
|
||||||
|
case biNumBiomes:
|
||||||
|
case biNumVariantBiomes:
|
||||||
|
case biInvalidBiome:
|
||||||
|
{
|
||||||
|
// These biomes have no trees, or are non-biome members of the enum.
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ASSERT(!"Invalid biome type!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) :
|
|||||||
|
|
||||||
cHTTPConnection::~cHTTPConnection()
|
cHTTPConnection::~cHTTPConnection()
|
||||||
{
|
{
|
||||||
|
// LOGD("HTTP: Connection deleting: %p", this);
|
||||||
delete m_CurrentRequest;
|
delete m_CurrentRequest;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +145,7 @@ void cHTTPConnection::Terminate(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
bool cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
{
|
{
|
||||||
switch (m_State)
|
switch (m_State)
|
||||||
{
|
{
|
||||||
@ -162,12 +163,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
m_CurrentRequest = NULL;
|
m_CurrentRequest = NULL;
|
||||||
m_State = wcsInvalid;
|
m_State = wcsInvalid;
|
||||||
m_HTTPServer.CloseConnection(*this);
|
m_HTTPServer.CloseConnection(*this);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
if (m_CurrentRequest->IsInHeaders())
|
if (m_CurrentRequest->IsInHeaders())
|
||||||
{
|
{
|
||||||
// The request headers are not yet complete
|
// The request headers are not yet complete
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The request has finished parsing its headers successfully, notify of it:
|
// The request has finished parsing its headers successfully, notify of it:
|
||||||
@ -183,13 +184,12 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
// Process the rest of the incoming data into the request body:
|
// Process the rest of the incoming data into the request body:
|
||||||
if (a_Size > BytesConsumed)
|
if (a_Size > BytesConsumed)
|
||||||
{
|
{
|
||||||
DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed);
|
return cHTTPConnection::DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DataReceived("", 0); // If the request has zero body length, let it be processed right-away
|
return cHTTPConnection::DataReceived("", 0); // If the request has zero body length, let it be processed right-away
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case wcsRecvBody:
|
case wcsRecvBody:
|
||||||
@ -209,7 +209,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
{
|
{
|
||||||
m_State = wcsInvalid;
|
m_State = wcsInvalid;
|
||||||
m_HTTPServer.CloseConnection(*this);
|
m_HTTPServer.CloseConnection(*this);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
delete m_CurrentRequest;
|
delete m_CurrentRequest;
|
||||||
m_CurrentRequest = NULL;
|
m_CurrentRequest = NULL;
|
||||||
@ -223,6 +223,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -91,9 +91,15 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
// cSocketThreads::cCallback overrides:
|
// cSocketThreads::cCallback overrides:
|
||||||
virtual void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
/** Data is received from the client.
|
||||||
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
Returns true if the connection has been closed as the result of parsing the data. */
|
||||||
virtual void SocketClosed (void) override; // The socket has been closed for any reason
|
virtual bool DataReceived(const char * a_Data, size_t a_Size) override;
|
||||||
|
|
||||||
|
/** Data can be sent to client */
|
||||||
|
virtual void GetOutgoingData(AString & a_Data) override;
|
||||||
|
|
||||||
|
/** The socket has been closed for any reason */
|
||||||
|
virtual void SocketClosed(void) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
typedef std::vector<cHTTPConnection *> cHTTPConnections;
|
typedef std::vector<cHTTPConnection *> cHTTPConnections;
|
||||||
|
@ -201,7 +201,7 @@ size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size)
|
|||||||
return AString::npos;
|
return AString::npos;
|
||||||
}
|
}
|
||||||
// Check that there's HTTP/version at the end
|
// Check that there's HTTP/version at the end
|
||||||
if (strncmp(a_Data + URLEnd + 1, "HTTP/1.", 7) != 0)
|
if (strncmp(m_IncomingHeaderData.c_str() + URLEnd + 1, "HTTP/1.", 7) != 0)
|
||||||
{
|
{
|
||||||
m_IsValid = false;
|
m_IsValid = false;
|
||||||
return AString::npos;
|
return AString::npos;
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
#include "HTTPMessage.h"
|
#include "HTTPMessage.h"
|
||||||
#include "HTTPConnection.h"
|
#include "HTTPConnection.h"
|
||||||
#include "HTTPFormParser.h"
|
#include "HTTPFormParser.h"
|
||||||
|
#include "SslHTTPConnection.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -142,6 +143,41 @@ cHTTPServer::~cHTTPServer()
|
|||||||
|
|
||||||
bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6)
|
bool cHTTPServer::Initialize(const AString & a_PortsIPv4, const AString & a_PortsIPv6)
|
||||||
{
|
{
|
||||||
|
// Read the HTTPS cert + key:
|
||||||
|
AString CertFile = cFile::ReadWholeFile("webadmin/httpscert.crt");
|
||||||
|
AString KeyFile = cFile::ReadWholeFile("webadmin/httpskey.pem");
|
||||||
|
if (!CertFile.empty() && !KeyFile.empty())
|
||||||
|
{
|
||||||
|
m_Cert.reset(new cX509Cert);
|
||||||
|
int res = m_Cert->Parse(CertFile.data(), CertFile.size());
|
||||||
|
if (res == 0)
|
||||||
|
{
|
||||||
|
m_CertPrivKey.reset(new cCryptoKey);
|
||||||
|
int res2 = m_CertPrivKey->ParsePrivate(KeyFile.data(), KeyFile.size(), "");
|
||||||
|
if (res2 != 0)
|
||||||
|
{
|
||||||
|
// Reading the private key failed, reset the cert:
|
||||||
|
LOGWARNING("WebServer: Cannot read HTTPS certificate private key: -0x%x", -res2);
|
||||||
|
m_Cert.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGWARNING("WebServer: Cannot read HTTPS certificate: -0x%x", -res);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify the admin about the HTTPS / HTTP status
|
||||||
|
if (m_Cert.get() == NULL)
|
||||||
|
{
|
||||||
|
LOGWARNING("WebServer: The server is running in unsecure HTTP mode.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGINFO("WebServer: The server is running in secure HTTPS mode.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open up requested ports:
|
||||||
bool HasAnyPort;
|
bool HasAnyPort;
|
||||||
HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4);
|
HasAnyPort = m_ListenThreadIPv4.Initialize(a_PortsIPv4);
|
||||||
HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort;
|
HasAnyPort = m_ListenThreadIPv6.Initialize(a_PortsIPv6) || HasAnyPort;
|
||||||
@ -195,7 +231,15 @@ void cHTTPServer::Stop(void)
|
|||||||
|
|
||||||
void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket)
|
void cHTTPServer::OnConnectionAccepted(cSocket & a_Socket)
|
||||||
{
|
{
|
||||||
cHTTPConnection * Connection = new cHTTPConnection(*this);
|
cHTTPConnection * Connection;
|
||||||
|
if (m_Cert.get() != NULL)
|
||||||
|
{
|
||||||
|
Connection = new cSslHTTPConnection(*this, m_Cert, m_CertPrivKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Connection = new cHTTPConnection(*this);
|
||||||
|
}
|
||||||
m_SocketThreads.AddClient(a_Socket, Connection);
|
m_SocketThreads.AddClient(a_Socket, Connection);
|
||||||
cCSLock Lock(m_CSConnections);
|
cCSLock Lock(m_CSConnections);
|
||||||
m_Connections.push_back(Connection);
|
m_Connections.push_back(Connection);
|
||||||
|
@ -12,6 +12,9 @@
|
|||||||
#include "../OSSupport/ListenThread.h"
|
#include "../OSSupport/ListenThread.h"
|
||||||
#include "../OSSupport/SocketThreads.h"
|
#include "../OSSupport/SocketThreads.h"
|
||||||
#include "inifile/iniFile.h"
|
#include "inifile/iniFile.h"
|
||||||
|
#include "PolarSSL++/RsaPrivateKey.h"
|
||||||
|
#include "PolarSSL++/CryptoKey.h"
|
||||||
|
#include "PolarSSL++/X509Cert.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -66,6 +69,7 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class cHTTPConnection;
|
friend class cHTTPConnection;
|
||||||
|
friend class cSslHTTPConnection;
|
||||||
|
|
||||||
cListenThread m_ListenThreadIPv4;
|
cListenThread m_ListenThreadIPv4;
|
||||||
cListenThread m_ListenThreadIPv6;
|
cListenThread m_ListenThreadIPv6;
|
||||||
@ -78,6 +82,12 @@ protected:
|
|||||||
/// The callbacks to call for various events
|
/// The callbacks to call for various events
|
||||||
cCallbacks * m_Callbacks;
|
cCallbacks * m_Callbacks;
|
||||||
|
|
||||||
|
/** The server certificate to use for the SSL connections */
|
||||||
|
cX509CertPtr m_Cert;
|
||||||
|
|
||||||
|
/** The private key for m_Cert. */
|
||||||
|
cCryptoKeyPtr m_CertPrivKey;
|
||||||
|
|
||||||
|
|
||||||
// cListenThread::cCallback overrides:
|
// cListenThread::cCallback overrides:
|
||||||
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
|
virtual void OnConnectionAccepted(cSocket & a_Socket) override;
|
||||||
|
107
src/HTTPServer/SslHTTPConnection.cpp
Normal file
107
src/HTTPServer/SslHTTPConnection.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
// SslHTTPConnection.cpp
|
||||||
|
|
||||||
|
// Implements the cSslHTTPConnection class representing a HTTP connection made over a SSL link
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "SslHTTPConnection.h"
|
||||||
|
#include "HTTPServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cSslHTTPConnection::cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey) :
|
||||||
|
super(a_HTTPServer),
|
||||||
|
m_Ssl(64000),
|
||||||
|
m_Cert(a_Cert),
|
||||||
|
m_PrivateKey(a_PrivateKey)
|
||||||
|
{
|
||||||
|
m_Ssl.Initialize(false);
|
||||||
|
m_Ssl.SetOwnCert(a_Cert, a_PrivateKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cSslHTTPConnection::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
|
{
|
||||||
|
// If there is outgoing data in the queue, notify the server that it should write it out:
|
||||||
|
if (!m_OutgoingData.empty())
|
||||||
|
{
|
||||||
|
m_HTTPServer.NotifyConnectionWrite(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the received data:
|
||||||
|
const char * Data = a_Data;
|
||||||
|
size_t Size = a_Size;
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// Try to write as many bytes into Ssl's "incoming" buffer as possible:
|
||||||
|
size_t BytesWritten = 0;
|
||||||
|
if (Size > 0)
|
||||||
|
{
|
||||||
|
BytesWritten = m_Ssl.WriteIncoming(Data, Size);
|
||||||
|
Data += BytesWritten;
|
||||||
|
Size -= BytesWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to read as many bytes from SSL's decryption as possible:
|
||||||
|
char Buffer[32000];
|
||||||
|
int NumRead = m_Ssl.ReadPlain(Buffer, sizeof(Buffer));
|
||||||
|
if (NumRead > 0)
|
||||||
|
{
|
||||||
|
if (super::DataReceived(Buffer, (size_t)NumRead))
|
||||||
|
{
|
||||||
|
// The socket has been closed, and the object is already deleted. Bail out.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both failed, bail out:
|
||||||
|
if ((BytesWritten == 0) && (NumRead <= 0))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSslHTTPConnection::GetOutgoingData(AString & a_Data)
|
||||||
|
{
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
// Write as many bytes from our buffer to SSL's encryption as possible:
|
||||||
|
int NumWritten = 0;
|
||||||
|
if (!m_OutgoingData.empty())
|
||||||
|
{
|
||||||
|
NumWritten = m_Ssl.WritePlain(m_OutgoingData.data(), m_OutgoingData.size());
|
||||||
|
if (NumWritten > 0)
|
||||||
|
{
|
||||||
|
m_OutgoingData.erase(0, (size_t)NumWritten);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read as many bytes from SSL's "outgoing" buffer as possible:
|
||||||
|
char Buffer[32000];
|
||||||
|
size_t NumBytes = m_Ssl.ReadOutgoing(Buffer, sizeof(Buffer));
|
||||||
|
if (NumBytes > 0)
|
||||||
|
{
|
||||||
|
a_Data.append(Buffer, NumBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If both failed, bail out:
|
||||||
|
if ((NumWritten <= 0) && (NumBytes == 0))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
45
src/HTTPServer/SslHTTPConnection.h
Normal file
45
src/HTTPServer/SslHTTPConnection.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
|
||||||
|
// SslHTTPConnection.h
|
||||||
|
|
||||||
|
// Declared the cSslHTTPConnection class representing a HTTP connection made over a SSL link
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "HTTPConnection.h"
|
||||||
|
#include "PolarSSL++/BufferedSslContext.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cSslHTTPConnection :
|
||||||
|
public cHTTPConnection
|
||||||
|
{
|
||||||
|
typedef cHTTPConnection super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Creates a new connection on the specified server.
|
||||||
|
Sends the specified cert as the server certificate, uses the private key for decryption. */
|
||||||
|
cSslHTTPConnection(cHTTPServer & a_HTTPServer, const cX509CertPtr & a_Cert, const cCryptoKeyPtr & a_PrivateKey);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cBufferedSslContext m_Ssl;
|
||||||
|
|
||||||
|
/** The certificate to send to the client */
|
||||||
|
cX509CertPtr m_Cert;
|
||||||
|
|
||||||
|
/** The private key used for the certificate */
|
||||||
|
cCryptoKeyPtr m_PrivateKey;
|
||||||
|
|
||||||
|
// cHTTPConnection overrides:
|
||||||
|
virtual bool DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
||||||
|
virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -243,6 +243,16 @@ void cInventory::SetHotbarSlot(int a_HotBarSlotNum, const cItem & a_Item)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cInventory::SendEquippedSlot()
|
||||||
|
{
|
||||||
|
int EquippedSlotNum = cInventory::invArmorCount + cInventory::invInventoryCount + GetEquippedSlotNum();
|
||||||
|
SendSlot(EquippedSlotNum);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const cItem & cInventory::GetSlot(int a_SlotNum) const
|
const cItem & cInventory::GetSlot(int a_SlotNum) const
|
||||||
{
|
{
|
||||||
if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
|
if ((a_SlotNum < 0) || (a_SlotNum >= invNumSlots))
|
||||||
|
@ -56,13 +56,13 @@ public:
|
|||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
||||||
/// Removes all items from the entire inventory
|
/** Removes all items from the entire inventory */
|
||||||
void Clear(void);
|
void Clear(void);
|
||||||
|
|
||||||
/// Returns number of items out of a_ItemStack that can fit in the storage
|
/** Returns number of items out of a_ItemStack that can fit in the storage */
|
||||||
int HowManyCanFit(const cItem & a_ItemStack, bool a_ConsiderEmptySlots);
|
int HowManyCanFit(const cItem & a_ItemStack, bool a_ConsiderEmptySlots);
|
||||||
|
|
||||||
/// Returns how many items of the specified type would fit into the slot range specified
|
/** Returns how many items of the specified type would fit into the slot range specified */
|
||||||
int HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots);
|
int HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int a_EndSlotNum, bool a_ConsiderEmptySlots);
|
||||||
|
|
||||||
/** Adds as many items out of a_ItemStack as can fit.
|
/** Adds as many items out of a_ItemStack as can fit.
|
||||||
@ -86,33 +86,36 @@ public:
|
|||||||
*/
|
*/
|
||||||
int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst);
|
int AddItems(cItems & a_ItemStackList, bool a_AllowNewStacks, bool a_tryToFillEquippedFirst);
|
||||||
|
|
||||||
/// Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed
|
/** Removes one item out of the currently equipped item stack, returns true if successful, false if empty-handed */
|
||||||
bool RemoveOneEquippedItem(void);
|
bool RemoveOneEquippedItem(void);
|
||||||
|
|
||||||
/// Returns the number of items of type a_Item that are stored
|
/** Returns the number of items of type a_Item that are stored */
|
||||||
int HowManyItems(const cItem & a_Item);
|
int HowManyItems(const cItem & a_Item);
|
||||||
|
|
||||||
/// Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack
|
/** Returns true if there are at least as many items of type a_ItemStack as in a_ItemStack */
|
||||||
bool HasItems(const cItem & a_ItemStack);
|
bool HasItems(const cItem & a_ItemStack);
|
||||||
|
|
||||||
/// Returns the cItemGrid object representing the armor slots
|
/** Sends the equipped item slot to the client */
|
||||||
|
void SendEquippedSlot();
|
||||||
|
|
||||||
|
/** Returns the cItemGrid object representing the armor slots */
|
||||||
cItemGrid & GetArmorGrid(void) { return m_ArmorSlots; }
|
cItemGrid & GetArmorGrid(void) { return m_ArmorSlots; }
|
||||||
|
|
||||||
/// Returns the cItemGrid object representing the main inventory slots
|
/** Returns the cItemGrid object representing the main inventory slots */
|
||||||
cItemGrid & GetInventoryGrid(void) { return m_InventorySlots; }
|
cItemGrid & GetInventoryGrid(void) { return m_InventorySlots; }
|
||||||
|
|
||||||
/// Returns the cItemGrid object representing the hotbar slots
|
/** Returns the cItemGrid object representing the hotbar slots */
|
||||||
cItemGrid & GetHotbarGrid(void) { return m_HotbarSlots; }
|
cItemGrid & GetHotbarGrid(void) { return m_HotbarSlots; }
|
||||||
|
|
||||||
/// Returns the player associated with this inventory
|
/** Returns the player associated with this inventory */
|
||||||
cPlayer & GetOwner(void) { return m_Owner; }
|
cPlayer & GetOwner(void) { return m_Owner; }
|
||||||
|
|
||||||
/// Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents
|
/** Copies the non-empty slots into a_ItemStacks; preserves the original a_Items contents */
|
||||||
void CopyToItems(cItems & a_Items);
|
void CopyToItems(cItems & a_Items);
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
/// Returns the player associated with this inventory (const version)
|
/** Returns the player associated with this inventory (const version) */
|
||||||
const cPlayer & GetOwner(void) const { return m_Owner; }
|
const cPlayer & GetOwner(void) const { return m_Owner; }
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
@ -136,10 +139,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
int ChangeSlotCount(int a_SlotNum, int a_AddToCount);
|
int ChangeSlotCount(int a_SlotNum, int a_AddToCount);
|
||||||
|
|
||||||
/// Adds the specified damage to the specified item; deletes the item and returns true if the item broke.
|
/** Adds the specified damage to the specified item; deletes the item and returns true if the item broke. */
|
||||||
bool DamageItem(int a_SlotNum, short a_Amount);
|
bool DamageItem(int a_SlotNum, short a_Amount);
|
||||||
|
|
||||||
/// Adds the specified damage to the currently held item; deletes the item and returns true if the item broke.
|
/** Adds the specified damage to the currently held item; deletes the item and returns true if the item broke. */
|
||||||
bool DamageEquippedItem(short a_Amount = 1);
|
bool DamageEquippedItem(short a_Amount = 1);
|
||||||
|
|
||||||
const cItem & GetEquippedHelmet (void) const { return m_ArmorSlots.GetSlot(0); }
|
const cItem & GetEquippedHelmet (void) const { return m_ArmorSlots.GetSlot(0); }
|
||||||
@ -149,13 +152,13 @@ public:
|
|||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
/// Sends the slot contents to the owner
|
/** Sends the slot contents to the owner */
|
||||||
void SendSlot(int a_SlotNum);
|
void SendSlot(int a_SlotNum);
|
||||||
|
|
||||||
/// Update items (e.g. Maps)
|
/** Update items (e.g. Maps) */
|
||||||
void UpdateItems(void);
|
void UpdateItems(void);
|
||||||
|
|
||||||
/// Converts an armor slot number into the ID for the EntityEquipment packet
|
/** Converts an armor slot number into the ID for the EntityEquipment packet */
|
||||||
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum);
|
static int ArmorSlotNumToEntityEquipmentID(short a_ArmorSlotNum);
|
||||||
|
|
||||||
void SaveToJson(Json::Value & a_Value);
|
void SaveToJson(Json::Value & a_Value);
|
||||||
@ -172,10 +175,10 @@ protected:
|
|||||||
|
|
||||||
cPlayer & m_Owner;
|
cPlayer & m_Owner;
|
||||||
|
|
||||||
/// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum
|
/** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */
|
||||||
const cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const;
|
const cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum) const;
|
||||||
|
|
||||||
/// Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum
|
/** Returns the ItemGrid and the (grid-local) slot number for a (global) slot number; return NULL for invalid SlotNum */
|
||||||
cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum);
|
cItemGrid * GetGridForSlotNum(int a_SlotNum, int & a_GridSlotNum);
|
||||||
|
|
||||||
// cItemGrid::cListener override:
|
// cItemGrid::cListener override:
|
||||||
|
@ -228,7 +228,7 @@ public:
|
|||||||
void Add (const cItem & a_Item) {push_back(a_Item); }
|
void Add (const cItem & a_Item) {push_back(a_Item); }
|
||||||
void Delete(int a_Idx);
|
void Delete(int a_Idx);
|
||||||
void Clear (void) {clear(); }
|
void Clear (void) {clear(); }
|
||||||
size_t Size (void) {return size(); }
|
size_t Size (void) const { return size(); }
|
||||||
void Set (int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDamage);
|
void Set (int a_Idx, short a_ItemType, char a_ItemCount, short a_ItemDamage);
|
||||||
|
|
||||||
void Add (short a_ItemType, char a_ItemCount, short a_ItemDamage)
|
void Add (short a_ItemType, char a_ItemCount, short a_ItemDamage)
|
||||||
|
@ -355,6 +355,8 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
InStateEscaping(a_Dt);
|
InStateEscaping(a_Dt);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ATTACKING: break;
|
||||||
} // switch (m_EMState)
|
} // switch (m_EMState)
|
||||||
|
|
||||||
BroadcastMovementUpdate();
|
BroadcastMovementUpdate();
|
||||||
@ -464,8 +466,10 @@ bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if((m_SoundHurt != "") && (m_Health > 0))
|
if (!m_SoundHurt.empty() && (m_Health > 0))
|
||||||
|
{
|
||||||
m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
|
m_World->BroadcastSoundEffect(m_SoundHurt, (int)(GetPosX() * 8), (int)(GetPosY() * 8), (int)(GetPosZ() * 8), 1.0f, 0.8f);
|
||||||
|
}
|
||||||
|
|
||||||
if (a_TDI.Attacker != NULL)
|
if (a_TDI.Attacker != NULL)
|
||||||
{
|
{
|
||||||
|
@ -63,8 +63,10 @@ public:
|
|||||||
// Force a virtual destructor in all subclasses:
|
// Force a virtual destructor in all subclasses:
|
||||||
virtual ~cCallback() {}
|
virtual ~cCallback() {}
|
||||||
|
|
||||||
/** Called when data is received from the remote party */
|
/** Called when data is received from the remote party.
|
||||||
virtual void DataReceived(const char * a_Data, size_t a_Size) = 0;
|
SocketThreads does not care about the return value, others can use it for their specific purpose -
|
||||||
|
for example HTTPServer uses it to signal if the connection was terminated as a result of the data received. */
|
||||||
|
virtual bool DataReceived(const char * a_Data, size_t a_Size) = 0;
|
||||||
|
|
||||||
/** Called when data can be sent to remote party
|
/** Called when data can be sent to remote party
|
||||||
The function is supposed to *set* outgoing data to a_Data (overwrite) */
|
The function is supposed to *set* outgoing data to a_Data (overwrite) */
|
||||||
|
@ -20,6 +20,37 @@ cBufferedSslContext::cBufferedSslContext(size_t a_BufferSize):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t cBufferedSslContext::WriteIncoming(const void * a_Data, size_t a_NumBytes)
|
||||||
|
{
|
||||||
|
size_t NumBytes = std::min(m_IncomingData.GetFreeSpace(), a_NumBytes);
|
||||||
|
if (NumBytes > 0)
|
||||||
|
{
|
||||||
|
m_IncomingData.Write(a_Data, NumBytes);
|
||||||
|
return NumBytes;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
size_t cBufferedSslContext::ReadOutgoing(void * a_Data, size_t a_DataMaxSize)
|
||||||
|
{
|
||||||
|
size_t NumBytes = std::min(m_OutgoingData.GetReadableSpace(), a_DataMaxSize);
|
||||||
|
if (NumBytes > 0)
|
||||||
|
{
|
||||||
|
m_OutgoingData.ReadBuf(a_Data, NumBytes);
|
||||||
|
m_OutgoingData.CommitRead();
|
||||||
|
return NumBytes;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
int cBufferedSslContext::ReceiveEncrypted(unsigned char * a_Buffer, size_t a_NumBytes)
|
||||||
{
|
{
|
||||||
// Called when PolarSSL wants to read encrypted data from the SSL peer
|
// Called when PolarSSL wants to read encrypted data from the SSL peer
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
cmake_minimum_required (VERSION 2.6)
|
cmake_minimum_required (VERSION 2.6)
|
||||||
project (MCServer)
|
project (MCServer)
|
||||||
|
|
||||||
@ -11,8 +10,8 @@ set(SOURCES
|
|||||||
BufferedSslContext.cpp
|
BufferedSslContext.cpp
|
||||||
CallbackSslContext.cpp
|
CallbackSslContext.cpp
|
||||||
CtrDrbgContext.cpp
|
CtrDrbgContext.cpp
|
||||||
|
CryptoKey.cpp
|
||||||
EntropyContext.cpp
|
EntropyContext.cpp
|
||||||
PublicKey.cpp
|
|
||||||
RsaPrivateKey.cpp
|
RsaPrivateKey.cpp
|
||||||
Sha1Checksum.cpp
|
Sha1Checksum.cpp
|
||||||
SslContext.cpp
|
SslContext.cpp
|
||||||
@ -26,8 +25,8 @@ set(HEADERS
|
|||||||
BufferedSslContext.h
|
BufferedSslContext.h
|
||||||
CallbackSslContext.h
|
CallbackSslContext.h
|
||||||
CtrDrbgContext.h
|
CtrDrbgContext.h
|
||||||
|
CryptoKey.h
|
||||||
EntropyContext.h
|
EntropyContext.h
|
||||||
PublicKey.h
|
|
||||||
RsaPrivateKey.h
|
RsaPrivateKey.h
|
||||||
SslContext.h
|
SslContext.h
|
||||||
Sha1Checksum.h
|
Sha1Checksum.h
|
||||||
|
149
src/PolarSSL++/CryptoKey.cpp
Normal file
149
src/PolarSSL++/CryptoKey.cpp
Normal file
@ -0,0 +1,149 @@
|
|||||||
|
|
||||||
|
// CryptoKey.cpp
|
||||||
|
|
||||||
|
// Implements the cCryptoKey class representing a RSA public key in PolarSSL
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CryptoKey.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::cCryptoKey(void)
|
||||||
|
{
|
||||||
|
pk_init(&m_Pk);
|
||||||
|
m_CtrDrbg.Initialize("rsa_pubkey", 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::cCryptoKey(const AString & a_PublicKeyData)
|
||||||
|
{
|
||||||
|
pk_init(&m_Pk);
|
||||||
|
m_CtrDrbg.Initialize("rsa_pubkey", 10);
|
||||||
|
int res = ParsePublic(a_PublicKeyData.data(), a_PublicKeyData.size());
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
LOGWARNING("Failed to parse public key: -0x%x", res);
|
||||||
|
ASSERT(!"Cannot parse PubKey");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password)
|
||||||
|
{
|
||||||
|
pk_init(&m_Pk);
|
||||||
|
m_CtrDrbg.Initialize("rsa_privkey", 11);
|
||||||
|
int res = ParsePrivate(a_PrivateKeyData.data(), a_PrivateKeyData.size(), a_Password);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
LOGWARNING("Failed to parse private key: -0x%x", res);
|
||||||
|
ASSERT(!"Cannot parse PubKey");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cCryptoKey::~cCryptoKey()
|
||||||
|
{
|
||||||
|
pk_free(&m_Pk);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
||||||
|
{
|
||||||
|
ASSERT(IsValid());
|
||||||
|
|
||||||
|
size_t DecryptedLen = a_DecryptedMaxLength;
|
||||||
|
int res = pk_decrypt(&m_Pk,
|
||||||
|
a_EncryptedData, a_EncryptedLength,
|
||||||
|
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
||||||
|
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
||||||
|
);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (int)DecryptedLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
||||||
|
{
|
||||||
|
ASSERT(IsValid());
|
||||||
|
|
||||||
|
size_t EncryptedLength = a_EncryptedMaxLength;
|
||||||
|
int res = pk_encrypt(&m_Pk,
|
||||||
|
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
||||||
|
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
||||||
|
);
|
||||||
|
if (res != 0)
|
||||||
|
{
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (int)EncryptedLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::ParsePublic(const void * a_Data, size_t a_NumBytes)
|
||||||
|
{
|
||||||
|
ASSERT(!IsValid()); // Cannot parse a second key
|
||||||
|
|
||||||
|
return pk_parse_public_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cCryptoKey::ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password)
|
||||||
|
{
|
||||||
|
ASSERT(!IsValid()); // Cannot parse a second key
|
||||||
|
|
||||||
|
if (a_Password.empty())
|
||||||
|
{
|
||||||
|
return pk_parse_key(&m_Pk, (const unsigned char *)a_Data, a_NumBytes, NULL, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return pk_parse_key(
|
||||||
|
&m_Pk,
|
||||||
|
(const unsigned char *)a_Data, a_NumBytes,
|
||||||
|
(const unsigned char *)a_Password.c_str(), a_Password.size()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cCryptoKey::IsValid(void) const
|
||||||
|
{
|
||||||
|
return (pk_get_type(&m_Pk) != POLARSSL_PK_NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
76
src/PolarSSL++/CryptoKey.h
Normal file
76
src/PolarSSL++/CryptoKey.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
|
||||||
|
// CryptoKey.h
|
||||||
|
|
||||||
|
// Declares the cCryptoKey class representing a RSA public key in PolarSSL
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "CtrDrbgContext.h"
|
||||||
|
#include "polarssl/pk.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cCryptoKey
|
||||||
|
{
|
||||||
|
friend class cSslContext;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/** Constructs an empty key instance. Before use, it needs to be filled by ParsePublic() or ParsePrivate() */
|
||||||
|
cCryptoKey(void);
|
||||||
|
|
||||||
|
/** Constructs the public key out of the DER- or PEM-encoded pubkey data */
|
||||||
|
cCryptoKey(const AString & a_PublicKeyData);
|
||||||
|
|
||||||
|
/** Constructs the private key out of the DER- or PEM-encoded privkey data, with the specified password.
|
||||||
|
If a_Password is empty, no password is assumed. */
|
||||||
|
cCryptoKey(const AString & a_PrivateKeyData, const AString & a_Password);
|
||||||
|
|
||||||
|
~cCryptoKey();
|
||||||
|
|
||||||
|
/** Decrypts the data using the stored public key
|
||||||
|
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||||
|
Returns the number of bytes decrypted, or negative number for error. */
|
||||||
|
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
||||||
|
|
||||||
|
/** Encrypts the data using the stored public key
|
||||||
|
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
||||||
|
Returns the number of bytes decrypted, or negative number for error. */
|
||||||
|
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
||||||
|
|
||||||
|
/** Parses the specified data into a public key representation.
|
||||||
|
The key can be DER- or PEM-encoded.
|
||||||
|
Returns 0 on success, PolarSSL error code on failure. */
|
||||||
|
int ParsePublic(const void * a_Data, size_t a_NumBytes);
|
||||||
|
|
||||||
|
/** Parses the specified data into a private key representation.
|
||||||
|
If a_Password is empty, no password is assumed.
|
||||||
|
The key can be DER- or PEM-encoded.
|
||||||
|
Returns 0 on success, PolarSSL error code on failure. */
|
||||||
|
int ParsePrivate(const void * a_Data, size_t a_NumBytes, const AString & a_Password);
|
||||||
|
|
||||||
|
/** Returns true if the contained key is valid. */
|
||||||
|
bool IsValid(void) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** The PolarSSL representation of the key data */
|
||||||
|
pk_context m_Pk;
|
||||||
|
|
||||||
|
/** The random generator used in encryption and decryption */
|
||||||
|
cCtrDrbgContext m_CtrDrbg;
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the internal context ptr. Only use in PolarSSL API calls. */
|
||||||
|
pk_context * GetInternal(void) { return &m_Pk; }
|
||||||
|
} ;
|
||||||
|
|
||||||
|
typedef SharedPtr<cCryptoKey> cCryptoKeyPtr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -26,7 +26,7 @@ class cCtrDrbgContext
|
|||||||
{
|
{
|
||||||
friend class cSslContext;
|
friend class cSslContext;
|
||||||
friend class cRsaPrivateKey;
|
friend class cRsaPrivateKey;
|
||||||
friend class cPublicKey;
|
friend class cCryptoKey;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Constructs the context with a new entropy context. */
|
/** Constructs the context with a new entropy context. */
|
||||||
|
@ -1,73 +0,0 @@
|
|||||||
|
|
||||||
// PublicKey.cpp
|
|
||||||
|
|
||||||
// Implements the cPublicKey class representing a RSA public key in PolarSSL
|
|
||||||
|
|
||||||
#include "Globals.h"
|
|
||||||
#include "PublicKey.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPublicKey::cPublicKey(const AString & a_PublicKeyDER)
|
|
||||||
{
|
|
||||||
pk_init(&m_Pk);
|
|
||||||
if (pk_parse_public_key(&m_Pk, (const Byte *)a_PublicKeyDER.data(), a_PublicKeyDER.size()) != 0)
|
|
||||||
{
|
|
||||||
ASSERT(!"Cannot parse PubKey");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_CtrDrbg.Initialize("rsa_pubkey", 10);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPublicKey::~cPublicKey()
|
|
||||||
{
|
|
||||||
pk_free(&m_Pk);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cPublicKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
|
||||||
{
|
|
||||||
size_t DecryptedLen = a_DecryptedMaxLength;
|
|
||||||
int res = pk_decrypt(&m_Pk,
|
|
||||||
a_EncryptedData, a_EncryptedLength,
|
|
||||||
a_DecryptedData, &DecryptedLen, a_DecryptedMaxLength,
|
|
||||||
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
|
||||||
);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return (int)DecryptedLen;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cPublicKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
|
||||||
{
|
|
||||||
size_t EncryptedLength = a_EncryptedMaxLength;
|
|
||||||
int res = pk_encrypt(&m_Pk,
|
|
||||||
a_PlainData, a_PlainLength, a_EncryptedData, &EncryptedLength, a_EncryptedMaxLength,
|
|
||||||
ctr_drbg_random, m_CtrDrbg.GetInternal()
|
|
||||||
);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return (int)EncryptedLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
|||||||
|
|
||||||
// PublicKey.h
|
|
||||||
|
|
||||||
// Declares the cPublicKey class representing a RSA public key in PolarSSL
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "CtrDrbgContext.h"
|
|
||||||
#include "polarssl/pk.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cPublicKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** Constructs the public key out of the DER-encoded pubkey data */
|
|
||||||
cPublicKey(const AString & a_PublicKeyDER);
|
|
||||||
|
|
||||||
~cPublicKey();
|
|
||||||
|
|
||||||
/** Decrypts the data using the stored public key
|
|
||||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
|
||||||
Returns the number of bytes decrypted, or negative number for error. */
|
|
||||||
int Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength);
|
|
||||||
|
|
||||||
/** Encrypts the data using the stored public key
|
|
||||||
Both a_EncryptedData and a_DecryptedData must be at least <KeySizeBytes> bytes large.
|
|
||||||
Returns the number of bytes decrypted, or negative number for error. */
|
|
||||||
int Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** The public key PolarSSL representation */
|
|
||||||
pk_context m_Pk;
|
|
||||||
|
|
||||||
/** The random generator used in encryption and decryption */
|
|
||||||
cCtrDrbgContext m_CtrDrbg;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -19,6 +19,8 @@
|
|||||||
/** Encapsulates an RSA private key used in PKI cryptography */
|
/** Encapsulates an RSA private key used in PKI cryptography */
|
||||||
class cRsaPrivateKey
|
class cRsaPrivateKey
|
||||||
{
|
{
|
||||||
|
friend class cSslContext;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/** Creates a new empty object, the key is not assigned */
|
/** Creates a new empty object, the key is not assigned */
|
||||||
cRsaPrivateKey(void);
|
cRsaPrivateKey(void);
|
||||||
@ -51,8 +53,14 @@ protected:
|
|||||||
|
|
||||||
/** The random generator used for generating the key and encryption / decryption */
|
/** The random generator used for generating the key and encryption / decryption */
|
||||||
cCtrDrbgContext m_CtrDrbg;
|
cCtrDrbgContext m_CtrDrbg;
|
||||||
|
|
||||||
|
|
||||||
|
/** Returns the internal context ptr. Only use in PolarSSL API calls. */
|
||||||
|
rsa_context * GetInternal(void) { return &m_Rsa; }
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
typedef SharedPtr<cRsaPrivateKey> cRsaPrivateKeyPtr;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
if (m_IsValid)
|
if (m_IsValid)
|
||||||
{
|
{
|
||||||
LOGWARNING("SSL: Double initialization is not supported.");
|
LOGWARNING("SSL: Double initialization is not supported.");
|
||||||
return POLARSSL_ERR_SSL_MALLOC_FAILED; // There is no return value well-suited for this, reuse this one.
|
return POLARSSL_ERR_SSL_BAD_INPUT_DATA; // There is no return value well-suited for this, reuse this one.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the CtrDrbg context, create a new one if needed:
|
// Set the CtrDrbg context, create a new one if needed:
|
||||||
@ -59,7 +59,7 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
|
ssl_set_endpoint(&m_Ssl, a_IsClient ? SSL_IS_CLIENT : SSL_IS_SERVER);
|
||||||
ssl_set_authmode(&m_Ssl, SSL_VERIFY_OPTIONAL);
|
ssl_set_authmode(&m_Ssl, a_IsClient ? SSL_VERIFY_OPTIONAL : SSL_VERIFY_NONE); // Clients ask for server's cert but don't verify strictly; servers don't ask clients for certs by default
|
||||||
ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
|
ssl_set_rng(&m_Ssl, ctr_drbg_random, &m_CtrDrbg->m_CtrDrbg);
|
||||||
ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
|
ssl_set_bio(&m_Ssl, ReceiveEncrypted, this, SendEncrypted, this);
|
||||||
|
|
||||||
@ -70,6 +70,18 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
|
ssl_set_dbg(&m_Ssl, &SSLDebugMessage, this);
|
||||||
ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
|
ssl_set_verify(&m_Ssl, &SSLVerifyCert, this);
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Set ciphersuite to the easiest one to decode, so that the connection can be wireshark-decoded:
|
||||||
|
static const int CipherSuites[] =
|
||||||
|
{
|
||||||
|
TLS_RSA_WITH_RC4_128_MD5,
|
||||||
|
TLS_RSA_WITH_RC4_128_SHA,
|
||||||
|
TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||||
|
0, // Must be 0-terminated!
|
||||||
|
};
|
||||||
|
ssl_set_ciphersuites(&m_Ssl, CipherSuites);
|
||||||
|
*/
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_IsValid = true;
|
m_IsValid = true;
|
||||||
@ -80,8 +92,56 @@ int cSslContext::Initialize(bool a_IsClient, const SharedPtr<cCtrDrbgContext> &
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey)
|
||||||
|
{
|
||||||
|
ASSERT(m_IsValid); // Call Initialize() first
|
||||||
|
|
||||||
|
// Check that both the cert and the key is valid:
|
||||||
|
if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL))
|
||||||
|
{
|
||||||
|
LOGWARNING("SSL: Own certificate is not valid, skipping the set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have the cert stored for later, PolarSSL only uses the cert later on
|
||||||
|
m_OwnCert = a_OwnCert;
|
||||||
|
m_OwnCertPrivKey = a_OwnCertPrivKey;
|
||||||
|
|
||||||
|
// Set into the context:
|
||||||
|
ssl_set_own_cert_rsa(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey->GetInternal());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSslContext::SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey)
|
||||||
|
{
|
||||||
|
ASSERT(m_IsValid); // Call Initialize() first
|
||||||
|
|
||||||
|
// Check that both the cert and the key is valid:
|
||||||
|
if ((a_OwnCert.get() == NULL) || (a_OwnCertPrivKey.get() == NULL))
|
||||||
|
{
|
||||||
|
LOGWARNING("SSL: Own certificate is not valid, skipping the set.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we have the cert stored for later, PolarSSL only uses the cert later on
|
||||||
|
m_OwnCert = a_OwnCert;
|
||||||
|
m_OwnCertPrivKey2 = a_OwnCertPrivKey;
|
||||||
|
|
||||||
|
// Set into the context:
|
||||||
|
ssl_set_own_cert(&m_Ssl, m_OwnCert->GetInternal(), m_OwnCertPrivKey2->GetInternal());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
|
void cSslContext::SetCACerts(const cX509CertPtr & a_CACert, const AString & a_ExpectedPeerName)
|
||||||
{
|
{
|
||||||
|
ASSERT(m_IsValid); // Call Initialize() first
|
||||||
|
|
||||||
// Store the data in our internal buffers, to avoid losing the pointers later on
|
// Store the data in our internal buffers, to avoid losing the pointers later on
|
||||||
// PolarSSL will need these after this call returns, and the caller may move / delete the data before that:
|
// PolarSSL will need these after this call returns, and the caller may move / delete the data before that:
|
||||||
m_ExpectedPeerName = a_ExpectedPeerName;
|
m_ExpectedPeerName = a_ExpectedPeerName;
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include "polarssl/ssl.h"
|
#include "polarssl/ssl.h"
|
||||||
#include "../ByteBuffer.h"
|
#include "../ByteBuffer.h"
|
||||||
|
#include "CryptoKey.h"
|
||||||
|
#include "RsaPrivateKey.h"
|
||||||
#include "X509Cert.h"
|
#include "X509Cert.h"
|
||||||
|
|
||||||
|
|
||||||
@ -38,7 +40,7 @@ public:
|
|||||||
/** Creates a new uninitialized context */
|
/** Creates a new uninitialized context */
|
||||||
cSslContext(void);
|
cSslContext(void);
|
||||||
|
|
||||||
~cSslContext();
|
virtual ~cSslContext();
|
||||||
|
|
||||||
/** Initializes the context for use as a server or client.
|
/** Initializes the context for use as a server or client.
|
||||||
Returns 0 on success, PolarSSL error on failure. */
|
Returns 0 on success, PolarSSL error on failure. */
|
||||||
@ -47,7 +49,15 @@ public:
|
|||||||
/** Returns true if the object has been initialized properly. */
|
/** Returns true if the object has been initialized properly. */
|
||||||
bool IsValid(void) const { return m_IsValid; }
|
bool IsValid(void) const { return m_IsValid; }
|
||||||
|
|
||||||
/** Sets a cert chain as the trusted cert store for this context.
|
/** Sets the certificate to use as our own. Must be used when representing a server, optional when client.
|
||||||
|
Must be called after Initialize(). */
|
||||||
|
void SetOwnCert(const cX509CertPtr & a_OwnCert, const cRsaPrivateKeyPtr & a_OwnCertPrivKey);
|
||||||
|
|
||||||
|
/** Sets the certificate to use as our own. Must be used when representing a server, optional when client.
|
||||||
|
Must be called after Initialize(). */
|
||||||
|
void SetOwnCert(const cX509CertPtr & a_OwnCert, const cCryptoKeyPtr & a_OwnCertPrivKey);
|
||||||
|
|
||||||
|
/** Sets a cert chain as the trusted cert store for this context. Must be called after Initialize().
|
||||||
Calling this will switch the context into strict cert verification mode.
|
Calling this will switch the context into strict cert verification mode.
|
||||||
a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert,
|
a_ExpectedPeerName is the CommonName that we expect the SSL peer to have in its cert,
|
||||||
if it is different, the verification will fail. An empty string will disable the CN check. */
|
if it is different, the verification will fail. An empty string will disable the CN check. */
|
||||||
@ -93,6 +103,15 @@ protected:
|
|||||||
/** The SSL context that PolarSSL uses. */
|
/** The SSL context that PolarSSL uses. */
|
||||||
ssl_context m_Ssl;
|
ssl_context m_Ssl;
|
||||||
|
|
||||||
|
/** The certificate that we present to the peer. */
|
||||||
|
cX509CertPtr m_OwnCert;
|
||||||
|
|
||||||
|
/** Private key for m_OwnCert, if initialized from a cRsaPrivateKey. */
|
||||||
|
cRsaPrivateKeyPtr m_OwnCertPrivKey;
|
||||||
|
|
||||||
|
/** Private key for m_OwnCert, if initialized from a cCryptoKey. */
|
||||||
|
cCryptoKeyPtr m_OwnCertPrivKey2;
|
||||||
|
|
||||||
/** True if the SSL handshake has been completed. */
|
/** True if the SSL handshake has been completed. */
|
||||||
bool m_HasHandshaken;
|
bool m_HasHandshaken;
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@ class cMonster;
|
|||||||
class cChunkDataSerializer;
|
class cChunkDataSerializer;
|
||||||
class cFallingBlock;
|
class cFallingBlock;
|
||||||
class cCompositeChat;
|
class cCompositeChat;
|
||||||
|
class cStatManager;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -111,6 +112,7 @@ public:
|
|||||||
virtual void SendSpawnMob (const cMonster & a_Mob) = 0;
|
virtual void SendSpawnMob (const cMonster & a_Mob) = 0;
|
||||||
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) = 0;
|
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) = 0;
|
||||||
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) = 0;
|
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) = 0;
|
||||||
|
virtual void SendStatistics (const cStatManager & a_Manager) = 0;
|
||||||
virtual void SendTabCompletionResults(const AStringVector & a_Results) = 0;
|
virtual void SendTabCompletionResults(const AStringVector & a_Results) = 0;
|
||||||
virtual void SendTeleportEntity (const cEntity & a_Entity) = 0;
|
virtual void SendTeleportEntity (const cEntity & a_Entity) = 0;
|
||||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
|
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) = 0;
|
||||||
|
@ -99,6 +99,7 @@ enum
|
|||||||
PACKET_ENCHANT_ITEM = 0x6C,
|
PACKET_ENCHANT_ITEM = 0x6C,
|
||||||
PACKET_UPDATE_SIGN = 0x82,
|
PACKET_UPDATE_SIGN = 0x82,
|
||||||
PACKET_ITEM_DATA = 0x83,
|
PACKET_ITEM_DATA = 0x83,
|
||||||
|
PACKET_INCREMENT_STATISTIC = 0xC8,
|
||||||
PACKET_PLAYER_LIST_ITEM = 0xC9,
|
PACKET_PLAYER_LIST_ITEM = 0xC9,
|
||||||
PACKET_PLAYER_ABILITIES = 0xca,
|
PACKET_PLAYER_ABILITIES = 0xca,
|
||||||
PACKET_PLUGIN_MESSAGE = 0xfa,
|
PACKET_PLUGIN_MESSAGE = 0xfa,
|
||||||
@ -992,6 +993,33 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol125::SendStatistics(const cStatManager & a_Manager)
|
||||||
|
{
|
||||||
|
/* NOTE:
|
||||||
|
* Versions prior to minecraft 1.7 use an incremental statistic sync
|
||||||
|
* method. The current setup does not allow us to implement that, because
|
||||||
|
* of performance considerations.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
|
||||||
|
{
|
||||||
|
StatValue Value = m_Manager->GetValue((eStatistic) i);
|
||||||
|
|
||||||
|
unsigned int StatID = cStatInfo::GetID((eStatistic) i);
|
||||||
|
|
||||||
|
cCSLock Lock(m_CSPacket);
|
||||||
|
WriteByte(PACKET_INCREMENT_STATISTIC);
|
||||||
|
WriteInt(StatID);
|
||||||
|
WriteByte(Value); /* Can overflow! */
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocol125::SendTabCompletionResults(const AStringVector & a_Results)
|
void cProtocol125::SendTabCompletionResults(const AStringVector & a_Results)
|
||||||
{
|
{
|
||||||
// This protocol version doesn't support tab completion
|
// This protocol version doesn't support tab completion
|
||||||
|
@ -84,6 +84,7 @@ public:
|
|||||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||||
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
||||||
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
||||||
|
virtual void SendStatistics (const cStatManager & a_Manager) override;
|
||||||
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
||||||
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
|
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
|
||||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||||
|
@ -11,13 +11,19 @@ Implements the 1.7.x protocol classes:
|
|||||||
#include "json/json.h"
|
#include "json/json.h"
|
||||||
#include "Protocol17x.h"
|
#include "Protocol17x.h"
|
||||||
#include "ChunkDataSerializer.h"
|
#include "ChunkDataSerializer.h"
|
||||||
|
#include "PolarSSL++/Sha1Checksum.h"
|
||||||
|
|
||||||
#include "../ClientHandle.h"
|
#include "../ClientHandle.h"
|
||||||
#include "../Root.h"
|
#include "../Root.h"
|
||||||
#include "../Server.h"
|
#include "../Server.h"
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
|
#include "../StringCompression.h"
|
||||||
|
#include "../CompositeChat.h"
|
||||||
|
#include "../Statistics.h"
|
||||||
|
|
||||||
#include "../WorldStorage/FastNBT.h"
|
#include "../WorldStorage/FastNBT.h"
|
||||||
#include "../WorldStorage/EnchantmentSerializer.h"
|
#include "../WorldStorage/EnchantmentSerializer.h"
|
||||||
#include "../StringCompression.h"
|
|
||||||
#include "../Entities/ExpOrb.h"
|
#include "../Entities/ExpOrb.h"
|
||||||
#include "../Entities/Minecart.h"
|
#include "../Entities/Minecart.h"
|
||||||
#include "../Entities/FallingBlock.h"
|
#include "../Entities/FallingBlock.h"
|
||||||
@ -25,15 +31,15 @@ Implements the 1.7.x protocol classes:
|
|||||||
#include "../Entities/Pickup.h"
|
#include "../Entities/Pickup.h"
|
||||||
#include "../Entities/Player.h"
|
#include "../Entities/Player.h"
|
||||||
#include "../Entities/ItemFrame.h"
|
#include "../Entities/ItemFrame.h"
|
||||||
|
#include "../Entities/ArrowEntity.h"
|
||||||
|
#include "../Entities/FireworkEntity.h"
|
||||||
|
|
||||||
#include "../Mobs/IncludeAllMonsters.h"
|
#include "../Mobs/IncludeAllMonsters.h"
|
||||||
#include "../UI/Window.h"
|
#include "../UI/Window.h"
|
||||||
|
|
||||||
#include "../BlockEntities/CommandBlockEntity.h"
|
#include "../BlockEntities/CommandBlockEntity.h"
|
||||||
#include "../BlockEntities/MobHeadEntity.h"
|
#include "../BlockEntities/MobHeadEntity.h"
|
||||||
#include "../BlockEntities/FlowerPotEntity.h"
|
#include "../BlockEntities/FlowerPotEntity.h"
|
||||||
#include "../CompositeChat.h"
|
|
||||||
#include "../Entities/ArrowEntity.h"
|
|
||||||
#include "../Entities/FireworkEntity.h"
|
|
||||||
#include "PolarSSL++/Sha1Checksum.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1169,6 +1175,28 @@ void cProtocol172::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocol172::SendStatistics(const cStatManager & a_Manager)
|
||||||
|
{
|
||||||
|
ASSERT(m_State == 3); // In game mode?
|
||||||
|
|
||||||
|
cPacketizer Pkt(*this, 0x37);
|
||||||
|
Pkt.WriteVarInt(statCount); // TODO 2014-05-11 xdot: Optimization: Send "dirty" statistics only
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
|
||||||
|
{
|
||||||
|
StatValue Value = a_Manager.GetValue((eStatistic) i);
|
||||||
|
|
||||||
|
const AString & StatName = cStatInfo::GetName((eStatistic) i);
|
||||||
|
|
||||||
|
Pkt.WriteString(StatName);
|
||||||
|
Pkt.WriteVarInt(Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
|
void cProtocol172::SendTabCompletionResults(const AStringVector & a_Results)
|
||||||
{
|
{
|
||||||
ASSERT(m_State == 3); // In game mode?
|
ASSERT(m_State == 3); // In game mode?
|
||||||
@ -1843,13 +1871,15 @@ void cProtocol172::HandlePacketClientStatus(cByteBuffer & a_ByteBuffer)
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// Request stats
|
// Request stats
|
||||||
// TODO
|
const cStatManager & Manager = m_Client->GetPlayer()->GetStatManager();
|
||||||
|
SendStatistics(Manager);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// Open Inventory achievement
|
// Open Inventory achievement
|
||||||
// TODO
|
m_Client->GetPlayer()->AwardAchievement(achOpenInv);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -116,6 +116,7 @@ public:
|
|||||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||||
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
||||||
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
||||||
|
virtual void SendStatistics (const cStatManager & a_Manager) override;
|
||||||
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
||||||
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
|
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
|
||||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||||
|
@ -675,6 +675,16 @@ void cProtocolRecognizer::SendSpawnVehicle(const cEntity & a_Vehicle, char a_Veh
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cProtocolRecognizer::SendStatistics(const cStatManager & a_Manager)
|
||||||
|
{
|
||||||
|
ASSERT(m_Protocol != NULL);
|
||||||
|
m_Protocol->SendStatistics(a_Manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Results)
|
void cProtocolRecognizer::SendTabCompletionResults(const AStringVector & a_Results)
|
||||||
{
|
{
|
||||||
ASSERT(m_Protocol != NULL);
|
ASSERT(m_Protocol != NULL);
|
||||||
|
@ -119,6 +119,7 @@ public:
|
|||||||
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
virtual void SendSpawnMob (const cMonster & a_Mob) override;
|
||||||
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
virtual void SendSpawnObject (const cEntity & a_Entity, char a_ObjectType, int a_ObjectData, Byte a_Yaw, Byte a_Pitch) override;
|
||||||
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
virtual void SendSpawnVehicle (const cEntity & a_Vehicle, char a_VehicleType, char a_VehicleSubType) override;
|
||||||
|
virtual void SendStatistics (const cStatManager & a_Manager) override;
|
||||||
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
virtual void SendTabCompletionResults(const AStringVector & a_Results) override;
|
||||||
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
|
virtual void SendTeleportEntity (const cEntity & a_Entity) override;
|
||||||
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
virtual void SendThunderbolt (int a_BlockX, int a_BlockY, int a_BlockZ) override;
|
||||||
|
@ -169,7 +169,7 @@ cRCONServer::cConnection::cConnection(cRCONServer & a_RCONServer, cSocket & a_So
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
bool cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
||||||
{
|
{
|
||||||
// Append data to the buffer:
|
// Append data to the buffer:
|
||||||
m_Buffer.append(a_Data, a_Size);
|
m_Buffer.append(a_Data, a_Size);
|
||||||
@ -187,12 +187,12 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
||||||
m_Socket.CloseSocket();
|
m_Socket.CloseSocket();
|
||||||
delete this;
|
delete this;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
if (Length > (int)(m_Buffer.size() + 4))
|
if (Length > (int)(m_Buffer.size() + 4))
|
||||||
{
|
{
|
||||||
// Incomplete packet yet, wait for more data to come
|
// Incomplete packet yet, wait for more data to come
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int RequestID = IntFromBuffer(m_Buffer.data() + 4);
|
int RequestID = IntFromBuffer(m_Buffer.data() + 4);
|
||||||
@ -202,10 +202,11 @@ void cRCONServer::cConnection::DataReceived(const char * a_Data, size_t a_Size)
|
|||||||
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
m_RCONServer.m_SocketThreads.RemoveClient(this);
|
||||||
m_Socket.CloseSocket();
|
m_Socket.CloseSocket();
|
||||||
delete this;
|
delete this;
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
m_Buffer.erase(0, Length + 4);
|
m_Buffer.erase(0, Length + 4);
|
||||||
} // while (m_Buffer.size() >= 14)
|
} // while (m_Buffer.size() >= 14)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ protected:
|
|||||||
|
|
||||||
|
|
||||||
// cSocketThreads::cCallback overrides:
|
// cSocketThreads::cCallback overrides:
|
||||||
virtual void DataReceived(const char * a_Data, size_t a_Size) override;
|
virtual bool DataReceived(const char * a_Data, size_t a_Size) override;
|
||||||
virtual void GetOutgoingData(AString & a_Data) override;
|
virtual void GetOutgoingData(AString & a_Data) override;
|
||||||
virtual void SocketClosed(void) override;
|
virtual void SocketClosed(void) override;
|
||||||
|
|
||||||
|
@ -476,6 +476,36 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
|
|||||||
a_Output.Finished();
|
a_Output.Finished();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (split[0] == "load")
|
||||||
|
{
|
||||||
|
if (split.size() > 1)
|
||||||
|
{
|
||||||
|
cPluginManager::Get()->LoadPlugin(split[1]);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_Output.Out("No plugin given! Command: load <pluginname>");
|
||||||
|
a_Output.Finished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (split[0] == "unload")
|
||||||
|
{
|
||||||
|
if (split.size() > 1)
|
||||||
|
{
|
||||||
|
cPluginManager::Get()->RemovePlugin(cPluginManager::Get()->GetPlugin(split[1]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
a_Output.Out("No plugin given! Command: unload <pluginname>");
|
||||||
|
a_Output.Finished();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// There is currently no way a plugin can do these (and probably won't ever be):
|
// There is currently no way a plugin can do these (and probably won't ever be):
|
||||||
if (split[0].compare("chunkstats") == 0)
|
if (split[0].compare("chunkstats") == 0)
|
||||||
@ -567,6 +597,9 @@ void cServer::BindBuiltInConsoleCommands(void)
|
|||||||
PlgMgr->BindConsoleCommand("restart", NULL, " - Restarts the server cleanly");
|
PlgMgr->BindConsoleCommand("restart", NULL, " - Restarts the server cleanly");
|
||||||
PlgMgr->BindConsoleCommand("stop", NULL, " - Stops the server cleanly");
|
PlgMgr->BindConsoleCommand("stop", NULL, " - Stops the server cleanly");
|
||||||
PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics");
|
PlgMgr->BindConsoleCommand("chunkstats", NULL, " - Displays detailed chunk memory statistics");
|
||||||
|
PlgMgr->BindConsoleCommand("load <pluginname>", NULL, " - Adds and enables the specified plugin");
|
||||||
|
PlgMgr->BindConsoleCommand("unload <pluginname>", NULL, " - Disables the specified plugin");
|
||||||
|
|
||||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||||
PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
|
PlgMgr->BindConsoleCommand("dumpmem", NULL, " - Dumps all used memory blocks together with their callstacks into memdump.xml");
|
||||||
#endif
|
#endif
|
||||||
|
@ -13,39 +13,39 @@ cStatInfo cStatInfo::ms_Info[statCount] = {
|
|||||||
// http://minecraft.gamepedia.com/Achievements
|
// http://minecraft.gamepedia.com/Achievements
|
||||||
|
|
||||||
/* Type | Name | Prerequisite */
|
/* Type | Name | Prerequisite */
|
||||||
cStatInfo(achOpenInv, "openInventory"),
|
cStatInfo(achOpenInv, "achievement.openInventory"),
|
||||||
cStatInfo(achMineWood, "mineWood", achOpenInv),
|
cStatInfo(achMineWood, "achievement.mineWood", achOpenInv),
|
||||||
cStatInfo(achCraftWorkbench, "buildWorkBench", achMineWood),
|
cStatInfo(achCraftWorkbench, "achievement.buildWorkBench", achMineWood),
|
||||||
cStatInfo(achCraftPickaxe, "buildPickaxe", achCraftWorkbench),
|
cStatInfo(achCraftPickaxe, "achievement.buildPickaxe", achCraftWorkbench),
|
||||||
cStatInfo(achCraftFurnace, "buildFurnace", achCraftPickaxe),
|
cStatInfo(achCraftFurnace, "achievement.buildFurnace", achCraftPickaxe),
|
||||||
cStatInfo(achAcquireIron, "acquireIron", achCraftFurnace),
|
cStatInfo(achAcquireIron, "achievement.acquireIron", achCraftFurnace),
|
||||||
cStatInfo(achCraftHoe, "buildHoe", achCraftWorkbench),
|
cStatInfo(achCraftHoe, "achievement.buildHoe", achCraftWorkbench),
|
||||||
cStatInfo(achMakeBread, "makeBread", achCraftHoe),
|
cStatInfo(achMakeBread, "achievement.makeBread", achCraftHoe),
|
||||||
cStatInfo(achBakeCake, "bakeCake", achCraftHoe),
|
cStatInfo(achBakeCake, "achievement.bakeCake", achCraftHoe),
|
||||||
cStatInfo(achCraftBetterPick, "buildBetterPickaxe", achCraftPickaxe),
|
cStatInfo(achCraftBetterPick, "achievement.buildBetterPickaxe", achCraftPickaxe),
|
||||||
cStatInfo(achCookFish, "cookFish", achAcquireIron),
|
cStatInfo(achCookFish, "achievement.cookFish", achAcquireIron),
|
||||||
cStatInfo(achOnARail, "onARail", achAcquireIron),
|
cStatInfo(achOnARail, "achievement.onARail", achAcquireIron),
|
||||||
cStatInfo(achCraftSword, "buildSword", achCraftWorkbench),
|
cStatInfo(achCraftSword, "achievement.buildSword", achCraftWorkbench),
|
||||||
cStatInfo(achKillMonster, "killEnemy", achCraftSword),
|
cStatInfo(achKillMonster, "achievement.killEnemy", achCraftSword),
|
||||||
cStatInfo(achKillCow, "killCow", achCraftSword),
|
cStatInfo(achKillCow, "achievement.killCow", achCraftSword),
|
||||||
cStatInfo(achFlyPig, "flyPig", achKillCow),
|
cStatInfo(achFlyPig, "achievement.flyPig", achKillCow),
|
||||||
cStatInfo(achSnipeSkeleton, "snipeSkeleton", achKillMonster),
|
cStatInfo(achSnipeSkeleton, "achievement.snipeSkeleton", achKillMonster),
|
||||||
cStatInfo(achDiamonds, "diamonds", achAcquireIron),
|
cStatInfo(achDiamonds, "achievement.diamonds", achAcquireIron),
|
||||||
cStatInfo(achEnterPortal, "portal", achDiamonds),
|
cStatInfo(achEnterPortal, "achievement.portal", achDiamonds),
|
||||||
cStatInfo(achReturnToSender, "ghast", achEnterPortal),
|
cStatInfo(achReturnToSender, "achievement.ghast", achEnterPortal),
|
||||||
cStatInfo(achBlazeRod, "blazeRod", achEnterPortal),
|
cStatInfo(achBlazeRod, "achievement.blazeRod", achEnterPortal),
|
||||||
cStatInfo(achBrewPotion, "potion", achBlazeRod),
|
cStatInfo(achBrewPotion, "achievement.potion", achBlazeRod),
|
||||||
cStatInfo(achEnterTheEnd, "theEnd", achBlazeRod),
|
cStatInfo(achEnterTheEnd, "achievement.theEnd", achBlazeRod),
|
||||||
cStatInfo(achDefeatDragon, "theEnd2", achEnterTheEnd),
|
cStatInfo(achDefeatDragon, "achievement.theEnd2", achEnterTheEnd),
|
||||||
cStatInfo(achCraftEnchantTable, "enchantments", achDiamonds),
|
cStatInfo(achCraftEnchantTable, "achievement.enchantments", achDiamonds),
|
||||||
cStatInfo(achOverkill, "overkill", achCraftEnchantTable),
|
cStatInfo(achOverkill, "achievement.overkill", achCraftEnchantTable),
|
||||||
cStatInfo(achBookshelf, "bookcase", achCraftEnchantTable),
|
cStatInfo(achBookshelf, "achievement.bookcase", achCraftEnchantTable),
|
||||||
cStatInfo(achExploreAllBiomes, "exploreAllBiomes", achEnterTheEnd),
|
cStatInfo(achExploreAllBiomes, "achievement.exploreAllBiomes", achEnterTheEnd),
|
||||||
cStatInfo(achSpawnWither, "spawnWither", achDefeatDragon),
|
cStatInfo(achSpawnWither, "achievement.spawnWither", achDefeatDragon),
|
||||||
cStatInfo(achKillWither, "killWither", achSpawnWither),
|
cStatInfo(achKillWither, "achievement.killWither", achSpawnWither),
|
||||||
cStatInfo(achFullBeacon, "fullBeacon", achKillWither),
|
cStatInfo(achFullBeacon, "achievement.fullBeacon", achKillWither),
|
||||||
cStatInfo(achBreedCow, "breedCow", achKillCow),
|
cStatInfo(achBreedCow, "achievement.breedCow", achKillCow),
|
||||||
cStatInfo(achThrowDiamonds, "diamondsToYou", achDiamonds),
|
cStatInfo(achThrowDiamonds, "achievement.diamondsToYou", achDiamonds),
|
||||||
|
|
||||||
// http://minecraft.gamepedia.com/Statistics
|
// http://minecraft.gamepedia.com/Statistics
|
||||||
|
|
||||||
@ -57,13 +57,14 @@ cStatInfo cStatInfo::ms_Info[statCount] = {
|
|||||||
cStatInfo(statDistFallen, "stat.fallOneCm"),
|
cStatInfo(statDistFallen, "stat.fallOneCm"),
|
||||||
cStatInfo(statDistClimbed, "stat.climbOneCm"),
|
cStatInfo(statDistClimbed, "stat.climbOneCm"),
|
||||||
cStatInfo(statDistFlown, "stat.flyOneCm"),
|
cStatInfo(statDistFlown, "stat.flyOneCm"),
|
||||||
|
cStatInfo(statDistDove, "stat.diveOneCm"),
|
||||||
cStatInfo(statDistMinecart, "stat.minecartOneCm"),
|
cStatInfo(statDistMinecart, "stat.minecartOneCm"),
|
||||||
cStatInfo(statDistBoat, "stat.boatOneCm"),
|
cStatInfo(statDistBoat, "stat.boatOneCm"),
|
||||||
cStatInfo(statDistPig, "stat.pigOneCm"),
|
cStatInfo(statDistPig, "stat.pigOneCm"),
|
||||||
cStatInfo(statDistHorse, "stat.horseOneCm"),
|
cStatInfo(statDistHorse, "stat.horseOneCm"),
|
||||||
cStatInfo(statJumps, "stat.jump"),
|
cStatInfo(statJumps, "stat.jump"),
|
||||||
cStatInfo(statItemsDropped, "stat.drop"),
|
cStatInfo(statItemsDropped, "stat.drop"),
|
||||||
cStatInfo(statDamageDealt, "stat.damageDealth"),
|
cStatInfo(statDamageDealt, "stat.damageDealt"),
|
||||||
cStatInfo(statDamageTaken, "stat.damageTaken"),
|
cStatInfo(statDamageTaken, "stat.damageTaken"),
|
||||||
cStatInfo(statDeaths, "stat.deaths"),
|
cStatInfo(statDeaths, "stat.deaths"),
|
||||||
cStatInfo(statMobKills, "stat.mobKills"),
|
cStatInfo(statMobKills, "stat.mobKills"),
|
||||||
@ -113,7 +114,7 @@ eStatistic cStatInfo::GetType(const AString & a_Name)
|
|||||||
{
|
{
|
||||||
for (unsigned int i = 0; i < ARRAYCOUNT(ms_Info); ++i)
|
for (unsigned int i = 0; i < ARRAYCOUNT(ms_Info); ++i)
|
||||||
{
|
{
|
||||||
if (NoCaseCompare(ms_Info[i].m_Name, a_Name))
|
if (NoCaseCompare(ms_Info[i].m_Name, a_Name) == 0)
|
||||||
{
|
{
|
||||||
return ms_Info[i].m_Type;
|
return ms_Info[i].m_Type;
|
||||||
}
|
}
|
||||||
@ -137,3 +138,59 @@ eStatistic cStatInfo::GetPrerequisite(const eStatistic a_Type)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cStatManager::cStatManager()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
StatValue cStatManager::GetValue(const eStatistic a_Stat) const
|
||||||
|
{
|
||||||
|
ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
|
||||||
|
|
||||||
|
return m_MainStats[a_Stat];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cStatManager::SetValue(const eStatistic a_Stat, const StatValue a_Value)
|
||||||
|
{
|
||||||
|
ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
|
||||||
|
|
||||||
|
m_MainStats[a_Stat] = a_Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
StatValue cStatManager::AddValue(const eStatistic a_Stat, const StatValue a_Delta)
|
||||||
|
{
|
||||||
|
ASSERT((a_Stat > statInvalid) && (a_Stat < statCount));
|
||||||
|
|
||||||
|
m_MainStats[a_Stat] += a_Delta;
|
||||||
|
|
||||||
|
return m_MainStats[a_Stat];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cStatManager::Reset(void)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
|
||||||
|
{
|
||||||
|
m_MainStats[i] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
enum eStatistic
|
enum eStatistic
|
||||||
{
|
{
|
||||||
// The order must match the order of cStatInfo::ms_Info
|
// The order must match the order of cStatInfo::ms_Info
|
||||||
@ -77,6 +78,7 @@ enum eStatistic
|
|||||||
|
|
||||||
statCount
|
statCount
|
||||||
};
|
};
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -114,3 +116,49 @@ private:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Signed (?) integral value. */
|
||||||
|
typedef int StatValue; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Class that manages the statistics and achievements of a single player. */
|
||||||
|
// tolua_begin
|
||||||
|
class cStatManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
cStatManager();
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
/** Return the value of the specified stat. */
|
||||||
|
StatValue GetValue(const eStatistic a_Stat) const;
|
||||||
|
|
||||||
|
/** Set the value of the specified stat. */
|
||||||
|
void SetValue(const eStatistic a_Stat, const StatValue a_Value);
|
||||||
|
|
||||||
|
/** Reset everything. */
|
||||||
|
void Reset();
|
||||||
|
|
||||||
|
/** Increment the specified stat.
|
||||||
|
*
|
||||||
|
* Returns the new value.
|
||||||
|
*/
|
||||||
|
StatValue AddValue(const eStatistic a_Stat, const StatValue a_Delta = 1);
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
StatValue m_MainStats[statCount];
|
||||||
|
|
||||||
|
// TODO 10-05-2014 xdot: Use, mine, craft statistics
|
||||||
|
|
||||||
|
|
||||||
|
}; // tolua_export
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -496,6 +496,8 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
|
|||||||
DraggingItem = Result;
|
DraggingItem = Result;
|
||||||
Recipe.ConsumeIngredients(Grid);
|
Recipe.ConsumeIngredients(Grid);
|
||||||
Grid.CopyToItems(PlayerSlots);
|
Grid.CopyToItems(PlayerSlots);
|
||||||
|
|
||||||
|
HandleCraftItem(Result, a_Player);
|
||||||
}
|
}
|
||||||
else if (DraggingItem.IsEqual(Result))
|
else if (DraggingItem.IsEqual(Result))
|
||||||
{
|
{
|
||||||
@ -505,6 +507,8 @@ void cSlotAreaCrafting::ClickedResult(cPlayer & a_Player)
|
|||||||
DraggingItem.m_ItemCount += Result.m_ItemCount;
|
DraggingItem.m_ItemCount += Result.m_ItemCount;
|
||||||
Recipe.ConsumeIngredients(Grid);
|
Recipe.ConsumeIngredients(Grid);
|
||||||
Grid.CopyToItems(PlayerSlots);
|
Grid.CopyToItems(PlayerSlots);
|
||||||
|
|
||||||
|
HandleCraftItem(Result, a_Player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,6 +598,27 @@ cCraftingRecipe & cSlotAreaCrafting::GetRecipeForPlayer(cPlayer & a_Player)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSlotAreaCrafting::HandleCraftItem(const cItem & a_Result, cPlayer & a_Player)
|
||||||
|
{
|
||||||
|
switch (a_Result.m_ItemType)
|
||||||
|
{
|
||||||
|
case E_BLOCK_WORKBENCH: a_Player.AwardAchievement(achCraftWorkbench); break;
|
||||||
|
case E_BLOCK_FURNACE: a_Player.AwardAchievement(achCraftFurnace); break;
|
||||||
|
case E_BLOCK_CAKE: a_Player.AwardAchievement(achBakeCake); break;
|
||||||
|
case E_BLOCK_ENCHANTMENT_TABLE: a_Player.AwardAchievement(achCraftEnchantTable); break;
|
||||||
|
case E_BLOCK_BOOKCASE: a_Player.AwardAchievement(achBookshelf); break;
|
||||||
|
case E_ITEM_WOODEN_PICKAXE: a_Player.AwardAchievement(achCraftPickaxe); break;
|
||||||
|
case E_ITEM_WOODEN_SWORD: a_Player.AwardAchievement(achCraftSword); break;
|
||||||
|
case E_ITEM_STONE_PICKAXE: a_Player.AwardAchievement(achCraftBetterPick); break;
|
||||||
|
case E_ITEM_WOODEN_HOE: a_Player.AwardAchievement(achCraftHoe); break;
|
||||||
|
case E_ITEM_BREAD: a_Player.AwardAchievement(achMakeBread); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cSlotAreaAnvil:
|
// cSlotAreaAnvil:
|
||||||
@ -760,7 +785,7 @@ void cSlotAreaAnvil::OnTakeResult(cPlayer & a_Player)
|
|||||||
{
|
{
|
||||||
if (!a_Player.IsGameModeCreative())
|
if (!a_Player.IsGameModeCreative())
|
||||||
{
|
{
|
||||||
a_Player.DeltaExperience(cPlayer::XpForLevel(m_MaximumCost));
|
a_Player.DeltaExperience(-cPlayer::XpForLevel(m_MaximumCost));
|
||||||
}
|
}
|
||||||
SetSlot(0, a_Player, cItem());
|
SetSlot(0, a_Player, cItem());
|
||||||
|
|
||||||
@ -1401,6 +1426,21 @@ void cSlotAreaFurnace::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cSlotAreaFurnace::HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player)
|
||||||
|
{
|
||||||
|
/** TODO 2014-05-12 xdot: Figure out when to call this method. */
|
||||||
|
switch (a_Result.m_ItemType)
|
||||||
|
{
|
||||||
|
case E_ITEM_IRON: a_Player.AwardAchievement(achAcquireIron); break;
|
||||||
|
case E_ITEM_COOKED_FISH: a_Player.AwardAchievement(achCookFish); break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// cSlotAreaInventoryBase:
|
// cSlotAreaInventoryBase:
|
||||||
|
|
||||||
|
@ -254,6 +254,9 @@ protected:
|
|||||||
|
|
||||||
/// Retrieves the recipe for the specified player from the map, or creates one if not found
|
/// Retrieves the recipe for the specified player from the map, or creates one if not found
|
||||||
cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player);
|
cCraftingRecipe & GetRecipeForPlayer(cPlayer & a_Player);
|
||||||
|
|
||||||
|
/// Called after an item has been crafted to handle statistics e.t.c.
|
||||||
|
void HandleCraftItem(const cItem & a_Result, cPlayer & a_Player);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
@ -397,6 +400,9 @@ protected:
|
|||||||
|
|
||||||
// cItemGrid::cListener overrides:
|
// cItemGrid::cListener overrides:
|
||||||
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
|
virtual void OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum) override;
|
||||||
|
|
||||||
|
/// Called after an item has been smelted to handle statistics e.t.c.
|
||||||
|
void HandleSmeltItem(const cItem & a_Result, cPlayer & a_Player);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -391,38 +391,41 @@ void cNBTChunkSerializer::AddFallingBlockEntity(cFallingBlock * a_FallingBlock)
|
|||||||
|
|
||||||
void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart)
|
void cNBTChunkSerializer::AddMinecartEntity(cMinecart * a_Minecart)
|
||||||
{
|
{
|
||||||
const char * EntityClass = NULL;
|
|
||||||
switch (a_Minecart->GetPayload())
|
|
||||||
{
|
|
||||||
case cMinecart::mpNone: EntityClass = "MinecartRideable"; break;
|
|
||||||
case cMinecart::mpChest: EntityClass = "MinecartChest"; break;
|
|
||||||
case cMinecart::mpFurnace: EntityClass = "MinecartFurnace"; break;
|
|
||||||
case cMinecart::mpTNT: EntityClass = "MinecartTNT"; break;
|
|
||||||
case cMinecart::mpHopper: EntityClass = "MinecartHopper"; break;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
ASSERT(!"Unhandled minecart payload type");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} // switch (payload)
|
|
||||||
|
|
||||||
m_Writer.BeginCompound("");
|
m_Writer.BeginCompound("");
|
||||||
AddBasicEntity(a_Minecart, EntityClass);
|
|
||||||
switch (a_Minecart->GetPayload())
|
switch (a_Minecart->GetPayload())
|
||||||
{
|
{
|
||||||
case cMinecart::mpChest:
|
case cMinecart::mpChest:
|
||||||
{
|
{
|
||||||
|
AddBasicEntity(a_Minecart, "MinecartChest");
|
||||||
// Add chest contents into the Items tag:
|
// Add chest contents into the Items tag:
|
||||||
AddMinecartChestContents((cMinecartWithChest *)a_Minecart);
|
AddMinecartChestContents((cMinecartWithChest *)a_Minecart);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case cMinecart::mpFurnace:
|
case cMinecart::mpFurnace:
|
||||||
{
|
{
|
||||||
|
AddBasicEntity(a_Minecart, "MinecartFurnace");
|
||||||
// TODO: Add "Push" and "Fuel" tags
|
// TODO: Add "Push" and "Fuel" tags
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case cMinecart::mpHopper:
|
||||||
|
{
|
||||||
|
AddBasicEntity(a_Minecart, "MinecartHopper");
|
||||||
|
// TODO: Add hopper contents?
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMinecart::mpTNT:
|
||||||
|
{
|
||||||
|
AddBasicEntity(a_Minecart, "MinecartTNT");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case cMinecart::mpNone:
|
||||||
|
{
|
||||||
|
AddBasicEntity(a_Minecart, "MinecartRideable");
|
||||||
|
break;
|
||||||
|
}
|
||||||
} // switch (Payload)
|
} // switch (Payload)
|
||||||
|
|
||||||
m_Writer.EndCompound();
|
m_Writer.EndCompound();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -650,6 +653,13 @@ void cNBTChunkSerializer::AddHangingEntity(cHangingEntity * a_Hanging)
|
|||||||
case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break;
|
case BLOCK_FACE_YP: m_Writer.AddByte("Dir", (unsigned char)1); break;
|
||||||
case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break;
|
case BLOCK_FACE_ZM: m_Writer.AddByte("Dir", (unsigned char)0); break;
|
||||||
case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break;
|
case BLOCK_FACE_ZP: m_Writer.AddByte("Dir", (unsigned char)3); break;
|
||||||
|
|
||||||
|
case BLOCK_FACE_XM:
|
||||||
|
case BLOCK_FACE_XP:
|
||||||
|
case BLOCK_FACE_NONE:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
146
src/WorldStorage/StatSerializer.cpp
Normal file
146
src/WorldStorage/StatSerializer.cpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
|
||||||
|
// StatSerializer.cpp
|
||||||
|
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "StatSerializer.h"
|
||||||
|
|
||||||
|
#include "../Statistics.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cStatSerializer::cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager)
|
||||||
|
: m_Manager(a_Manager)
|
||||||
|
{
|
||||||
|
// Even though stats are shared between worlds, they are (usually) saved
|
||||||
|
// inside the folder of the default world.
|
||||||
|
|
||||||
|
AString StatsPath;
|
||||||
|
Printf(StatsPath, "%s/stats", a_WorldName.c_str());
|
||||||
|
|
||||||
|
m_Path = StatsPath + "/" + a_PlayerName + ".json";
|
||||||
|
|
||||||
|
// Ensure that the directory exists.
|
||||||
|
cFile::CreateFolder(FILE_IO_PREFIX + StatsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cStatSerializer::Load(void)
|
||||||
|
{
|
||||||
|
AString Data = cFile::ReadWholeFile(FILE_IO_PREFIX + m_Path);
|
||||||
|
if (Data.empty())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value Root;
|
||||||
|
Json::Reader Reader;
|
||||||
|
|
||||||
|
if (Reader.parse(Data, Root, false))
|
||||||
|
{
|
||||||
|
return LoadStatFromJSON(Root);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cStatSerializer::Save(void)
|
||||||
|
{
|
||||||
|
Json::Value Root;
|
||||||
|
SaveStatToJSON(Root);
|
||||||
|
|
||||||
|
cFile File;
|
||||||
|
if (!File.Open(FILE_IO_PREFIX + m_Path, cFile::fmWrite))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::StyledWriter Writer;
|
||||||
|
AString JsonData = Writer.write(Root);
|
||||||
|
|
||||||
|
File.Write(JsonData.data(), JsonData.size());
|
||||||
|
File.Close();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cStatSerializer::SaveStatToJSON(Json::Value & a_Out)
|
||||||
|
{
|
||||||
|
for (unsigned int i = 0; i < (unsigned int)statCount; ++i)
|
||||||
|
{
|
||||||
|
StatValue Value = m_Manager->GetValue((eStatistic) i);
|
||||||
|
|
||||||
|
if (Value != 0)
|
||||||
|
{
|
||||||
|
const AString & StatName = cStatInfo::GetName((eStatistic) i);
|
||||||
|
|
||||||
|
a_Out[StatName] = Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO 2014-05-11 xdot: Save "progress"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cStatSerializer::LoadStatFromJSON(const Json::Value & a_In)
|
||||||
|
{
|
||||||
|
m_Manager->Reset();
|
||||||
|
|
||||||
|
for (Json::ValueIterator it = a_In.begin() ; it != a_In.end() ; ++it)
|
||||||
|
{
|
||||||
|
AString StatName = it.key().asString();
|
||||||
|
|
||||||
|
eStatistic StatType = cStatInfo::GetType(StatName);
|
||||||
|
|
||||||
|
if (StatType == statInvalid)
|
||||||
|
{
|
||||||
|
LOGWARNING("Invalid statistic type \"%s\"", StatName.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Json::Value & Node = *it;
|
||||||
|
|
||||||
|
if (Node.isInt())
|
||||||
|
{
|
||||||
|
m_Manager->SetValue(StatType, Node.asInt());
|
||||||
|
}
|
||||||
|
else if (Node.isObject())
|
||||||
|
{
|
||||||
|
StatValue Value = Node.get("value", 0).asInt();
|
||||||
|
|
||||||
|
// TODO 2014-05-11 xdot: Load "progress"
|
||||||
|
|
||||||
|
m_Manager->SetValue(StatType, Value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LOGWARNING("Invalid statistic value for type \"%s\"", StatName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
55
src/WorldStorage/StatSerializer.h
Normal file
55
src/WorldStorage/StatSerializer.h
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
// StatSerializer.h
|
||||||
|
|
||||||
|
// Declares the cStatSerializer class that is used for saving stats into JSON
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "json/json.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// fwd:
|
||||||
|
class cStatManager;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class cStatSerializer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
cStatSerializer(const AString & a_WorldName, const AString & a_PlayerName, cStatManager * a_Manager);
|
||||||
|
|
||||||
|
/* Try to load the player statistics. Returns whether the operation was successful or not. */
|
||||||
|
bool Load(void);
|
||||||
|
|
||||||
|
/* Try to save the player statistics. Returns whether the operation was successful or not. */
|
||||||
|
bool Save(void);
|
||||||
|
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void SaveStatToJSON(Json::Value & a_Out);
|
||||||
|
|
||||||
|
bool LoadStatFromJSON(const Json::Value & a_In);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
cStatManager* m_Manager;
|
||||||
|
|
||||||
|
AString m_Path;
|
||||||
|
|
||||||
|
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -243,7 +243,6 @@ void cWorldStorage::Execute(void)
|
|||||||
bool Success;
|
bool Success;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
Success = false;
|
|
||||||
if (m_ShouldTerminate)
|
if (m_ShouldTerminate)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user