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
|
||||
[submodule "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).
|
||||
|
||||
## 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:
|
||||
```
|
||||
@ -61,6 +84,14 @@ git submodule init
|
||||
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 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
|
||||
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`.
|
||||
|
||||
### Debug Mode ###
|
||||
@ -81,8 +114,10 @@ Assuming you are in the MCServer folder created in the Getting the sources step,
|
||||
```
|
||||
mkdir 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`.
|
||||
|
||||
### 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 =
|
||||
{
|
||||
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
|
||||
Desc = [[
|
||||
This hook is called when a client is about to be disconnected from the server, for whatever reason.
|
||||
|
||||
<p><b>Note that this hook will be removed after <1.7 protocol support is removed, as it was originally a hook for
|
||||
the client sending the server a disconnect packet, which no longer happens.</b></p>
|
||||
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
|
||||
for server ping connections.</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 =
|
||||
{
|
||||
{ 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" },
|
||||
},
|
||||
Returns = [[
|
||||
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,
|
||||
the player is disconnected.
|
||||
the client is disconnected.
|
||||
]],
|
||||
}, -- HOOK_DISCONNECT
|
||||
}
|
||||
|
@ -27,10 +27,14 @@ local function LoadAPIFiles(a_Folder, a_DstTable)
|
||||
-- We only want .lua files from the folder:
|
||||
if (cFile:IsFile(FileName) and fnam:match(".*%.lua$")) then
|
||||
local TablesFn, Err = loadfile(FileName);
|
||||
if (TablesFn == nil) then
|
||||
if (type(TablesFn) ~= "function") then
|
||||
LOGWARNING("Cannot load API descriptions from " .. FileName .. ", Lua error '" .. Err .. "'.");
|
||||
else
|
||||
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
|
||||
a_DstTable[k] = cls;
|
||||
end
|
||||
|
@ -36,14 +36,24 @@ set(SHARED_SRC
|
||||
../../src/StringUtils.cpp
|
||||
../../src/Log.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
|
||||
../../src/ByteBuffer.h
|
||||
../../src/StringUtils.h
|
||||
../../src/Log.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
|
||||
../../src/OSSupport/CriticalSection.cpp
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "Connection.h"
|
||||
#include "Server.h"
|
||||
#include <iostream>
|
||||
#include "PolarSSL++/PublicKey.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#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);
|
||||
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;
|
||||
a_Data.ReadAll(All);
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "OSSupport/Timer.h"
|
||||
#include "PolarSSL++/AesCfb128Decryptor.h"
|
||||
#include "PolarSSL++/AesCfb128Encryptor.h"
|
||||
|
||||
|
||||
|
||||
@ -66,8 +68,8 @@ protected:
|
||||
cByteBuffer m_ClientBuffer;
|
||||
cByteBuffer m_ServerBuffer;
|
||||
|
||||
cAESCFBDecryptor m_ServerDecryptor;
|
||||
cAESCFBEncryptor m_ServerEncryptor;
|
||||
cAesCfb128Decryptor m_ServerDecryptor;
|
||||
cAesCfb128Encryptor m_ServerEncryptor;
|
||||
|
||||
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);
|
||||
|
||||
/// 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
|
||||
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
|
||||
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
|
||||
#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 LOGINFO 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.
|
||||
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
|
||||
|
||||
#include "PolarSSL++/RsaPrivateKey.h"
|
||||
|
||||
|
||||
|
||||
|
||||
@ -17,7 +19,7 @@
|
||||
class cServer
|
||||
{
|
||||
SOCKET m_ListenSocket;
|
||||
cRSAPrivateKey m_PrivateKey;
|
||||
cRsaPrivateKey m_PrivateKey;
|
||||
AString m_PublicKeyDER;
|
||||
short m_ConnectPort;
|
||||
|
||||
@ -27,7 +29,7 @@ public:
|
||||
int Init(short a_ListenPort, short a_ConnectPort);
|
||||
void Run(void);
|
||||
|
||||
cRSAPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
cRsaPrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
|
||||
const AString & GetPublicKeyDER (void) { return m_PublicKeyDER; }
|
||||
|
||||
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:
|
||||
int NumChunks = luaL_getn(L, a_ChunkCoordTableStackPos);
|
||||
m_Chunks.reserve(NumChunks);
|
||||
m_Chunks.reserve((size_t)NumChunks);
|
||||
for (int idx = 1; idx <= NumChunks; idx++)
|
||||
{
|
||||
// Push the idx-th element of the array onto stack top, check that it's a table:
|
||||
|
@ -4,12 +4,12 @@
|
||||
#include <time.h>
|
||||
// tolua_begin
|
||||
|
||||
unsigned int GetTime()
|
||||
inline unsigned int GetTime()
|
||||
{
|
||||
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 ]);
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
/****************************
|
||||
* 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
|
||||
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
|
||||
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:
|
||||
lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME);
|
||||
@ -1750,7 +1750,6 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
|
||||
|
||||
// Read the params:
|
||||
cWorld * World = (cWorld *)tolua_tousertype(tolua_S, 1, NULL);
|
||||
@ -1760,8 +1759,12 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
|
||||
L.LogStackTrace();
|
||||
return 0;
|
||||
}
|
||||
|
||||
cLuaChunkStay * ChunkStay = new cLuaChunkStay(*Plugin);
|
||||
|
||||
if (!ChunkStay->AddChunks(2))
|
||||
{
|
||||
delete ChunkStay;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1773,20 +1776,20 @@ static int tolua_cWorld_ChunkStay(lua_State * tolua_S)
|
||||
|
||||
|
||||
|
||||
static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
|
||||
static int tolua_cPlayer_GetGroups(lua_State * tolua_S)
|
||||
{
|
||||
cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
|
||||
cPlayer * self = (cPlayer *)tolua_tousertype(tolua_S, 1, NULL);
|
||||
|
||||
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 index = 1;
|
||||
cPlayer::GroupList::const_iterator iter = AllGroups.begin();
|
||||
while(iter != AllGroups.end())
|
||||
while (iter != AllGroups.end())
|
||||
{
|
||||
const cGroup* Group = *iter;
|
||||
tolua_pushusertype( tolua_S, (void*)Group, "const cGroup" );
|
||||
const cGroup * Group = *iter;
|
||||
tolua_pushusertype(tolua_S, (void *)Group, "const cGroup");
|
||||
lua_rawseti(tolua_S, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
@ -1798,20 +1801,20 @@ static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
|
||||
|
||||
|
||||
|
||||
static int tolua_cPlayer_GetResolvedPermissions(lua_State* tolua_S)
|
||||
static int tolua_cPlayer_GetResolvedPermissions(lua_State * tolua_S)
|
||||
{
|
||||
cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
|
||||
cPlayer * self = (cPlayer*) tolua_tousertype(tolua_S, 1, NULL);
|
||||
|
||||
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 index = 1;
|
||||
cPlayer::StringList::iterator iter = AllPermissions.begin();
|
||||
while(iter != AllPermissions.end())
|
||||
while (iter != AllPermissions.end())
|
||||
{
|
||||
std::string& Permission = *iter;
|
||||
tolua_pushstring( tolua_S, Permission.c_str() );
|
||||
std::string & Permission = *iter;
|
||||
lua_pushlstring(tolua_S, Permission.c_str(), Permission.length());
|
||||
lua_rawseti(tolua_S, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
@ -2073,18 +2076,18 @@ static int tolua_get_HTTPRequest_FormData(lua_State* tolua_S)
|
||||
|
||||
static int tolua_cWebAdmin_GetPlugins(lua_State * tolua_S)
|
||||
{
|
||||
cWebAdmin* self = (cWebAdmin*) tolua_tousertype(tolua_S, 1, NULL);
|
||||
cWebAdmin * self = (cWebAdmin *)tolua_tousertype(tolua_S, 1, NULL);
|
||||
|
||||
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 index = 1;
|
||||
cWebAdmin::PluginList::const_iterator iter = AllPlugins.begin();
|
||||
while(iter != AllPlugins.end())
|
||||
while (iter != AllPlugins.end())
|
||||
{
|
||||
const cWebPlugin* Plugin = *iter;
|
||||
tolua_pushusertype( tolua_S, (void*)Plugin, "const cWebPlugin" );
|
||||
const cWebPlugin * Plugin = *iter;
|
||||
tolua_pushusertype(tolua_S, (void *)Plugin, "const cWebPlugin");
|
||||
lua_rawseti(tolua_S, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
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 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 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;
|
||||
|
@ -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);
|
||||
bool res = false;
|
||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_DISCONNECT];
|
||||
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)
|
||||
{
|
||||
return true;
|
||||
@ -1042,7 +1042,7 @@ bool cPluginLua::OnPluginMessage(cClientHandle & a_Client, const AString & a_Cha
|
||||
cLuaRefs & Refs = m_HookMap[cPluginManager::HOOK_PLUGIN_MESSAGE];
|
||||
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)
|
||||
{
|
||||
return true;
|
||||
|
@ -79,7 +79,7 @@ public:
|
||||
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 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 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;
|
||||
|
@ -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);
|
||||
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)
|
||||
{
|
||||
if ((*itr)->OnDisconnect(a_Player, a_Reason))
|
||||
if ((*itr)->OnDisconnect(a_Client, a_Reason))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ public: // tolua_export
|
||||
bool CallHookChunkUnloading (cWorld * a_World, int a_ChunkX, int a_ChunkZ);
|
||||
bool CallHookCollectingPickup (cPlayer * a_Player, cPickup & a_Pickup);
|
||||
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 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);
|
||||
|
@ -7,30 +7,14 @@
|
||||
#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:
|
||||
static struct {
|
||||
|
||||
// The "map" used for biome <-> string conversions:
|
||||
static struct {
|
||||
EMCSBiome m_Biome;
|
||||
const char * m_String;
|
||||
} BiomeMap[] =
|
||||
{
|
||||
} g_BiomeMap[] =
|
||||
{
|
||||
{biOcean, "Ocean"} ,
|
||||
{biPlains, "Plains"},
|
||||
{biDesert, "Desert"},
|
||||
@ -99,13 +83,35 @@ EMCSBiome StringToBiome(const AString & a_BiomeString)
|
||||
{biMesaBryce, "MesaBryce"},
|
||||
{biMesaPlateauFM, "MesaPlateauFM"},
|
||||
{biMesaPlateauM, "MesaPlateauM"},
|
||||
} ;
|
||||
} ;
|
||||
|
||||
for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++)
|
||||
|
||||
|
||||
|
||||
|
||||
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 (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0)
|
||||
if ((res >= biFirstBiome) && (res < biNumBiomes))
|
||||
{
|
||||
return BiomeMap[i].m_Biome;
|
||||
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[]
|
||||
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)
|
||||
{
|
||||
switch (a_Biome)
|
||||
|
@ -104,10 +104,13 @@ enum EMCSBiome
|
||||
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);
|
||||
|
||||
/// 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);
|
||||
|
||||
|
||||
|
@ -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 :)
|
||||
/// 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,
|
||||
NIBBLETYPE * a_DstMetas, const NIBBLETYPE * a_SrcMetas,
|
||||
int a_SizeX, int a_SizeY, int a_SizeZ,
|
||||
int a_SrcOffX, int a_SrcOffY, int a_SrcOffZ,
|
||||
int a_DstOffX, int a_DstOffY, int a_DstOffZ,
|
||||
int a_SrcSizeX, int a_SrcSizeY, int a_SrcSizeZ,
|
||||
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ,
|
||||
Combinator a_Combinator
|
||||
int a_DstSizeX, int a_DstSizeY, int a_DstSizeZ
|
||||
)
|
||||
{
|
||||
UNUSED(a_SrcSizeY);
|
||||
@ -41,7 +53,15 @@ template<typename Combinator> void InternalMergeBlocks(
|
||||
int DstIdx = DstBaseZ + a_DstOffX;
|
||||
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;
|
||||
++SrcIdx;
|
||||
} // for x
|
||||
@ -54,10 +74,14 @@ template<typename Combinator> void InternalMergeBlocks(
|
||||
|
||||
|
||||
/// 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;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -65,13 +89,17 @@ static inline void MergeCombinatorOverwrite(BLOCKTYPE & a_DstType, BLOCKTYPE a_S
|
||||
|
||||
|
||||
/// 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)
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
// "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
|
||||
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)
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
// "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
|
||||
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
|
||||
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)
|
||||
{
|
||||
a_DstType = E_BLOCK_AIR;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -132,7 +168,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
||||
case E_BLOCK_STATIONARY_LAVA:
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -146,7 +185,10 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
||||
case E_BLOCK_MYCELIUM:
|
||||
{
|
||||
a_DstType = E_BLOCK_STONE;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -159,14 +201,18 @@ static inline void MergeCombinatorLake(BLOCKTYPE & a_DstType, BLOCKTYPE a_SrcTyp
|
||||
|
||||
|
||||
/** 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
|
||||
if (a_SrcType != E_BLOCK_SPONGE)
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -174,18 +220,25 @@ static inline void MergeCombinatorSpongePrint(BLOCKTYPE & a_DstType, BLOCKTYPE a
|
||||
|
||||
|
||||
/** 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;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
a_DstType = a_SrcType;
|
||||
if (MetaValid)
|
||||
{
|
||||
a_DstMeta = a_SrcMeta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -193,16 +246,25 @@ static inline void MergeCombinatorDifference(BLOCKTYPE & a_DstType, BLOCKTYPE a_
|
||||
|
||||
|
||||
/** 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 ((a_SrcType != a_DstType) || (a_SrcMeta != a_DstMeta))
|
||||
if ((a_SrcType != a_DstType) || !MetaValid || (a_SrcMeta != a_DstMeta))
|
||||
{
|
||||
a_DstType = E_BLOCK_AIR;
|
||||
if (MetaValid)
|
||||
{
|
||||
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.SetSize(m_Size.x, m_Size.y, m_Size.z, GetDataTypes());
|
||||
a_Into.m_Origin = m_Origin;
|
||||
int BlockCount = GetBlockCount();
|
||||
size_t BlockCount = GetBlockCount();
|
||||
if (HasBlockTypes())
|
||||
{
|
||||
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);
|
||||
unsigned char DataTypes = (unsigned char)GetDataTypes();
|
||||
f.Write(&DataTypes, 1);
|
||||
int NumBlocks = GetBlockCount();
|
||||
size_t NumBlocks = GetBlockCount();
|
||||
if (HasBlockTypes())
|
||||
{
|
||||
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)
|
||||
{
|
||||
// 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();
|
||||
NIBBLETYPE * DstMetas = m_BlockMetas;
|
||||
|
||||
bool IsDummyMetas = ((SrcMetas == NULL) || (DstMetas == NULL));
|
||||
|
||||
if (IsDummyMetas)
|
||||
{
|
||||
SrcMetas = new NIBBLETYPE[a_Src.GetBlockCount()];
|
||||
DstMetas = new NIBBLETYPE[GetBlockCount()];
|
||||
MergeByStrategy<true>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, DstMetas);
|
||||
}
|
||||
|
||||
switch (a_Strategy)
|
||||
else
|
||||
{
|
||||
case msOverwrite:
|
||||
{
|
||||
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;
|
||||
MergeByStrategy<false>(a_Src, a_RelX, a_RelY, a_RelZ, a_Strategy, SrcMetas, 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 NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
||||
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];
|
||||
memset(NewBlockTypes, 0, BlockCount * sizeof(BLOCKTYPE));
|
||||
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 NewSizeY = m_Size.y + a_SubMinY + a_AddMaxY;
|
||||
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];
|
||||
memset(NewNibbles, 0, BlockCount * sizeof(NIBBLETYPE));
|
||||
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 * GetBlockLight (void) const { return m_BlockLight; } // 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;
|
||||
|
||||
protected:
|
||||
@ -363,6 +363,9 @@ protected:
|
||||
int a_DataTypes, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta,
|
||||
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_end
|
||||
|
@ -21,7 +21,8 @@
|
||||
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),
|
||||
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) :
|
||||
super(E_BLOCK_HEAD, a_BlockX, a_BlockY, a_BlockZ, a_World),
|
||||
m_Type(SKULL_TYPE_SKELETON),
|
||||
m_Rotation(SKULL_ROTATION_NORTH),
|
||||
m_Owner("")
|
||||
{
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ public:
|
||||
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"))
|
||||
{
|
||||
// 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_ICE ].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_LEAVES ].m_Transparent = true;
|
||||
ms_Info[E_BLOCK_LEVER ].m_Transparent = true;
|
||||
|
@ -69,7 +69,6 @@ public:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
for (int newY = Y + 1; newY < cChunkDef::Height; newY++)
|
||||
{
|
||||
BLOCKTYPE Block = a_ChunkInterface.GetBlock(X, newY, Z);
|
||||
@ -84,7 +83,7 @@ public:
|
||||
// This is because the frame is a solid obsidian pillar
|
||||
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
|
||||
{
|
||||
@ -99,18 +98,18 @@ public:
|
||||
}
|
||||
|
||||
/// 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
|
||||
{
|
||||
if (a_ChunkInterface.GetBlock(X, checkBorder, Z) != E_BLOCK_OBSIDIAN)
|
||||
{
|
||||
// Base obsidian, base + 1 obsidian, base + x NOT obsidian -> not complete portal
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// 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)
|
||||
@ -169,7 +168,7 @@ public:
|
||||
{
|
||||
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)
|
||||
{
|
||||
int Value = FindObsidianCeiling(X2, Y, Z, a_ChunkInterface, MaxY);
|
||||
@ -199,13 +198,13 @@ public:
|
||||
if ((Value == -1) || (ValueTwo == -1))
|
||||
{
|
||||
FoundFrameZP = true;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
else if ((Value != MaxY) && (ValueTwo != MaxY))
|
||||
{
|
||||
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--)
|
||||
{
|
||||
int Value = FindObsidianCeiling(X, Y, Z2, a_ChunkInterface, MaxY);
|
||||
@ -213,13 +212,13 @@ public:
|
||||
if ((Value == -1) || (ValueTwo == -1))
|
||||
{
|
||||
FoundFrameZM = true;
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
else if ((Value != MaxY) && (ValueTwo != MaxY))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} XZM = Z2 + 2;
|
||||
} XZM = Z2 + 1;
|
||||
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;
|
||||
CheckValid();
|
||||
@ -187,13 +187,14 @@ bool cByteBuffer::Write(const char * a_Bytes, size_t a_Count)
|
||||
}
|
||||
ASSERT(m_BufferSize >= m_WritePos);
|
||||
size_t TillEnd = m_BufferSize - m_WritePos;
|
||||
const char * Bytes = (const char *)a_Bytes;
|
||||
if (TillEnd <= a_Count)
|
||||
{
|
||||
// Need to wrap around the ringbuffer end
|
||||
if (TillEnd > 0)
|
||||
{
|
||||
memcpy(m_Buffer + m_WritePos, a_Bytes, TillEnd);
|
||||
a_Bytes += TillEnd;
|
||||
memcpy(m_Buffer + m_WritePos, Bytes, TillEnd);
|
||||
Bytes += TillEnd;
|
||||
a_Count -= 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
|
||||
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;
|
||||
WrittenBytes += a_Count;
|
||||
}
|
||||
@ -326,7 +327,7 @@ bool cByteBuffer::ReadBEShort(short & a_Value)
|
||||
CheckValid();
|
||||
NEEDBYTES(2);
|
||||
ReadBuf(&a_Value, 2);
|
||||
a_Value = ntohs(a_Value);
|
||||
a_Value = (short)ntohs((u_short)a_Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -340,7 +341,7 @@ bool cByteBuffer::ReadBEInt(int & a_Value)
|
||||
CheckValid();
|
||||
NEEDBYTES(4);
|
||||
ReadBuf(&a_Value, 4);
|
||||
a_Value = ntohl(a_Value);
|
||||
a_Value = (int)ntohl((u_long)a_Value);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -419,7 +420,7 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value)
|
||||
ASSERT(!"Negative string length? Are you sure?");
|
||||
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);
|
||||
ReadBuf(&b, 1);
|
||||
Value = Value | (((Int64)(b & 0x7f)) << Shift);
|
||||
Value = Value | (((UInt32)(b & 0x7f)) << Shift);
|
||||
Shift += 7;
|
||||
} while ((b & 0x80) != 0);
|
||||
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);
|
||||
}
|
||||
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;
|
||||
CheckValid();
|
||||
PUTBYTES(2);
|
||||
short Converted = htons(a_Value);
|
||||
u_short Converted = htons((u_short)a_Value);
|
||||
return WriteBuf(&Converted, 2);
|
||||
}
|
||||
|
||||
@ -529,7 +530,7 @@ bool cByteBuffer::WriteBEInt(int a_Value)
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
PUTBYTES(4);
|
||||
int Converted = HostToNetwork4(&a_Value);
|
||||
UInt32 Converted = HostToNetwork4(&a_Value);
|
||||
return WriteBuf(&Converted, 4);
|
||||
}
|
||||
|
||||
@ -542,7 +543,7 @@ bool cByteBuffer::WriteBEInt64(Int64 a_Value)
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
PUTBYTES(8);
|
||||
Int64 Converted = HostToNetwork8(&a_Value);
|
||||
UInt64 Converted = HostToNetwork8(&a_Value);
|
||||
return WriteBuf(&Converted, 8);
|
||||
}
|
||||
|
||||
@ -555,7 +556,7 @@ bool cByteBuffer::WriteBEFloat(float a_Value)
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
PUTBYTES(4);
|
||||
int Converted = HostToNetwork4(&a_Value);
|
||||
UInt32 Converted = HostToNetwork4(&a_Value);
|
||||
return WriteBuf(&Converted, 4);
|
||||
}
|
||||
|
||||
@ -568,7 +569,7 @@ bool cByteBuffer::WriteBEDouble(double a_Value)
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
PUTBYTES(8);
|
||||
Int64 Converted = HostToNetwork8(&a_Value);
|
||||
UInt64 Converted = HostToNetwork8(&a_Value);
|
||||
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:
|
||||
unsigned char b[5];
|
||||
int idx = 0;
|
||||
size_t idx = 0;
|
||||
do
|
||||
{
|
||||
b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00);
|
||||
@ -631,7 +632,7 @@ bool cByteBuffer::WriteVarUTF8String(const AString & a_Value)
|
||||
CHECK_THREAD;
|
||||
CheckValid();
|
||||
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)
|
||||
{
|
||||
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
|
||||
CHECK_THREAD;
|
||||
@ -887,9 +888,7 @@ void cByteBuffer::AdvanceReadPos(size_t a_Count)
|
||||
|
||||
void cByteBuffer::CheckValid(void) const
|
||||
{
|
||||
ASSERT(m_ReadPos >= 0);
|
||||
ASSERT(m_ReadPos < m_BufferSize);
|
||||
ASSERT(m_WritePos >= 0);
|
||||
ASSERT(m_WritePos < m_BufferSize);
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
~cByteBuffer();
|
||||
|
||||
/// 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
|
||||
size_t GetFreeSpace(void) const;
|
||||
@ -101,7 +101,7 @@ public:
|
||||
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
|
||||
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
|
||||
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/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)
|
||||
|
||||
|
||||
@ -57,6 +57,14 @@ if (NOT MSVC)
|
||||
Entities/Pickup.h
|
||||
Entities/Player.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/ExpOrb.h
|
||||
Entities/HangingEntity.h
|
||||
@ -234,7 +242,7 @@ endif ()
|
||||
if (NOT MSVC)
|
||||
target_link_libraries(${EXECUTABLE} OSSupport HTTPServer Bindings Items Blocks)
|
||||
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 ()
|
||||
if (WIN32)
|
||||
target_link_libraries(${EXECUTABLE} expat tolualib ws2_32.lib Psapi.lib)
|
||||
|
@ -380,12 +380,12 @@ void cChunk::SetLight(
|
||||
|
||||
{ // Compress blocklight
|
||||
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
|
||||
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;
|
||||
|
@ -246,8 +246,8 @@ public:
|
||||
{
|
||||
if ((x < Width) && (x > -1) && (y < Height) && (y > -1) && (z < Width) && (z > -1))
|
||||
{
|
||||
int Index = MakeIndexNoCheck(x, y, z);
|
||||
if ((size_t)(Index / 2) >= a_Buffer.size())
|
||||
size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
|
||||
if ((Index / 2) >= a_Buffer.size())
|
||||
{
|
||||
return (a_IsSkyLightNibble ? 0xff : 0);
|
||||
}
|
||||
@ -281,7 +281,7 @@ public:
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
int Index = MakeIndexNoCheck(x, y, z);
|
||||
if ((size_t)(Index / 2) >= a_Buffer.size())
|
||||
size_t Index = (size_t)MakeIndexNoCheck(x, y, z);
|
||||
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:
|
||||
|
||||
|
||||
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>(
|
||||
(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;
|
||||
}
|
||||
|
@ -1652,7 +1652,10 @@ void cChunkMap::AddEntity(cEntity * a_Entity)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
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.",
|
||||
a_Entity, a_Entity->GetClass(), a_Entity->GetUniqueID()
|
||||
|
@ -214,11 +214,15 @@ AString cClientHandle::FormatMessageType(bool ShouldAppendChatPrefixes, eMessage
|
||||
case mtPrivateMessage:
|
||||
{
|
||||
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());
|
||||
}
|
||||
else
|
||||
{
|
||||
return Printf("%s: %s", a_AdditionalData.c_str(), cChatColor::LightBlue.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(!"Unhandled chat prefix type!");
|
||||
return "";
|
||||
}
|
||||
@ -333,6 +337,11 @@ void cClientHandle::Authenticate(const AString & a_Name, const AString & a_UUID)
|
||||
// Send scoreboard data
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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)
|
||||
{
|
||||
@ -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());
|
||||
|
||||
cRoot::Get()->GetPluginManager()->CallHookDisconnect(m_Player, a_Reason);
|
||||
cRoot::Get()->GetPluginManager()->CallHookDisconnect(*this, a_Reason);
|
||||
|
||||
m_HasSentDC = true;
|
||||
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
|
||||
m_OutgoingDataOverflow.append(a_Data, a_Size);
|
||||
int CanFit = m_OutgoingData.GetFreeSpace();
|
||||
size_t CanFit = m_OutgoingData.GetFreeSpace();
|
||||
if (CanFit > 128)
|
||||
{
|
||||
// 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());
|
||||
|
||||
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();
|
||||
|
@ -384,7 +384,7 @@ private:
|
||||
void UnregisterPluginChannels(const AStringVector & a_ChannelList);
|
||||
|
||||
/** 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:
|
||||
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)
|
||||
{
|
||||
@ -50,6 +53,7 @@ void cBoat::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
}
|
||||
Destroy(true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
// cEntity overrides:
|
||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) 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 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_IsSwimming(false)
|
||||
, m_IsSubmerged(false)
|
||||
, m_AirLevel(0)
|
||||
, m_AirTickTimer(0)
|
||||
, m_HeadYaw( 0.0 )
|
||||
, m_Rot(0.0, 0.0, 0.0)
|
||||
, 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_Width(a_Width)
|
||||
, m_Height(a_Height)
|
||||
, m_InvulnerableTicks(0)
|
||||
{
|
||||
cCSLock Lock(m_CSCount);
|
||||
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))
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_Health <= 0)
|
||||
{
|
||||
// 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()))
|
||||
@ -362,10 +371,13 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
|
||||
m_World->BroadcastEntityStatus(*this, esGenericHurt);
|
||||
|
||||
m_InvulnerableTicks = 10;
|
||||
|
||||
if (m_Health <= 0)
|
||||
{
|
||||
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)
|
||||
{
|
||||
if (m_InvulnerableTicks > 0)
|
||||
{
|
||||
m_InvulnerableTicks--;
|
||||
}
|
||||
|
||||
if (m_AttachedTo != NULL)
|
||||
{
|
||||
if ((m_Pos - m_AttachedTo->GetPosition()).Length() > 0.5)
|
||||
|
@ -262,8 +262,10 @@ public:
|
||||
|
||||
// tolua_end
|
||||
|
||||
/// Makes this entity take damage specified in the a_TDI. The TDI is sent through plugins first, then applied
|
||||
virtual void DoTakeDamage(TakeDamageInfo & a_TDI);
|
||||
/** Makes this entity take damage specified in the 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
|
||||
|
||||
@ -395,6 +397,12 @@ public:
|
||||
/** Gets remaining air of a monster */
|
||||
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
|
||||
|
||||
/// Called when the specified player right-clicks this entity
|
||||
@ -478,29 +486,33 @@ protected:
|
||||
int m_AirTickTimer;
|
||||
|
||||
private:
|
||||
// Measured in degrees, [-180, +180)
|
||||
/** Measured in degrees, [-180, +180) */
|
||||
double m_HeadYaw;
|
||||
|
||||
// Measured in meter/second (m/s)
|
||||
/** Measured in meter/second (m/s) */
|
||||
Vector3d m_Speed;
|
||||
|
||||
// Measured in degrees, [-180, +180)
|
||||
/** Measured in degrees, [-180, +180) */
|
||||
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;
|
||||
|
||||
// Measured in meter / second
|
||||
/** Measured in meter / second */
|
||||
Vector3d m_WaterSpeed;
|
||||
|
||||
// Measured in Kilograms (Kg)
|
||||
/** Measured in Kilograms (Kg) */
|
||||
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;
|
||||
|
||||
/// Height of the entity (Y axis)
|
||||
/** Height of the entity (Y axis) */
|
||||
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
|
||||
|
||||
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);
|
||||
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()))
|
||||
{
|
||||
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())
|
||||
{
|
||||
Destroy();
|
||||
TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
|
||||
super::DoTakeDamage(TDI);
|
||||
return; // No drops for creative
|
||||
SetInvulnerableTicks(0);
|
||||
return super::DoTakeDamage(TDI); // No drops for creative
|
||||
}
|
||||
|
||||
m_LastDamage = TDI.FinalDamage;
|
||||
super::DoTakeDamage(TDI);
|
||||
if (!super::DoTakeDamage(TDI))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
|
||||
@ -952,12 +955,13 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
|
||||
default:
|
||||
{
|
||||
ASSERT(!"Unhandled minecart type when spawning pickup!");
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
// cEntity overrides:
|
||||
virtual void SpawnOn(cClientHandle & a_ClientHandle) 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;
|
||||
|
||||
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 (IsGameModeCreative())
|
||||
{
|
||||
// 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())
|
||||
{
|
||||
// Friendly fire is disabled
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super::DoTakeDamage(a_TDI);
|
||||
|
||||
if (super::DoTakeDamage(a_TDI))
|
||||
{
|
||||
// Any kind of damage adds food exhaustion
|
||||
AddFoodExhaustion(0.3f);
|
||||
|
||||
SendHealth();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -897,6 +899,7 @@ void cPlayer::KilledBy(cEntity * a_Killer)
|
||||
void cPlayer::Respawn(void)
|
||||
{
|
||||
m_Health = GetMaxHealth();
|
||||
SetInvulnerableTicks(20);
|
||||
|
||||
// Reset food level:
|
||||
m_FoodLevel = MAX_FOOD_LEVEL;
|
||||
|
@ -498,7 +498,7 @@ protected:
|
||||
virtual void Destroyed(void);
|
||||
|
||||
/** 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 */
|
||||
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
|
||||
|
||||
#include "Globals.h"
|
||||
|
||||
#include "../Bindings/PluginManager.h"
|
||||
#include "ProjectileEntity.h"
|
||||
#include "../ClientHandle.h"
|
||||
#include "Player.h"
|
||||
#include "../LineBlockTracer.h"
|
||||
#include "../BoundingBox.h"
|
||||
#include "../ChunkMap.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
|
||||
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 SpawnOn(cClientHandle & a_Client) override;
|
||||
|
||||
// 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_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
|
||||
|
||||
|
||||
|
||||
} ; // tolua_export
|
||||
|
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) :
|
||||
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())
|
||||
{
|
||||
BlockMeta = (NIBBLETYPE)atoi(CharDef[2].c_str());
|
||||
ASSERT((BlockMeta >= 0) && (BlockMeta <= 15));
|
||||
ASSERT((BlockMeta <= 15));
|
||||
}
|
||||
a_CharMapOut[Src].m_BlockMeta = BlockMeta;
|
||||
} // for itr - Lines[]
|
||||
|
@ -264,7 +264,21 @@ template class SizeChecker<UInt16, 2>;
|
||||
|
||||
// Same as assert but in all Self test builds
|
||||
#ifdef SELF_TEST
|
||||
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
||||
#define assert_test(x) ( !!(x) || (assert(!#x), exit(1), 0))
|
||||
#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
|
||||
|
||||
|
||||
@ -296,7 +310,7 @@ T Clamp(T a_Value, T a_Min, T a_Max)
|
||||
|
||||
|
||||
#ifndef TOLUA_TEMPLATE_BIND
|
||||
#define TOLUA_TEMPLATE_BIND(x)
|
||||
#define TOLUA_TEMPLATE_BIND(x)
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -64,7 +64,7 @@ public:
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -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 */
|
||||
cItem(const cItem & a_CopyFrom) :
|
||||
m_ItemType (a_CopyFrom.m_ItemType),
|
||||
@ -85,6 +89,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void Empty(void)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "../Entities/ProjectileEntity.h"
|
||||
#include "../Entities/ArrowEntity.h"
|
||||
|
||||
|
||||
|
||||
|
@ -33,7 +33,10 @@ public:
|
||||
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())
|
||||
{
|
||||
@ -45,6 +48,41 @@ public:
|
||||
|
||||
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 "../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)
|
||||
{
|
||||
@ -85,6 +88,7 @@ void cCreeper::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
}
|
||||
|
||||
m_World->BroadcastEntityMetadata(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
CLASS_PROTODEF(cCreeper);
|
||||
|
||||
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 Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
virtual void OnRightClicked(cPlayer & a_Player) override;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Ghast.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))
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -823,6 +827,10 @@ cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType)
|
||||
switch (a_MobType)
|
||||
{
|
||||
case mtMagmaCube:
|
||||
{
|
||||
toReturn = new cMagmaCube(Random.NextInt(2) + 1);
|
||||
break;
|
||||
}
|
||||
case mtSlime:
|
||||
{
|
||||
toReturn = new cSlime(Random.NextInt(2) + 1);
|
||||
|
@ -88,7 +88,7 @@ public:
|
||||
|
||||
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;
|
||||
|
||||
|
@ -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()))
|
||||
{
|
||||
@ -30,6 +33,7 @@ void cPassiveAggressiveMonster::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
m_EMState = CHASING;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -15,7 +15,7 @@ class cPassiveAggressiveMonster :
|
||||
public:
|
||||
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))
|
||||
{
|
||||
m_EMState = ESCAPING;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
|
||||
/// 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
|
||||
Return an empty item not to follow (default). */
|
||||
virtual const cItem GetFollowedItem(void) const { return cItem(); }
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "Skeleton.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 (m_World->GetTickRandomNumber(5) == 3)
|
||||
@ -33,6 +37,7 @@ void cVillager::DoTakeDamage(TakeDamageInfo & a_TDI)
|
||||
m_World->BroadcastEntityStatus(*this, esVillagerAngry);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
CLASS_PROTODEF(cVillager);
|
||||
|
||||
// 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;
|
||||
|
||||
// cVillager functions
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
cWither::cWither(void) :
|
||||
super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0),
|
||||
m_InvulnerableTicks(220)
|
||||
m_WitherInvulnerableTicks(220)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_InvulnerableTicks > 0)
|
||||
if (m_WitherInvulnerableTicks > 0)
|
||||
{
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (m_InvulnerableTicks > 0)
|
||||
if (m_WitherInvulnerableTicks > 0)
|
||||
{
|
||||
unsigned int NewTicks = m_InvulnerableTicks - 1;
|
||||
unsigned int NewTicks = m_WitherInvulnerableTicks - 1;
|
||||
|
||||
if (NewTicks == 0)
|
||||
{
|
||||
m_World->DoExplosionAt(7.0, GetPosX(), GetPosY(), GetPosZ(), false, esWitherBirth, this);
|
||||
}
|
||||
|
||||
m_InvulnerableTicks = NewTicks;
|
||||
m_WitherInvulnerableTicks = NewTicks;
|
||||
|
||||
if ((NewTicks % 10) == 0)
|
||||
{
|
||||
|
@ -17,9 +17,9 @@ public:
|
||||
|
||||
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. */
|
||||
bool IsArmored(void) const;
|
||||
@ -27,13 +27,13 @@ public:
|
||||
// cEntity overrides
|
||||
virtual bool Initialize(cWorld * a_World) 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;
|
||||
|
||||
private:
|
||||
|
||||
/** 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)
|
||||
{
|
||||
m_IsAngry = true;
|
||||
}
|
||||
m_World->BroadcastEntityMetadata(*this); // Broadcast health and possibly angry face
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
|
||||
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 Tick(float a_Dt, cChunk & a_Chunk) override;
|
||||
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
|
||||
) const
|
||||
{
|
||||
ASSERT(a_SizeX > 0);
|
||||
ASSERT(a_SizeY > 0);
|
||||
ASSERT(a_SizeX < MAX_SIZE);
|
||||
ASSERT(a_SizeY < MAX_SIZE);
|
||||
ASSERT(a_StartX < a_EndX);
|
||||
@ -744,6 +746,8 @@ void cCubicNoise::CalcFloorFrac(
|
||||
int * a_Same, int & a_NumSame
|
||||
) const
|
||||
{
|
||||
ASSERT(a_Size > 0);
|
||||
|
||||
NOISE_DATATYPE val = a_Start;
|
||||
NOISE_DATATYPE dif = (a_End - a_Start) / (a_Size - 1);
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
fopen_s(&m_File, (FILE_IO_PREFIX + iFileName).c_str(), Mode);
|
||||
m_File = _fsopen((FILE_IO_PREFIX + iFileName).c_str(), Mode, _SH_DENYWR);
|
||||
#else
|
||||
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), Mode);
|
||||
#endif // _WIN32
|
||||
@ -88,7 +88,7 @@ bool cFile::Open(const AString & iFileName, eMode iMode)
|
||||
// Simply re-open for read-writing, erasing existing contents:
|
||||
|
||||
#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
|
||||
m_File = fopen((FILE_IO_PREFIX + iFileName).c_str(), "wb+");
|
||||
#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());
|
||||
|
||||
@ -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());
|
||||
|
||||
|
@ -80,10 +80,10 @@ public:
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
int Seek (int iPosition);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
// 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());
|
||||
if (addr == INADDR_NONE)
|
||||
{
|
||||
@ -307,10 +307,16 @@ bool cSocket::ConnectIPv4(const AString & a_HostNameOrAddr, unsigned short a_Por
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
// Should be optimised to a single word copy
|
||||
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;
|
||||
server.sin_addr.s_addr = addr;
|
||||
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