Merge branch 'master' into redstoneimprovements
Conflicts: src/ClientHandle.cpp src/Entities/FallingBlock.cpp src/Mobs/AggressiveMonster.cpp src/Simulator/IncrementalRedstoneSimulator.cpp
This commit is contained in:
commit
0d1804e439
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -9,4 +9,4 @@
|
|||||||
url = https://github.com/bearbin/transapi.git
|
url = https://github.com/bearbin/transapi.git
|
||||||
[submodule "lib/polarssl"]
|
[submodule "lib/polarssl"]
|
||||||
path = lib/polarssl
|
path = lib/polarssl
|
||||||
url = https://github.com/polarssl/polarssl
|
url = https://github.com/mc-server/polarssl
|
||||||
|
41
COMPILING.md
41
COMPILING.md
@ -45,7 +45,30 @@ It is possible to use an external profiler to learn more about how the code perf
|
|||||||
|
|
||||||
There's a script file, `MCServer/profile_run.cmd` that encapsulates most of the profiling work, have a look at the comments at the top of that script for details on how to get it to work. You'll need to change to a profiled configuration (both debug and release can be profiled).
|
There's a script file, `MCServer/profile_run.cmd` that encapsulates most of the profiling work, have a look at the comments at the top of that script for details on how to get it to work. You'll need to change to a profiled configuration (both debug and release can be profiled).
|
||||||
|
|
||||||
## Linux, MacOS, FreeBSD etc. ##
|
## OSX ##
|
||||||
|
Install git from its [website](http://git-scm.com) or homebrew: `brew install git`.
|
||||||
|
|
||||||
|
Install Xcode (commandline tools are recommended) from the App Store or https://developer.apple.com/downloads.
|
||||||
|
|
||||||
|
Install CMake from its [website](http://cmake.org) or homebrew: `brew install cmake`.
|
||||||
|
|
||||||
|
### Getting the sources ###
|
||||||
|
```
|
||||||
|
mkdir MCServer
|
||||||
|
cd MCServer
|
||||||
|
git clone https://github.com/mc-server/MCServer.git .
|
||||||
|
git submodule init
|
||||||
|
git submodule update
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building ###
|
||||||
|
|
||||||
|
Follow the instructions at [CMake on Unix-based platforms](#cmake-on-unix-based-platforms), using Xcode as cmake's generator. If no generator is specified, CMake will use the Makefile generator, in which case you must build with the `make` command.
|
||||||
|
|
||||||
|
After doing so, run the command `xcodebuild lib/polarssl/POLARSSL.xcodeproj` in the build directory, in order to build polarssl, a library that is required by MCServer. Lastly, run the command `xcodebuild` to build MCServer. Optionally, you may open the project files for polarssl and then MCServer in Xcode and build there.
|
||||||
|
|
||||||
|
|
||||||
|
## Linux, FreeBSD etc. ##
|
||||||
|
|
||||||
Install git, cmake and gcc or clang, using your platform's package manager:
|
Install git, cmake and gcc or clang, using your platform's package manager:
|
||||||
```
|
```
|
||||||
@ -61,6 +84,14 @@ git submodule init
|
|||||||
git submodule update
|
git submodule update
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Building ###
|
||||||
|
|
||||||
|
Follow the instructions at [CMake on Unix-based platforms](#cmake-on-unix-based-platforms).
|
||||||
|
|
||||||
|
After doing so, run the command `make` in the build directory, and MCServer will build.
|
||||||
|
|
||||||
|
## CMake on Unix-based platforms ###
|
||||||
|
|
||||||
### Release Mode ###
|
### Release Mode ###
|
||||||
|
|
||||||
Release mode is preferred for almost all cases, it has much better speed and less console spam. However, if you are developing MCServer actively, debug mode might be better.
|
Release mode is preferred for almost all cases, it has much better speed and less console spam. However, if you are developing MCServer actively, debug mode might be better.
|
||||||
@ -69,8 +100,10 @@ Assuming you are in the MCServer folder created in the initial setup step, you n
|
|||||||
```
|
```
|
||||||
mkdir Release
|
mkdir Release
|
||||||
cd Release
|
cd Release
|
||||||
cmake -DCMAKE_BUILD_TYPE=RELEASE .. && make
|
cmake -DCMAKE_BUILD_TYPE=RELEASE ..
|
||||||
```
|
```
|
||||||
|
NOTE: CMake can generate project files for many different programs, such as Xcode, eclipse, and ninja. To use a different generator, first type `cmake --help`, and at the end, cmake will output the different generators that are available. To specify one, add `-G` followed by the name of the generator, in the `cmake` command. Note that the name is case-sensitive.
|
||||||
|
|
||||||
The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer`.
|
The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer`.
|
||||||
|
|
||||||
### Debug Mode ###
|
### Debug Mode ###
|
||||||
@ -81,8 +114,10 @@ Assuming you are in the MCServer folder created in the Getting the sources step,
|
|||||||
```
|
```
|
||||||
mkdir Debug
|
mkdir Debug
|
||||||
cd Debug
|
cd Debug
|
||||||
cmake -DCMAKE_BUILD_TYPE=DEBUG .. && make
|
cmake -DCMAKE_BUILD_TYPE=DEBUG ..
|
||||||
```
|
```
|
||||||
|
NOTE: CMake can generate project files for many different programs, such as Xcode, eclipse, and ninja. To use a different generator, first type `cmake --help`, and at the end, cmake will output the different generators that are available. To specify one, add `-G` followed by the name of the generator, in the `cmake` command. Note that the name is case-sensitive.
|
||||||
|
|
||||||
The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer_debug`.
|
The executable will be built in the `MCServer/MCServer` folder and will be named `MCServer_debug`.
|
||||||
|
|
||||||
### 32 Bit Mode switch ###
|
### 32 Bit Mode switch ###
|
||||||
|
17
CoverityModel.cpp
Normal file
17
CoverityModel.cpp
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
struct lua_State;
|
||||||
|
struct tolua_Error
|
||||||
|
{
|
||||||
|
int index;
|
||||||
|
int array;
|
||||||
|
const char* type;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tolua_error (lua_State* L, const char* msg, tolua_Error* err)
|
||||||
|
{
|
||||||
|
__coverity_panic__();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,23 +2,33 @@ return
|
|||||||
{
|
{
|
||||||
HOOK_DISCONNECT =
|
HOOK_DISCONNECT =
|
||||||
{
|
{
|
||||||
CalledWhen = "A player has explicitly disconnected.",
|
CalledWhen = [[
|
||||||
|
A client has disconnected, either by explicitly sending the disconnect packet (in older protocols) or
|
||||||
|
their connection was terminated
|
||||||
|
]],
|
||||||
DefaultFnName = "OnDisconnect", -- also used as pagename
|
DefaultFnName = "OnDisconnect", -- also used as pagename
|
||||||
Desc = [[
|
Desc = [[
|
||||||
This hook is called when a client is about to be disconnected from the server, for whatever reason.
|
This hook is called when a client has disconnected from the server, for whatever reason. It is also
|
||||||
|
called when the client sends the Disconnect packet (only in pre-1.7 protocols). This hook is not called
|
||||||
<p><b>Note that this hook will be removed after <1.7 protocol support is removed, as it was originally a hook for
|
for server ping connections.</p>
|
||||||
the client sending the server a disconnect packet, which no longer happens.</b></p>
|
<p>
|
||||||
|
Note that the hook is called even for connections to players who failed to auth. In such a case there's
|
||||||
|
no {{cPlayer}} object associated with the client.</p>
|
||||||
|
<p>
|
||||||
|
See also the {{OnHandshake|HOOK_HANDSHAKE}} hook which is called when the client connects (and presents
|
||||||
|
a handshake message, so that they are not just status-pinging). If you need to store a per-player
|
||||||
|
object, use the {{OnPlayerJoined|HOOK_PLAYER_JOINED}} and {{OnPlayerDestroyed|HOOK_PLAYER_DESTROYED}}
|
||||||
|
hooks instead, those are guaranteed to have the {{cPlayer}} object associated.
|
||||||
]],
|
]],
|
||||||
Params =
|
Params =
|
||||||
{
|
{
|
||||||
{ Name = "Player", Type = "{{cPlayer}}", Notes = "The player who has disconnected" },
|
{ Name = "Client", Type = "{{cClientHandle}}", Notes = "The client who has disconnected" },
|
||||||
{ Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" },
|
{ Name = "Reason", Type = "string", Notes = "The reason that the client has sent in the disconnect packet" },
|
||||||
},
|
},
|
||||||
Returns = [[
|
Returns = [[
|
||||||
If the function returns false or no value, MCServer calls other plugins' callbacks for this event.
|
If the function returns false or no value, MCServer calls other plugins' callbacks for this event.
|
||||||
If the function returns true, no other plugins are called for this event. In either case,
|
If the function returns true, no other plugins are called for this event. In either case,
|
||||||
the player is disconnected.
|
the client is disconnected.
|
||||||
]],
|
]],
|
||||||
}, -- HOOK_DISCONNECT
|
}, -- HOOK_DISCONNECT
|
||||||
}
|
}
|
||||||
|
@ -27,10 +27,14 @@ local function LoadAPIFiles(a_Folder, a_DstTable)
|
|||||||
-- We only want .lua files from the folder:
|
-- We only want .lua files from the folder:
|
||||||
if (cFile:IsFile(FileName) and fnam:match(".*%.lua$")) then
|
if (cFile:IsFile(FileName) and fnam:match(".*%.lua$")) then
|
||||||
local TablesFn, Err = loadfile(FileName);
|
local TablesFn, Err = loadfile(FileName);
|
||||||
if (TablesFn == nil) then
|
if (type(TablesFn) ~= "function") then
|
||||||
LOGWARNING("Cannot load API descriptions from " .. FileName .. ", Lua error '" .. Err .. "'.");
|
LOGWARNING("Cannot load API descriptions from " .. FileName .. ", Lua error '" .. Err .. "'.");
|
||||||
else
|
else
|
||||||
local Tables = TablesFn();
|
local Tables = TablesFn();
|
||||||
|
if (type(Tables) ~= "table") then
|
||||||
|
LOGWARNING("Cannot load API descriptions from " .. FileName .. ", returned object is not a table (" .. type(Tables) .. ").");
|
||||||
|
break
|
||||||
|
end
|
||||||
for k, cls in pairs(Tables) do
|
for k, cls in pairs(Tables) do
|
||||||
a_DstTable[k] = cls;
|
a_DstTable[k] = cls;
|
||||||
end
|
end
|
||||||
|
@ -36,14 +36,24 @@ set(SHARED_SRC
|
|||||||
../../src/StringUtils.cpp
|
../../src/StringUtils.cpp
|
||||||
../../src/Log.cpp
|
../../src/Log.cpp
|
||||||
../../src/MCLogger.cpp
|
../../src/MCLogger.cpp
|
||||||
../../src/Crypto.cpp
|
../../src/PolarSSL++/AesCfb128Decryptor.cpp
|
||||||
|
../../src/PolarSSL++/AesCfb128Encryptor.cpp
|
||||||
|
../../src/PolarSSL++/CtrDrbgContext.cpp
|
||||||
|
../../src/PolarSSL++/EntropyContext.cpp
|
||||||
|
../../src/PolarSSL++/PublicKey.cpp
|
||||||
|
../../src/PolarSSL++/RsaPrivateKey.cpp
|
||||||
)
|
)
|
||||||
set(SHARED_HDR
|
set(SHARED_HDR
|
||||||
../../src/ByteBuffer.h
|
../../src/ByteBuffer.h
|
||||||
../../src/StringUtils.h
|
../../src/StringUtils.h
|
||||||
../../src/Log.h
|
../../src/Log.h
|
||||||
../../src/MCLogger.h
|
../../src/MCLogger.h
|
||||||
../../src/Crypto.h
|
../../src/PolarSSL++/AesCfb128Decryptor.h
|
||||||
|
../../src/PolarSSL++/AesCfb128Encryptor.h
|
||||||
|
../../src/PolarSSL++/CtrDrbgContext.h
|
||||||
|
../../src/PolarSSL++/EntropyContext.h
|
||||||
|
../../src/PolarSSL++/PublicKey.h
|
||||||
|
../../src/PolarSSL++/RsaPrivateKey.h
|
||||||
)
|
)
|
||||||
set(SHARED_OSS_SRC
|
set(SHARED_OSS_SRC
|
||||||
../../src/OSSupport/CriticalSection.cpp
|
../../src/OSSupport/CriticalSection.cpp
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "Connection.h"
|
#include "Connection.h"
|
||||||
#include "Server.h"
|
#include "Server.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include "PolarSSL++/PublicKey.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <direct.h> // For _mkdir()
|
#include <direct.h> // For _mkdir()
|
||||||
@ -471,7 +472,7 @@ bool cConnection::SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
|
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer)
|
||||||
{
|
{
|
||||||
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
|
DataLog(a_Data, a_Size, "Encrypting %d bytes to %s", a_Size, a_Peer);
|
||||||
const Byte * Data = (const Byte *)a_Data;
|
const Byte * Data = (const Byte *)a_Data;
|
||||||
@ -495,7 +496,7 @@ bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryp
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
|
bool cConnection::SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer)
|
||||||
{
|
{
|
||||||
AString All;
|
AString All;
|
||||||
a_Data.ReadAll(All);
|
a_Data.ReadAll(All);
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
|
|
||||||
#include "ByteBuffer.h"
|
#include "ByteBuffer.h"
|
||||||
#include "OSSupport/Timer.h"
|
#include "OSSupport/Timer.h"
|
||||||
|
#include "PolarSSL++/AesCfb128Decryptor.h"
|
||||||
|
#include "PolarSSL++/AesCfb128Encryptor.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -66,8 +68,8 @@ protected:
|
|||||||
cByteBuffer m_ClientBuffer;
|
cByteBuffer m_ClientBuffer;
|
||||||
cByteBuffer m_ServerBuffer;
|
cByteBuffer m_ServerBuffer;
|
||||||
|
|
||||||
cAESCFBDecryptor m_ServerDecryptor;
|
cAesCfb128Decryptor m_ServerDecryptor;
|
||||||
cAESCFBEncryptor m_ServerEncryptor;
|
cAesCfb128Encryptor m_ServerEncryptor;
|
||||||
|
|
||||||
AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
|
AString m_ServerEncryptionBuffer; // Buffer for the data to be sent to the server once encryption is established
|
||||||
|
|
||||||
@ -109,10 +111,10 @@ protected:
|
|||||||
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
|
bool SendData(SOCKET a_Socket, cByteBuffer & a_Data, const char * a_Peer);
|
||||||
|
|
||||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
|
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, const char * a_Data, size_t a_Size, const char * a_Peer);
|
||||||
|
|
||||||
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
/// Sends data to the specfied socket, after encrypting it using a_Encryptor. If sending fails, prints a fail message using a_Peer and returns false
|
||||||
bool SendEncryptedData(SOCKET a_Socket, cAESCFBEncryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
|
bool SendEncryptedData(SOCKET a_Socket, cAesCfb128Encryptor & a_Encryptor, cByteBuffer & a_Data, const char * a_Peer);
|
||||||
|
|
||||||
/// Decodes packets coming from the client, sends appropriate counterparts to the server; returns false if the connection is to be dropped
|
/// Decodes packets coming from the client, sends appropriate counterparts to the server; returns false if the connection is to be dropped
|
||||||
bool DecodeClientsPackets(const char * a_Data, int a_Size);
|
bool DecodeClientsPackets(const char * a_Data, int a_Size);
|
||||||
|
@ -216,6 +216,20 @@ typedef unsigned char Byte;
|
|||||||
// Pretty much the same as ASSERT() but stays in Release builds
|
// Pretty much the same as ASSERT() but stays in Release builds
|
||||||
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
|
#define VERIFY( x ) ( !!(x) || ( LOGERROR("Verification failed: %s, file %s, line %i", #x, __FILE__, __LINE__ ), exit(1), 0 ) )
|
||||||
|
|
||||||
|
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
|
||||||
|
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
|
||||||
|
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||||
|
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
|
||||||
|
#define SharedPtr std::tr1::shared_ptr
|
||||||
|
#elif (__cplusplus >= 201103L)
|
||||||
|
// C++11 has std::shared_ptr in <memory>, included earlier
|
||||||
|
#define SharedPtr std::shared_ptr
|
||||||
|
#else
|
||||||
|
// C++03 has std::tr1::shared_ptr in <tr1/memory>
|
||||||
|
#include <tr1/memory>
|
||||||
|
#define SharedPtr std::tr1::shared_ptr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -232,12 +246,6 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "../../src/Crypto.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define LOGERROR printf
|
#define LOGERROR printf
|
||||||
#define LOGINFO printf
|
#define LOGINFO printf
|
||||||
#define LOGWARNING printf
|
#define LOGWARNING printf
|
||||||
|
@ -20,7 +20,7 @@ You need to set the server *not* to verify usernames ("online-mode=false" in ser
|
|||||||
|
|
||||||
|
|
||||||
ProtoProxy is not much dependent on the protocol - it will work with unknown packets, it just won't parse them into human-readable format.
|
ProtoProxy is not much dependent on the protocol - it will work with unknown packets, it just won't parse them into human-readable format.
|
||||||
The latest protocol which has been tested is 1.6.1 (#73).
|
The latest protocol which has been tested is 1.7.9 (#5).
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "PolarSSL++/RsaPrivateKey.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -17,7 +19,7 @@
|
|||||||
class cServer
|
class cServer
|
||||||
{
|
{
|
||||||
SOCKET m_ListenSocket;
|
SOCKET m_ListenSocket;
|
||||||
cRSAPrivateKey m_PrivateKey;
|
cRsaPrivateKey m_PrivateKey;
|
||||||
AString m_PublicKeyDER;
|
AString m_PublicKeyDER;
|
||||||
short m_ConnectPort;
|
short m_ConnectPort;
|
||||||
|
|
||||||
@ -27,7 +29,7 @@ public:
|
|||||||
int Init(short a_ListenPort, short a_ConnectPort);
|
int Init(short a_ListenPort, short a_ConnectPort);
|
||||||
void Run(void);
|
void Run(void);
|
||||||
|
|
||||||
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||||
const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; }
|
const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; }
|
||||||
|
|
||||||
short GetConnectPort(void) const { return m_ConnectPort; }
|
short GetConnectPort(void) const { return m_ConnectPort; }
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit 2cb1a0c4009ecf368ecc74eb428394e10f9e6d00
|
Subproject commit 1ed82759c68f92c4acc7e3f33b850cf9f01c8aba
|
@ -42,7 +42,7 @@ bool cLuaChunkStay::AddChunks(int a_ChunkCoordTableStackPos)
|
|||||||
|
|
||||||
// Add each set of coords:
|
// Add each set of coords:
|
||||||
int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos);
|
int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos);
|
||||||
m_Chunks.reserve(NumChunks);
|
m_Chunks.reserve((size_t)NumChunks);
|
||||||
for (int idx = 1; idx <= NumChunks; idx++)
|
for (int idx = 1; idx <= NumChunks; idx++)
|
||||||
{
|
{
|
||||||
// Push the idx-th element of the array onto stack top, check that it's a table:
|
// Push the idx-th element of the array onto stack top, check that it's a table:
|
||||||
|
@ -4,12 +4,12 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
||||||
unsigned int GetTime()
|
inline unsigned int GetTime()
|
||||||
{
|
{
|
||||||
return (unsigned int)time(0);
|
return (unsigned int)time(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetChar( std::string & a_Str, unsigned int a_Idx )
|
inline std::string GetChar( std::string & a_Str, unsigned int a_Idx )
|
||||||
{
|
{
|
||||||
return std::string(1, a_Str[ a_Idx ]);
|
return std::string(1, a_Str[ a_Idx ]);
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
/****************************
|
/****************************
|
||||||
* Better error reporting for Lua
|
* Better error reporting for Lua
|
||||||
**/
|
**/
|
||||||
int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError)
|
static int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaError)
|
||||||
{
|
{
|
||||||
// Retrieve current function name
|
// Retrieve current function name
|
||||||
lua_Debug entry;
|
lua_Debug entry;
|
||||||
@ -57,7 +57,7 @@ int tolua_do_error(lua_State* L, const char * a_pMsg, tolua_Error * a_pToLuaErro
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int lua_do_error(lua_State* L, const char * a_pFormat, ...)
|
static int lua_do_error(lua_State* L, const char * a_pFormat, ...)
|
||||||
{
|
{
|
||||||
// Retrieve current function name
|
// Retrieve current function name
|
||||||
lua_Debug entry;
|
lua_Debug entry;
|
||||||
@ -235,7 +235,7 @@ static int tolua_Base64Decode(lua_State * tolua_S)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
cPluginLua * GetLuaPlugin(lua_State * L)
|
static cPluginLua * GetLuaPlugin(lua_State * L)
|
||||||
{
|
{
|
||||||
// Get the plugin identification out of LuaState:
|
// Get the plugin identification out of LuaState:
|
||||||
lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME);
|
lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME);
|
||||||
@ -1750,7 +1750,6 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
|
|
||||||
|
|
||||||
// Read the params:
|
// Read the params:
|
||||||
cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL);
|
cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL);
|
||||||
@ -1760,8 +1759,12 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
|
|||||||
L.LogStackTrace();
|
L.LogStackTrace();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
|
||||||
|
|
||||||
if (!ChunkStay->AddChunks(2))
|
if (!ChunkStay->AddChunks(2))
|
||||||
{
|
{
|
||||||
|
delete ChunkStay;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1779,7 +1782,7 @@ static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
|
|||||||
|
|
||||||
const cPlayer::GroupList & AllGroups = self->GetGroups();
|
const cPlayer::GroupList & AllGroups = self->GetGroups();
|
||||||
|
|
||||||
lua_createtable(tolua_S, AllGroups.size(), 0);
|
lua_createtable(tolua_S, (int)AllGroups.size(), 0);
|
||||||
int newTable = lua_gettop(tolua_S);
|
int newTable = lua_gettop(tolua_S);
|
||||||
int index = 1;
|
int index = 1;
|
||||||
cPlayer::GroupList::const_iterator iter = AllGroups.begin();
|
cPlayer::GroupList::const_iterator iter = AllGroups.begin();
|
||||||
@ -1804,14 +1807,14 @@ static int tolua_cPlayer_GetResolvedPermissions(lua_State* tolua_S)
|
|||||||
|
|
||||||
cPlayer::StringList AllPermissions = self->GetResolvedPermissions();
|
cPlayer::StringList AllPermissions = self->GetResolvedPermissions();
|
||||||
|
|
||||||
lua_createtable(tolua_S, AllPermissions.size(), 0);
|
lua_createtable(tolua_S, (int)AllPermissions.size(), 0);
|
||||||
int newTable = lua_gettop(tolua_S);
|
int newTable = lua_gettop(tolua_S);
|
||||||
int index = 1;
|
int index = 1;
|
||||||
cPlayer::StringList::iterator iter = AllPermissions.begin();
|
cPlayer::StringList::iterator iter = AllPermissions.begin();
|
||||||
while (iter != AllPermissions.end())
|
while (iter != AllPermissions.end())
|
||||||
{
|
{
|
||||||
std::string & Permission = *iter;
|
std::string & Permission = *iter;
|
||||||
tolua_pushstring( tolua_S, Permission.c_str() );
|
lua_pushlstring(tolua_S, Permission.c_str(), Permission.length());
|
||||||
lua_rawseti(tolua_S, newTable, index);
|
lua_rawseti(tolua_S, newTable, index);
|
||||||
++iter;
|
++iter;
|
||||||
++index;
|
++index;
|
||||||
@ -2077,7 +2080,7 @@ static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
|
|||||||
|
|
||||||
const cWebAdmin::PluginList & AllPlugins = self->GetPlugins();
|
const cWebAdmin::PluginList & AllPlugins = self->GetPlugins();
|
||||||
|
|
||||||
lua_createtable(tolua_S, AllPlugins.size(), 0);
|
lua_createtable(tolua_S, (int)AllPlugins.size(), 0);
|
||||||
int newTable = lua_gettop(tolua_S);
|
int newTable = lua_gettop(tolua_S);
|
||||||
int index = 1;
|
int index = 1;
|
||||||
cWebAdmin::PluginList::const_iterator iter = AllPlugins.begin();
|
cWebAdmin::PluginList::const_iterator iter = AllPlugins.begin();
|
||||||
|
@ -56,7 +56,7 @@ public:
|
|||||||
virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0;
|
virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) = 0;
|
||||||
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) = 0;
|
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) = 0;
|
||||||
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
|
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) = 0;
|
||||||
virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) = 0;
|
virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) = 0;
|
||||||
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0;
|
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) = 0;
|
||||||
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
|
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
|
||||||
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
|
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) = 0;
|
||||||
|
@ -400,14 +400,14 @@ bool cPluginLua::OnCraftingNoRecipe(const cPlayer * a_Player, const cCraftingGri
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cPluginLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason)
|
bool cPluginLua::OnDisconnect(cClientHandle & a_Client, const AString & a_Reason)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CriticalSection);
|
cCSLock Lock(m_CriticalSection);
|
||||||
bool res = false;
|
bool res = false;
|
||||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
|
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
|
||||||
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
|
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
m_LuaState.Call((int)(**itr), a_Player, a_Reason, cLuaState::Return, res);
|
m_LuaState.Call((int)(**itr), &a_Client, a_Reason, cLuaState::Return, res);
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
@ -1042,7 +1042,7 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
|
|||||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
|
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
|
||||||
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
|
for (cLuaRefs::iterator itr = Refs.begin(), end = Refs.end(); itr != end; ++itr)
|
||||||
{
|
{
|
||||||
m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message);
|
m_LuaState.Call((int)(**itr), &a_Client, a_Channel, a_Message, cLuaState::Return, res);
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -79,7 +79,7 @@ public:
|
|||||||
virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override;
|
virtual bool OnChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ) override;
|
||||||
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) override;
|
virtual bool OnCollectingPickup (cPlayer * a_Player, cPickup * a_Pickup) override;
|
||||||
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
|
virtual bool OnCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe) override;
|
||||||
virtual bool OnDisconnect (cPlayer * a_Player, const AString & a_Reason) override;
|
virtual bool OnDisconnect (cClientHandle & a_Client, const AString & a_Reason) override;
|
||||||
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override;
|
virtual bool OnExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split) override;
|
||||||
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
|
virtual bool OnExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
|
||||||
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
|
virtual bool OnExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData) override;
|
||||||
|
@ -442,7 +442,7 @@ bool cPluginManager::CallHookCraftingNoRecipe(const cPlayer * a_Player, const cC
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Reason)
|
bool cPluginManager::CallHookDisconnect(cClientHandle & a_Client, const AString & a_Reason)
|
||||||
{
|
{
|
||||||
HookMap::iterator Plugins = m_Hooks.find(HOOK_DISCONNECT);
|
HookMap::iterator Plugins = m_Hooks.find(HOOK_DISCONNECT);
|
||||||
if (Plugins == m_Hooks.end())
|
if (Plugins == m_Hooks.end())
|
||||||
@ -451,7 +451,7 @@ bool cPluginManager::CallHookDisconnect(cPlayer * a_Player, const AString & a_Re
|
|||||||
}
|
}
|
||||||
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
|
for (PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr)
|
||||||
{
|
{
|
||||||
if ((*itr)->OnDisconnect(a_Player, a_Reason))
|
if ((*itr)->OnDisconnect(a_Client, a_Reason))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -172,7 +172,7 @@ public: // tolua_export
|
|||||||
bool CallHookChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ);
|
bool CallHookChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ);
|
||||||
bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup);
|
bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup);
|
||||||
bool CallHookCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
|
bool CallHookCraftingNoRecipe (const cPlayer * a_Player, const cCraftingGrid * a_Grid, cCraftingRecipe * a_Recipe);
|
||||||
bool CallHookDisconnect (cPlayer * a_Player, const AString & a_Reason);
|
bool CallHookDisconnect (cClientHandle & a_Client, const AString & a_Reason);
|
||||||
bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd
|
bool CallHookExecuteCommand (cPlayer * a_Player, const AStringVector & a_Split); // If a_Player == NULL, it is a console cmd
|
||||||
bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
|
bool CallHookExploded (cWorld & a_World, double a_ExplosionSize, bool a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
|
||||||
bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
|
bool CallHookExploding (cWorld & a_World, double & a_ExplosionSize, bool & a_CanCauseFire, double a_X, double a_Y, double a_Z, eExplosionSource a_Source, void * a_SourceData);
|
||||||
|
@ -7,29 +7,13 @@
|
|||||||
#include "BiomeDef.h"
|
#include "BiomeDef.h"
|
||||||
|
|
||||||
|
|
||||||
EMCSBiome StringToBiome(const AString & a_BiomeString)
|
|
||||||
{
|
|
||||||
// If it is a number, return it:
|
|
||||||
int res = atoi(a_BiomeString.c_str());
|
|
||||||
if ((res != 0) || (a_BiomeString.compare("0") == 0))
|
|
||||||
{
|
|
||||||
if ((res >= biFirstBiome) && (res < biNumBiomes))
|
|
||||||
{
|
|
||||||
return (EMCSBiome)res;
|
|
||||||
}
|
|
||||||
else if ((res >= biFirstVariantBiome) && (res < biNumVariantBiomes))
|
|
||||||
{
|
|
||||||
return (EMCSBiome)res;
|
|
||||||
}
|
|
||||||
// It was an invalid number
|
|
||||||
return biInvalidBiome;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert using the built-in map:
|
|
||||||
|
// The "map" used for biome <-> string conversions:
|
||||||
static struct {
|
static struct {
|
||||||
EMCSBiome m_Biome;
|
EMCSBiome m_Biome;
|
||||||
const char * m_String;
|
const char * m_String;
|
||||||
} BiomeMap[] =
|
} g_BiomeMap[] =
|
||||||
{
|
{
|
||||||
{biOcean, "Ocean"} ,
|
{biOcean, "Ocean"} ,
|
||||||
{biPlains, "Plains"},
|
{biPlains, "Plains"},
|
||||||
@ -101,11 +85,33 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
|
|||||||
{biMesaPlateauM, "MesaPlateauM"},
|
{biMesaPlateauM, "MesaPlateauM"},
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
EMCSBiome StringToBiome(const AString & a_BiomeString)
|
||||||
{
|
{
|
||||||
if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0)
|
// If it is a number, return it:
|
||||||
|
int res = atoi(a_BiomeString.c_str());
|
||||||
|
if ((res != 0) || (a_BiomeString.compare("0") == 0))
|
||||||
{
|
{
|
||||||
return BiomeMap[i].m_Biome;
|
if ((res >= biFirstBiome) && (res < biNumBiomes))
|
||||||
|
{
|
||||||
|
return (EMCSBiome)res;
|
||||||
|
}
|
||||||
|
else if ((res >= biFirstVariantBiome) && (res < biNumVariantBiomes))
|
||||||
|
{
|
||||||
|
return (EMCSBiome)res;
|
||||||
|
}
|
||||||
|
// It was an invalid number
|
||||||
|
return biInvalidBiome;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++)
|
||||||
|
{
|
||||||
|
if (NoCaseCompare(g_BiomeMap[i].m_String, a_BiomeString) == 0)
|
||||||
|
{
|
||||||
|
return g_BiomeMap[i].m_Biome;
|
||||||
}
|
}
|
||||||
} // for i - BiomeMap[]
|
} // for i - BiomeMap[]
|
||||||
return biInvalidBiome;
|
return biInvalidBiome;
|
||||||
@ -115,6 +121,22 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
AString BiomeToString(int a_Biome)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < ARRAYCOUNT(g_BiomeMap); i++)
|
||||||
|
{
|
||||||
|
if (g_BiomeMap[i].m_Biome == a_Biome)
|
||||||
|
{
|
||||||
|
return g_BiomeMap[i].m_String;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool IsBiomeNoDownfall(EMCSBiome a_Biome)
|
bool IsBiomeNoDownfall(EMCSBiome a_Biome)
|
||||||
{
|
{
|
||||||
switch (a_Biome)
|
switch (a_Biome)
|
||||||
|
@ -104,10 +104,13 @@ enum EMCSBiome
|
|||||||
biMaxVariantBiome = biNumVariantBiomes - 1, // The maximum biome value
|
biMaxVariantBiome = biNumVariantBiomes - 1, // The maximum biome value
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure.
|
/** Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns biInvalidBiome on failure. */
|
||||||
extern EMCSBiome StringToBiome(const AString & a_BiomeString);
|
extern EMCSBiome StringToBiome(const AString & a_BiomeString);
|
||||||
|
|
||||||
/// Returns true if the biome has no downfall - deserts and savannas
|
/** Translates biome enum into biome string. Returns empty string on failure (unknown biome). */
|
||||||
|
extern AString BiomeToString(int a_Biome);
|
||||||
|
|
||||||
|
/** Returns true if the biome has no downfall - deserts and savannas */
|
||||||
extern bool IsBiomeNoDownfall(EMCSBiome a_Biome);
|
extern bool IsBiomeNoDownfall(EMCSBiome a_Biome);
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,17 +14,29 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Disable MSVC warnings: "conditional expression is constant"
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4127)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
typedef void (CombinatorFunc)(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta);
|
||||||
|
|
||||||
// This wild construct allows us to pass a function argument and still have it inlined by the compiler :)
|
// This wild construct allows us to pass a function argument and still have it inlined by the compiler :)
|
||||||
/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function
|
/// Merges two blocktypes and blockmetas of the specified sizes and offsets using the specified combinator function
|
||||||
template<typename Combinator> void InternalMergeBlocks(
|
template<bool MetasValid, CombinatorFunc Combinator>
|
||||||
|
void InternalMergeBlocks(
|
||||||
BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes,
|
BLOCKTYPE * a_DstTypes, const BLOCKTYPE * a_SrcTypes,
|
||||||
NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas,
|
NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas,
|
||||||
int a_SizeX, int a_SizeY, int a_SizeZ,
|
int a_SizeX, int a_SizeY, int a_SizeZ,
|
||||||
int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ,
|
int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ,
|
||||||
int a_DstOffX, int a_DstOffY, int a_DstOffZ,
|
int a_DstOffX, int a_DstOffY, int a_DstOffZ,
|
||||||
int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ,
|
int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ,
|
||||||
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ,
|
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ
|
||||||
Combinator a_Combinator
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
UNUSED(a_SrcSizeY);
|
UNUSED(a_SrcSizeY);
|
||||||
@ -41,7 +53,15 @@ template<typename Combinator> void InternalMergeBlocks(
|
|||||||
int DstIdx = DstBaseZ + a_DstOffX;
|
int DstIdx = DstBaseZ + a_DstOffX;
|
||||||
for (int x = 0; x < a_SizeX; x++)
|
for (int x = 0; x < a_SizeX; x++)
|
||||||
{
|
{
|
||||||
a_Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
|
if (MetasValid)
|
||||||
|
{
|
||||||
|
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], a_DstMetas[DstIdx], a_SrcMetas[SrcIdx]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BLOCKTYPE FakeDestMeta = 0;
|
||||||
|
Combinator(a_DstTypes[DstIdx], a_SrcTypes[SrcIdx], FakeDestMeta, (NIBBLETYPE)0);
|
||||||
|
}
|
||||||
++DstIdx;
|
++DstIdx;
|
||||||
++SrcIdx;
|
++SrcIdx;
|
||||||
} // for x
|
} // for x
|
||||||
@ -54,24 +74,32 @@ template<typename Combinator> void InternalMergeBlocks(
|
|||||||
|
|
||||||
|
|
||||||
/// Combinator used for cBlockArea::msOverwrite merging
|
/// Combinator used for cBlockArea::msOverwrite merging
|
||||||
static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
template<bool MetaValid>
|
||||||
|
void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||||
{
|
{
|
||||||
a_DstType = a_SrcType;
|
a_DstType = a_SrcType;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = a_SrcMeta;
|
a_DstMeta = a_SrcMeta;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// Combinator used for cBlockArea::msFillAir merging
|
/// Combinator used for cBlockArea::msFillAir merging
|
||||||
static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
template<bool MetaValid>
|
||||||
|
void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||||
{
|
{
|
||||||
if (a_DstType == E_BLOCK_AIR)
|
if (a_DstType == E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
a_DstType = a_SrcType;
|
a_DstType = a_SrcType;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = a_SrcMeta;
|
a_DstMeta = a_SrcMeta;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// "else" is the default, already in place
|
// "else" is the default, already in place
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,13 +108,17 @@ static inline void MergeCombinatorFillAir(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src
|
|||||||
|
|
||||||
|
|
||||||
/// Combinator used for cBlockArea::msImprint merging
|
/// Combinator used for cBlockArea::msImprint merging
|
||||||
static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
template<bool MetaValid>
|
||||||
|
void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||||
{
|
{
|
||||||
if (a_SrcType != E_BLOCK_AIR)
|
if (a_SrcType != E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
a_DstType = a_SrcType;
|
a_DstType = a_SrcType;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = a_SrcMeta;
|
a_DstMeta = a_SrcMeta;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// "else" is the default, already in place
|
// "else" is the default, already in place
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +127,8 @@ static inline void MergeCombinatorImprint(BLOCKTYPE & a_DstType, BLOCKTYPE a_Src
|
|||||||
|
|
||||||
|
|
||||||
/// Combinator used for cBlockArea::msLake merging
|
/// Combinator used for cBlockArea::msLake merging
|
||||||
static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
template<bool MetaValid>
|
||||||
|
void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||||
{
|
{
|
||||||
// Sponge is the NOP block
|
// Sponge is the NOP block
|
||||||
if (a_SrcType == E_BLOCK_SPONGE)
|
if (a_SrcType == E_BLOCK_SPONGE)
|
||||||
@ -107,7 +140,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
|||||||
if (a_SrcType == E_BLOCK_AIR)
|
if (a_SrcType == E_BLOCK_AIR)
|
||||||
{
|
{
|
||||||
a_DstType = E_BLOCK_AIR;
|
a_DstType = E_BLOCK_AIR;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = 0;
|
a_DstMeta = 0;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +168,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
|||||||
case E_BLOCK_STATIONARY_LAVA:
|
case E_BLOCK_STATIONARY_LAVA:
|
||||||
{
|
{
|
||||||
a_DstType = a_SrcType;
|
a_DstType = a_SrcType;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = a_SrcMeta;
|
a_DstMeta = a_SrcMeta;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -146,7 +185,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
|||||||
case E_BLOCK_MYCELIUM:
|
case E_BLOCK_MYCELIUM:
|
||||||
{
|
{
|
||||||
a_DstType = E_BLOCK_STONE;
|
a_DstType = E_BLOCK_STONE;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = 0;
|
a_DstMeta = 0;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,49 +201,69 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
|||||||
|
|
||||||
|
|
||||||
/** Combinator used for cBlockArea::msSpongePrint merging */
|
/** Combinator used for cBlockArea::msSpongePrint merging */
|
||||||
static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
template<bool MetaValid>
|
||||||
|
void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||||
{
|
{
|
||||||
// Sponge overwrites nothing, everything else overwrites anything
|
// Sponge overwrites nothing, everything else overwrites anything
|
||||||
if (a_SrcType != E_BLOCK_SPONGE)
|
if (a_SrcType != E_BLOCK_SPONGE)
|
||||||
{
|
{
|
||||||
a_DstType = a_SrcType;
|
a_DstType = a_SrcType;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = a_SrcMeta;
|
a_DstMeta = a_SrcMeta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Combinator used for cBlockArea::msDifference merging */
|
/** Combinator used for cBlockArea::msDifference merging */
|
||||||
static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
template<bool MetaValid>
|
||||||
|
void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||||
{
|
{
|
||||||
if ((a_DstType == a_SrcType) && (a_DstMeta == a_SrcMeta))
|
if ((a_DstType == a_SrcType) && (!MetaValid || (a_DstMeta == a_SrcMeta)))
|
||||||
{
|
{
|
||||||
a_DstType = E_BLOCK_AIR;
|
a_DstType = E_BLOCK_AIR;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = 0;
|
a_DstMeta = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
a_DstType = a_SrcType;
|
a_DstType = a_SrcType;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = a_SrcMeta;
|
a_DstMeta = a_SrcMeta;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Combinator used for cBlockArea::msMask merging */
|
/** Combinator used for cBlockArea::msMask merging */
|
||||||
static inline void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
template<bool MetaValid>
|
||||||
|
void MergeCombinatorMask(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcType, NIBBLETYPE & a_DstMeta, NIBBLETYPE a_SrcMeta)
|
||||||
{
|
{
|
||||||
// If the blocks are the same, keep the dest; otherwise replace with air
|
// If the blocks are the same, keep the dest; otherwise replace with air
|
||||||
if ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta))
|
if ((a_SrcType != a_DstType) || !MetaValid || (a_SrcMeta != a_DstMeta))
|
||||||
{
|
{
|
||||||
a_DstType = E_BLOCK_AIR;
|
a_DstType = E_BLOCK_AIR;
|
||||||
|
if (MetaValid)
|
||||||
|
{
|
||||||
a_DstMeta = 0;
|
a_DstMeta = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-enable previously disabled MSVC warnings
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -484,7 +546,7 @@ void cBlockArea::CopyTo(cBlockArea & a_Into) const
|
|||||||
a_Into.Clear();
|
a_Into.Clear();
|
||||||
a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
|
a_Into.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
|
||||||
a_Into.m_Origin = m_Origin;
|
a_Into.m_Origin = m_Origin;
|
||||||
int BlockCount = GetBlockCount();
|
size_t BlockCount = GetBlockCount();
|
||||||
if (HasBlockTypes())
|
if (HasBlockTypes())
|
||||||
{
|
{
|
||||||
memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE));
|
memcpy(a_Into.m_BlockTypes, m_BlockTypes, BlockCount * sizeof(BLOCKTYPE));
|
||||||
@ -532,7 +594,7 @@ void cBlockArea::DumpToRawFile(const AString & a_FileName)
|
|||||||
f.Write(&SizeZ, 4);
|
f.Write(&SizeZ, 4);
|
||||||
unsigned char DataTypes = (unsigned char)GetDataTypes();
|
unsigned char DataTypes = (unsigned char)GetDataTypes();
|
||||||
f.Write(&DataTypes, 1);
|
f.Write(&DataTypes, 1);
|
||||||
int NumBlocks = GetBlockCount();
|
size_t NumBlocks = GetBlockCount();
|
||||||
if (HasBlockTypes())
|
if (HasBlockTypes())
|
||||||
{
|
{
|
||||||
f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE));
|
f.Write(m_BlockTypes, NumBlocks * sizeof(BLOCKTYPE));
|
||||||
@ -637,155 +699,19 @@ void cBlockArea::Expand(int a_SubMinX, int a_AddMaxX, int a_SubMinY, int a_AddMa
|
|||||||
|
|
||||||
void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
|
void cBlockArea::Merge(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy)
|
||||||
{
|
{
|
||||||
// Block types are compulsory, block metas are voluntary
|
|
||||||
if (!HasBlockTypes() || !a_Src.HasBlockTypes())
|
|
||||||
{
|
|
||||||
LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dst is *this, Src is a_Src
|
|
||||||
int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
|
|
||||||
int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
|
|
||||||
int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
|
|
||||||
|
|
||||||
int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
|
|
||||||
int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
|
|
||||||
int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
|
|
||||||
|
|
||||||
int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
|
|
||||||
int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
|
|
||||||
int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
|
|
||||||
|
|
||||||
const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas();
|
const NIBBLETYPE * SrcMetas = a_Src.GetBlockMetas();
|
||||||
NIBBLETYPE * DstMetas = m_BlockMetas;
|
NIBBLETYPE * DstMetas = m_BlockMetas;
|
||||||
|
|
||||||
bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL));
|
bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL));
|
||||||
|
|
||||||
if (IsDummyMetas)
|
if (IsDummyMetas)
|
||||||
{
|
{
|
||||||
SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()];
|
MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
|
||||||
DstMetas = new NIBBLETYPE[GetBlockCount()];
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
switch (a_Strategy)
|
|
||||||
{
|
{
|
||||||
case msOverwrite:
|
MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
|
||||||
{
|
|
||||||
InternalMergeBlocks(
|
|
||||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
|
||||||
DstMetas, SrcMetas,
|
|
||||||
SizeX, SizeY, SizeZ,
|
|
||||||
SrcOffX, SrcOffY, SrcOffZ,
|
|
||||||
DstOffX, DstOffY, DstOffZ,
|
|
||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
|
||||||
m_Size.x, m_Size.y, m_Size.z,
|
|
||||||
MergeCombinatorOverwrite
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} // case msOverwrite
|
|
||||||
|
|
||||||
case msFillAir:
|
|
||||||
{
|
|
||||||
InternalMergeBlocks(
|
|
||||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
|
||||||
DstMetas, SrcMetas,
|
|
||||||
SizeX, SizeY, SizeZ,
|
|
||||||
SrcOffX, SrcOffY, SrcOffZ,
|
|
||||||
DstOffX, DstOffY, DstOffZ,
|
|
||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
|
||||||
m_Size.x, m_Size.y, m_Size.z,
|
|
||||||
MergeCombinatorFillAir
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} // case msFillAir
|
|
||||||
|
|
||||||
case msImprint:
|
|
||||||
{
|
|
||||||
InternalMergeBlocks(
|
|
||||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
|
||||||
DstMetas, SrcMetas,
|
|
||||||
SizeX, SizeY, SizeZ,
|
|
||||||
SrcOffX, SrcOffY, SrcOffZ,
|
|
||||||
DstOffX, DstOffY, DstOffZ,
|
|
||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
|
||||||
m_Size.x, m_Size.y, m_Size.z,
|
|
||||||
MergeCombinatorImprint
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} // case msImprint
|
|
||||||
|
|
||||||
case msLake:
|
|
||||||
{
|
|
||||||
InternalMergeBlocks(
|
|
||||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
|
||||||
DstMetas, SrcMetas,
|
|
||||||
SizeX, SizeY, SizeZ,
|
|
||||||
SrcOffX, SrcOffY, SrcOffZ,
|
|
||||||
DstOffX, DstOffY, DstOffZ,
|
|
||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
|
||||||
m_Size.x, m_Size.y, m_Size.z,
|
|
||||||
MergeCombinatorLake
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} // case msLake
|
|
||||||
|
|
||||||
case msSpongePrint:
|
|
||||||
{
|
|
||||||
InternalMergeBlocks(
|
|
||||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
|
||||||
DstMetas, SrcMetas,
|
|
||||||
SizeX, SizeY, SizeZ,
|
|
||||||
SrcOffX, SrcOffY, SrcOffZ,
|
|
||||||
DstOffX, DstOffY, DstOffZ,
|
|
||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
|
||||||
m_Size.x, m_Size.y, m_Size.z,
|
|
||||||
MergeCombinatorSpongePrint
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} // case msSpongePrint
|
|
||||||
|
|
||||||
case msDifference:
|
|
||||||
{
|
|
||||||
InternalMergeBlocks(
|
|
||||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
|
||||||
DstMetas, SrcMetas,
|
|
||||||
SizeX, SizeY, SizeZ,
|
|
||||||
SrcOffX, SrcOffY, SrcOffZ,
|
|
||||||
DstOffX, DstOffY, DstOffZ,
|
|
||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
|
||||||
m_Size.x, m_Size.y, m_Size.z,
|
|
||||||
MergeCombinatorDifference
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} // case msDifference
|
|
||||||
|
|
||||||
case msMask:
|
|
||||||
{
|
|
||||||
InternalMergeBlocks(
|
|
||||||
m_BlockTypes, a_Src.GetBlockTypes(),
|
|
||||||
DstMetas, SrcMetas,
|
|
||||||
SizeX, SizeY, SizeZ,
|
|
||||||
SrcOffX, SrcOffY, SrcOffZ,
|
|
||||||
DstOffX, DstOffY, DstOffZ,
|
|
||||||
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
|
||||||
m_Size.x, m_Size.y, m_Size.z,
|
|
||||||
MergeCombinatorMask
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
} // case msMask
|
|
||||||
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
|
|
||||||
ASSERT(!"Unknown block area merge strategy");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // switch (a_Strategy)
|
|
||||||
|
|
||||||
if (IsDummyMetas)
|
|
||||||
{
|
|
||||||
delete[] SrcMetas;
|
|
||||||
delete[] DstMetas;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2079,7 +2005,7 @@ void cBlockArea::ExpandBlockTypes(int a_SubMinX, int a_AddMaxX, int a_SubMinY, i
|
|||||||
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
|
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
|
||||||
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
||||||
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
|
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
|
||||||
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
|
size_t BlockCount = (size_t)(NewSizeX * NewSizeY * NewSizeZ);
|
||||||
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
|
BLOCKTYPE * NewBlockTypes = new BLOCKTYPE[BlockCount];
|
||||||
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
|
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
|
||||||
int OldIndex = 0;
|
int OldIndex = 0;
|
||||||
@ -2109,7 +2035,7 @@ void cBlockArea::ExpandNibbles(NIBBLEARRAY & a_Array, int a_SubMinX, int a_AddMa
|
|||||||
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
|
int NewSizeX = m_Size.x + a_SubMinX + a_AddMaxX;
|
||||||
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
int NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
||||||
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
|
int NewSizeZ = m_Size.z + a_SubMinZ + a_AddMaxZ;
|
||||||
int BlockCount = NewSizeX * NewSizeY * NewSizeZ;
|
size_t BlockCount = (size_t)(NewSizeX * NewSizeY * NewSizeZ);
|
||||||
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
|
NIBBLETYPE * NewNibbles = new NIBBLETYPE[BlockCount];
|
||||||
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
|
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
|
||||||
int OldIndex = 0;
|
int OldIndex = 0;
|
||||||
@ -2161,4 +2087,137 @@ void cBlockArea::RelSetData(
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template<bool MetasValid>
|
||||||
|
void cBlockArea::MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas)
|
||||||
|
{
|
||||||
|
// Block types are compulsory, block metas are voluntary
|
||||||
|
if (!HasBlockTypes() || !a_Src.HasBlockTypes())
|
||||||
|
{
|
||||||
|
LOGWARNING("%s: cannot merge because one of the areas doesn't have blocktypes.", __FUNCTION__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dst is *this, Src is a_Src
|
||||||
|
int SrcOffX = std::max(0, -a_RelX); // Offset in Src where to start reading
|
||||||
|
int DstOffX = std::max(0, a_RelX); // Offset in Dst where to start writing
|
||||||
|
int SizeX = std::min(a_Src.GetSizeX() - SrcOffX, GetSizeX() - DstOffX); // How many blocks to copy
|
||||||
|
|
||||||
|
int SrcOffY = std::max(0, -a_RelY); // Offset in Src where to start reading
|
||||||
|
int DstOffY = std::max(0, a_RelY); // Offset in Dst where to start writing
|
||||||
|
int SizeY = std::min(a_Src.GetSizeY() - SrcOffY, GetSizeY() - DstOffY); // How many blocks to copy
|
||||||
|
|
||||||
|
int SrcOffZ = std::max(0, -a_RelZ); // Offset in Src where to start reading
|
||||||
|
int DstOffZ = std::max(0, a_RelZ); // Offset in Dst where to start writing
|
||||||
|
int SizeZ = std::min(a_Src.GetSizeZ() - SrcOffZ, GetSizeZ() - DstOffZ); // How many blocks to copy
|
||||||
|
|
||||||
|
switch (a_Strategy)
|
||||||
|
{
|
||||||
|
case cBlockArea::msOverwrite:
|
||||||
|
{
|
||||||
|
InternalMergeBlocks<MetasValid, MergeCombinatorOverwrite<MetasValid> >(
|
||||||
|
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||||
|
DstMetas, SrcMetas,
|
||||||
|
SizeX, SizeY, SizeZ,
|
||||||
|
SrcOffX, SrcOffY, SrcOffZ,
|
||||||
|
DstOffX, DstOffY, DstOffZ,
|
||||||
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} // case msOverwrite
|
||||||
|
|
||||||
|
case cBlockArea::msFillAir:
|
||||||
|
{
|
||||||
|
InternalMergeBlocks<MetasValid, MergeCombinatorFillAir<MetasValid> >(
|
||||||
|
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||||
|
DstMetas, SrcMetas,
|
||||||
|
SizeX, SizeY, SizeZ,
|
||||||
|
SrcOffX, SrcOffY, SrcOffZ,
|
||||||
|
DstOffX, DstOffY, DstOffZ,
|
||||||
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} // case msFillAir
|
||||||
|
|
||||||
|
case cBlockArea::msImprint:
|
||||||
|
{
|
||||||
|
InternalMergeBlocks<MetasValid, MergeCombinatorImprint<MetasValid> >(
|
||||||
|
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||||
|
DstMetas, SrcMetas,
|
||||||
|
SizeX, SizeY, SizeZ,
|
||||||
|
SrcOffX, SrcOffY, SrcOffZ,
|
||||||
|
DstOffX, DstOffY, DstOffZ,
|
||||||
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} // case msImprint
|
||||||
|
|
||||||
|
case cBlockArea::msLake:
|
||||||
|
{
|
||||||
|
InternalMergeBlocks<MetasValid, MergeCombinatorLake<MetasValid> >(
|
||||||
|
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||||
|
DstMetas, SrcMetas,
|
||||||
|
SizeX, SizeY, SizeZ,
|
||||||
|
SrcOffX, SrcOffY, SrcOffZ,
|
||||||
|
DstOffX, DstOffY, DstOffZ,
|
||||||
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} // case msLake
|
||||||
|
|
||||||
|
case cBlockArea::msSpongePrint:
|
||||||
|
{
|
||||||
|
InternalMergeBlocks<MetasValid, MergeCombinatorSpongePrint<MetasValid> >(
|
||||||
|
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||||
|
DstMetas, SrcMetas,
|
||||||
|
SizeX, SizeY, SizeZ,
|
||||||
|
SrcOffX, SrcOffY, SrcOffZ,
|
||||||
|
DstOffX, DstOffY, DstOffZ,
|
||||||
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} // case msSpongePrint
|
||||||
|
|
||||||
|
case cBlockArea::msDifference:
|
||||||
|
{
|
||||||
|
InternalMergeBlocks<MetasValid, MergeCombinatorDifference<MetasValid> >(
|
||||||
|
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||||
|
DstMetas, SrcMetas,
|
||||||
|
SizeX, SizeY, SizeZ,
|
||||||
|
SrcOffX, SrcOffY, SrcOffZ,
|
||||||
|
DstOffX, DstOffY, DstOffZ,
|
||||||
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} // case msDifference
|
||||||
|
|
||||||
|
case cBlockArea::msMask:
|
||||||
|
{
|
||||||
|
InternalMergeBlocks<MetasValid, MergeCombinatorMask<MetasValid> >(
|
||||||
|
m_BlockTypes, a_Src.GetBlockTypes(),
|
||||||
|
DstMetas, SrcMetas,
|
||||||
|
SizeX, SizeY, SizeZ,
|
||||||
|
SrcOffX, SrcOffY, SrcOffZ,
|
||||||
|
DstOffX, DstOffY, DstOffZ,
|
||||||
|
a_Src.GetSizeX(), a_Src.GetSizeY(), a_Src.GetSizeZ(),
|
||||||
|
m_Size.x, m_Size.y, m_Size.z
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
} // case msMask
|
||||||
|
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
LOGWARNING("Unknown block area merge strategy: %d", a_Strategy);
|
||||||
|
ASSERT(!"Unknown block area merge strategy");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // switch (a_Strategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -294,7 +294,7 @@ public:
|
|||||||
NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block!
|
NIBBLETYPE * GetBlockMetas (void) const { return m_BlockMetas; } // NOTE: one byte per block!
|
||||||
NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block!
|
NIBBLETYPE * GetBlockLight (void) const { return m_BlockLight; } // NOTE: one byte per block!
|
||||||
NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block!
|
NIBBLETYPE * GetBlockSkyLight(void) const { return m_BlockSkyLight; } // NOTE: one byte per block!
|
||||||
int GetBlockCount(void) const { return m_Size.x * m_Size.y * m_Size.z; }
|
size_t GetBlockCount(void) const { return (size_t)(m_Size.x * m_Size.y * m_Size.z); }
|
||||||
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
|
int MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -363,6 +363,9 @@ protected:
|
|||||||
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
||||||
NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
|
NIBBLETYPE a_BlockLight, NIBBLETYPE a_BlockSkyLight
|
||||||
);
|
);
|
||||||
|
|
||||||
|
template<bool MetasValid>
|
||||||
|
void MergeByStrategy(const cBlockArea & a_Src, int a_RelX, int a_RelY, int a_RelZ, eMergeStrategy a_Strategy, const NIBBLETYPE * SrcMetas, NIBBLETYPE * DstMetas);
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
} ;
|
} ;
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
@ -21,7 +21,8 @@
|
|||||||
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) :
|
cCommandBlockEntity::cCommandBlockEntity(int a_X, int a_Y, int a_Z, cWorld * a_World) :
|
||||||
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World),
|
super(E_BLOCK_COMMAND_BLOCK, a_X, a_Y, a_Z, a_World),
|
||||||
m_ShouldExecute(false),
|
m_ShouldExecute(false),
|
||||||
m_IsPowered(false)
|
m_IsPowered(false),
|
||||||
|
m_Result(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
|
cMobHeadEntity::cMobHeadEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World) :
|
||||||
super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World),
|
super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World),
|
||||||
|
m_Type(SKULL_TYPE_SKELETON),
|
||||||
|
m_Rotation(SKULL_ROTATION_NORTH),
|
||||||
m_Owner("")
|
m_Owner("")
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
a_Item.m_ItemDamage = atoi(Split[1].c_str());
|
a_Item.m_ItemDamage = (short)atoi(Split[1].c_str());
|
||||||
if ((a_Item.m_ItemDamage == 0) && (Split[1] != "0"))
|
if ((a_Item.m_ItemDamage == 0) && (Split[1] != "0"))
|
||||||
{
|
{
|
||||||
// Parsing the number failed
|
// Parsing the number failed
|
||||||
|
@ -129,6 +129,7 @@ void cBlockInfo::Initialize(void)
|
|||||||
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
|
ms_Info[E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE].m_Transparent = true;
|
||||||
ms_Info[E_BLOCK_ICE ].m_Transparent = true;
|
ms_Info[E_BLOCK_ICE ].m_Transparent = true;
|
||||||
ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true;
|
ms_Info[E_BLOCK_IRON_DOOR ].m_Transparent = true;
|
||||||
|
ms_Info[E_BLOCK_LADDER ].m_Transparent = true;
|
||||||
ms_Info[E_BLOCK_LAVA ].m_Transparent = true;
|
ms_Info[E_BLOCK_LAVA ].m_Transparent = true;
|
||||||
ms_Info[E_BLOCK_LEAVES ].m_Transparent = true;
|
ms_Info[E_BLOCK_LEAVES ].m_Transparent = true;
|
||||||
ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
|
ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
|
||||||
|
@ -69,7 +69,6 @@ public:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int newY = Y + 1; newY < cChunkDef::Height; newY++)
|
for (int newY = Y + 1; newY < cChunkDef::Height; newY++)
|
||||||
{
|
{
|
||||||
BLOCKTYPE Block = a_ChunkInterface.GetBlock(X, newY, Z);
|
BLOCKTYPE Block = a_ChunkInterface.GetBlock(X, newY, Z);
|
||||||
@ -84,7 +83,7 @@ public:
|
|||||||
// This is because the frame is a solid obsidian pillar
|
// This is because the frame is a solid obsidian pillar
|
||||||
if ((MaxY != 0) && (newY == Y + 1))
|
if ((MaxY != 0) && (newY == Y + 1))
|
||||||
{
|
{
|
||||||
return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface);
|
return EvaluatePortalBorder(X, newY, Z, MaxY, a_ChunkInterface) ? -1 /* -1 = found a frame */ : 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -99,18 +98,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates if coords have a valid border on top, based on MaxY
|
/// Evaluates if coords have a valid border on top, based on MaxY
|
||||||
int EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
|
bool EvaluatePortalBorder(int X, int FoundObsidianY, int Z, int MaxY, cChunkInterface & a_ChunkInterface)
|
||||||
{
|
{
|
||||||
for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners
|
for (int checkBorder = FoundObsidianY + 1; checkBorder <= MaxY - 1; checkBorder++) // FoundObsidianY + 1: FoundObsidianY has already been checked in FindObsidianCeiling; MaxY - 1: portal doesn't need corners
|
||||||
{
|
{
|
||||||
if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN)
|
if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN)
|
||||||
{
|
{
|
||||||
// Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
|
// Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Everything was obsidian, found a border!
|
// Everything was obsidian, found a border!
|
||||||
return -1; // Return -1 for a frame border
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE)
|
/// Finds entire frame in any direction with the coordinates of a base block and fills hole with nether portal (START HERE)
|
||||||
@ -169,7 +168,7 @@ public:
|
|||||||
{
|
{
|
||||||
return false; // Not valid slice, no portal can be formed
|
return false; // Not valid slice, no portal can be formed
|
||||||
}
|
}
|
||||||
} XZP = X1 - 1; // Set boundary of frame interior, note that for some reason, the loop of X and the loop of Z go to different numbers, hence -1 here and -2 there
|
} XZP = X1 - 1; // Set boundary of frame interior
|
||||||
for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM)
|
for (; ((a_ChunkInterface.GetBlock(X2, Y, Z) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X2, Y + 1, Z) == E_BLOCK_OBSIDIAN)); X2--) // Go the other direction (XM)
|
||||||
{
|
{
|
||||||
int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY);
|
int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY);
|
||||||
@ -199,13 +198,13 @@ public:
|
|||||||
if ((Value == -1) || (ValueTwo == -1))
|
if ((Value == -1) || (ValueTwo == -1))
|
||||||
{
|
{
|
||||||
FoundFrameZP = true;
|
FoundFrameZP = true;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
else if ((Value != MaxY) && (ValueTwo != MaxY))
|
else if ((Value != MaxY) && (ValueTwo != MaxY))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} XZP = Z1 - 2;
|
} XZP = Z1 - 1;
|
||||||
for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--)
|
for (; ((a_ChunkInterface.GetBlock(X, Y, Z2) == E_BLOCK_OBSIDIAN) || (a_ChunkInterface.GetBlock(X, Y + 1, Z2) == E_BLOCK_OBSIDIAN)); Z2--)
|
||||||
{
|
{
|
||||||
int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY);
|
int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY);
|
||||||
@ -213,13 +212,13 @@ public:
|
|||||||
if ((Value == -1) || (ValueTwo == -1))
|
if ((Value == -1) || (ValueTwo == -1))
|
||||||
{
|
{
|
||||||
FoundFrameZM = true;
|
FoundFrameZM = true;
|
||||||
continue;
|
break;
|
||||||
}
|
}
|
||||||
else if ((Value != MaxY) && (ValueTwo != MaxY))
|
else if ((Value != MaxY) && (ValueTwo != MaxY))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} XZM = Z2 + 2;
|
} XZM = Z2 + 1;
|
||||||
return (FoundFrameZP && FoundFrameZM);
|
return (FoundFrameZP && FoundFrameZM);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -171,7 +171,7 @@ cByteBuffer::~cByteBuffer()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
bool cByteBuffer::Write(const void * a_Bytes, size_t a_Count)
|
||||||
{
|
{
|
||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
CheckValid();
|
CheckValid();
|
||||||
@ -187,13 +187,14 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
|||||||
}
|
}
|
||||||
ASSERT(m_BufferSize >= m_WritePos);
|
ASSERT(m_BufferSize >= m_WritePos);
|
||||||
size_t TillEnd = m_BufferSize - m_WritePos;
|
size_t TillEnd = m_BufferSize - m_WritePos;
|
||||||
|
const char * Bytes = (const char *)a_Bytes;
|
||||||
if (TillEnd <= a_Count)
|
if (TillEnd <= a_Count)
|
||||||
{
|
{
|
||||||
// Need to wrap around the ringbuffer end
|
// Need to wrap around the ringbuffer end
|
||||||
if (TillEnd > 0)
|
if (TillEnd > 0)
|
||||||
{
|
{
|
||||||
memcpy(m_Buffer + m_WritePos, a_Bytes, TillEnd);
|
memcpy(m_Buffer + m_WritePos, Bytes, TillEnd);
|
||||||
a_Bytes += TillEnd;
|
Bytes += TillEnd;
|
||||||
a_Count -= TillEnd;
|
a_Count -= TillEnd;
|
||||||
WrittenBytes = TillEnd;
|
WrittenBytes = TillEnd;
|
||||||
}
|
}
|
||||||
@ -203,7 +204,7 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
|||||||
// We're guaranteed that we'll fit in a single write op
|
// We're guaranteed that we'll fit in a single write op
|
||||||
if (a_Count > 0)
|
if (a_Count > 0)
|
||||||
{
|
{
|
||||||
memcpy(m_Buffer + m_WritePos, a_Bytes, a_Count);
|
memcpy(m_Buffer + m_WritePos, Bytes, a_Count);
|
||||||
m_WritePos += a_Count;
|
m_WritePos += a_Count;
|
||||||
WrittenBytes += a_Count;
|
WrittenBytes += a_Count;
|
||||||
}
|
}
|
||||||
@ -326,7 +327,7 @@ bool cByteBuffer::ReadBEShort(short & a_Value)
|
|||||||
CheckValid();
|
CheckValid();
|
||||||
NEEDBYTES(2);
|
NEEDBYTES(2);
|
||||||
ReadBuf(&a_Value, 2);
|
ReadBuf(&a_Value, 2);
|
||||||
a_Value = ntohs(a_Value);
|
a_Value = (short)ntohs((u_short)a_Value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -340,7 +341,7 @@ bool cByteBuffer::ReadBEInt(int & a_Value)
|
|||||||
CheckValid();
|
CheckValid();
|
||||||
NEEDBYTES(4);
|
NEEDBYTES(4);
|
||||||
ReadBuf(&a_Value, 4);
|
ReadBuf(&a_Value, 4);
|
||||||
a_Value = ntohl(a_Value);
|
a_Value = (int)ntohl((u_long)a_Value);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -419,7 +420,7 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value)
|
|||||||
ASSERT(!"Negative string length? Are you sure?");
|
ASSERT(!"Negative string length? Are you sure?");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return ReadUTF16String(a_Value, Length);
|
return ReadUTF16String(a_Value, (size_t)Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -437,7 +438,7 @@ bool cByteBuffer::ReadVarInt(UInt32 & a_Value)
|
|||||||
{
|
{
|
||||||
NEEDBYTES(1);
|
NEEDBYTES(1);
|
||||||
ReadBuf(&b, 1);
|
ReadBuf(&b, 1);
|
||||||
Value = Value | (((Int64)(b & 0x7f)) << Shift);
|
Value = Value | (((UInt32)(b & 0x7f)) << Shift);
|
||||||
Shift += 7;
|
Shift += 7;
|
||||||
} while ((b & 0x80) != 0);
|
} while ((b & 0x80) != 0);
|
||||||
a_Value = Value;
|
a_Value = Value;
|
||||||
@ -461,7 +462,7 @@ bool cByteBuffer::ReadVarUTF8String(AString & a_Value)
|
|||||||
{
|
{
|
||||||
LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024);
|
LOGWARNING("%s: String too large: %u (%u KiB)", __FUNCTION__, Size, Size / 1024);
|
||||||
}
|
}
|
||||||
return ReadString(a_Value, (int)Size);
|
return ReadString(a_Value, (size_t)Size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -516,7 +517,7 @@ bool cByteBuffer::WriteBEShort(short a_Value)
|
|||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
CheckValid();
|
CheckValid();
|
||||||
PUTBYTES(2);
|
PUTBYTES(2);
|
||||||
short Converted = htons(a_Value);
|
u_short Converted = htons((u_short)a_Value);
|
||||||
return WriteBuf(&Converted, 2);
|
return WriteBuf(&Converted, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,7 +530,7 @@ bool cByteBuffer::WriteBEInt(int a_Value)
|
|||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
CheckValid();
|
CheckValid();
|
||||||
PUTBYTES(4);
|
PUTBYTES(4);
|
||||||
int Converted = HostToNetwork4(&a_Value);
|
UInt32 Converted = HostToNetwork4(&a_Value);
|
||||||
return WriteBuf(&Converted, 4);
|
return WriteBuf(&Converted, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,7 +543,7 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value)
|
|||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
CheckValid();
|
CheckValid();
|
||||||
PUTBYTES(8);
|
PUTBYTES(8);
|
||||||
Int64 Converted = HostToNetwork8(&a_Value);
|
UInt64 Converted = HostToNetwork8(&a_Value);
|
||||||
return WriteBuf(&Converted, 8);
|
return WriteBuf(&Converted, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -555,7 +556,7 @@ bool cByteBuffer::WriteBEFloat(float a_Value)
|
|||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
CheckValid();
|
CheckValid();
|
||||||
PUTBYTES(4);
|
PUTBYTES(4);
|
||||||
int Converted = HostToNetwork4(&a_Value);
|
UInt32 Converted = HostToNetwork4(&a_Value);
|
||||||
return WriteBuf(&Converted, 4);
|
return WriteBuf(&Converted, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -568,7 +569,7 @@ bool cByteBuffer::WriteBEDouble(double a_Value)
|
|||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
CheckValid();
|
CheckValid();
|
||||||
PUTBYTES(8);
|
PUTBYTES(8);
|
||||||
Int64 Converted = HostToNetwork8(&a_Value);
|
UInt64 Converted = HostToNetwork8(&a_Value);
|
||||||
return WriteBuf(&Converted, 8);
|
return WriteBuf(&Converted, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -612,7 +613,7 @@ bool cByteBuffer::WriteVarInt(UInt32 a_Value)
|
|||||||
|
|
||||||
// A 32-bit integer can be encoded by at most 5 bytes:
|
// A 32-bit integer can be encoded by at most 5 bytes:
|
||||||
unsigned char b[5];
|
unsigned char b[5];
|
||||||
int idx = 0;
|
size_t idx = 0;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
|
b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
|
||||||
@ -631,7 +632,7 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
|
|||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
CheckValid();
|
CheckValid();
|
||||||
PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early.
|
PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early.
|
||||||
bool res = WriteVarInt(a_Value.size());
|
bool res = WriteVarInt((UInt32)(a_Value.size()));
|
||||||
if (!res)
|
if (!res)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -756,7 +757,7 @@ bool cByteBuffer::ReadString(AString & a_String, size_t a_Count)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cByteBuffer::ReadUTF16String(AString & a_String, int a_NumChars)
|
bool cByteBuffer::ReadUTF16String(AString & a_String, size_t a_NumChars)
|
||||||
{
|
{
|
||||||
// Reads 2 * a_NumChars bytes and interprets it as a UTF16 string, converting it into UTF8 string a_String
|
// Reads 2 * a_NumChars bytes and interprets it as a UTF16 string, converting it into UTF8 string a_String
|
||||||
CHECK_THREAD;
|
CHECK_THREAD;
|
||||||
@ -887,9 +888,7 @@ void cByteBuffer::AdvanceReadPos(size_t a_Count)
|
|||||||
|
|
||||||
void cByteBuffer::CheckValid(void) const
|
void cByteBuffer::CheckValid(void) const
|
||||||
{
|
{
|
||||||
ASSERT(m_ReadPos >= 0);
|
|
||||||
ASSERT(m_ReadPos < m_BufferSize);
|
ASSERT(m_ReadPos < m_BufferSize);
|
||||||
ASSERT(m_WritePos >= 0);
|
|
||||||
ASSERT(m_WritePos < m_BufferSize);
|
ASSERT(m_WritePos < m_BufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public:
|
|||||||
~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 char * 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;
|
||||||
@ -101,7 +101,7 @@ public:
|
|||||||
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, int 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);
|
||||||
|
@ -5,7 +5,7 @@ include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
|
|||||||
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
|
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
|
||||||
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
|
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/polarssl/include")
|
||||||
|
|
||||||
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating)
|
set(FOLDERS OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++)
|
||||||
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs)
|
set(FOLDERS ${FOLDERS} WorldStorage Mobs Entities Simulator UI BlockEntities Generating/Prefabs)
|
||||||
|
|
||||||
|
|
||||||
@ -57,6 +57,14 @@ if (NOT MSVC)
|
|||||||
Entities/Pickup.h
|
Entities/Pickup.h
|
||||||
Entities/Player.h
|
Entities/Player.h
|
||||||
Entities/ProjectileEntity.h
|
Entities/ProjectileEntity.h
|
||||||
|
Entities/ArrowEntity.h
|
||||||
|
Entities/ThrownEggEntity.h
|
||||||
|
Entities/ThrownEnderPearlEntity.h
|
||||||
|
Entities/ExpBottleEntity.h
|
||||||
|
Entities/ThrownSnowballEntity.h
|
||||||
|
Entities/FireChargeEntity.h
|
||||||
|
Entities/FireworkEntity.h
|
||||||
|
Entities/GhastFireballEntity.h
|
||||||
Entities/TNTEntity.h
|
Entities/TNTEntity.h
|
||||||
Entities/ExpOrb.h
|
Entities/ExpOrb.h
|
||||||
Entities/HangingEntity.h
|
Entities/HangingEntity.h
|
||||||
@ -234,7 +242,7 @@ endif ()
|
|||||||
if (NOT MSVC)
|
if (NOT MSVC)
|
||||||
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
|
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
|
||||||
target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
|
target_link_libraries(${EXECUTABLE} Protocol Generating Generating_Prefabs WorldStorage)
|
||||||
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities)
|
target_link_libraries(${EXECUTABLE} Mobs Entities Simulator UI BlockEntities PolarSSL++)
|
||||||
endif ()
|
endif ()
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
|
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
|
||||||
|
@ -380,12 +380,12 @@ void cChunk::SetLight(
|
|||||||
|
|
||||||
{ // Compress blocklight
|
{ // Compress blocklight
|
||||||
m_BlockLight.clear();
|
m_BlockLight.clear();
|
||||||
m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size()]);
|
m_BlockLight.insert(m_BlockLight.end(), &a_BlockLight[0], &a_BlockLight[m_BlockTypes.size() / 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
{ // Compress skylight
|
{ // Compress skylight
|
||||||
m_BlockSkyLight.clear();
|
m_BlockSkyLight.clear();
|
||||||
m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size()]);
|
m_BlockSkyLight.insert(m_BlockSkyLight.end(), &a_SkyLight[0], &a_SkyLight[m_BlockTypes.size() / 2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_IsLightValid = true;
|
m_IsLightValid = true;
|
||||||
|
@ -246,8 +246,8 @@ public:
|
|||||||
{
|
{
|
||||||
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
|
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
|
||||||
{
|
{
|
||||||
int Index = MakeIndexNoCheck(x, y, z);
|
size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
|
||||||
if ((size_t)(Index / 2) >= a_Buffer.size())
|
if ((Index / 2) >= a_Buffer.size())
|
||||||
{
|
{
|
||||||
return (a_IsSkyLightNibble ? 0xff : 0);
|
return (a_IsSkyLightNibble ? 0xff : 0);
|
||||||
}
|
}
|
||||||
@ -281,7 +281,7 @@ public:
|
|||||||
{
|
{
|
||||||
a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1));
|
a_Buffer.resize((size_t)((a_BlockIdx / 2) + 1));
|
||||||
}
|
}
|
||||||
a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, a_BlockIdx, a_Nibble);
|
a_Buffer[(size_t)(a_BlockIdx / 2)] = PackNibble(a_Buffer, (size_t)a_BlockIdx, a_Nibble);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -297,19 +297,19 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Index = MakeIndexNoCheck(x, y, z);
|
size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
|
||||||
if ((size_t)(Index / 2) >= a_Buffer.size())
|
if ((Index / 2) >= a_Buffer.size())
|
||||||
{
|
{
|
||||||
a_Buffer.resize((size_t)((Index / 2) + 1));
|
a_Buffer.resize(((Index / 2) + 1));
|
||||||
}
|
}
|
||||||
a_Buffer[(size_t)(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble);
|
a_Buffer[(Index / 2)] = PackNibble(a_Buffer, Index, a_Nibble);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
||||||
inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index, NIBBLETYPE a_Nibble)
|
inline static NIBBLETYPE PackNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index, NIBBLETYPE a_Nibble)
|
||||||
{
|
{
|
||||||
return static_cast<NIBBLETYPE>(
|
return static_cast<NIBBLETYPE>(
|
||||||
(a_Buffer[a_Index / 2] & (0xf0 >> ((a_Index & 1) * 4))) | // The untouched nibble
|
(a_Buffer[a_Index / 2] & (0xf0 >> ((a_Index & 1) * 4))) | // The untouched nibble
|
||||||
@ -318,7 +318,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, int a_Index)
|
inline static NIBBLETYPE ExpandNibble(const COMPRESSED_NIBBLETYPE & a_Buffer, size_t a_Index)
|
||||||
{
|
{
|
||||||
return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f;
|
return (a_Buffer[a_Index / 2] >> ((a_Index & 1) * 4)) & 0x0f;
|
||||||
}
|
}
|
||||||
|
@ -1652,7 +1652,10 @@ void cChunkMap::AddEntity(cEntity * a_Entity)
|
|||||||
{
|
{
|
||||||
cCSLock Lock(m_CSLayers);
|
cCSLock Lock(m_CSLayers);
|
||||||
cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
|
cChunkPtr Chunk = GetChunkNoGen(a_Entity->GetChunkX(), ZERO_CHUNK_Y, a_Entity->GetChunkZ());
|
||||||
if ((Chunk == NULL) || !Chunk->IsValid())
|
if (
|
||||||
|
(Chunk == NULL) || // Chunk not present at all
|
||||||
|
(!Chunk->IsValid() && !a_Entity->IsPlayer()) // Chunk present, but no valid data; players need to spawn in such chunks (#953)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.",
|
LOGWARNING("Entity at %p (%s, ID %d) spawning in a non-existent chunk, the entity is lost.",
|
||||||
a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID()
|
a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID()
|
||||||
|
@ -214,11 +214,15 @@ AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessage
|
|||||||
case mtPrivateMessage:
|
case mtPrivateMessage:
|
||||||
{
|
{
|
||||||
if (ShouldAppendChatPrefixes)
|
if (ShouldAppendChatPrefixes)
|
||||||
|
{
|
||||||
return Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str());
|
return Printf("%s[MSG: %s] %s%s", cChatColor::LightBlue.c_str(), a_AdditionalData.c_str(), cChatColor::White.c_str(), cChatColor::Italic.c_str());
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
|
return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
ASSERT(!"Unhandled chat prefix type!");
|
ASSERT(!"Unhandled chat prefix type!");
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
@ -333,6 +337,11 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID)
|
|||||||
// Send scoreboard data
|
// Send scoreboard data
|
||||||
World->GetScoreBoard().SendTo(*this);
|
World->GetScoreBoard().SendTo(*this);
|
||||||
|
|
||||||
|
// Delay the first ping until the client "settles down"
|
||||||
|
// This should fix #889, "BadCast exception, cannot convert bit to fm" error in client
|
||||||
|
cTimer t1;
|
||||||
|
m_LastPingTime = t1.GetNowTime() + 3000; // Send the first KeepAlive packet in 3 seconds
|
||||||
|
|
||||||
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
|
cRoot::Get()->GetPluginManager()->CallHookPlayerSpawned(*m_Player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,7 +716,7 @@ void cClientHandle::UnregisterPluginChannels(const AStringVector & a_ChannelList
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cClientHandle::HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length)
|
void cClientHandle::HandleCommandBlockMessage(const char * a_Data, size_t a_Length)
|
||||||
{
|
{
|
||||||
if (a_Length < 14)
|
if (a_Length < 14)
|
||||||
{
|
{
|
||||||
@ -1501,7 +1510,7 @@ void cClientHandle::HandleDisconnect(const AString & a_Reason)
|
|||||||
{
|
{
|
||||||
LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str());
|
LOGD("Received d/c packet from %s with reason \"%s\"", m_Username.c_str(), a_Reason.c_str());
|
||||||
|
|
||||||
cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason);
|
cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason);
|
||||||
|
|
||||||
m_HasSentDC = true;
|
m_HasSentDC = true;
|
||||||
Destroy();
|
Destroy();
|
||||||
@ -1649,7 +1658,7 @@ void cClientHandle::SendData(const char * a_Data, size_t a_Size)
|
|||||||
{
|
{
|
||||||
// There is a queued overflow. Append to it, then send as much from its front as possible
|
// There is a queued overflow. Append to it, then send as much from its front as possible
|
||||||
m_OutgoingDataOverflow.append(a_Data, a_Size);
|
m_OutgoingDataOverflow.append(a_Data, a_Size);
|
||||||
int CanFit = m_OutgoingData.GetFreeSpace();
|
size_t CanFit = m_OutgoingData.GetFreeSpace();
|
||||||
if (CanFit > 128)
|
if (CanFit > 128)
|
||||||
{
|
{
|
||||||
// No point in moving the data over if it's not large enough - too much effort for too little an effect
|
// No point in moving the data over if it's not large enough - too much effort for too little an effect
|
||||||
@ -2680,9 +2689,9 @@ void cClientHandle::SocketClosed(void)
|
|||||||
|
|
||||||
LOGD("Player %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str());
|
LOGD("Player %s @ %s disconnected", m_Username.c_str(), m_IPString.c_str());
|
||||||
|
|
||||||
if (m_Username != "") // Ignore client pings
|
if (!m_Username.empty()) // Ignore client pings
|
||||||
{
|
{
|
||||||
cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, "Player disconnected");
|
cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, "Player disconnected");
|
||||||
}
|
}
|
||||||
|
|
||||||
Destroy();
|
Destroy();
|
||||||
|
@ -384,7 +384,7 @@ private:
|
|||||||
void UnregisterPluginChannels(const AStringVector & a_ChannelList);
|
void UnregisterPluginChannels(const AStringVector & a_ChannelList);
|
||||||
|
|
||||||
/** Handles the "MC|AdvCdm" plugin message */
|
/** Handles the "MC|AdvCdm" plugin message */
|
||||||
void HandleCommandBlockMessage(const char * a_Data, unsigned int a_Length);
|
void HandleCommandBlockMessage(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 void DataReceived (const char * a_Data, size_t a_Size) override; // Data is received from the client
|
||||||
|
509
src/Crypto.cpp
509
src/Crypto.cpp
@ -1,509 +0,0 @@
|
|||||||
|
|
||||||
// Crypto.cpp
|
|
||||||
|
|
||||||
// Implements classes that wrap the cryptographic code library
|
|
||||||
|
|
||||||
#include "Globals.h"
|
|
||||||
#include "Crypto.h"
|
|
||||||
|
|
||||||
#include "polarssl/pk.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
// Self-test the hash formatting for known values:
|
|
||||||
// sha1(Notch) : 4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48
|
|
||||||
// sha1(jeb_) : -7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1
|
|
||||||
// sha1(simon) : 88e16a1019277b15d58faf0541e11910eb756f6
|
|
||||||
|
|
||||||
class Test
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Test(void)
|
|
||||||
{
|
|
||||||
AString DigestNotch, DigestJeb, DigestSimon;
|
|
||||||
Byte Digest[20];
|
|
||||||
cSHA1Checksum Checksum;
|
|
||||||
Checksum.Update((const Byte *)"Notch", 5);
|
|
||||||
Checksum.Finalize(Digest);
|
|
||||||
cSHA1Checksum::DigestToJava(Digest, DigestNotch);
|
|
||||||
Checksum.Restart();
|
|
||||||
Checksum.Update((const Byte *)"jeb_", 4);
|
|
||||||
Checksum.Finalize(Digest);
|
|
||||||
cSHA1Checksum::DigestToJava(Digest, DigestJeb);
|
|
||||||
Checksum.Restart();
|
|
||||||
Checksum.Update((const Byte *)"simon", 5);
|
|
||||||
Checksum.Finalize(Digest);
|
|
||||||
cSHA1Checksum::DigestToJava(Digest, DigestSimon);
|
|
||||||
printf("Notch: \"%s\"\n", DigestNotch.c_str());
|
|
||||||
printf("jeb_: \"%s\"\n", DigestJeb.c_str());
|
|
||||||
printf("simon: \"%s\"\n", DigestSimon.c_str());
|
|
||||||
assert(DigestNotch == "4ed1f46bbe04bc756bcb17c0c7ce3e4632f06a48");
|
|
||||||
assert(DigestJeb == "-7c9d5b0044c130109a5d7b5fb5c317c02b4e28c1");
|
|
||||||
assert(DigestSimon == "88e16a1019277b15d58faf0541e11910eb756f6");
|
|
||||||
}
|
|
||||||
} test;
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cRSAPrivateKey:
|
|
||||||
|
|
||||||
cRSAPrivateKey::cRSAPrivateKey(void)
|
|
||||||
{
|
|
||||||
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
|
|
||||||
InitRnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cRSAPrivateKey::cRSAPrivateKey(const cRSAPrivateKey & a_Other)
|
|
||||||
{
|
|
||||||
rsa_init(&m_Rsa, RSA_PKCS_V15, 0);
|
|
||||||
rsa_copy(&m_Rsa, &a_Other.m_Rsa);
|
|
||||||
InitRnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cRSAPrivateKey::~cRSAPrivateKey()
|
|
||||||
{
|
|
||||||
entropy_free(&m_Entropy);
|
|
||||||
rsa_free(&m_Rsa);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cRSAPrivateKey::InitRnd(void)
|
|
||||||
{
|
|
||||||
entropy_init(&m_Entropy);
|
|
||||||
const unsigned char pers[] = "rsa_genkey";
|
|
||||||
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cRSAPrivateKey::Generate(unsigned a_KeySizeBits)
|
|
||||||
{
|
|
||||||
if (rsa_gen_key(&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, a_KeySizeBits, 65537) != 0)
|
|
||||||
{
|
|
||||||
// Key generation failed
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AString cRSAPrivateKey::GetPubKeyDER(void)
|
|
||||||
{
|
|
||||||
class cPubKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cPubKey(rsa_context * a_Rsa) :
|
|
||||||
m_IsValid(false)
|
|
||||||
{
|
|
||||||
pk_init(&m_Key);
|
|
||||||
if (pk_init_ctx(&m_Key, pk_info_from_type(POLARSSL_PK_RSA)) != 0)
|
|
||||||
{
|
|
||||||
ASSERT(!"Cannot init PrivKey context");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rsa_copy(pk_rsa(m_Key), a_Rsa) != 0)
|
|
||||||
{
|
|
||||||
ASSERT(!"Cannot copy PrivKey to PK context");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
m_IsValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~cPubKey()
|
|
||||||
{
|
|
||||||
if (m_IsValid)
|
|
||||||
{
|
|
||||||
pk_free(&m_Key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator pk_context * (void) { return &m_Key; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool m_IsValid;
|
|
||||||
pk_context m_Key;
|
|
||||||
} PkCtx(&m_Rsa);
|
|
||||||
|
|
||||||
unsigned char buf[3000];
|
|
||||||
int res = pk_write_pubkey_der(PkCtx, buf, sizeof(buf));
|
|
||||||
if (res < 0)
|
|
||||||
{
|
|
||||||
return AString();
|
|
||||||
}
|
|
||||||
return AString((const char *)(buf + sizeof(buf) - res), (size_t)res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cRSAPrivateKey::Decrypt(const Byte * a_EncryptedData, size_t a_EncryptedLength, Byte * a_DecryptedData, size_t a_DecryptedMaxLength)
|
|
||||||
{
|
|
||||||
if (a_EncryptedLength < m_Rsa.len)
|
|
||||||
{
|
|
||||||
LOGD("%s: Invalid a_EncryptedLength: got %u, exp at least %u",
|
|
||||||
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
|
|
||||||
);
|
|
||||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (a_DecryptedMaxLength < m_Rsa.len)
|
|
||||||
{
|
|
||||||
LOGD("%s: Invalid a_DecryptedMaxLength: got %u, exp at least %u",
|
|
||||||
__FUNCTION__, (unsigned)a_EncryptedLength, (unsigned)(m_Rsa.len)
|
|
||||||
);
|
|
||||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
size_t DecryptedLength;
|
|
||||||
int res = rsa_pkcs1_decrypt(
|
|
||||||
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE, &DecryptedLength,
|
|
||||||
a_EncryptedData, a_DecryptedData, a_DecryptedMaxLength
|
|
||||||
);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return (int)DecryptedLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cRSAPrivateKey::Encrypt(const Byte * a_PlainData, size_t a_PlainLength, Byte * a_EncryptedData, size_t a_EncryptedMaxLength)
|
|
||||||
{
|
|
||||||
if (a_EncryptedMaxLength < m_Rsa.len)
|
|
||||||
{
|
|
||||||
LOGD("%s: Invalid a_EncryptedMaxLength: got %u, exp at least %u",
|
|
||||||
__FUNCTION__, (unsigned)a_EncryptedMaxLength, (unsigned)(m_Rsa.len)
|
|
||||||
);
|
|
||||||
ASSERT(!"Invalid a_DecryptedMaxLength!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (a_PlainLength < m_Rsa.len)
|
|
||||||
{
|
|
||||||
LOGD("%s: Invalid a_PlainLength: got %u, exp at least %u",
|
|
||||||
__FUNCTION__, (unsigned)a_PlainLength, (unsigned)(m_Rsa.len)
|
|
||||||
);
|
|
||||||
ASSERT(!"Invalid a_PlainLength!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
int res = rsa_pkcs1_encrypt(
|
|
||||||
&m_Rsa, ctr_drbg_random, &m_Ctr_drbg, RSA_PRIVATE,
|
|
||||||
a_PlainLength, a_PlainData, a_EncryptedData
|
|
||||||
);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return (int)m_Rsa.len;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cPublicKey:
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
InitRnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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_Ctr_drbg
|
|
||||||
);
|
|
||||||
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_Ctr_drbg
|
|
||||||
);
|
|
||||||
if (res != 0)
|
|
||||||
{
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
return (int)EncryptedLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPublicKey::InitRnd(void)
|
|
||||||
{
|
|
||||||
entropy_init(&m_Entropy);
|
|
||||||
const unsigned char pers[] = "rsa_genkey";
|
|
||||||
ctr_drbg_init(&m_Ctr_drbg, entropy_func, &m_Entropy, pers, sizeof(pers) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cAESCFBDecryptor:
|
|
||||||
|
|
||||||
cAESCFBDecryptor::cAESCFBDecryptor(void) :
|
|
||||||
m_IVOffset(0),
|
|
||||||
m_IsValid(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cAESCFBDecryptor::~cAESCFBDecryptor()
|
|
||||||
{
|
|
||||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
|
||||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cAESCFBDecryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
|
||||||
{
|
|
||||||
ASSERT(!IsValid()); // Cannot Init twice
|
|
||||||
|
|
||||||
memcpy(m_IV, a_IV, 16);
|
|
||||||
aes_setkey_enc(&m_Aes, a_Key, 128);
|
|
||||||
m_IsValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cAESCFBDecryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
|
|
||||||
{
|
|
||||||
ASSERT(IsValid()); // Must Init() first
|
|
||||||
|
|
||||||
// PolarSSL doesn't support AES-CFB8, need to implement it manually:
|
|
||||||
for (size_t i = 0; i < a_Length; i++)
|
|
||||||
{
|
|
||||||
Byte Buffer[sizeof(m_IV)];
|
|
||||||
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
|
||||||
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
|
||||||
{
|
|
||||||
m_IV[idx] = m_IV[idx + 1];
|
|
||||||
}
|
|
||||||
m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
|
|
||||||
a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cAESCFBEncryptor:
|
|
||||||
|
|
||||||
cAESCFBEncryptor::cAESCFBEncryptor(void) :
|
|
||||||
m_IVOffset(0),
|
|
||||||
m_IsValid(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cAESCFBEncryptor::~cAESCFBEncryptor()
|
|
||||||
{
|
|
||||||
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
|
||||||
memset(&m_Aes, 0, sizeof(m_Aes));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cAESCFBEncryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
|
||||||
{
|
|
||||||
ASSERT(!IsValid()); // Cannot Init twice
|
|
||||||
ASSERT(m_IVOffset == 0);
|
|
||||||
|
|
||||||
memcpy(m_IV, a_IV, 16);
|
|
||||||
aes_setkey_enc(&m_Aes, a_Key, 128);
|
|
||||||
m_IsValid = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cAESCFBEncryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
|
|
||||||
{
|
|
||||||
ASSERT(IsValid()); // Must Init() first
|
|
||||||
|
|
||||||
// PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
|
|
||||||
for (size_t i = 0; i < a_Length; i++)
|
|
||||||
{
|
|
||||||
Byte Buffer[sizeof(m_IV)];
|
|
||||||
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
|
||||||
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
|
||||||
{
|
|
||||||
m_IV[idx] = m_IV[idx + 1];
|
|
||||||
}
|
|
||||||
a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
|
|
||||||
m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cSHA1Checksum:
|
|
||||||
|
|
||||||
cSHA1Checksum::cSHA1Checksum(void) :
|
|
||||||
m_DoesAcceptInput(true)
|
|
||||||
{
|
|
||||||
sha1_starts(&m_Sha1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSHA1Checksum::Update(const Byte * a_Data, size_t a_Length)
|
|
||||||
{
|
|
||||||
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
|
|
||||||
|
|
||||||
sha1_update(&m_Sha1, a_Data, a_Length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSHA1Checksum::Finalize(cSHA1Checksum::Checksum & a_Output)
|
|
||||||
{
|
|
||||||
ASSERT(m_DoesAcceptInput); // Not Finalize()-d yet, or Restart()-ed
|
|
||||||
|
|
||||||
sha1_finish(&m_Sha1, a_Output);
|
|
||||||
m_DoesAcceptInput = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSHA1Checksum::DigestToJava(const Checksum & a_Digest, AString & a_Out)
|
|
||||||
{
|
|
||||||
Checksum Digest;
|
|
||||||
memcpy(Digest, a_Digest, sizeof(Digest));
|
|
||||||
|
|
||||||
bool IsNegative = (Digest[0] >= 0x80);
|
|
||||||
if (IsNegative)
|
|
||||||
{
|
|
||||||
// Two's complement:
|
|
||||||
bool carry = true; // Add one to the whole number
|
|
||||||
for (int i = 19; i >= 0; i--)
|
|
||||||
{
|
|
||||||
Digest[i] = ~Digest[i];
|
|
||||||
if (carry)
|
|
||||||
{
|
|
||||||
carry = (Digest[i] == 0xff);
|
|
||||||
Digest[i]++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a_Out.clear();
|
|
||||||
a_Out.reserve(40);
|
|
||||||
for (int i = 0; i < 20; i++)
|
|
||||||
{
|
|
||||||
AppendPrintf(a_Out, "%02x", Digest[i]);
|
|
||||||
}
|
|
||||||
while ((a_Out.length() > 0) && (a_Out[0] == '0'))
|
|
||||||
{
|
|
||||||
a_Out.erase(0, 1);
|
|
||||||
}
|
|
||||||
if (IsNegative)
|
|
||||||
{
|
|
||||||
a_Out.insert(0, "-");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cSHA1Checksum::Restart(void)
|
|
||||||
{
|
|
||||||
sha1_starts(&m_Sha1);
|
|
||||||
m_DoesAcceptInput = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
198
src/Crypto.h
198
src/Crypto.h
@ -1,198 +0,0 @@
|
|||||||
|
|
||||||
// Crypto.h
|
|
||||||
|
|
||||||
// Declares classes that wrap the cryptographic code library
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "polarssl/rsa.h"
|
|
||||||
#include "polarssl/aes.h"
|
|
||||||
#include "polarssl/entropy.h"
|
|
||||||
#include "polarssl/ctr_drbg.h"
|
|
||||||
#include "polarssl/sha1.h"
|
|
||||||
#include "polarssl/pk.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Encapsulates an RSA private key used in PKI cryptography */
|
|
||||||
class cRSAPrivateKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** Creates a new empty object, the key is not assigned */
|
|
||||||
cRSAPrivateKey(void);
|
|
||||||
|
|
||||||
/** Deep-copies the key from a_Other */
|
|
||||||
cRSAPrivateKey(const cRSAPrivateKey & a_Other);
|
|
||||||
|
|
||||||
~cRSAPrivateKey();
|
|
||||||
|
|
||||||
/** Generates a new key within this object, with the specified size in bits.
|
|
||||||
Returns true on success, false on failure. */
|
|
||||||
bool Generate(unsigned a_KeySizeBits = 1024);
|
|
||||||
|
|
||||||
/** Returns the public key part encoded in ASN1 DER encoding */
|
|
||||||
AString GetPubKeyDER(void);
|
|
||||||
|
|
||||||
/** Decrypts the data using RSAES-PKCS#1 algorithm.
|
|
||||||
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 RSAES-PKCS#1 algorithm.
|
|
||||||
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:
|
|
||||||
rsa_context m_Rsa;
|
|
||||||
entropy_context m_Entropy;
|
|
||||||
ctr_drbg_context m_Ctr_drbg;
|
|
||||||
|
|
||||||
/** Initializes the m_Entropy and m_Ctr_drbg contexts
|
|
||||||
Common part of this object's construction, called from all constructors. */
|
|
||||||
void InitRnd(void);
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cPublicKey
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
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:
|
|
||||||
pk_context m_Pk;
|
|
||||||
entropy_context m_Entropy;
|
|
||||||
ctr_drbg_context m_Ctr_drbg;
|
|
||||||
|
|
||||||
/** Initializes the m_Entropy and m_Ctr_drbg contexts
|
|
||||||
Common part of this object's construction, called from all constructors. */
|
|
||||||
void InitRnd(void);
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Decrypts data using the AES / CFB (128) algorithm */
|
|
||||||
class cAESCFBDecryptor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Byte test;
|
|
||||||
|
|
||||||
cAESCFBDecryptor(void);
|
|
||||||
~cAESCFBDecryptor();
|
|
||||||
|
|
||||||
/** Initializes the decryptor with the specified Key / IV */
|
|
||||||
void Init(const Byte a_Key[16], const Byte a_IV[16]);
|
|
||||||
|
|
||||||
/** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
|
|
||||||
void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
|
|
||||||
|
|
||||||
/** Returns true if the object has been initialized with the Key / IV */
|
|
||||||
bool IsValid(void) const { return m_IsValid; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
aes_context m_Aes;
|
|
||||||
|
|
||||||
/** The InitialVector, used by the CFB mode decryption */
|
|
||||||
Byte m_IV[16];
|
|
||||||
|
|
||||||
/** Current offset in the m_IV, used by the CFB mode decryption */
|
|
||||||
size_t m_IVOffset;
|
|
||||||
|
|
||||||
/** Indicates whether the object has been initialized with the Key / IV */
|
|
||||||
bool m_IsValid;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Encrypts data using the AES / CFB (128) algorithm */
|
|
||||||
class cAESCFBEncryptor
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
cAESCFBEncryptor(void);
|
|
||||||
~cAESCFBEncryptor();
|
|
||||||
|
|
||||||
/** Initializes the decryptor with the specified Key / IV */
|
|
||||||
void Init(const Byte a_Key[16], const Byte a_IV[16]);
|
|
||||||
|
|
||||||
/** Encrypts a_Length bytes of the plain data; produces a_Length output bytes */
|
|
||||||
void ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length);
|
|
||||||
|
|
||||||
/** Returns true if the object has been initialized with the Key / IV */
|
|
||||||
bool IsValid(void) const { return m_IsValid; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
aes_context m_Aes;
|
|
||||||
|
|
||||||
/** The InitialVector, used by the CFB mode encryption */
|
|
||||||
Byte m_IV[16];
|
|
||||||
|
|
||||||
/** Current offset in the m_IV, used by the CFB mode encryption */
|
|
||||||
size_t m_IVOffset;
|
|
||||||
|
|
||||||
/** Indicates whether the object has been initialized with the Key / IV */
|
|
||||||
bool m_IsValid;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Calculates a SHA1 checksum for data stream */
|
|
||||||
class cSHA1Checksum
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef Byte Checksum[20]; // The type used for storing the checksum
|
|
||||||
|
|
||||||
cSHA1Checksum(void);
|
|
||||||
|
|
||||||
/** Adds the specified data to the checksum */
|
|
||||||
void Update(const Byte * a_Data, size_t a_Length);
|
|
||||||
|
|
||||||
/** Calculates and returns the final checksum */
|
|
||||||
void Finalize(Checksum & a_Output);
|
|
||||||
|
|
||||||
/** Returns true if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
|
|
||||||
bool DoesAcceptInput(void) const { return m_DoesAcceptInput; }
|
|
||||||
|
|
||||||
/** Converts a raw 160-bit SHA1 digest into a Java Hex representation
|
|
||||||
According to http://wiki.vg/wiki/index.php?title=Protocol_Encryption&oldid=2802
|
|
||||||
*/
|
|
||||||
static void DigestToJava(const Checksum & a_Digest, AString & a_JavaOut);
|
|
||||||
|
|
||||||
/** Clears the current context and start a new checksum calculation */
|
|
||||||
void Restart(void);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
/** True if the object is accepts more input data, false if Finalize()-d (need to Restart()) */
|
|
||||||
bool m_DoesAcceptInput;
|
|
||||||
|
|
||||||
sha1_context m_Sha1;
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
193
src/Entities/ArrowEntity.cpp
Normal file
193
src/Entities/ArrowEntity.cpp
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "Player.h"
|
||||||
|
#include "ArrowEntity.h"
|
||||||
|
#include "../Chunk.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
|
super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
|
||||||
|
m_PickupState(psNoPickup),
|
||||||
|
m_DamageCoeff(2),
|
||||||
|
m_IsCritical(false),
|
||||||
|
m_Timer(0),
|
||||||
|
m_HitGroundTimer(0),
|
||||||
|
m_bIsCollected(false),
|
||||||
|
m_HitBlockPos(Vector3i(0, 0, 0))
|
||||||
|
{
|
||||||
|
SetSpeed(a_Speed);
|
||||||
|
SetMass(0.1);
|
||||||
|
SetYawFromSpeed();
|
||||||
|
SetPitchFromSpeed();
|
||||||
|
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
|
||||||
|
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
|
||||||
|
GetYaw(), GetPitch()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
|
||||||
|
super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
|
||||||
|
m_PickupState(psInSurvivalOrCreative),
|
||||||
|
m_DamageCoeff(2),
|
||||||
|
m_IsCritical((a_Force >= 1)),
|
||||||
|
m_Timer(0),
|
||||||
|
m_HitGroundTimer(0),
|
||||||
|
m_HasTeleported(false),
|
||||||
|
m_bIsCollected(false),
|
||||||
|
m_HitBlockPos(0, 0, 0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
|
||||||
|
{
|
||||||
|
switch (m_PickupState)
|
||||||
|
{
|
||||||
|
case psNoPickup: return false;
|
||||||
|
case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
|
||||||
|
case psInCreative: return a_Player.IsGameModeCreative();
|
||||||
|
}
|
||||||
|
ASSERT(!"Unhandled pickup state");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
|
{
|
||||||
|
if (a_HitFace == BLOCK_FACE_NONE) { return; }
|
||||||
|
|
||||||
|
super::OnHitSolidBlock(a_HitPos, a_HitFace);
|
||||||
|
int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
|
||||||
|
|
||||||
|
switch (a_HitFace)
|
||||||
|
{
|
||||||
|
case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed
|
||||||
|
case BLOCK_FACE_YM:
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
|
||||||
|
|
||||||
|
// Broadcast arrow hit sound
|
||||||
|
m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
|
||||||
|
{
|
||||||
|
// Not an entity that interacts with an arrow
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
|
||||||
|
if (m_IsCritical)
|
||||||
|
{
|
||||||
|
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
|
||||||
|
}
|
||||||
|
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
|
||||||
|
|
||||||
|
// Broadcast successful hit sound
|
||||||
|
m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cArrowEntity::CollectedBy(cPlayer * a_Dest)
|
||||||
|
{
|
||||||
|
if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
|
||||||
|
{
|
||||||
|
int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
|
||||||
|
if (NumAdded > 0) // Only play effects if there was space in inventory
|
||||||
|
{
|
||||||
|
m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
|
||||||
|
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
||||||
|
m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
||||||
|
m_bIsCollected = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
|
{
|
||||||
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
m_Timer += a_Dt;
|
||||||
|
|
||||||
|
if (m_bIsCollected)
|
||||||
|
{
|
||||||
|
if (m_Timer > 500.f) // 0.5 seconds
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_IsInGround)
|
||||||
|
{
|
||||||
|
// When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
|
||||||
|
// Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
|
||||||
|
// We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
|
||||||
|
// Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
|
||||||
|
|
||||||
|
if (!m_HasTeleported) // Sent a teleport already, don't do again
|
||||||
|
{
|
||||||
|
if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
|
||||||
|
{
|
||||||
|
m_World->BroadcastTeleportEntity(*this);
|
||||||
|
m_HasTeleported = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_HitGroundTimer += a_Dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||||
|
int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||||
|
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
|
||||||
|
|
||||||
|
if (Chunk == NULL)
|
||||||
|
{
|
||||||
|
// Inside an unloaded chunk, abort
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
|
||||||
|
{
|
||||||
|
m_IsInGround = false; // Yes, begin simulating physics again
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
96
src/Entities/ArrowEntity.h
Normal file
96
src/Entities/ArrowEntity.h
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
//
|
||||||
|
// ArrowEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cArrowEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
|
||||||
|
enum ePickupState
|
||||||
|
{
|
||||||
|
psNoPickup = 0,
|
||||||
|
psInSurvivalOrCreative = 1,
|
||||||
|
psInCreative = 2,
|
||||||
|
} ;
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cArrowEntity);
|
||||||
|
|
||||||
|
/// Creates a new arrow with psNoPickup state and default damage modifier coeff
|
||||||
|
cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||||
|
|
||||||
|
/// Creates a new arrow as shot by a player, initializes it from the player object
|
||||||
|
cArrowEntity(cPlayer & a_Player, double a_Force);
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
/// Returns whether the arrow can be picked up by players
|
||||||
|
ePickupState GetPickupState(void) const { return m_PickupState; }
|
||||||
|
|
||||||
|
/// Sets a new pickup state
|
||||||
|
void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
|
||||||
|
|
||||||
|
/// Returns the damage modifier coeff.
|
||||||
|
double GetDamageCoeff(void) const { return m_DamageCoeff; }
|
||||||
|
|
||||||
|
/// Sets the damage modifier coeff
|
||||||
|
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
|
||||||
|
|
||||||
|
/// Returns true if the specified player can pick the arrow up
|
||||||
|
bool CanPickup(const cPlayer & a_Player) const;
|
||||||
|
|
||||||
|
/// Returns true if the arrow is set as critical
|
||||||
|
bool IsCritical(void) const { return m_IsCritical; }
|
||||||
|
|
||||||
|
/// Sets the IsCritical flag
|
||||||
|
void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/// Determines when the arrow can be picked up by players
|
||||||
|
ePickupState m_PickupState;
|
||||||
|
|
||||||
|
/// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
|
||||||
|
double m_DamageCoeff;
|
||||||
|
|
||||||
|
/// If true, the arrow deals more damage
|
||||||
|
bool m_IsCritical;
|
||||||
|
|
||||||
|
/// Timer for pickup collection animation or five minute timeout
|
||||||
|
float m_Timer;
|
||||||
|
|
||||||
|
/// Timer for client arrow position confirmation via TeleportEntity
|
||||||
|
float m_HitGroundTimer;
|
||||||
|
|
||||||
|
// Whether the arrow has already been teleported into the proper position in the ground.
|
||||||
|
bool m_HasTeleported;
|
||||||
|
|
||||||
|
/// If true, the arrow is in the process of being collected - don't go to anyone else
|
||||||
|
bool m_bIsCollected;
|
||||||
|
|
||||||
|
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
|
||||||
|
Vector3i m_HitBlockPos;
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
|
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
virtual void CollectedBy(cPlayer * a_Player) override;
|
||||||
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
|
}; // tolua_export
|
@ -33,9 +33,12 @@ void cBoat::SpawnOn(cClientHandle & a_ClientHandle)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
|
bool cBoat::DoTakeDamage(TakeDamageInfo & TDI)
|
||||||
{
|
{
|
||||||
super::DoTakeDamage(TDI);
|
if (!super::DoTakeDamage(TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (GetHealth() == 0)
|
if (GetHealth() == 0)
|
||||||
{
|
{
|
||||||
@ -50,6 +53,7 @@ void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
|
|||||||
}
|
}
|
||||||
Destroy(true);
|
Destroy(true);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ public:
|
|||||||
// cEntity overrides:
|
// cEntity overrides:
|
||||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override;
|
virtual void HandleSpeedFromAttachee(float a_Forward, float a_Sideways) override;
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
|
|||||||
, m_TicksSinceLastVoidDamage(0)
|
, m_TicksSinceLastVoidDamage(0)
|
||||||
, m_IsSwimming(false)
|
, m_IsSwimming(false)
|
||||||
, m_IsSubmerged(false)
|
, m_IsSubmerged(false)
|
||||||
|
, m_AirLevel(0)
|
||||||
|
, m_AirTickTimer(0)
|
||||||
, m_HeadYaw( 0.0 )
|
, m_HeadYaw( 0.0 )
|
||||||
, m_Rot(0.0, 0.0, 0.0)
|
, m_Rot(0.0, 0.0, 0.0)
|
||||||
, m_Pos(a_X, a_Y, a_Z)
|
, m_Pos(a_X, a_Y, a_Z)
|
||||||
@ -60,6 +62,7 @@ cEntity::cEntity(eEntityType a_EntityType, double a_X, double a_Y, double a_Z, d
|
|||||||
, m_Mass (0.001) // Default 1g
|
, m_Mass (0.001) // Default 1g
|
||||||
, m_Width(a_Width)
|
, m_Width(a_Width)
|
||||||
, m_Height(a_Height)
|
, m_Height(a_Height)
|
||||||
|
, m_InvulnerableTicks(0)
|
||||||
{
|
{
|
||||||
cCSLock Lock(m_CSCount);
|
cCSLock Lock(m_CSCount);
|
||||||
m_EntityCount++;
|
m_EntityCount++;
|
||||||
@ -294,17 +297,23 @@ void cEntity::SetPitchFromSpeed(void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI))
|
if (cRoot::Get()->GetPluginManager()->CallHookTakeDamage(*this, a_TDI))
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_Health <= 0)
|
if (m_Health <= 0)
|
||||||
{
|
{
|
||||||
// Can't take damage if already dead
|
// Can't take damage if already dead
|
||||||
return;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_InvulnerableTicks > 0)
|
||||||
|
{
|
||||||
|
// Entity is invulnerable
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
|
if ((a_TDI.Attacker != NULL) && (a_TDI.Attacker->IsPlayer()))
|
||||||
@ -362,10 +371,13 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
|
|
||||||
m_World->BroadcastEntityStatus(*this, esGenericHurt);
|
m_World->BroadcastEntityStatus(*this, esGenericHurt);
|
||||||
|
|
||||||
|
m_InvulnerableTicks = 10;
|
||||||
|
|
||||||
if (m_Health <= 0)
|
if (m_Health <= 0)
|
||||||
{
|
{
|
||||||
KilledBy(a_TDI.Attacker);
|
KilledBy(a_TDI.Attacker);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -562,6 +574,11 @@ void cEntity::SetHealth(int a_Health)
|
|||||||
|
|
||||||
void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
void cEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
|
if (m_InvulnerableTicks > 0)
|
||||||
|
{
|
||||||
|
m_InvulnerableTicks--;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_AttachedTo != NULL)
|
if (m_AttachedTo != NULL)
|
||||||
{
|
{
|
||||||
if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5)
|
if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5)
|
||||||
|
@ -262,8 +262,10 @@ public:
|
|||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
/// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied
|
/** Makes this entity take damage specified in the a_TDI.
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI);
|
The TDI is sent through plugins first, then applied.
|
||||||
|
If it returns false, the entity hasn't receive any damage. */
|
||||||
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI);
|
||||||
|
|
||||||
// tolua_begin
|
// tolua_begin
|
||||||
|
|
||||||
@ -395,6 +397,12 @@ public:
|
|||||||
/** Gets remaining air of a monster */
|
/** Gets remaining air of a monster */
|
||||||
int GetAirLevel(void) const { return m_AirLevel; }
|
int GetAirLevel(void) const { return m_AirLevel; }
|
||||||
|
|
||||||
|
/** Gets the invulnerable ticks from the entity */
|
||||||
|
int GetInvulnerableTicks(void) const { return m_InvulnerableTicks; }
|
||||||
|
|
||||||
|
/** Set the invulnerable ticks from the entity */
|
||||||
|
void SetInvulnerableTicks(int a_InvulnerableTicks) { m_InvulnerableTicks = a_InvulnerableTicks; }
|
||||||
|
|
||||||
// tolua_end
|
// tolua_end
|
||||||
|
|
||||||
/// Called when the specified player right-clicks this entity
|
/// Called when the specified player right-clicks this entity
|
||||||
@ -478,29 +486,33 @@ protected:
|
|||||||
int m_AirTickTimer;
|
int m_AirTickTimer;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Measured in degrees, [-180, +180)
|
/** Measured in degrees, [-180, +180) */
|
||||||
double m_HeadYaw;
|
double m_HeadYaw;
|
||||||
|
|
||||||
// Measured in meter/second (m/s)
|
/** Measured in meter/second (m/s) */
|
||||||
Vector3d m_Speed;
|
Vector3d m_Speed;
|
||||||
|
|
||||||
// Measured in degrees, [-180, +180)
|
/** Measured in degrees, [-180, +180) */
|
||||||
Vector3d m_Rot;
|
Vector3d m_Rot;
|
||||||
|
|
||||||
/// Position of the entity's XZ center and Y bottom
|
/** Position of the entity's XZ center and Y bottom */
|
||||||
Vector3d m_Pos;
|
Vector3d m_Pos;
|
||||||
|
|
||||||
// Measured in meter / second
|
/** Measured in meter / second */
|
||||||
Vector3d m_WaterSpeed;
|
Vector3d m_WaterSpeed;
|
||||||
|
|
||||||
// Measured in Kilograms (Kg)
|
/** Measured in Kilograms (Kg) */
|
||||||
double m_Mass;
|
double m_Mass;
|
||||||
|
|
||||||
/// Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter.
|
/** Width of the entity, in the XZ plane. Since entities are represented as cylinders, this is more of a diameter. */
|
||||||
double m_Width;
|
double m_Width;
|
||||||
|
|
||||||
/// Height of the entity (Y axis)
|
/** Height of the entity (Y axis) */
|
||||||
double m_Height;
|
double m_Height;
|
||||||
|
|
||||||
|
/** If a player hit a entity, the entity receive a invulnerable of 10 ticks.
|
||||||
|
While this ticks, a player can't hit this entity. */
|
||||||
|
int m_InvulnerableTicks;
|
||||||
} ; // tolua_export
|
} ; // tolua_export
|
||||||
|
|
||||||
typedef std::list<cEntity *> cEntityList;
|
typedef std::list<cEntity *> cEntityList;
|
||||||
|
27
src/Entities/ExpBottleEntity.cpp
Normal file
27
src/Entities/ExpBottleEntity.cpp
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "ExpBottleEntity.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
|
super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||||
|
{
|
||||||
|
SetSpeed(a_Speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
|
{
|
||||||
|
// Spawn an experience orb with a reward between 3 and 11.
|
||||||
|
m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
|
||||||
|
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
33
src/Entities/ExpBottleEntity.h
Normal file
33
src/Entities/ExpBottleEntity.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
//
|
||||||
|
// ExpBottleEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cExpBottleEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cExpBottleEntity);
|
||||||
|
|
||||||
|
cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
|
|
||||||
|
}; // tolua_export
|
@ -87,7 +87,7 @@ void cFallingBlock::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
AddSpeedY(MilliDt * -9.8f);
|
AddSpeedY(MilliDt * -9.8f);
|
||||||
AddPosition(GetSpeed() * MilliDt);
|
AddPosition(GetSpeed() * MilliDt);
|
||||||
|
|
||||||
// If not static (One billionth precision) broadcast movement.
|
// If not static (one billionth precision) broadcast movement
|
||||||
if ((fabs(GetSpeedX()) > std::numeric_limits<double>::epsilon()) || (fabs(GetSpeedZ()) > std::numeric_limits<double>::epsilon()))
|
if ((fabs(GetSpeedX()) > std::numeric_limits<double>::epsilon()) || (fabs(GetSpeedZ()) > std::numeric_limits<double>::epsilon()))
|
||||||
{
|
{
|
||||||
BroadcastMovementUpdate();
|
BroadcastMovementUpdate();
|
||||||
|
50
src/Entities/FireChargeEntity.cpp
Normal file
50
src/Entities/FireChargeEntity.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "FireChargeEntity.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
|
super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125)
|
||||||
|
{
|
||||||
|
SetSpeed(a_Speed);
|
||||||
|
SetGravity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
|
{
|
||||||
|
if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||||
|
|
||||||
|
// TODO: Some entities are immune to hits
|
||||||
|
a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning
|
||||||
|
}
|
36
src/Entities/FireChargeEntity.h
Normal file
36
src/Entities/FireChargeEntity.h
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//
|
||||||
|
// FireChargeEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cFireChargeEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cFireChargeEntity);
|
||||||
|
|
||||||
|
cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
|
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
|
||||||
|
} ; // tolua_export
|
73
src/Entities/FireworkEntity.cpp
Normal file
73
src/Entities/FireworkEntity.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "FireworkEntity.h"
|
||||||
|
#include "../World.h"
|
||||||
|
#include "../Chunk.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
|
||||||
|
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
||||||
|
m_ExplodeTimer(0),
|
||||||
|
m_FireworkItem(a_Item)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
||||||
|
{
|
||||||
|
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
|
||||||
|
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
|
||||||
|
int PosY = POSY_TOINT;
|
||||||
|
|
||||||
|
if ((PosY < 0) || (PosY >= cChunkDef::Height))
|
||||||
|
{
|
||||||
|
goto setspeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_IsInGround)
|
||||||
|
{
|
||||||
|
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
m_IsInGround = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
|
||||||
|
{
|
||||||
|
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setspeed:
|
||||||
|
AddSpeedY(1);
|
||||||
|
AddPosition(GetSpeed() * (a_Dt / 1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
||||||
|
{
|
||||||
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
|
||||||
|
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
|
||||||
|
{
|
||||||
|
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_ExplodeTimer++;
|
||||||
|
}
|
40
src/Entities/FireworkEntity.h
Normal file
40
src/Entities/FireworkEntity.h
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
//
|
||||||
|
// FireworkEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cFireworkEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cFireworkEntity);
|
||||||
|
|
||||||
|
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
|
||||||
|
const cItem & GetItem(void) const { return m_FireworkItem; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
int m_ExplodeTimer;
|
||||||
|
cItem m_FireworkItem;
|
||||||
|
|
||||||
|
}; // tolua_export
|
44
src/Entities/GhastFireballEntity.cpp
Normal file
44
src/Entities/GhastFireballEntity.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "GhastFireballEntity.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
|
super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1)
|
||||||
|
{
|
||||||
|
SetSpeed(a_Speed);
|
||||||
|
SetGravity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
||||||
|
{
|
||||||
|
m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
||||||
|
}
|
38
src/Entities/GhastFireballEntity.h
Normal file
38
src/Entities/GhastFireballEntity.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// GhastFireballEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cGhastFireballEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cGhastFireballEntity);
|
||||||
|
|
||||||
|
cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
|
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
|
||||||
|
// TODO: Deflecting the fireballs by arrow- or sword- hits
|
||||||
|
|
||||||
|
} ; // tolua_export
|
@ -902,18 +902,21 @@ bool cMinecart::TestEntityCollision(NIBBLETYPE a_RailMeta)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
bool cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
||||||
{
|
{
|
||||||
if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
|
if ((TDI.Attacker != NULL) && TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
|
||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
|
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
|
||||||
super::DoTakeDamage(TDI);
|
SetInvulnerableTicks(0);
|
||||||
return; // No drops for creative
|
return super::DoTakeDamage(TDI); // No drops for creative
|
||||||
}
|
}
|
||||||
|
|
||||||
m_LastDamage = TDI.FinalDamage;
|
m_LastDamage = TDI.FinalDamage;
|
||||||
super::DoTakeDamage(TDI);
|
if (!super::DoTakeDamage(TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
m_World->BroadcastEntityMetadata(*this);
|
m_World->BroadcastEntityMetadata(*this);
|
||||||
|
|
||||||
@ -952,12 +955,13 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
|||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
ASSERT(!"Unhandled minecart type when spawning pickup!");
|
ASSERT(!"Unhandled minecart type when spawning pickup!");
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
|
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ public:
|
|||||||
// cEntity overrides:
|
// cEntity overrides:
|
||||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
|
||||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||||
virtual void Destroyed() override;
|
virtual void Destroyed() override;
|
||||||
|
|
||||||
int LastDamage(void) const { return m_LastDamage; }
|
int LastDamage(void) const { return m_LastDamage; }
|
||||||
|
@ -808,14 +808,14 @@ void cPlayer::SetFlying(bool a_IsFlying)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin))
|
if ((a_TDI.DamageType != dtInVoid) && (a_TDI.DamageType != dtPlugin))
|
||||||
{
|
{
|
||||||
if (IsGameModeCreative())
|
if (IsGameModeCreative())
|
||||||
{
|
{
|
||||||
// No damage / health in creative mode if not void or plugin damage
|
// No damage / health in creative mode if not void or plugin damage
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -828,17 +828,19 @@ void cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
if (!m_Team->AllowsFriendlyFire())
|
if (!m_Team->AllowsFriendlyFire())
|
||||||
{
|
{
|
||||||
// Friendly fire is disabled
|
// Friendly fire is disabled
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super::DoTakeDamage(a_TDI);
|
if (super::DoTakeDamage(a_TDI))
|
||||||
|
{
|
||||||
// Any kind of damage adds food exhaustion
|
// Any kind of damage adds food exhaustion
|
||||||
AddFoodExhaustion(0.3f);
|
AddFoodExhaustion(0.3f);
|
||||||
|
|
||||||
SendHealth();
|
SendHealth();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -897,6 +899,7 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
|||||||
void cPlayer::Respawn(void)
|
void cPlayer::Respawn(void)
|
||||||
{
|
{
|
||||||
m_Health = GetMaxHealth();
|
m_Health = GetMaxHealth();
|
||||||
|
SetInvulnerableTicks(20);
|
||||||
|
|
||||||
// Reset food level:
|
// Reset food level:
|
||||||
m_FoodLevel = MAX_FOOD_LEVEL;
|
m_FoodLevel = MAX_FOOD_LEVEL;
|
||||||
|
@ -498,7 +498,7 @@ protected:
|
|||||||
virtual void Destroyed(void);
|
virtual void Destroyed(void);
|
||||||
|
|
||||||
/** Filters out damage for creative mode/friendly fire */
|
/** Filters out damage for creative mode/friendly fire */
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & TDI) override;
|
||||||
|
|
||||||
/** Stops players from burning in creative mode */
|
/** Stops players from burning in creative mode */
|
||||||
virtual void TickBurning(cChunk & a_Chunk) override;
|
virtual void TickBurning(cChunk & a_Chunk) override;
|
||||||
|
@ -4,15 +4,24 @@
|
|||||||
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
|
// Implements the cProjectileEntity class representing the common base class for projectiles, as well as individual projectile types
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
|
|
||||||
#include "../Bindings/PluginManager.h"
|
#include "../Bindings/PluginManager.h"
|
||||||
#include "ProjectileEntity.h"
|
#include "ProjectileEntity.h"
|
||||||
#include "../ClientHandle.h"
|
#include "../ClientHandle.h"
|
||||||
#include "Player.h"
|
|
||||||
#include "../LineBlockTracer.h"
|
#include "../LineBlockTracer.h"
|
||||||
#include "../BoundingBox.h"
|
#include "../BoundingBox.h"
|
||||||
#include "../ChunkMap.h"
|
#include "../ChunkMap.h"
|
||||||
#include "../Chunk.h"
|
#include "../Chunk.h"
|
||||||
|
|
||||||
|
#include "ArrowEntity.h"
|
||||||
|
#include "ThrownEggEntity.h"
|
||||||
|
#include "ThrownEnderPearlEntity.h"
|
||||||
|
#include "ExpBottleEntity.h"
|
||||||
|
#include "ThrownSnowballEntity.h"
|
||||||
|
#include "FireChargeEntity.h"
|
||||||
|
#include "FireworkEntity.h"
|
||||||
|
#include "GhastFireballEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -401,546 +410,3 @@ void cProjectileEntity::CollectedBy(cPlayer * a_Dest)
|
|||||||
// Overriden in arrow
|
// Overriden in arrow
|
||||||
UNUSED(a_Dest);
|
UNUSED(a_Dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cArrowEntity:
|
|
||||||
|
|
||||||
cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
|
||||||
super(pkArrow, a_Creator, a_X, a_Y, a_Z, 0.5, 0.5),
|
|
||||||
m_PickupState(psNoPickup),
|
|
||||||
m_DamageCoeff(2),
|
|
||||||
m_IsCritical(false),
|
|
||||||
m_Timer(0),
|
|
||||||
m_HitGroundTimer(0),
|
|
||||||
m_bIsCollected(false),
|
|
||||||
m_HitBlockPos(Vector3i(0, 0, 0))
|
|
||||||
{
|
|
||||||
SetSpeed(a_Speed);
|
|
||||||
SetMass(0.1);
|
|
||||||
SetYawFromSpeed();
|
|
||||||
SetPitchFromSpeed();
|
|
||||||
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
|
|
||||||
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
|
|
||||||
GetYaw(), GetPitch()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cArrowEntity::cArrowEntity(cPlayer & a_Player, double a_Force) :
|
|
||||||
super(pkArrow, &a_Player, a_Player.GetThrowStartPos(), a_Player.GetThrowSpeed(a_Force * 1.5 * 20), 0.5, 0.5),
|
|
||||||
m_PickupState(psInSurvivalOrCreative),
|
|
||||||
m_DamageCoeff(2),
|
|
||||||
m_IsCritical((a_Force >= 1)),
|
|
||||||
m_Timer(0),
|
|
||||||
m_HitGroundTimer(0),
|
|
||||||
m_HasTeleported(false),
|
|
||||||
m_bIsCollected(false),
|
|
||||||
m_HitBlockPos(0, 0, 0)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cArrowEntity::CanPickup(const cPlayer & a_Player) const
|
|
||||||
{
|
|
||||||
switch (m_PickupState)
|
|
||||||
{
|
|
||||||
case psNoPickup: return false;
|
|
||||||
case psInSurvivalOrCreative: return (a_Player.IsGameModeSurvival() || a_Player.IsGameModeCreative());
|
|
||||||
case psInCreative: return a_Player.IsGameModeCreative();
|
|
||||||
}
|
|
||||||
ASSERT(!"Unhandled pickup state");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cArrowEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
|
||||||
{
|
|
||||||
if (a_HitFace == BLOCK_FACE_NONE) { return; }
|
|
||||||
|
|
||||||
super::OnHitSolidBlock(a_HitPos, a_HitFace);
|
|
||||||
int a_X = (int)a_HitPos.x, a_Y = (int)a_HitPos.y, a_Z = (int)a_HitPos.z;
|
|
||||||
|
|
||||||
switch (a_HitFace)
|
|
||||||
{
|
|
||||||
case BLOCK_FACE_XM: // Strangely, bounding boxes / block tracers return the actual block for these two directions, so AddFace not needed
|
|
||||||
case BLOCK_FACE_YM:
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: AddFaceDirection(a_X, a_Y, a_Z, a_HitFace, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_HitBlockPos = Vector3i(a_X, a_Y, a_Z);
|
|
||||||
|
|
||||||
// Broadcast arrow hit sound
|
|
||||||
m_World->BroadcastSoundEffect("random.bowhit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5f, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cArrowEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
if (!a_EntityHit.IsMob() && !a_EntityHit.IsMinecart() && !a_EntityHit.IsPlayer() && !a_EntityHit.IsBoat())
|
|
||||||
{
|
|
||||||
// Not an entity that interacts with an arrow
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Damage = (int)(GetSpeed().Length() / 20 * m_DamageCoeff + 0.5);
|
|
||||||
if (m_IsCritical)
|
|
||||||
{
|
|
||||||
Damage += m_World->GetTickRandomNumber(Damage / 2 + 2);
|
|
||||||
}
|
|
||||||
a_EntityHit.TakeDamage(dtRangedAttack, this, Damage, 1);
|
|
||||||
|
|
||||||
// Broadcast successful hit sound
|
|
||||||
m_World->BroadcastSoundEffect("random.successful_hit", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
|
||||||
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cArrowEntity::CollectedBy(cPlayer * a_Dest)
|
|
||||||
{
|
|
||||||
if ((m_IsInGround) && (!m_bIsCollected) && (CanPickup(*a_Dest)))
|
|
||||||
{
|
|
||||||
int NumAdded = a_Dest->GetInventory().AddItem(E_ITEM_ARROW);
|
|
||||||
if (NumAdded > 0) // Only play effects if there was space in inventory
|
|
||||||
{
|
|
||||||
m_World->BroadcastCollectPickup((const cPickup &)*this, *a_Dest);
|
|
||||||
// Also send the "pop" sound effect with a somewhat random pitch (fast-random using EntityID ;)
|
|
||||||
m_World->BroadcastSoundEffect("random.pop", (int)GetPosX() * 8, (int)GetPosY() * 8, (int)GetPosZ() * 8, 0.5, (float)(0.75 + ((float)((GetUniqueID() * 23) % 32)) / 64));
|
|
||||||
m_bIsCollected = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cArrowEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
|
||||||
{
|
|
||||||
super::Tick(a_Dt, a_Chunk);
|
|
||||||
m_Timer += a_Dt;
|
|
||||||
|
|
||||||
if (m_bIsCollected)
|
|
||||||
{
|
|
||||||
if (m_Timer > 500.f) // 0.5 seconds
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (m_Timer > 1000 * 60 * 5) // 5 minutes
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_IsInGround)
|
|
||||||
{
|
|
||||||
// When an arrow hits, the client doesn't think its in the ground and keeps on moving, IF BroadcastMovementUpdate() and TeleportEntity was called during flight, AT ALL
|
|
||||||
// Fix is to simply not sync with the client and send a teleport to confirm pos after arrow has stabilised (around 1 sec after landing)
|
|
||||||
// We can afford to do this because xoft's algorithm for trajectory is near perfect, so things are pretty close anyway without sync
|
|
||||||
// Besides, this seems to be what the vanilla server does, note how arrows teleport half a second after they hit to the server position
|
|
||||||
|
|
||||||
if (!m_HasTeleported) // Sent a teleport already, don't do again
|
|
||||||
{
|
|
||||||
if (m_HitGroundTimer > 1000.f) // Send after a second, could be less, but just in case
|
|
||||||
{
|
|
||||||
m_World->BroadcastTeleportEntity(*this);
|
|
||||||
m_HasTeleported = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_HitGroundTimer += a_Dt;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int RelPosX = m_HitBlockPos.x - a_Chunk.GetPosX() * cChunkDef::Width;
|
|
||||||
int RelPosZ = m_HitBlockPos.z - a_Chunk.GetPosZ() * cChunkDef::Width;
|
|
||||||
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelPosX, RelPosZ);
|
|
||||||
|
|
||||||
if (Chunk == NULL)
|
|
||||||
{
|
|
||||||
// Inside an unloaded chunk, abort
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Chunk->GetBlock(RelPosX, m_HitBlockPos.y, RelPosZ) == E_BLOCK_AIR) // Block attached to was destroyed?
|
|
||||||
{
|
|
||||||
m_IsInGround = false; // Yes, begin simulating physics again
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cThrownEggEntity:
|
|
||||||
|
|
||||||
cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
|
||||||
super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
|
||||||
{
|
|
||||||
SetSpeed(a_Speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
|
||||||
{
|
|
||||||
TrySpawnChicken(a_HitPos);
|
|
||||||
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
int TotalDamage = 0;
|
|
||||||
// TODO: If entity is Ender Crystal, destroy it
|
|
||||||
|
|
||||||
TrySpawnChicken(a_HitPos);
|
|
||||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
|
||||||
|
|
||||||
Destroy(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
if (m_World->GetTickRandomNumber(7) == 1)
|
|
||||||
{
|
|
||||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
|
||||||
}
|
|
||||||
else if (m_World->GetTickRandomNumber(32) == 1)
|
|
||||||
{
|
|
||||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
|
||||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
|
||||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
|
||||||
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cThrownEnderPearlEntity :
|
|
||||||
|
|
||||||
cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
|
||||||
super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
|
||||||
{
|
|
||||||
SetSpeed(a_Speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
|
||||||
{
|
|
||||||
// TODO: Tweak a_HitPos based on block face.
|
|
||||||
TeleportCreator(a_HitPos);
|
|
||||||
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
int TotalDamage = 0;
|
|
||||||
// TODO: If entity is Ender Crystal, destroy it
|
|
||||||
|
|
||||||
TeleportCreator(a_HitPos);
|
|
||||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
|
||||||
|
|
||||||
Destroy(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
// Teleport the creator here, make them take 5 damage:
|
|
||||||
if (m_Creator != NULL)
|
|
||||||
{
|
|
||||||
m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
|
|
||||||
m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cThrownSnowballEntity :
|
|
||||||
|
|
||||||
cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
|
||||||
super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
|
||||||
{
|
|
||||||
SetSpeed(a_Speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
int TotalDamage = 0;
|
|
||||||
if (a_EntityHit.IsMob())
|
|
||||||
{
|
|
||||||
cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
|
|
||||||
if (MobType == cMonster::mtBlaze)
|
|
||||||
{
|
|
||||||
TotalDamage = 3;
|
|
||||||
}
|
|
||||||
else if (MobType == cMonster::mtEnderDragon)
|
|
||||||
{
|
|
||||||
TotalDamage = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// TODO: If entity is Ender Crystal, destroy it
|
|
||||||
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
|
||||||
|
|
||||||
Destroy(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cBottleOEnchantingEntity :
|
|
||||||
|
|
||||||
cExpBottleEntity::cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
|
||||||
super(pkExpBottle, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
|
||||||
{
|
|
||||||
SetSpeed(a_Speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cExpBottleEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
|
||||||
{
|
|
||||||
// Spawn an experience orb with a reward between 3 and 11.
|
|
||||||
m_World->BroadcastSoundParticleEffect(2002, POSX_TOINT, POSY_TOINT, POSZ_TOINT, 0);
|
|
||||||
m_World->SpawnExperienceOrb(GetPosX(), GetPosY(), GetPosZ(), 3 + m_World->GetTickRandomNumber(8));
|
|
||||||
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cFireworkEntity :
|
|
||||||
|
|
||||||
cFireworkEntity::cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item) :
|
|
||||||
super(pkFirework, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25),
|
|
||||||
m_ExplodeTimer(0),
|
|
||||||
m_FireworkItem(a_Item)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireworkEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
|
|
||||||
{
|
|
||||||
int RelX = POSX_TOINT - a_Chunk.GetPosX() * cChunkDef::Width;
|
|
||||||
int RelZ = POSZ_TOINT - a_Chunk.GetPosZ() * cChunkDef::Width;
|
|
||||||
int PosY = POSY_TOINT;
|
|
||||||
|
|
||||||
if ((PosY < 0) || (PosY >= cChunkDef::Height))
|
|
||||||
{
|
|
||||||
goto setspeed;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_IsInGround)
|
|
||||||
{
|
|
||||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) == E_BLOCK_AIR)
|
|
||||||
{
|
|
||||||
m_IsInGround = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (a_Chunk.GetBlock(RelX, POSY_TOINT + 1, RelZ) != E_BLOCK_AIR)
|
|
||||||
{
|
|
||||||
OnHitSolidBlock(GetPosition(), BLOCK_FACE_YM);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setspeed:
|
|
||||||
AddSpeedY(1);
|
|
||||||
AddPosition(GetSpeed() * (a_Dt / 1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireworkEntity::Tick(float a_Dt, cChunk & a_Chunk)
|
|
||||||
{
|
|
||||||
super::Tick(a_Dt, a_Chunk);
|
|
||||||
|
|
||||||
if (m_ExplodeTimer == m_FireworkItem.m_FireworkItem.m_FlightTimeInTicks)
|
|
||||||
{
|
|
||||||
m_World->BroadcastEntityStatus(*this, esFireworkExploding);
|
|
||||||
Destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_ExplodeTimer++;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cGhastFireballEntity :
|
|
||||||
|
|
||||||
cGhastFireballEntity::cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
|
||||||
super(pkGhastFireball, a_Creator, a_X, a_Y, a_Z, 1, 1)
|
|
||||||
{
|
|
||||||
SetSpeed(a_Speed);
|
|
||||||
SetGravity(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cGhastFireballEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
|
||||||
{
|
|
||||||
m_World->DoExplosionAt(1, a_BlockX, a_BlockY, a_BlockZ, true, esGhastFireball, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cGhastFireballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cGhastFireballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// cFireChargeEntity :
|
|
||||||
|
|
||||||
cFireChargeEntity::cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
|
||||||
super(pkFireCharge, a_Creator, a_X, a_Y, a_Z, 0.3125, 0.3125)
|
|
||||||
{
|
|
||||||
SetSpeed(a_Speed);
|
|
||||||
SetGravity(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireChargeEntity::Explode(int a_BlockX, int a_BlockY, int a_BlockZ)
|
|
||||||
{
|
|
||||||
if (m_World->GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_AIR)
|
|
||||||
{
|
|
||||||
m_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_FIRE, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireChargeEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cFireChargeEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
|
||||||
{
|
|
||||||
Destroy();
|
|
||||||
Explode((int)floor(a_HitPos.x), (int)floor(a_HitPos.y), (int)floor(a_HitPos.z));
|
|
||||||
|
|
||||||
// TODO: Some entities are immune to hits
|
|
||||||
a_EntityHit.StartBurning(5 * 20); // 5 seconds of burning
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -94,311 +94,4 @@ protected:
|
|||||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void SpawnOn(cClientHandle & a_Client) override;
|
virtual void SpawnOn(cClientHandle & a_Client) override;
|
||||||
|
|
||||||
// tolua_begin
|
} ; // tolua_export
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cArrowEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/// Determines when the arrow can be picked up (depending on player gamemode). Corresponds to the MCA file "pickup" field
|
|
||||||
enum ePickupState
|
|
||||||
{
|
|
||||||
psNoPickup = 0,
|
|
||||||
psInSurvivalOrCreative = 1,
|
|
||||||
psInCreative = 2,
|
|
||||||
} ;
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cArrowEntity);
|
|
||||||
|
|
||||||
/// Creates a new arrow with psNoPickup state and default damage modifier coeff
|
|
||||||
cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
|
||||||
|
|
||||||
/// Creates a new arrow as shot by a player, initializes it from the player object
|
|
||||||
cArrowEntity(cPlayer & a_Player, double a_Force);
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
/// Returns whether the arrow can be picked up by players
|
|
||||||
ePickupState GetPickupState(void) const { return m_PickupState; }
|
|
||||||
|
|
||||||
/// Sets a new pickup state
|
|
||||||
void SetPickupState(ePickupState a_PickupState) { m_PickupState = a_PickupState; }
|
|
||||||
|
|
||||||
/// Returns the damage modifier coeff.
|
|
||||||
double GetDamageCoeff(void) const { return m_DamageCoeff; }
|
|
||||||
|
|
||||||
/// Sets the damage modifier coeff
|
|
||||||
void SetDamageCoeff(double a_DamageCoeff) { m_DamageCoeff = a_DamageCoeff; }
|
|
||||||
|
|
||||||
/// Returns true if the specified player can pick the arrow up
|
|
||||||
bool CanPickup(const cPlayer & a_Player) const;
|
|
||||||
|
|
||||||
/// Returns true if the arrow is set as critical
|
|
||||||
bool IsCritical(void) const { return m_IsCritical; }
|
|
||||||
|
|
||||||
/// Sets the IsCritical flag
|
|
||||||
void SetIsCritical(bool a_IsCritical) { m_IsCritical = a_IsCritical; }
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/// Determines when the arrow can be picked up by players
|
|
||||||
ePickupState m_PickupState;
|
|
||||||
|
|
||||||
/// The coefficient applied to the damage that the arrow will deal, based on the bow enchantment. 2.0 for normal arrow
|
|
||||||
double m_DamageCoeff;
|
|
||||||
|
|
||||||
/// If true, the arrow deals more damage
|
|
||||||
bool m_IsCritical;
|
|
||||||
|
|
||||||
/// Timer for pickup collection animation or five minute timeout
|
|
||||||
float m_Timer;
|
|
||||||
|
|
||||||
/// Timer for client arrow position confirmation via TeleportEntity
|
|
||||||
float m_HitGroundTimer;
|
|
||||||
|
|
||||||
// Whether the arrow has already been teleported into the proper position in the ground.
|
|
||||||
bool m_HasTeleported;
|
|
||||||
|
|
||||||
/// If true, the arrow is in the process of being collected - don't go to anyone else
|
|
||||||
bool m_bIsCollected;
|
|
||||||
|
|
||||||
/// Stores the block position that arrow is lodged into, sets m_IsInGround to false if it becomes air
|
|
||||||
Vector3i m_HitBlockPos;
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
|
||||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
|
||||||
virtual void CollectedBy(cPlayer * a_Player) override;
|
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cThrownEggEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cThrownEggEntity);
|
|
||||||
|
|
||||||
cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
|
||||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
|
||||||
|
|
||||||
// Randomly decides whether to spawn a chicken where the egg lands.
|
|
||||||
void TrySpawnChicken(const Vector3d & a_HitPos);
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cThrownEnderPearlEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cThrownEnderPearlEntity);
|
|
||||||
|
|
||||||
cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
|
||||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
|
||||||
|
|
||||||
// Teleports the creator where the ender pearl lands.
|
|
||||||
void TeleportCreator(const Vector3d & a_HitPos);
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cThrownSnowballEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cThrownSnowballEntity);
|
|
||||||
|
|
||||||
cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
|
||||||
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cExpBottleEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cExpBottleEntity);
|
|
||||||
|
|
||||||
cExpBottleEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cFireworkEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cFireworkEntity);
|
|
||||||
|
|
||||||
cFireworkEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const cItem & a_Item);
|
|
||||||
const cItem & GetItem(void) const { return m_FireworkItem; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
|
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
int m_ExplodeTimer;
|
|
||||||
cItem m_FireworkItem;
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cGhastFireballEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cGhastFireballEntity);
|
|
||||||
|
|
||||||
cGhastFireballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
|
||||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
|
||||||
|
|
||||||
// TODO: Deflecting the fireballs by arrow- or sword- hits
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cFireChargeEntity :
|
|
||||||
public cProjectileEntity
|
|
||||||
{
|
|
||||||
typedef cProjectileEntity super;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
CLASS_PROTODEF(cFireChargeEntity);
|
|
||||||
|
|
||||||
cFireChargeEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
void Explode(int a_BlockX, int a_BlockY, int a_BlockZ);
|
|
||||||
|
|
||||||
// cProjectileEntity overrides:
|
|
||||||
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
|
||||||
virtual void OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
|
||||||
|
|
||||||
// tolua_begin
|
|
||||||
|
|
||||||
} ;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// tolua_end
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
59
src/Entities/ThrownEggEntity.cpp
Normal file
59
src/Entities/ThrownEggEntity.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "ThrownEggEntity.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
|
super(pkEgg, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||||
|
{
|
||||||
|
SetSpeed(a_Speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
|
{
|
||||||
|
TrySpawnChicken(a_HitPos);
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownEggEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
int TotalDamage = 0;
|
||||||
|
// TODO: If entity is Ender Crystal, destroy it
|
||||||
|
|
||||||
|
TrySpawnChicken(a_HitPos);
|
||||||
|
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||||
|
|
||||||
|
Destroy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownEggEntity::TrySpawnChicken(const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
if (m_World->GetTickRandomNumber(7) == 1)
|
||||||
|
{
|
||||||
|
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||||
|
}
|
||||||
|
else if (m_World->GetTickRandomNumber(32) == 1)
|
||||||
|
{
|
||||||
|
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||||
|
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||||
|
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||||
|
m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken);
|
||||||
|
}
|
||||||
|
}
|
37
src/Entities/ThrownEggEntity.h
Normal file
37
src/Entities/ThrownEggEntity.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// ThrownEggEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cThrownEggEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cThrownEggEntity);
|
||||||
|
|
||||||
|
cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
|
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
|
||||||
|
// Randomly decides whether to spawn a chicken where the egg lands.
|
||||||
|
void TrySpawnChicken(const Vector3d & a_HitPos);
|
||||||
|
|
||||||
|
} ; // tolua_export
|
54
src/Entities/ThrownEnderPearlEntity.cpp
Normal file
54
src/Entities/ThrownEnderPearlEntity.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "ThrownEnderPearlEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cThrownEnderPearlEntity::cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
|
super(pkEnderPearl, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||||
|
{
|
||||||
|
SetSpeed(a_Speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownEnderPearlEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
|
{
|
||||||
|
// TODO: Tweak a_HitPos based on block face.
|
||||||
|
TeleportCreator(a_HitPos);
|
||||||
|
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownEnderPearlEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
int TotalDamage = 0;
|
||||||
|
// TODO: If entity is Ender Crystal, destroy it
|
||||||
|
|
||||||
|
TeleportCreator(a_HitPos);
|
||||||
|
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||||
|
|
||||||
|
Destroy(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
// Teleport the creator here, make them take 5 damage:
|
||||||
|
if (m_Creator != NULL)
|
||||||
|
{
|
||||||
|
m_Creator->TeleportToCoords(a_HitPos.x + 0.5, a_HitPos.y + 1.7, a_HitPos.z + 0.5);
|
||||||
|
m_Creator->TakeDamage(dtEnderPearl, this, 5, 0);
|
||||||
|
}
|
||||||
|
}
|
37
src/Entities/ThrownEnderPearlEntity.h
Normal file
37
src/Entities/ThrownEnderPearlEntity.h
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// ThrownEnderPearlEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cThrownEnderPearlEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cThrownEnderPearlEntity);
|
||||||
|
|
||||||
|
cThrownEnderPearlEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
|
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
|
||||||
|
// Teleports the creator where the ender pearl lands.
|
||||||
|
void TeleportCreator(const Vector3d & a_HitPos);
|
||||||
|
|
||||||
|
} ; // tolua_export
|
48
src/Entities/ThrownSnowballEntity.cpp
Normal file
48
src/Entities/ThrownSnowballEntity.cpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
||||||
|
|
||||||
|
#include "ThrownSnowballEntity.h"
|
||||||
|
#include "../World.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cThrownSnowballEntity::cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed) :
|
||||||
|
super(pkSnowball, a_Creator, a_X, a_Y, a_Z, 0.25, 0.25)
|
||||||
|
{
|
||||||
|
SetSpeed(a_Speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownSnowballEntity::OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace)
|
||||||
|
{
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cThrownSnowballEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_HitPos)
|
||||||
|
{
|
||||||
|
int TotalDamage = 0;
|
||||||
|
if (a_EntityHit.IsMob())
|
||||||
|
{
|
||||||
|
cMonster::eType MobType = ((cMonster &) a_EntityHit).GetMobType();
|
||||||
|
if (MobType == cMonster::mtBlaze)
|
||||||
|
{
|
||||||
|
TotalDamage = 3;
|
||||||
|
}
|
||||||
|
else if (MobType == cMonster::mtEnderDragon)
|
||||||
|
{
|
||||||
|
TotalDamage = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: If entity is Ender Crystal, destroy it
|
||||||
|
a_EntityHit.TakeDamage(dtRangedAttack, this, TotalDamage, 1);
|
||||||
|
|
||||||
|
Destroy(true);
|
||||||
|
}
|
34
src/Entities/ThrownSnowballEntity.h
Normal file
34
src/Entities/ThrownSnowballEntity.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
//
|
||||||
|
// ThrownSnowballEntity.h
|
||||||
|
//
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ProjectileEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// tolua_begin
|
||||||
|
|
||||||
|
class cThrownSnowballEntity :
|
||||||
|
public cProjectileEntity
|
||||||
|
{
|
||||||
|
typedef cProjectileEntity super;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// tolua_end
|
||||||
|
|
||||||
|
CLASS_PROTODEF(cThrownSnowballEntity);
|
||||||
|
|
||||||
|
cThrownSnowballEntity(cEntity * a_Creator, double a_X, double a_Y, double a_Z, const Vector3d & a_Speed);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// cProjectileEntity overrides:
|
||||||
|
virtual void OnHitSolidBlock(const Vector3d & a_HitPos, eBlockFace a_HitFace) override;
|
||||||
|
virtual void OnHitEntity (cEntity & a_EntityHit, const Vector3d & a_HitPos) override;
|
||||||
|
|
||||||
|
} ; // tolua_export
|
@ -91,7 +91,8 @@ int cFastRandom::m_SeedCounter = 0;
|
|||||||
|
|
||||||
|
|
||||||
cFastRandom::cFastRandom(void) :
|
cFastRandom::cFastRandom(void) :
|
||||||
m_Seed(m_SeedCounter++)
|
m_Seed(m_SeedCounter++),
|
||||||
|
m_Counter(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ void cPrefab::ParseCharMap(CharMap & a_CharMapOut, const char * a_CharMapDef)
|
|||||||
if ((NumElements >= 3) && !CharDef[2].empty())
|
if ((NumElements >= 3) && !CharDef[2].empty())
|
||||||
{
|
{
|
||||||
BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
|
BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
|
||||||
ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
|
ASSERT((BlockMeta <= 15));
|
||||||
}
|
}
|
||||||
a_CharMapOut[Src].m_BlockMeta = BlockMeta;
|
a_CharMapOut[Src].m_BlockMeta = BlockMeta;
|
||||||
} // for itr - Lines[]
|
} // for itr - Lines[]
|
||||||
|
@ -267,6 +267,20 @@ template class SizeChecker<UInt16, 2>;
|
|||||||
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Allow both Older versions of MSVC and newer versions of everything use a shared_ptr:
|
||||||
|
// Note that we cannot typedef, because C++ doesn't allow (partial) templates to be typedeffed.
|
||||||
|
#if (defined(_MSC_VER) && (_MSC_VER < 1600))
|
||||||
|
// MSVC before 2010 doesn't have std::shared_ptr, but has std::tr1::shared_ptr, defined in <memory> included earlier
|
||||||
|
#define SharedPtr std::tr1::shared_ptr
|
||||||
|
#elif (defined(_MSC_VER) || (__cplusplus >= 201103L))
|
||||||
|
// C++11 has std::shared_ptr in <memory>, included earlier
|
||||||
|
#define SharedPtr std::shared_ptr
|
||||||
|
#else
|
||||||
|
// C++03 has std::tr1::shared_ptr in <tr1/memory>
|
||||||
|
#include <tr1/memory>
|
||||||
|
#define SharedPtr std::tr1::shared_ptr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,7 +64,7 @@ public:
|
|||||||
{
|
{
|
||||||
if (!IsValidItem(m_ItemType))
|
if (!IsValidItem(m_ItemType))
|
||||||
{
|
{
|
||||||
if (m_ItemType != E_BLOCK_AIR)
|
if ((m_ItemType != E_BLOCK_AIR) && (m_ItemType != E_ITEM_EMPTY))
|
||||||
{
|
{
|
||||||
LOGWARNING("%s: creating an invalid item type (%d), resetting to empty.", __FUNCTION__, a_ItemType);
|
LOGWARNING("%s: creating an invalid item type (%d), resetting to empty.", __FUNCTION__, a_ItemType);
|
||||||
}
|
}
|
||||||
@ -73,6 +73,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// The constructor is disabled in code, because the compiler generates it anyway,
|
||||||
|
// but it needs to stay because ToLua needs to generate the binding for it
|
||||||
|
#if 0
|
||||||
|
|
||||||
/** Creates an exact copy of the item */
|
/** Creates an exact copy of the item */
|
||||||
cItem(const cItem & a_CopyFrom) :
|
cItem(const cItem & a_CopyFrom) :
|
||||||
m_ItemType (a_CopyFrom.m_ItemType),
|
m_ItemType (a_CopyFrom.m_ItemType),
|
||||||
@ -85,6 +89,8 @@ public:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
void Empty(void)
|
void Empty(void)
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../Entities/ProjectileEntity.h"
|
#include "../Entities/ArrowEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +33,10 @@ public:
|
|||||||
a_BlockY--;
|
a_BlockY--;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, (cMonster::eType)(a_Item.m_ItemDamage)) >= 0)
|
cMonster::eType MonsterType = ItemDamageToMonsterType(a_Item.m_ItemDamage);
|
||||||
|
if (
|
||||||
|
(MonsterType != cMonster::mtInvalidType) && // Valid monster type
|
||||||
|
(a_World->SpawnMob(a_BlockX + 0.5, a_BlockY, a_BlockZ + 0.5, MonsterType) >= 0)) // Spawning succeeded
|
||||||
{
|
{
|
||||||
if (!a_Player->IsGameModeCreative())
|
if (!a_Player->IsGameModeCreative())
|
||||||
{
|
{
|
||||||
@ -45,6 +48,41 @@ public:
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Converts the Spawn egg item damage to the monster type to spawn.
|
||||||
|
Returns mtInvalidType for invalid damage values. */
|
||||||
|
static cMonster::eType ItemDamageToMonsterType(short a_ItemDamage)
|
||||||
|
{
|
||||||
|
switch (a_ItemDamage)
|
||||||
|
{
|
||||||
|
case E_META_SPAWN_EGG_BAT: return cMonster::mtBat;
|
||||||
|
case E_META_SPAWN_EGG_BLAZE: return cMonster::mtBlaze;
|
||||||
|
case E_META_SPAWN_EGG_CAVE_SPIDER: return cMonster::mtCaveSpider;
|
||||||
|
case E_META_SPAWN_EGG_CHICKEN: return cMonster::mtChicken;
|
||||||
|
case E_META_SPAWN_EGG_COW: return cMonster::mtCow;
|
||||||
|
case E_META_SPAWN_EGG_CREEPER: return cMonster::mtCreeper;
|
||||||
|
case E_META_SPAWN_EGG_ENDERMAN: return cMonster::mtEnderman;
|
||||||
|
case E_META_SPAWN_EGG_GHAST: return cMonster::mtGhast;
|
||||||
|
case E_META_SPAWN_EGG_HORSE: return cMonster::mtHorse;
|
||||||
|
case E_META_SPAWN_EGG_MAGMA_CUBE: return cMonster::mtMagmaCube;
|
||||||
|
case E_META_SPAWN_EGG_MOOSHROOM: return cMonster::mtMooshroom;
|
||||||
|
case E_META_SPAWN_EGG_OCELOT: return cMonster::mtOcelot;
|
||||||
|
case E_META_SPAWN_EGG_PIG: return cMonster::mtPig;
|
||||||
|
case E_META_SPAWN_EGG_SHEEP: return cMonster::mtSheep;
|
||||||
|
case E_META_SPAWN_EGG_SILVERFISH: return cMonster::mtSilverfish;
|
||||||
|
case E_META_SPAWN_EGG_SKELETON: return cMonster::mtSkeleton;
|
||||||
|
case E_META_SPAWN_EGG_SLIME: return cMonster::mtSlime;
|
||||||
|
case E_META_SPAWN_EGG_SPIDER: return cMonster::mtSpider;
|
||||||
|
case E_META_SPAWN_EGG_SQUID: return cMonster::mtSquid;
|
||||||
|
case E_META_SPAWN_EGG_VILLAGER: return cMonster::mtVillager;
|
||||||
|
case E_META_SPAWN_EGG_WITCH: return cMonster::mtWitch;
|
||||||
|
case E_META_SPAWN_EGG_WOLF: return cMonster::mtWolf;
|
||||||
|
case E_META_SPAWN_EGG_ZOMBIE: return cMonster::mtZombie;
|
||||||
|
case E_META_SPAWN_EGG_ZOMBIE_PIGMAN: return cMonster::mtZombiePigman;
|
||||||
|
}
|
||||||
|
return cMonster::mtInvalidType;
|
||||||
|
}
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Blaze.h"
|
#include "Blaze.h"
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
|
#include "../Entities/FireChargeEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,9 +75,12 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
super::DoTakeDamage(a_TDI);
|
if (!super::DoTakeDamage(a_TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (a_TDI.DamageType == dtLightning)
|
if (a_TDI.DamageType == dtLightning)
|
||||||
{
|
{
|
||||||
@ -85,6 +88,7 @@ void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_World->BroadcastEntityMetadata(*this);
|
m_World->BroadcastEntityMetadata(*this);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public:
|
|||||||
CLASS_PROTODEF(cCreeper);
|
CLASS_PROTODEF(cCreeper);
|
||||||
|
|
||||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
virtual void Attack(float a_Dt) override;
|
virtual void Attack(float a_Dt) override;
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Ghast.h"
|
#include "Ghast.h"
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
|
#include "../Entities/GhastFireballEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -457,9 +457,12 @@ int cMonster::FindFirstNonAirBlockPosition(double a_PosX, double a_PosZ)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
super::DoTakeDamage(a_TDI);
|
if (!super::DoTakeDamage(a_TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if((m_SoundHurt != "") && (m_Health > 0))
|
if((m_SoundHurt != "") && (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);
|
||||||
@ -468,6 +471,7 @@ void cMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
{
|
{
|
||||||
m_Target = a_TDI.Attacker;
|
m_Target = a_TDI.Attacker;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -823,6 +827,10 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
|
|||||||
switch (a_MobType)
|
switch (a_MobType)
|
||||||
{
|
{
|
||||||
case mtMagmaCube:
|
case mtMagmaCube:
|
||||||
|
{
|
||||||
|
toReturn = new cMagmaCube(Random.NextInt(2) + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case mtSlime:
|
case mtSlime:
|
||||||
{
|
{
|
||||||
toReturn = new cSlime(Random.NextInt(2) + 1);
|
toReturn = new cSlime(Random.NextInt(2) + 1);
|
||||||
|
@ -88,7 +88,7 @@ public:
|
|||||||
|
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
|
|
||||||
virtual void KilledBy(cEntity * a_Killer) override;
|
virtual void KilledBy(cEntity * a_Killer) override;
|
||||||
|
|
||||||
|
@ -19,9 +19,12 @@ cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigNam
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
super::DoTakeDamage(a_TDI);
|
if (!super::DoTakeDamage(a_TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((m_Target != NULL) && (m_Target->IsPlayer()))
|
if ((m_Target != NULL) && (m_Target->IsPlayer()))
|
||||||
{
|
{
|
||||||
@ -30,6 +33,7 @@ void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
m_EMState = CHASING;
|
m_EMState = CHASING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ class cPassiveAggressiveMonster :
|
|||||||
public:
|
public:
|
||||||
cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
|
cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height);
|
||||||
|
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,13 +18,17 @@ cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cPassiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
super::DoTakeDamage(a_TDI);
|
if (!super::DoTakeDamage(a_TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL))
|
if ((a_TDI.Attacker != this) && (a_TDI.Attacker != NULL))
|
||||||
{
|
{
|
||||||
m_EMState = ESCAPING;
|
m_EMState = ESCAPING;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public:
|
|||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
/// When hit by someone, run away
|
/// When hit by someone, run away
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
/** Returns the item that the animal of this class follows when a player holds it in hand
|
/** Returns the item that the animal of this class follows when a player holds it in hand
|
||||||
Return an empty item not to follow (default). */
|
Return an empty item not to follow (default). */
|
||||||
virtual const cItem GetFollowedItem(void) const { return cItem(); }
|
virtual const cItem GetFollowedItem(void) const { return cItem(); }
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "Skeleton.h"
|
#include "Skeleton.h"
|
||||||
#include "../World.h"
|
#include "../World.h"
|
||||||
|
#include "../Entities/ArrowEntity.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -23,9 +23,13 @@ cVillager::cVillager(eVillagerType VillagerType) :
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
super::DoTakeDamage(a_TDI);
|
if (!super::DoTakeDamage(a_TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer())
|
if ((a_TDI.Attacker != NULL) && a_TDI.Attacker->IsPlayer())
|
||||||
{
|
{
|
||||||
if (m_World->GetTickRandomNumber(5) == 3)
|
if (m_World->GetTickRandomNumber(5) == 3)
|
||||||
@ -33,6 +37,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
|||||||
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
|
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ public:
|
|||||||
CLASS_PROTODEF(cVillager);
|
CLASS_PROTODEF(cVillager);
|
||||||
|
|
||||||
// cEntity overrides
|
// cEntity overrides
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick (float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
// cVillager functions
|
// cVillager functions
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
cWither::cWither(void) :
|
cWither::cWither(void) :
|
||||||
super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
|
super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
|
||||||
m_InvulnerableTicks(220)
|
m_WitherInvulnerableTicks(220)
|
||||||
{
|
{
|
||||||
SetMaxHealth(300);
|
SetMaxHealth(300);
|
||||||
}
|
}
|
||||||
@ -40,24 +40,24 @@ bool cWither::Initialize(cWorld * a_World)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cWither::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
if (a_TDI.DamageType == dtDrowning)
|
if (a_TDI.DamageType == dtDrowning)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_InvulnerableTicks > 0)
|
if (m_WitherInvulnerableTicks > 0)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
|
if (IsArmored() && (a_TDI.DamageType == dtRangedAttack))
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
super::DoTakeDamage(a_TDI);
|
return super::DoTakeDamage(a_TDI);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -68,16 +68,16 @@ void cWither::Tick(float a_Dt, cChunk & a_Chunk)
|
|||||||
{
|
{
|
||||||
super::Tick(a_Dt, a_Chunk);
|
super::Tick(a_Dt, a_Chunk);
|
||||||
|
|
||||||
if (m_InvulnerableTicks > 0)
|
if (m_WitherInvulnerableTicks > 0)
|
||||||
{
|
{
|
||||||
unsigned int NewTicks = m_InvulnerableTicks - 1;
|
unsigned int NewTicks = m_WitherInvulnerableTicks - 1;
|
||||||
|
|
||||||
if (NewTicks == 0)
|
if (NewTicks == 0)
|
||||||
{
|
{
|
||||||
m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
|
m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_InvulnerableTicks = NewTicks;
|
m_WitherInvulnerableTicks = NewTicks;
|
||||||
|
|
||||||
if ((NewTicks % 10) == 0)
|
if ((NewTicks % 10) == 0)
|
||||||
{
|
{
|
||||||
|
@ -17,9 +17,9 @@ public:
|
|||||||
|
|
||||||
CLASS_PROTODEF(cWither);
|
CLASS_PROTODEF(cWither);
|
||||||
|
|
||||||
unsigned int GetNumInvulnerableTicks(void) const { return m_InvulnerableTicks; }
|
unsigned int GetWitherInvulnerableTicks(void) const { return m_WitherInvulnerableTicks; }
|
||||||
|
|
||||||
void SetNumInvulnerableTicks(unsigned int a_Ticks) { m_InvulnerableTicks = a_Ticks; }
|
void SetWitherInvulnerableTicks(unsigned int a_Ticks) { m_WitherInvulnerableTicks = a_Ticks; }
|
||||||
|
|
||||||
/** Returns whether the wither is invulnerable to arrows. */
|
/** Returns whether the wither is invulnerable to arrows. */
|
||||||
bool IsArmored(void) const;
|
bool IsArmored(void) const;
|
||||||
@ -27,13 +27,13 @@ public:
|
|||||||
// cEntity overrides
|
// cEntity overrides
|
||||||
virtual bool Initialize(cWorld * a_World) override;
|
virtual bool Initialize(cWorld * a_World) override;
|
||||||
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override;
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
|
/** The number of ticks of invulnerability left after being initially created. Zero once invulnerability has expired. */
|
||||||
unsigned int m_InvulnerableTicks;
|
unsigned int m_WitherInvulnerableTicks;
|
||||||
|
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
@ -25,14 +25,19 @@ cWolf::cWolf(void) :
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
|
bool cWolf::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||||
{
|
{
|
||||||
super::DoTakeDamage(a_TDI);
|
if (super::DoTakeDamage(a_TDI))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_IsTame)
|
if (!m_IsTame)
|
||||||
{
|
{
|
||||||
m_IsAngry = true;
|
m_IsAngry = true;
|
||||||
}
|
}
|
||||||
m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
|
m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -18,7 +18,7 @@ public:
|
|||||||
|
|
||||||
CLASS_PROTODEF(cWolf);
|
CLASS_PROTODEF(cWolf);
|
||||||
|
|
||||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
virtual bool DoTakeDamage(TakeDamageInfo & a_TDI) override;
|
||||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||||
virtual void TickFollowPlayer();
|
virtual void TickFollowPlayer();
|
||||||
|
@ -608,6 +608,8 @@ void cCubicNoise::Generate2D(
|
|||||||
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction
|
NOISE_DATATYPE a_StartY, NOISE_DATATYPE a_EndY ///< Noise-space coords of the array in the Y direction
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
|
ASSERT(a_SizeX > 0);
|
||||||
|
ASSERT(a_SizeY > 0);
|
||||||
ASSERT(a_SizeX < MAX_SIZE);
|
ASSERT(a_SizeX < MAX_SIZE);
|
||||||
ASSERT(a_SizeY < MAX_SIZE);
|
ASSERT(a_SizeY < MAX_SIZE);
|
||||||
ASSERT(a_StartX < a_EndX);
|
ASSERT(a_StartX < a_EndX);
|
||||||
@ -744,6 +746,8 @@ void cCubicNoise::CalcFloorFrac(
|
|||||||
int * a_Same, int & a_NumSame
|
int * a_Same, int & a_NumSame
|
||||||
) const
|
) const
|
||||||
{
|
{
|
||||||
|
ASSERT(a_Size > 0);
|
||||||
|
|
||||||
NOISE_DATATYPE val = a_Start;
|
NOISE_DATATYPE val = a_Start;
|
||||||
NOISE_DATATYPE dif = (a_End - a_Start) / (a_Size - 1);
|
NOISE_DATATYPE dif = (a_End - a_Start) / (a_Size - 1);
|
||||||
for (int i = 0; i < a_Size; i++)
|
for (int i = 0; i < a_Size; i++)
|
||||||
|
@ -280,7 +280,7 @@ NOISE_DATATYPE cNoise::CubicInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B,
|
|||||||
NOISE_DATATYPE cNoise::CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct)
|
NOISE_DATATYPE cNoise::CosineInterpolate(NOISE_DATATYPE a_A, NOISE_DATATYPE a_B, NOISE_DATATYPE a_Pct)
|
||||||
{
|
{
|
||||||
const NOISE_DATATYPE ft = a_Pct * (NOISE_DATATYPE)3.1415927;
|
const NOISE_DATATYPE ft = a_Pct * (NOISE_DATATYPE)3.1415927;
|
||||||
const NOISE_DATATYPE f = (1 - cos(ft)) * (NOISE_DATATYPE)0.5;
|
const NOISE_DATATYPE f = (NOISE_DATATYPE)((NOISE_DATATYPE)(1 - cos(ft)) * (NOISE_DATATYPE)0.5);
|
||||||
return a_A * (1 - f) + a_B * f;
|
return a_A * (1 - f) + a_B * f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,142 +0,0 @@
|
|||||||
|
|
||||||
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
|
|
||||||
|
|
||||||
#include "BlockingTCPLink.h"
|
|
||||||
#include "Errors.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cBlockingTCPLink::cBlockingTCPLink(void)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
cBlockingTCPLink::~cBlockingTCPLink()
|
|
||||||
{
|
|
||||||
CloseSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cBlockingTCPLink::CloseSocket()
|
|
||||||
{
|
|
||||||
if (!m_Socket.IsValid())
|
|
||||||
{
|
|
||||||
m_Socket.CloseSocket();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cBlockingTCPLink::Connect(const char * iAddress, unsigned int iPort)
|
|
||||||
{
|
|
||||||
ASSERT(!m_Socket.IsValid());
|
|
||||||
if (m_Socket.IsValid())
|
|
||||||
{
|
|
||||||
LOGWARN("WARNING: cTCPLink Connect() called while still connected.");
|
|
||||||
m_Socket.CloseSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct hostent *hp;
|
|
||||||
unsigned int addr;
|
|
||||||
struct sockaddr_in server;
|
|
||||||
|
|
||||||
m_Socket = socket(AF_INET, SOCK_STREAM, 0);
|
|
||||||
if (!m_Socket.IsValid())
|
|
||||||
{
|
|
||||||
LOGERROR("cTCPLink: Cannot create a socket");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
addr = inet_addr(iAddress);
|
|
||||||
hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
|
|
||||||
if (hp == NULL)
|
|
||||||
{
|
|
||||||
//LOGWARN("cTCPLink: gethostbyaddr returned NULL");
|
|
||||||
hp = gethostbyname(iAddress);
|
|
||||||
if (hp == NULL)
|
|
||||||
{
|
|
||||||
LOGWARN("cTCPLink: Could not resolve %s", iAddress);
|
|
||||||
CloseSocket();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(&server.sin_addr.s_addr,hp->h_addr, hp->h_length);
|
|
||||||
server.sin_family = AF_INET;
|
|
||||||
server.sin_port = htons( (unsigned short)iPort);
|
|
||||||
if (connect(m_Socket, (struct sockaddr *)&server, sizeof(server)))
|
|
||||||
{
|
|
||||||
LOGWARN("cTCPLink: Connection to \"%s:%d\" failed (%s)", iAddress, iPort,GetOSErrorString( cSocket::GetLastError() ).c_str() );
|
|
||||||
CloseSocket();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cBlockingTCPLink::Send(char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
|
|
||||||
{
|
|
||||||
UNUSED(a_Flags);
|
|
||||||
|
|
||||||
ASSERT(m_Socket.IsValid());
|
|
||||||
if (!m_Socket.IsValid())
|
|
||||||
{
|
|
||||||
LOGERROR("cBlockingTCPLink: Trying to send data without a valid connection!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return m_Socket.Send(a_Data, a_Size);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ )
|
|
||||||
{
|
|
||||||
UNUSED(a_Flags);
|
|
||||||
|
|
||||||
ASSERT(m_Socket.IsValid());
|
|
||||||
if (!m_Socket.IsValid())
|
|
||||||
{
|
|
||||||
LOGWARN("cBlockingTCPLink: Trying to send message without a valid connection!");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return m_Socket.Send(a_Message, strlen(a_Message));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cBlockingTCPLink::ReceiveData(AString & oData)
|
|
||||||
{
|
|
||||||
ASSERT(m_Socket.IsValid());
|
|
||||||
if (!m_Socket.IsValid())
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Received = 0;
|
|
||||||
char Buffer[256];
|
|
||||||
while ((Received = recv(m_Socket, Buffer, sizeof(Buffer), 0)) > 0)
|
|
||||||
{
|
|
||||||
oData.append(Buffer, Received);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
|||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Socket.h"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class cBlockingTCPLink // tolua_export
|
|
||||||
{ // tolua_export
|
|
||||||
public: // tolua_export
|
|
||||||
cBlockingTCPLink(void); // tolua_export
|
|
||||||
~cBlockingTCPLink(); // tolua_export
|
|
||||||
|
|
||||||
bool Connect( const char* a_Address, unsigned int a_Port ); // tolua_export
|
|
||||||
int Send( char* a_Data, unsigned int a_Size, int a_Flags = 0 ); // tolua_export
|
|
||||||
int SendMessage( const char* a_Message, int a_Flags = 0 ); // tolua_export
|
|
||||||
void CloseSocket(); // tolua_export
|
|
||||||
void ReceiveData(AString & oData); // tolua_export
|
|
||||||
protected:
|
|
||||||
|
|
||||||
cSocket m_Socket;
|
|
||||||
}; // tolua_export
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -75,7 +75,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), Mode);
|
m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), Mode, _SH_DENYWR);
|
||||||
#else
|
#else
|
||||||
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode);
|
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode);
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@ -88,7 +88,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
|
|||||||
// Simply re-open for read-writing, erasing existing contents:
|
// Simply re-open for read-writing, erasing existing contents:
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), "wb+");
|
m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+", _SH_DENYWR);
|
||||||
#else
|
#else
|
||||||
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+");
|
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+");
|
||||||
#endif // _WIN32
|
#endif // _WIN32
|
||||||
@ -143,7 +143,7 @@ bool cFile::IsEOF(void) const
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cFile::Read (void * iBuffer, int iNumBytes)
|
int cFile::Read (void * iBuffer, size_t iNumBytes)
|
||||||
{
|
{
|
||||||
ASSERT(IsOpen());
|
ASSERT(IsOpen());
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ int cFile::Read (void * iBuffer, int iNumBytes)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
int cFile::Write(const void * iBuffer, int iNumBytes)
|
int cFile::Write(const void * iBuffer, size_t iNumBytes)
|
||||||
{
|
{
|
||||||
ASSERT(IsOpen());
|
ASSERT(IsOpen());
|
||||||
|
|
||||||
|
@ -80,10 +80,10 @@ public:
|
|||||||
bool IsEOF(void) const;
|
bool IsEOF(void) const;
|
||||||
|
|
||||||
/** Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open */
|
/** Reads up to iNumBytes bytes into iBuffer, returns the number of bytes actually read, or -1 on failure; asserts if not open */
|
||||||
int Read (void * iBuffer, int iNumBytes);
|
int Read (void * iBuffer, size_t iNumBytes);
|
||||||
|
|
||||||
/** Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */
|
/** Writes up to iNumBytes bytes from iBuffer, returns the number of bytes actually written, or -1 on failure; asserts if not open */
|
||||||
int Write(const void * iBuffer, int iNumBytes);
|
int Write(const void * iBuffer, size_t iNumBytes);
|
||||||
|
|
||||||
/** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */
|
/** Seeks to iPosition bytes from file start, returns old position or -1 for failure; asserts if not open */
|
||||||
int Seek (int iPosition);
|
int Seek (int iPosition);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
|
|
||||||
cGZipFile::cGZipFile(void) :
|
cGZipFile::cGZipFile(void) :
|
||||||
m_File(NULL)
|
m_File(NULL), m_Mode(fmRead)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -295,7 +295,7 @@ bool cSocket::ConnectToLocalhostIPv4(unsigned short a_Port)
|
|||||||
|
|
||||||
bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port)
|
bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Port)
|
||||||
{
|
{
|
||||||
// First try IP Address string to hostent conversion, because it's faster
|
// First try IP Address string to hostent conversion, because it's faster and local:
|
||||||
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
|
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
|
||||||
if (addr == INADDR_NONE)
|
if (addr == INADDR_NONE)
|
||||||
{
|
{
|
||||||
@ -307,10 +307,16 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
|
|||||||
CloseSocket();
|
CloseSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Should be optimised to a single word copy
|
|
||||||
memcpy(&addr, hp->h_addr, hp->h_length);
|
memcpy(&addr, hp->h_addr, hp->h_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the socket is not created yet, create one:
|
||||||
|
if (!IsValid())
|
||||||
|
{
|
||||||
|
m_Socket = socket((int)IPv4, SOCK_STREAM, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Connect the socket:
|
||||||
sockaddr_in server;
|
sockaddr_in server;
|
||||||
server.sin_addr.s_addr = addr;
|
server.sin_addr.s_addr = addr;
|
||||||
server.sin_family = AF_INET;
|
server.sin_family = AF_INET;
|
||||||
|
67
src/PolarSSL++/AesCfb128Decryptor.cpp
Normal file
67
src/PolarSSL++/AesCfb128Decryptor.cpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
|
||||||
|
// AesCfb128Decryptor.cpp
|
||||||
|
|
||||||
|
// Implements the cAesCfb128Decryptor class decrypting data using AES CFB-128
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AesCfb128Decryptor.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cAesCfb128Decryptor::cAesCfb128Decryptor(void) :
|
||||||
|
m_IVOffset(0),
|
||||||
|
m_IsValid(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cAesCfb128Decryptor::~cAesCfb128Decryptor()
|
||||||
|
{
|
||||||
|
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||||
|
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cAesCfb128Decryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
||||||
|
{
|
||||||
|
ASSERT(!IsValid()); // Cannot Init twice
|
||||||
|
|
||||||
|
memcpy(m_IV, a_IV, 16);
|
||||||
|
aes_setkey_enc(&m_Aes, a_Key, 128);
|
||||||
|
m_IsValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cAesCfb128Decryptor::ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length)
|
||||||
|
{
|
||||||
|
ASSERT(IsValid()); // Must Init() first
|
||||||
|
|
||||||
|
// PolarSSL doesn't support AES-CFB8, need to implement it manually:
|
||||||
|
for (size_t i = 0; i < a_Length; i++)
|
||||||
|
{
|
||||||
|
Byte Buffer[sizeof(m_IV)];
|
||||||
|
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
||||||
|
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
||||||
|
{
|
||||||
|
m_IV[idx] = m_IV[idx + 1];
|
||||||
|
}
|
||||||
|
m_IV[sizeof(m_IV) - 1] = a_EncryptedIn[i];
|
||||||
|
a_DecryptedOut[i] = a_EncryptedIn[i] ^ Buffer[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
52
src/PolarSSL++/AesCfb128Decryptor.h
Normal file
52
src/PolarSSL++/AesCfb128Decryptor.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
// AesCfb128Decryptor.h
|
||||||
|
|
||||||
|
// Declares the cAesCfb128Decryptor class decrypting data using AES CFB-128
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "polarssl/aes.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** Decrypts data using the AES / CFB 128 algorithm */
|
||||||
|
class cAesCfb128Decryptor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Byte test;
|
||||||
|
|
||||||
|
cAesCfb128Decryptor(void);
|
||||||
|
~cAesCfb128Decryptor();
|
||||||
|
|
||||||
|
/** Initializes the decryptor with the specified Key / IV */
|
||||||
|
void Init(const Byte a_Key[16], const Byte a_IV[16]);
|
||||||
|
|
||||||
|
/** Decrypts a_Length bytes of the encrypted data; produces a_Length output bytes */
|
||||||
|
void ProcessData(Byte * a_DecryptedOut, const Byte * a_EncryptedIn, size_t a_Length);
|
||||||
|
|
||||||
|
/** Returns true if the object has been initialized with the Key / IV */
|
||||||
|
bool IsValid(void) const { return m_IsValid; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
aes_context m_Aes;
|
||||||
|
|
||||||
|
/** The InitialVector, used by the CFB mode decryption */
|
||||||
|
Byte m_IV[16];
|
||||||
|
|
||||||
|
/** Current offset in the m_IV, used by the CFB mode decryption */
|
||||||
|
size_t m_IVOffset;
|
||||||
|
|
||||||
|
/** Indicates whether the object has been initialized with the Key / IV */
|
||||||
|
bool m_IsValid;
|
||||||
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
68
src/PolarSSL++/AesCfb128Encryptor.cpp
Normal file
68
src/PolarSSL++/AesCfb128Encryptor.cpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
// AesCfb128Encryptor.cpp
|
||||||
|
|
||||||
|
// Implements the cAesCfb128Encryptor class encrypting data using AES CFB-128
|
||||||
|
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AesCfb128Encryptor.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cAesCfb128Encryptor::cAesCfb128Encryptor(void) :
|
||||||
|
m_IVOffset(0),
|
||||||
|
m_IsValid(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
cAesCfb128Encryptor::~cAesCfb128Encryptor()
|
||||||
|
{
|
||||||
|
// Clear the leftover in-memory data, so that they can't be accessed by a backdoor
|
||||||
|
memset(&m_Aes, 0, sizeof(m_Aes));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cAesCfb128Encryptor::Init(const Byte a_Key[16], const Byte a_IV[16])
|
||||||
|
{
|
||||||
|
ASSERT(!IsValid()); // Cannot Init twice
|
||||||
|
ASSERT(m_IVOffset == 0);
|
||||||
|
|
||||||
|
memcpy(m_IV, a_IV, 16);
|
||||||
|
aes_setkey_enc(&m_Aes, a_Key, 128);
|
||||||
|
m_IsValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cAesCfb128Encryptor::ProcessData(Byte * a_EncryptedOut, const Byte * a_PlainIn, size_t a_Length)
|
||||||
|
{
|
||||||
|
ASSERT(IsValid()); // Must Init() first
|
||||||
|
|
||||||
|
// PolarSSL doesn't do AES-CFB8, so we need to implement it ourselves:
|
||||||
|
for (size_t i = 0; i < a_Length; i++)
|
||||||
|
{
|
||||||
|
Byte Buffer[sizeof(m_IV)];
|
||||||
|
aes_crypt_ecb(&m_Aes, AES_ENCRYPT, m_IV, Buffer);
|
||||||
|
for (size_t idx = 0; idx < sizeof(m_IV) - 1; idx++)
|
||||||
|
{
|
||||||
|
m_IV[idx] = m_IV[idx + 1];
|
||||||
|
}
|
||||||
|
a_EncryptedOut[i] = a_PlainIn[i] ^ Buffer[0];
|
||||||
|
m_IV[sizeof(m_IV) - 1] = a_EncryptedOut[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user