summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Bindings/AllToLua.pkg3
-rw-r--r--src/Bindings/LuaState.cpp66
-rw-r--r--src/Bindings/LuaState.h101
-rw-r--r--src/Bindings/ManualBindings.cpp198
-rw-r--r--src/Bindings/PluginLua.cpp15
-rw-r--r--src/Bindings/PluginManager.cpp6
-rw-r--r--src/Bindings/tolua++.h6
-rw-r--r--src/Bindings/tolua_base.h128
-rw-r--r--src/Bindings/virtual_method_hooks.lua8
-rw-r--r--src/BiomeDef.cpp131
-rw-r--r--src/BiomeDef.h107
-rw-r--r--src/BlockEntities/FurnaceEntity.cpp4
-rw-r--r--src/BlockEntities/HopperEntity.cpp4
-rw-r--r--src/BlockID.cpp227
-rw-r--r--src/BlockID.h5
-rw-r--r--src/Blocks/BlockChest.h10
-rw-r--r--src/Blocks/BlockComparator.h2
-rw-r--r--src/Blocks/BlockDoor.h2
-rw-r--r--src/Blocks/BlockDropSpenser.h2
-rw-r--r--src/Blocks/BlockEnderchest.h2
-rw-r--r--src/Blocks/BlockFenceGate.h4
-rw-r--r--src/Blocks/BlockFurnace.h2
-rw-r--r--src/Blocks/BlockGlowstone.h4
-rw-r--r--src/Blocks/BlockLever.h2
-rw-r--r--src/Blocks/BlockPiston.cpp2
-rw-r--r--src/Blocks/BlockPumpkin.h2
-rw-r--r--src/Blocks/BlockRedstone.h2
-rw-r--r--src/Blocks/BlockRedstoneRepeater.h2
-rw-r--r--src/Blocks/BlockStairs.h2
-rw-r--r--src/Blocks/BlockTorch.h6
-rw-r--r--src/CMakeLists.txt48
-rw-r--r--src/Chunk.cpp17
-rw-r--r--src/ChunkDef.h94
-rw-r--r--src/ClientHandle.cpp24
-rw-r--r--src/ClientHandle.h7
-rw-r--r--src/Defines.h33
-rw-r--r--src/Entities/Entity.cpp75
-rw-r--r--src/Entities/Entity.h10
-rw-r--r--src/Entities/Minecart.cpp581
-rw-r--r--src/Entities/Minecart.h47
-rw-r--r--src/Entities/Player.cpp47
-rw-r--r--src/Entities/Player.h2
-rw-r--r--src/Entities/ProjectileEntity.cpp12
-rw-r--r--src/Generating/ChunkGenerator.cpp48
-rw-r--r--src/Generating/ChunkGenerator.h63
-rw-r--r--src/Generating/ComposableGenerator.cpp206
-rw-r--r--src/Generating/ComposableGenerator.h17
-rw-r--r--src/Generating/FinishGen.cpp6
-rw-r--r--src/Generating/FinishGen.h6
-rw-r--r--src/Generating/HeiGen.cpp74
-rw-r--r--src/Generating/Noise3DGenerator.cpp4
-rw-r--r--src/Generating/Noise3DGenerator.h2
-rw-r--r--src/Globals.h1
-rw-r--r--src/Inventory.cpp2
-rw-r--r--src/Item.cpp32
-rw-r--r--src/Item.h41
-rw-r--r--src/ItemGrid.cpp8
-rw-r--r--src/Items/ItemBed.h2
-rw-r--r--src/Items/ItemComparator.h2
-rw-r--r--src/Items/ItemMinecart.h2
-rw-r--r--src/Items/ItemRedstoneDust.h2
-rw-r--r--src/Items/ItemRedstoneRepeater.h2
-rw-r--r--src/Items/ItemSign.h2
-rw-r--r--src/Log.cpp8
-rw-r--r--src/Log.h8
-rw-r--r--src/MCServer.vcproj.user167
-rw-r--r--src/Mobs/Monster.cpp2
-rw-r--r--src/OSSupport/BlockingTCPLink.cpp11
-rw-r--r--src/OSSupport/Socket.cpp6
-rw-r--r--src/OSSupport/Socket.h12
-rw-r--r--src/Protocol/Protocol.h1
-rw-r--r--src/Protocol/Protocol125.cpp32
-rw-r--r--src/Protocol/Protocol125.h1
-rw-r--r--src/Protocol/Protocol132.cpp8
-rw-r--r--src/Protocol/Protocol14x.cpp2
-rw-r--r--src/Protocol/Protocol17x.cpp214
-rw-r--r--src/Protocol/Protocol17x.h7
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp10
-rw-r--r--src/Protocol/ProtocolRecognizer.h1
-rw-r--r--src/Resources/MCServer.rc17
-rw-r--r--src/Resources/icon.icobin0 -> 353118 bytes
-rw-r--r--src/Resources/icon_128.pngbin0 -> 26758 bytes
-rw-r--r--src/Resources/icon_256.pngbin0 -> 66137 bytes
-rw-r--r--src/Resources/resource_MCServer.h5
-rw-r--r--src/Server.h2
-rw-r--r--src/Simulator/RedstoneSimulator.cpp352
-rw-r--r--src/Simulator/RedstoneSimulator.h101
-rw-r--r--src/StringCompression.cpp4
-rw-r--r--src/StringCompression.h2
-rw-r--r--src/StringUtils.cpp33
-rw-r--r--src/StringUtils.h2
-rw-r--r--src/UI/SlotArea.cpp19
-rw-r--r--src/UI/Window.cpp2
-rw-r--r--src/World.cpp145
-rw-r--r--src/World.h53
-rw-r--r--src/WorldStorage/NBTChunkSerializer.cpp2
-rw-r--r--src/WorldStorage/WSSAnvil.cpp11
-rw-r--r--src/WorldStorage/WSSAnvil.h4
-rw-r--r--src/WorldStorage/WSSCompact.cpp11
-rw-r--r--src/WorldStorage/WSSCompact.h7
-rw-r--r--src/WorldStorage/WorldStorage.cpp10
-rw-r--r--src/WorldStorage/WorldStorage.h4
-rw-r--r--src/main.cpp13
103 files changed, 2454 insertions, 1409 deletions
diff --git a/src/Bindings/AllToLua.pkg b/src/Bindings/AllToLua.pkg
index e9a5ea0c6..2d0300ebf 100644
--- a/src/Bindings/AllToLua.pkg
+++ b/src/Bindings/AllToLua.pkg
@@ -1,8 +1,6 @@
$#include "../Globals.h"
-$#include "tolua_base.h"
-
// Typedefs from Globals.h, so that we don't have to process that file:
typedef long long Int64;
typedef int Int32;
@@ -14,6 +12,7 @@ typedef unsigned short UInt16;
$cfile "../ChunkDef.h"
+$cfile "../BiomeDef.h"
$cfile "../../lib/inifile/iniFile.h"
diff --git a/src/Bindings/LuaState.cpp b/src/Bindings/LuaState.cpp
index 83351591c..00e62fcf6 100644
--- a/src/Bindings/LuaState.cpp
+++ b/src/Bindings/LuaState.cpp
@@ -228,6 +228,9 @@ bool cLuaState::PushFunction(const char * a_FunctionName)
return false;
}
+ // Push the error handler for lua_pcall()
+ lua_pushcfunction(m_LuaState, &ReportFnCallErrors);
+
lua_getglobal(m_LuaState, a_FunctionName);
if (!lua_isfunction(m_LuaState, -1))
{
@@ -249,6 +252,9 @@ bool cLuaState::PushFunction(int a_FnRef)
ASSERT(IsValid());
ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack
+ // Push the error handler for lua_pcall()
+ lua_pushcfunction(m_LuaState, &ReportFnCallErrors);
+
lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // same as lua_getref()
if (!lua_isfunction(m_LuaState, -1))
{
@@ -264,27 +270,29 @@ bool cLuaState::PushFunction(int a_FnRef)
-bool cLuaState::PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName)
+bool cLuaState::PushFunction(const cTableRef & a_TableRef)
{
ASSERT(IsValid());
ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack
-
- lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef); // Get the table ref
+
+ // Push the error handler for lua_pcall()
+ lua_pushcfunction(m_LuaState, &ReportFnCallErrors);
+
+ lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef.GetTableRef()); // Get the table ref
if (!lua_istable(m_LuaState, -1))
{
// Not a table, bail out
lua_pop(m_LuaState, 1);
return false;
}
- lua_getfield(m_LuaState, -1, a_FnName);
+ lua_getfield(m_LuaState, -1, a_TableRef.GetFnName());
if (lua_isnil(m_LuaState, -1) || !lua_isfunction(m_LuaState, -1))
{
// Not a valid function, bail out
lua_pop(m_LuaState, 2);
return false;
}
- lua_remove(m_LuaState, -2); // Remove the table ref from the stack
- m_CurrentFunctionName = "<table_callback>";
+ Printf(m_CurrentFunctionName, "<table-callback %s>", a_TableRef.GetFnName());
m_NumCurrentFunctionArgs = 0;
return true;
}
@@ -624,18 +632,6 @@ void cLuaState::Push(cTNTEntity * a_TNTEntity)
-void cLuaState::Push(cCreeper * a_Creeper)
-{
- ASSERT(IsValid());
-
- tolua_pushusertype(m_LuaState, a_Creeper, "cCreeper");
- m_NumCurrentFunctionArgs += 1;
-}
-
-
-
-
-
void cLuaState::Push(Vector3i * a_Vector)
{
ASSERT(IsValid());
@@ -732,11 +728,13 @@ void cLuaState::GetReturn(int a_StackPos, double & a_ReturnedVal)
bool cLuaState::CallFunction(int a_NumResults)
{
ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first
- ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 1));
+ ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 1)); // The function to call
+ ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 2)); // The error handler
- int s = lua_pcall(m_LuaState, m_NumCurrentFunctionArgs, a_NumResults, 0);
- if (ReportErrors(s))
+ int s = lua_pcall(m_LuaState, m_NumCurrentFunctionArgs, a_NumResults, -m_NumCurrentFunctionArgs - 2);
+ if (s != 0)
{
+ // The error has already been printed together with the stacktrace
LOGWARNING("Error in %s calling function %s()", m_SubsystemName.c_str(), m_CurrentFunctionName.c_str());
m_NumCurrentFunctionArgs = -1;
m_CurrentFunctionName.clear();
@@ -964,15 +962,24 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status)
void cLuaState::LogStackTrace(void)
{
+ LogStackTrace(m_LuaState);
+}
+
+
+
+
+
+void cLuaState::LogStackTrace(lua_State * a_LuaState)
+{
LOGWARNING("Stack trace:");
lua_Debug entry;
int depth = 0;
- while (lua_getstack(m_LuaState, depth, &entry))
+ while (lua_getstack(a_LuaState, depth, &entry))
{
- int status = lua_getinfo(m_LuaState, "Sln", &entry);
+ int status = lua_getinfo(a_LuaState, "Sln", &entry);
assert(status);
- LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?");
+ LOGWARNING(" %s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "(no name)");
depth++;
}
LOGWARNING("Stack trace end");
@@ -1005,6 +1012,17 @@ AString cLuaState::GetTypeText(int a_StackPos)
+int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
+{
+ LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1));
+ LogStackTrace(a_LuaState);
+ return 1; // We left the error message on the stack as the return value
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cLuaState::cRef:
diff --git a/src/Bindings/LuaState.h b/src/Bindings/LuaState.h
index 796559b6f..414e5e4b2 100644
--- a/src/Bindings/LuaState.h
+++ b/src/Bindings/LuaState.h
@@ -85,6 +85,23 @@ public:
} ;
+ /** Used for calling functions stored in a reference-stored table */
+ class cTableRef
+ {
+ int m_TableRef;
+ const char * m_FnName;
+ public:
+ cTableRef(int a_TableRef, const char * a_FnName) :
+ m_TableRef(a_TableRef),
+ m_FnName(a_FnName)
+ {
+ }
+
+ int GetTableRef(void) const { return m_TableRef; }
+ const char * GetFnName(void) const { return m_FnName; }
+ } ;
+
+
/// A dummy class that's used only to delimit function args from return values for cLuaState::Call()
class cRet
{
@@ -133,24 +150,6 @@ public:
/// Returns true if a_FunctionName is a valid Lua function that can be called
bool HasFunction(const char * a_FunctionName);
- /** Pushes the function of the specified name onto the stack.
- Returns true if successful. Logs a warning on failure (incl. m_SubsystemName)
- */
- bool PushFunction(const char * a_FunctionName);
-
- /** Pushes a function that has been saved into the global registry, identified by a_FnRef.
- Returns true if successful. Logs a warning on failure
- */
- bool PushFunction(int a_FnRef);
-
- /** Pushes a function that is stored in a table ref.
- Returns true if successful, false on failure. Doesn't log failure.
- */
- bool PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName);
-
- /// Pushes a usertype of the specified class type onto the stack
- void PushUserType(void * a_Object, const char * a_Type);
-
// Push a value onto the stack
void Push(const AString & a_String);
void Push(const AStringVector & a_Vector);
@@ -178,12 +177,11 @@ public:
void Push(cWebAdmin * a_WebAdmin);
void Push(const HTTPTemplateRequest * a_Request);
void Push(cTNTEntity * a_TNTEntity);
- void Push(cCreeper * a_Creeper);
void Push(Vector3i * a_Vector);
void Push(void * a_Ptr);
void Push(cHopperEntity * a_Hopper);
void Push(cBlockEntity * a_BlockEntity);
-
+
/// Call any 0-param 0-return Lua function in a single line:
template <typename FnT>
bool Call(FnT a_FnName)
@@ -802,25 +800,6 @@ public:
}
- /// Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged
- void GetReturn(int a_StackPos, bool & a_ReturnedVal);
-
- /// Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged
- void GetReturn(int a_StackPos, AString & a_ReturnedVal);
-
- /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged
- void GetReturn(int a_StackPos, int & a_ReturnedVal);
-
- /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged
- void GetReturn(int a_StackPos, double & a_ReturnedVal);
-
- /**
- Calls the function that has been pushed onto the stack by PushFunction(),
- with arguments pushed by PushXXX().
- Returns true if successful, logs a warning on failure.
- */
- bool CallFunction(int a_NumReturnValues);
-
/// Returns true if the specified parameters on the stack are of the specified usertable type; also logs warning if not. Used for static functions
bool CheckParamUserTable(int a_StartParam, const char * a_UserTable, int a_EndParam = -1);
@@ -848,6 +827,9 @@ public:
/// Logs all items in the current stack trace to the server console
void LogStackTrace(void);
+ /// Logs all items in the current stack trace to the server console
+ static void LogStackTrace(lua_State * a_LuaState);
+
/// Returns the type of the item on the specified position in the stack
AString GetTypeText(int a_StackPos);
@@ -867,6 +849,47 @@ protected:
/// Number of arguments currently pushed (for the Push / Call chain)
int m_NumCurrentFunctionArgs;
+
+
+ /** Pushes the function of the specified name onto the stack.
+ Returns true if successful. Logs a warning on failure (incl. m_SubsystemName)
+ */
+ bool PushFunction(const char * a_FunctionName);
+
+ /** Pushes a function that has been saved into the global registry, identified by a_FnRef.
+ Returns true if successful. Logs a warning on failure
+ */
+ bool PushFunction(int a_FnRef);
+
+ /** Pushes a function that is stored in a referenced table by name
+ Returns true if successful. Logs a warning on failure
+ */
+ bool PushFunction(const cTableRef & a_TableRef);
+
+ /// Pushes a usertype of the specified class type onto the stack
+ void PushUserType(void * a_Object, const char * a_Type);
+
+ /// Retrieve value returned at a_StackPos, if it is a valid bool. If not, a_ReturnedVal is unchanged
+ void GetReturn(int a_StackPos, bool & a_ReturnedVal);
+
+ /// Retrieve value returned at a_StackPos, if it is a valid string. If not, a_ReturnedVal is unchanged
+ void GetReturn(int a_StackPos, AString & a_ReturnedVal);
+
+ /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged
+ void GetReturn(int a_StackPos, int & a_ReturnedVal);
+
+ /// Retrieve value returned at a_StackPos, if it is a valid number. If not, a_ReturnedVal is unchanged
+ void GetReturn(int a_StackPos, double & a_ReturnedVal);
+
+ /**
+ Calls the function that has been pushed onto the stack by PushFunction(),
+ with arguments pushed by PushXXX().
+ Returns true if successful, logs a warning on failure.
+ */
+ bool CallFunction(int a_NumReturnValues);
+
+ /** Used as the error reporting function for function calls */
+ static int ReportFnCallErrors(lua_State * a_LuaState);
} ;
diff --git a/src/Bindings/ManualBindings.cpp b/src/Bindings/ManualBindings.cpp
index 6221727c4..ebee2d697 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -984,6 +984,73 @@ static int tolua_cWorld_QueueTask(lua_State * tolua_S)
+class cLuaScheduledWorldTask :
+ public cWorld::cScheduledTask
+{
+public:
+ cLuaScheduledWorldTask(cPluginLua & a_Plugin, int a_FnRef, int a_Ticks) :
+ cScheduledTask(a_Ticks),
+ m_Plugin(a_Plugin),
+ m_FnRef(a_FnRef)
+ {
+ }
+
+protected:
+ cPluginLua & m_Plugin;
+ int m_FnRef;
+
+ // cWorld::cTask overrides:
+ virtual void Run(cWorld & a_World) override
+ {
+ m_Plugin.Call(m_FnRef, &a_World);
+ }
+};
+
+
+
+
+
+static int tolua_cWorld_ScheduleTask(lua_State * tolua_S)
+{
+ // Binding for cWorld::ScheduleTask
+ // Params: function, Ticks
+
+ // Retrieve the cPlugin from the LuaState:
+ cPluginLua * Plugin = GetLuaPlugin(tolua_S);
+ if (Plugin == NULL)
+ {
+ // An error message has been already printed in GetLuaPlugin()
+ return 0;
+ }
+
+ // Retrieve the args:
+ cWorld * self = (cWorld *)tolua_tousertype(tolua_S, 1, 0);
+ if (self == NULL)
+ {
+ return lua_do_error(tolua_S, "Error in function call '#funcname#': Not called on an object instance");
+ }
+ if (!lua_isfunction(tolua_S, 2))
+ {
+ return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #1");
+ }
+
+ // Create a reference to the function:
+ int FnRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
+ if (FnRef == LUA_REFNIL)
+ {
+ return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #1");
+ }
+
+ int Ticks = (int) tolua_tonumber (tolua_S, 3, 0);
+
+ self->ScheduleTask(new cLuaScheduledWorldTask(*Plugin, FnRef, Ticks));
+ return 0;
+}
+
+
+
+
+
static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S)
{
cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, 0);
@@ -991,7 +1058,6 @@ static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S)
const cPluginManager::PluginMap & AllPlugins = self->GetAllPlugins();
lua_newtable(tolua_S);
- int newTable = lua_gettop(tolua_S);
int index = 1;
cPluginManager::PluginMap::const_iterator iter = AllPlugins.begin();
while (iter != AllPlugins.end())
@@ -1883,7 +1949,6 @@ static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S)
const cWebPlugin::TabNameList & TabNames = self->GetTabNames();
lua_newtable(tolua_S);
- int newTable = lua_gettop(tolua_S);
int index = 1;
cWebPlugin::TabNameList::const_iterator iter = TabNames.begin();
while(iter != TabNames.end())
@@ -1904,6 +1969,35 @@ static int tolua_cWebPlugin_GetTabNames(lua_State * tolua_S)
+static int tolua_cClientHandle_SendPluginMessage(lua_State * L)
+{
+ cLuaState S(L);
+ if (
+ !S.CheckParamUserType(1, "cClientHandle") ||
+ !S.CheckParamString(2, 3) ||
+ !S.CheckParamEnd(4)
+ )
+ {
+ return 0;
+ }
+ cClientHandle * Client = (cClientHandle *)tolua_tousertype(L, 1, NULL);
+ if (Client == NULL)
+ {
+ LOGWARNING("ClientHandle is nil in cClientHandle:SendPluginMessage()");
+ S.LogStackTrace();
+ return 0;
+ }
+ AString Channel, Message;
+ Channel.assign(lua_tostring(L, 2), lua_strlen(L, 2));
+ Message.assign(lua_tostring(L, 3), lua_strlen(L, 3));
+ Client->SendPluginMessage(Channel, Message);
+ return 0;
+}
+
+
+
+
+
static int Lua_ItemGrid_GetSlotCoords(lua_State * L)
{
tolua_Error tolua_err;
@@ -1953,118 +2047,72 @@ public:
virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta, char a_EntryFace) override
{
- if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock"))
+ bool res = false;
+ if (!m_LuaState.Call(
+ cLuaState::cTableRef(m_TableRef, "OnNextBlock"),
+ a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, a_EntryFace,
+ cLuaState::Return, res
+ ))
{
// No such function in the table, skip the callback
return false;
}
- m_LuaState.Push(a_BlockX);
- m_LuaState.Push(a_BlockY);
- m_LuaState.Push(a_BlockZ);
- m_LuaState.Push(a_BlockType);
- m_LuaState.Push(a_BlockMeta);
- m_LuaState.Push(a_EntryFace);
- if (!m_LuaState.CallFunction(1))
- {
- return false;
- }
- bool res = false;
- if (lua_isboolean(m_LuaState, -1))
- {
- res = (lua_toboolean(m_LuaState, -1) != 0);
- }
- lua_pop(m_LuaState, 1);
return res;
}
virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ, char a_EntryFace) override
{
- if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData"))
+ bool res = false;
+ if (!m_LuaState.Call(
+ cLuaState::cTableRef(m_TableRef, "OnNextBlockNoData"),
+ a_BlockX, a_BlockY, a_BlockZ, a_EntryFace,
+ cLuaState::Return, res
+ ))
{
// No such function in the table, skip the callback
return false;
}
- m_LuaState.Push(a_BlockX);
- m_LuaState.Push(a_BlockY);
- m_LuaState.Push(a_BlockZ);
- m_LuaState.Push(a_EntryFace);
- if (!m_LuaState.CallFunction(1))
- {
- return false;
- }
- bool res = false;
- if (lua_isboolean(m_LuaState, -1))
- {
- res = (lua_toboolean(m_LuaState, -1) != 0);
- }
- lua_pop(m_LuaState, 1);
return res;
}
virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override
{
- if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnOutOfWorld"))
+ bool res = false;
+ if (!m_LuaState.Call(
+ cLuaState::cTableRef(m_TableRef, "OnOutOfWorld"),
+ a_BlockX, a_BlockY, a_BlockZ,
+ cLuaState::Return, res
+ ))
{
// No such function in the table, skip the callback
return false;
}
- m_LuaState.Push(a_BlockX);
- m_LuaState.Push(a_BlockY);
- m_LuaState.Push(a_BlockZ);
- if (!m_LuaState.CallFunction(1))
- {
- return false;
- }
- bool res = false;
- if (lua_isboolean(m_LuaState, -1))
- {
- res = (lua_toboolean(m_LuaState, -1) != 0);
- }
- lua_pop(m_LuaState, 1);
return res;
}
virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override
{
- if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnIntoWorld"))
+ bool res = false;
+ if (!m_LuaState.Call(
+ cLuaState::cTableRef(m_TableRef, "OnIntoWorld"),
+ a_BlockX, a_BlockY, a_BlockZ,
+ cLuaState::Return, res
+ ))
{
// No such function in the table, skip the callback
return false;
}
- m_LuaState.Push(a_BlockX);
- m_LuaState.Push(a_BlockY);
- m_LuaState.Push(a_BlockZ);
- if (!m_LuaState.CallFunction(1))
- {
- return false;
- }
- bool res = false;
- if (lua_isboolean(m_LuaState, -1))
- {
- res = (lua_toboolean(m_LuaState, -1) != 0);
- }
- lua_pop(m_LuaState, 1);
return res;
}
virtual void OnNoMoreHits(void) override
{
- if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoMoreHits"))
- {
- // No such function in the table, skip the callback
- return;
- }
- m_LuaState.CallFunction(0);
+ m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoMoreHits"));
}
virtual void OnNoChunk(void) override
{
- if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoChunk"))
- {
- // No such function in the table, skip the callback
- return;
- }
- m_LuaState.CallFunction(0);
+ m_LuaState.Call(cLuaState::cTableRef(m_TableRef, "OnNoChunk"));
}
protected:
@@ -2237,6 +2285,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_function(tolua_S, "GetBlockTypeMeta", tolua_cWorld_GetBlockTypeMeta);
tolua_function(tolua_S, "GetSignLines", tolua_cWorld_GetSignLines);
tolua_function(tolua_S, "QueueTask", tolua_cWorld_QueueTask);
+ tolua_function(tolua_S, "ScheduleTask", tolua_cWorld_ScheduleTask);
tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines);
tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight);
tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines);
@@ -2292,6 +2341,7 @@ void ManualBindings::Bind(lua_State * tolua_S)
tolua_beginmodule(tolua_S, "cClientHandle");
tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE);
tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE);
+ tolua_function(tolua_S, "SendPluginMessage", tolua_cClientHandle_SendPluginMessage);
tolua_endmodule(tolua_S);
tolua_beginmodule(tolua_S, "cItemGrid");
diff --git a/src/Bindings/PluginLua.cpp b/src/Bindings/PluginLua.cpp
index 209842e55..4c4664815 100644
--- a/src/Bindings/PluginLua.cpp
+++ b/src/Bindings/PluginLua.cpp
@@ -90,6 +90,8 @@ bool cPluginLua::Initialize(void)
// Load all files for this plugin, and execute them
AStringVector Files = cFile::GetFolderContents(PluginPath.c_str());
+
+ int numFiles = 0;
for (AStringVector::const_iterator itr = Files.begin(); itr != Files.end(); ++itr)
{
if (itr->rfind(".lua") == AString::npos)
@@ -101,9 +103,20 @@ bool cPluginLua::Initialize(void)
{
Close();
return false;
+ }
+ else
+ {
+ numFiles++;
}
} // for itr - Files[]
+ if (numFiles == 0)
+ {
+ LOGWARNING("No lua files found: plugin %s is missing.", GetName().c_str());
+ Close();
+ return false;
+ }
+
// Call intialize function
bool res = false;
if (!m_LuaState.Call("Initialize", this, cLuaState::Return, res))
@@ -423,7 +436,7 @@ bool cPluginLua::OnExploding(cWorld & a_World, double & a_ExplosionSize, bool &
{
case esOther: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esPrimedTNT: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cTNTEntity *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
- case esCreeper: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cCreeper *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
+ case esMonster: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (cMonster *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esBed: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esEnderCrystal: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, (Vector3i *)a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
case esGhastFireball: m_LuaState.Call((int)(**itr), &a_World, a_ExplosionSize, a_CanCauseFire, a_X, a_Y, a_Z, a_Source, a_SourceData, cLuaState::Return, res, a_CanCauseFire, a_ExplosionSize); break;
diff --git a/src/Bindings/PluginManager.cpp b/src/Bindings/PluginManager.cpp
index 68e6aea33..24bb914d1 100644
--- a/src/Bindings/PluginManager.cpp
+++ b/src/Bindings/PluginManager.cpp
@@ -169,9 +169,9 @@ void cPluginManager::InsertDefaultPlugins(cIniFile & a_SettingsIni)
a_SettingsIni.AddKeyComment("Plugins", " Plugin=HookNotify");
a_SettingsIni.AddKeyComment("Plugins", " Plugin=ChunkWorx");
a_SettingsIni.AddKeyComment("Plugins", " Plugin=APIDump");
- a_SettingsIni.SetValue("Plugins", "Plugin", "Core");
- a_SettingsIni.SetValue("Plugins", "Plugin", "TransAPI");
- a_SettingsIni.SetValue("Plugins", "Plugin", "ChatLog");
+ a_SettingsIni.AddValue("Plugins", "Plugin", "Core");
+ a_SettingsIni.AddValue("Plugins", "Plugin", "TransAPI");
+ a_SettingsIni.AddValue("Plugins", "Plugin", "ChatLog");
}
diff --git a/src/Bindings/tolua++.h b/src/Bindings/tolua++.h
index 4dfd06318..73e65b746 100644
--- a/src/Bindings/tolua++.h
+++ b/src/Bindings/tolua++.h
@@ -2,12 +2,18 @@
// tolua++.h
// Redirection file, needed because ToLua++ generates the Bindings.cpp file with >> #include "tolua++.h" <<
+// Only used from Bindings.cpp
#include "tolua++/include/tolua++.h"
+#ifdef _MSC_VER
+ // Disable specific warnings for the generated Bindings.cpp file:
+ #pragma warning(disable: 4800) // 'int' : forcing value to bool 'true' or 'false' (performance warning)
+#endif // _MSC_VER
+
diff --git a/src/Bindings/tolua_base.h b/src/Bindings/tolua_base.h
deleted file mode 100644
index 6a76f97b1..000000000
--- a/src/Bindings/tolua_base.h
+++ /dev/null
@@ -1,128 +0,0 @@
-#ifndef TOLUA_BASE_H
-#define TOLUA_BASE_H
-
-#pragma warning(disable:4800) // This file is ONLY included by Bindings.cpp and it throws lots of C4800 warnings
-
-#include "tolua++/include/tolua++.h"
-
-
-
-
-
-class ToluaBase {
-
- int lua_instance;
-
-protected:
-
- lua_State* lua_state;
-
- void lua_stacktrace(lua_State* L) const
- {
- lua_Debug entry;
- int depth = 0;
-
- while (lua_getstack(L, depth, &entry))
- {
- lua_getinfo(L, "Sln", &entry);
-
- LOGERROR("%s(%d): %s", entry.short_src, entry.currentline, entry.name ? entry.name : "?");
- depth++;
- }
- }
-
-
- bool report_errors(int status) const
- {
- if ( status!=0 )
- {
- const char* s = lua_tostring(lua_state, -1);
- LOGERROR("-- %s", s );
- //lua_pop(lua_state, 1);
- LOGERROR("Stack:");
- lua_stacktrace( lua_state );
- return true;
- }
- return false;
- }
-
- bool push_method(const char* name, lua_CFunction f) const {
-
- if (!lua_state) return false;
-
- lua_getref(lua_state, lua_instance);
- lua_pushstring(lua_state, name);
- //LOGINFO("1. push_method() Stack size: %i", lua_gettop( lua_state ) );
- lua_gettable(lua_state, -2);
- //LOGINFO("2. push_method() Stack size: %i", lua_gettop( lua_state ) );
-
- if (lua_isnil(lua_state, -1)) {
-
- // pop the table
- lua_pop(lua_state, 2);
- return false;
-
- } else {
-
- if (f) {
- if (lua_iscfunction(lua_state, -1)) {
- lua_pop(lua_state, 2);
- return false;
- };
- /* // not for now
- lua_pushcfunction(lua_state, f);
- if (lua_rawequal(lua_state, -1, -2)) {
-
- // avoid recursion, pop both functions and the table
- lua_pop(lua_state, 3);
- return false;
- };
-
- // pop f
- lua_pop(lua_state, 1);
- */
- };
-
- // swap table with function
- lua_insert(lua_state, -2);
- };
-
- return true;
- };
-
- void dbcall(lua_State* L, int nargs, int nresults) const {
-
- // using lua_call for now
- int s = lua_pcall(L, nargs, nresults, 0);
- report_errors( s );
- };
-public:
-
- int GetInstance() { return lua_instance; }
- lua_State* GetLuaState() { return lua_state; }
-
- void tolua__set_instance(lua_State* L, lua_Object lo) {
-
- lua_state = L;
-
- lua_pushvalue(L, lo);
- lua_instance = lua_ref(lua_state, 1);
- };
-
- ToluaBase() {
-
- lua_state = NULL;
- };
-
- ~ToluaBase() {
-
- if (lua_state) {
-
- lua_unref(lua_state, lua_instance);
- };
- };
-};
-
-#endif
-
-
diff --git a/src/Bindings/virtual_method_hooks.lua b/src/Bindings/virtual_method_hooks.lua
index 15ff1d7f8..c610d424f 100644
--- a/src/Bindings/virtual_method_hooks.lua
+++ b/src/Bindings/virtual_method_hooks.lua
@@ -504,3 +504,11 @@ end
+
+function post_output_hook()
+ print("Bindings have been generated.")
+end
+
+
+
+
diff --git a/src/BiomeDef.cpp b/src/BiomeDef.cpp
new file mode 100644
index 000000000..89a1cdefb
--- /dev/null
+++ b/src/BiomeDef.cpp
@@ -0,0 +1,131 @@
+
+// BiomeDef.cpp
+
+// Implements biome helper functions
+
+#include "Globals.h"
+#include "BiomeDef.h"
+
+
+EMCSBiome StringToBiome(const AString & a_BiomeString)
+{
+ // If it is a number, return it:
+ int res = atoi(a_BiomeString.c_str());
+ if ((res != 0) || (a_BiomeString.compare("0") == 0))
+ {
+ // It was a valid number
+ return (EMCSBiome)res;
+ }
+
+ // Convert using the built-in map:
+ static struct {
+ EMCSBiome m_Biome;
+ const char * m_String;
+ } BiomeMap[] =
+ {
+ {biOcean, "Ocean"} ,
+ {biPlains, "Plains"},
+ {biDesert, "Desert"},
+ {biExtremeHills, "ExtremeHills"},
+ {biForest, "Forest"},
+ {biTaiga, "Taiga"},
+ {biSwampland, "Swampland"},
+ {biRiver, "River"},
+ {biNether, "Hell"},
+ {biNether, "Nether"},
+ {biEnd, "Sky"},
+ {biEnd, "End"},
+ {biFrozenOcean, "FrozenOcean"},
+ {biFrozenRiver, "FrozenRiver"},
+ {biIcePlains, "IcePlains"},
+ {biIcePlains, "Tundra"},
+ {biIceMountains, "IceMountains"},
+ {biMushroomIsland, "MushroomIsland"},
+ {biMushroomShore, "MushroomShore"},
+ {biBeach, "Beach"},
+ {biDesertHills, "DesertHills"},
+ {biForestHills, "ForestHills"},
+ {biTaigaHills, "TaigaHills"},
+ {biExtremeHillsEdge, "ExtremeHillsEdge"},
+ {biJungle, "Jungle"},
+ {biJungleHills, "JungleHills"},
+
+ // Release 1.7 biomes:
+ {biJungleEdge, "JungleEdge"},
+ {biDeepOcean, "DeepOcean"},
+ {biStoneBeach, "StoneBeach"},
+ {biColdBeach, "ColdBeach"},
+ {biBirchForest, "BirchForest"},
+ {biBirchForestHills, "BirchForestHills"},
+ {biRoofedForest, "RoofedForest"},
+ {biColdTaiga, "ColdTaiga"},
+ {biColdTaigaHills, "ColdTaigaHills"},
+ {biMegaTaiga, "MegaTaiga"},
+ {biMegaTaigaHills, "MegaTaigaHills"},
+ {biExtremeHillsPlus, "ExtremeHillsPlus"},
+ {biSavanna, "Savanna"},
+ {biSavannaPlateau, "SavannaPlateau"},
+ {biMesa, "Mesa"},
+ {biMesaPlateauF, "MesaPlateauF"},
+ {biMesaPlateau, "MesaPlateau"},
+
+ // Release 1.7 variants:
+ {biSunflowerPlains, "SunflowerPlains"},
+ {biDesertM, "DesertM"},
+ {biExtremeHillsM, "ExtremeHillsM"},
+ {biFlowerForest, "FlowerForest"},
+ {biTaigaM, "TaigaM"},
+ {biSwamplandM, "SwamplandM"},
+ {biIcePlainsSpikes, "IcePlainsSpikes"},
+ {biJungleM, "JungleM"},
+ {biJungleEdgeM, "JungleEdgeM"},
+ {biBirchForestM, "BirchForestM"},
+ {biBirchForestHillsM, "BirchForestHillsM"},
+ {biRoofedForestM, "RoofedForestM"},
+ {biColdTaigaM, "ColdTaigaM"},
+ {biMegaSpruceTaiga, "MegaSpruceTaiga"},
+ {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"},
+ {biExtremeHillsPlusM, "ExtremeHillsPlusM"},
+ {biSavannaM, "SavannaM"},
+ {biSavannaPlateauM, "SavannaPlateauM"},
+ {biMesaBryce, "MesaBryce"},
+ {biMesaPlateauFM, "MesaPlateauFM"},
+ {biMesaPlateauM, "MesaPlateauM"},
+ } ;
+
+ for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++)
+ {
+ if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0)
+ {
+ return BiomeMap[i].m_Biome;
+ }
+ } // for i - BiomeMap[]
+ return (EMCSBiome)-1;
+}
+
+
+
+
+
+bool IsBiomeNoDownfall(EMCSBiome a_Biome)
+{
+ switch (a_Biome)
+ {
+ case biDesert:
+ case biDesertHills:
+ case biDesertM:
+ case biSavanna:
+ case biSavannaM:
+ case biSavannaPlateau:
+ case biSavannaPlateauM:
+ case biNether:
+ case biEnd:
+ {
+ return true;
+ }
+ default:
+ {
+ return false;
+ }
+ }
+}
diff --git a/src/BiomeDef.h b/src/BiomeDef.h
new file mode 100644
index 000000000..df1e387f0
--- /dev/null
+++ b/src/BiomeDef.h
@@ -0,0 +1,107 @@
+
+// BiomeDef.h
+
+// Defines relevant information and methods related to biomes
+
+
+
+
+
+#pragma once
+
+
+
+
+
+// tolua_begin
+/** Biome IDs
+The first batch corresponds to the clientside biomes, used by MineCraft.
+BiomeIDs over 255 are used by MCServer internally and are translated to MC biomes before sending them to client
+*/
+enum EMCSBiome
+{
+ biOcean = 0,
+ biPlains = 1,
+ biDesert = 2,
+ biExtremeHills = 3,
+ biForest = 4,
+ biTaiga = 5,
+ biSwampland = 6,
+ biRiver = 7,
+ biHell = 8, // same as Nether
+ biNether = 8,
+ biSky = 9, // same as biEnd
+ biEnd = 9,
+ biFrozenOcean = 10,
+ biFrozenRiver = 11,
+ biIcePlains = 12,
+ biTundra = 12, // same as Ice Plains
+ biIceMountains = 13,
+ biMushroomIsland = 14,
+ biMushroomShore = 15,
+ biBeach = 16,
+ biDesertHills = 17,
+ biForestHills = 18,
+ biTaigaHills = 19,
+ biExtremeHillsEdge = 20,
+ biJungle = 21,
+ biJungleHills = 22,
+
+ // Release 1.7 biomes:
+ biJungleEdge = 23,
+ biDeepOcean = 24,
+ biStoneBeach = 25,
+ biColdBeach = 26,
+ biBirchForest = 27,
+ biBirchForestHills = 28,
+ biRoofedForest = 29,
+ biColdTaiga = 30,
+ biColdTaigaHills = 31,
+ biMegaTaiga = 32,
+ biMegaTaigaHills = 33,
+ biExtremeHillsPlus = 34,
+ biSavanna = 35,
+ biSavannaPlateau = 36,
+ biMesa = 37,
+ biMesaPlateauF = 38,
+ biMesaPlateau = 39,
+
+ // Automatically capture the maximum consecutive biome value into biMaxBiome:
+ biNumBiomes, // True number of biomes, since they are zero-based
+ biMaxBiome = biNumBiomes - 1, // The maximum biome value
+
+ // Add this number to the biomes to get the variant
+ biVariant = 128,
+
+ // Release 1.7 biome variants:
+ biSunflowerPlains = 129,
+ biDesertM = 130,
+ biExtremeHillsM = 131,
+ biFlowerForest = 132,
+ biTaigaM = 133,
+ biSwamplandM = 134,
+ biIcePlainsSpikes = 140,
+ biJungleM = 149,
+ biJungleEdgeM = 151,
+ biBirchForestM = 155,
+ biBirchForestHillsM = 156,
+ biRoofedForestM = 157,
+ biColdTaigaM = 158,
+ biMegaSpruceTaiga = 160,
+ biMegaSpruceTaigaHills = 161,
+ biExtremeHillsPlusM = 162,
+ biSavannaM = 163,
+ biSavannaPlateauM = 164,
+ biMesaBryce = 165,
+ biMesaPlateauFM = 166,
+ biMesaPlateauM = 167,
+} ;
+
+/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure.
+extern EMCSBiome StringToBiome(const AString & a_BiomeString);
+
+/// Returns true if the biome has no downfall - deserts and savannas
+extern bool IsBiomeNoDownfall(EMCSBiome a_Biome);
+
+
+// tolua_end
diff --git a/src/BlockEntities/FurnaceEntity.cpp b/src/BlockEntities/FurnaceEntity.cpp
index f15553968..c6643bcff 100644
--- a/src/BlockEntities/FurnaceEntity.cpp
+++ b/src/BlockEntities/FurnaceEntity.cpp
@@ -307,7 +307,7 @@ void cFurnaceEntity::OnSlotChanged(cItemGrid * a_ItemGrid, int a_SlotNum)
/// Updates the current recipe, based on the current input
void cFurnaceEntity::UpdateInput(void)
{
- if (!m_Contents.GetSlot(fsInput).IsStackableWith(m_LastInput))
+ if (!m_Contents.GetSlot(fsInput).IsEqual(m_LastInput))
{
// The input is different from what we had before, reset the cooking time
m_TimeCooked = 0;
@@ -417,7 +417,7 @@ bool cFurnaceEntity::CanCookInputToOutput(void) const
return true;
}
- if (!m_Contents.GetSlot(fsOutput).IsStackableWith(*m_CurrentRecipe->Out))
+ if (!m_Contents.GetSlot(fsOutput).IsEqual(*m_CurrentRecipe->Out))
{
// The output slot is blocked with something that cannot be stacked with the recipe's output
return false;
diff --git a/src/BlockEntities/HopperEntity.cpp b/src/BlockEntities/HopperEntity.cpp
index eac59e74d..2255cad64 100644
--- a/src/BlockEntities/HopperEntity.cpp
+++ b/src/BlockEntities/HopperEntity.cpp
@@ -407,7 +407,7 @@ bool cHopperEntity::MoveItemsFromSlot(cBlockEntityWithItems & a_Entity, int a_Sl
m_Contents.SetSlot(i, One);
return true;
}
- else if (m_Contents.GetSlot(i).IsStackableWith(One))
+ else if (m_Contents.GetSlot(i).IsEqual(One))
{
if (cPluginManager::Get()->CallHookHopperPullingItem(*m_World, *this, i, a_Entity, a_SlotNum))
{
@@ -544,7 +544,7 @@ bool cHopperEntity::MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstS
}
for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
{
- if (m_Contents.GetSlot(i).IsStackableWith(DestSlot))
+ if (m_Contents.GetSlot(i).IsEqual(DestSlot))
{
if (cPluginManager::Get()->CallHookHopperPushingItem(*m_World, *this, i, a_Entity, a_DstSlotNum))
{
diff --git a/src/BlockID.cpp b/src/BlockID.cpp
index 05d4c6595..095865d07 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -20,7 +20,7 @@ bool g_BlockPistonBreakable[256];
bool g_BlockIsSnowable[256];
bool g_BlockRequiresSpecialTool[256];
bool g_BlockIsSolid[256];
-bool g_BlockIsTorchPlaceable[256];
+bool g_BlockFullyOccupiesVoxel[256];
@@ -267,106 +267,6 @@ AString ItemToFullString(const cItem & a_Item)
-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))
- {
- // It was a valid number
- return (EMCSBiome)res;
- }
-
- // Convert using the built-in map:
- static struct {
- EMCSBiome m_Biome;
- const char * m_String;
- } BiomeMap[] =
- {
- {biOcean, "Ocean"} ,
- {biPlains, "Plains"},
- {biDesert, "Desert"},
- {biExtremeHills, "ExtremeHills"},
- {biForest, "Forest"},
- {biTaiga, "Taiga"},
- {biSwampland, "Swampland"},
- {biRiver, "River"},
- {biNether, "Hell"},
- {biNether, "Nether"},
- {biEnd, "Sky"},
- {biEnd, "End"},
- {biFrozenOcean, "FrozenOcean"},
- {biFrozenRiver, "FrozenRiver"},
- {biIcePlains, "IcePlains"},
- {biIcePlains, "Tundra"},
- {biIceMountains, "IceMountains"},
- {biMushroomIsland, "MushroomIsland"},
- {biMushroomShore, "MushroomShore"},
- {biBeach, "Beach"},
- {biDesertHills, "DesertHills"},
- {biForestHills, "ForestHills"},
- {biTaigaHills, "TaigaHills"},
- {biExtremeHillsEdge, "ExtremeHillsEdge"},
- {biJungle, "Jungle"},
- {biJungleHills, "JungleHills"},
-
- // Release 1.7 biomes:
- {biJungleEdge, "JungleEdge"},
- {biDeepOcean, "DeepOcean"},
- {biStoneBeach, "StoneBeach"},
- {biColdBeach, "ColdBeach"},
- {biBirchForest, "BirchForest"},
- {biBirchForestHills, "BirchForestHills"},
- {biRoofedForest, "RoofedForest"},
- {biColdTaiga, "ColdTaiga"},
- {biColdTaigaHills, "ColdTaigaHills"},
- {biMegaTaiga, "MegaTaiga"},
- {biMegaTaigaHills, "MegaTaigaHills"},
- {biExtremeHillsPlus, "ExtremeHillsPlus"},
- {biSavanna, "Savanna"},
- {biSavannaPlateau, "SavannaPlateau"},
- {biMesa, "Mesa"},
- {biMesaPlateauF, "MesaPlateauF"},
- {biMesaPlateau, "MesaPlateau"},
-
- // Release 1.7 variants:
- {biSunflowerPlains, "SunflowerPlains"},
- {biDesertM, "DesertM"},
- {biExtremeHillsM, "ExtremeHillsM"},
- {biFlowerForest, "FlowerForest"},
- {biTaigaM, "TaigaM"},
- {biSwamplandM, "SwamplandM"},
- {biIcePlainsSpikes, "IcePlainsSpikes"},
- {biJungleM, "JungleM"},
- {biJungleEdgeM, "JungleEdgeM"},
- {biBirchForestM, "BirchForestM"},
- {biBirchForestHillsM, "BirchForestHillsM"},
- {biRoofedForestM, "RoofedForestM"},
- {biColdTaigaM, "ColdTaigaM"},
- {biMegaSpruceTaiga, "MegaSpruceTaiga"},
- {biMegaSpruceTaigaHills, "MegaSpruceTaigaHills"},
- {biExtremeHillsPlusM, "ExtremeHillsPlusM"},
- {biSavannaM, "SavannaM"},
- {biSavannaPlateauM, "SavannaPlateauM"},
- {biMesaBryce, "MesaBryce"},
- {biMesaPlateauFM, "MesaPlateauFM"},
- {biMesaPlateauM, "MesaPlateauM"},
- } ;
-
- for (size_t i = 0; i < ARRAYCOUNT(BiomeMap); i++)
- {
- if (NoCaseCompare(BiomeMap[i].m_String, a_BiomeString) == 0)
- {
- return BiomeMap[i].m_Biome;
- }
- } // for i - BiomeMap[]
- return (EMCSBiome)-1;
-}
-
-
-
-
-
int StringToMobType(const AString & a_MobString)
{
static struct {
@@ -591,7 +491,7 @@ public:
memset(g_BlockTransparent, 0x00, sizeof(g_BlockTransparent));
memset(g_BlockOneHitDig, 0x00, sizeof(g_BlockOneHitDig));
memset(g_BlockPistonBreakable, 0x00, sizeof(g_BlockPistonBreakable));
- memset(g_BlockIsTorchPlaceable, 0x00, sizeof(g_BlockIsTorchPlaceable));
+ memset(g_BlockFullyOccupiesVoxel, 0x00, sizeof(g_BlockFullyOccupiesVoxel));
// Setting bools to true must be done manually, see http://forum.mc-server.org/showthread.php?tid=629&pid=5415#pid5415
for (size_t i = 0; i < ARRAYCOUNT(g_BlockIsSnowable); i++)
@@ -867,6 +767,7 @@ public:
g_BlockIsSolid[E_BLOCK_MELON_STEM] = false;
g_BlockIsSolid[E_BLOCK_NETHER_PORTAL] = false;
g_BlockIsSolid[E_BLOCK_PISTON_EXTENSION] = false;
+ g_BlockIsSolid[E_BLOCK_POWERED_RAIL] = false;
g_BlockIsSolid[E_BLOCK_RAIL] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_OFF] = false;
g_BlockIsSolid[E_BLOCK_REDSTONE_TORCH_ON] = false;
@@ -891,67 +792,67 @@ public:
g_BlockIsSolid[E_BLOCK_WOODEN_SLAB] = false;
// Torch placeable blocks:
- g_BlockIsTorchPlaceable[E_BLOCK_BEDROCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_COAL] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_BLOCK_OF_REDSTONE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_BOOKCASE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_BRICK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_CLAY] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_COAL_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_COBBLESTONE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_COMMAND_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_CRAFTING_TABLE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_DIAMOND_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_DIAMOND_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_DIRT] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_DISPENSER] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_DOUBLE_STONE_SLAB] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_DOUBLE_WOODEN_SLAB] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_DROPPER] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_EMERALD_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_EMERALD_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_END_STONE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_FURNACE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_GLOWSTONE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_GOLD_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_GOLD_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_GRASS] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_GRAVEL] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_HARDENED_CLAY] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_HAY_BALE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_HUGE_BROWN_MUSHROOM] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_HUGE_RED_MUSHROOM] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_IRON_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_IRON_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_JACK_O_LANTERN] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_JUKEBOX] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_LAPIS_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_LAPIS_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_LOG] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_MELON] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_MOSSY_COBBLESTONE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_MYCELIUM] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_NETHERRACK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_NETHER_BRICK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_NETHER_QUARTZ_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_NOTE_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_OBSIDIAN] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_PACKED_ICE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_PLANKS] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_PUMPKIN] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_QUARTZ_BLOCK] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_LAMP_OFF] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_LAMP_ON] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_ORE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_SANDSTONE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_SAND] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_SILVERFISH_EGG] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_SPONGE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_STAINED_CLAY] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_WOOL] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_STONE] = true;
- g_BlockIsTorchPlaceable[E_BLOCK_STONE_BRICKS] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_BEDROCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_COAL] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_BLOCK_OF_REDSTONE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_BOOKCASE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_BRICK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_CLAY] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_COAL_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_COBBLESTONE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_COMMAND_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_CRAFTING_TABLE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_DIAMOND_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_DIRT] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_DISPENSER] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_STONE_SLAB] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_DOUBLE_WOODEN_SLAB] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_DROPPER] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_EMERALD_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_END_STONE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_FURNACE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_GLOWSTONE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_GOLD_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_GRASS] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_GRAVEL] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_HARDENED_CLAY] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_HAY_BALE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_BROWN_MUSHROOM] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_HUGE_RED_MUSHROOM] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_IRON_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_JACK_O_LANTERN] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_JUKEBOX] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_LAPIS_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_LOG] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_MELON] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_MOSSY_COBBLESTONE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_MYCELIUM] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_NETHERRACK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_BRICK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_NETHER_QUARTZ_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_NOTE_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_OBSIDIAN] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_PACKED_ICE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_PLANKS] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_PUMPKIN] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_QUARTZ_BLOCK] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_OFF] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_LAMP_ON] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_REDSTONE_ORE_GLOWING] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_SANDSTONE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_SAND] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_SILVERFISH_EGG] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_SPONGE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_STAINED_CLAY] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_WOOL] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_STONE] = true;
+ g_BlockFullyOccupiesVoxel[E_BLOCK_STONE_BRICKS] = true;
}
} BlockPropertiesInitializer;
diff --git a/src/BlockID.h b/src/BlockID.h
index 288719ccf..b31c589b9 100644
--- a/src/BlockID.h
+++ b/src/BlockID.h
@@ -876,9 +876,6 @@ extern AString ItemTypeToString(short a_ItemType);
/// Translates a full item into a fully-specified string (including meta and count). If the ItemType is not recognized, the ItemType number is output into the string.
extern AString ItemToFullString(const cItem & a_Item);
-/// Translates a biome string to biome enum. Takes either a number or a biome alias (built-in). Returns -1 on failure.
-extern EMCSBiome StringToBiome(const AString & a_BiomeString);
-
/// Translates a mob string ("ocelot") to mobtype (E_ENTITY_TYPE_OCELOT)
extern int StringToMobType(const AString & a_MobString);
@@ -909,7 +906,7 @@ extern bool g_BlockPistonBreakable[256];
extern bool g_BlockIsSnowable[256];
extern bool g_BlockRequiresSpecialTool[256];
extern bool g_BlockIsSolid[256];
-extern bool g_BlockIsTorchPlaceable[256];
+extern bool g_BlockFullyOccupiesVoxel[256];
diff --git a/src/Blocks/BlockChest.h b/src/Blocks/BlockChest.h
index 488c58ac5..88f7c4b32 100644
--- a/src/Blocks/BlockChest.h
+++ b/src/Blocks/BlockChest.h
@@ -42,13 +42,13 @@ public:
{
return false;
}
- double rot = a_Player->GetRotation();
+ double yaw = a_Player->GetYaw();
if (
(Area.GetRelBlockType(0, 0, 1) == E_BLOCK_CHEST) ||
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
- a_BlockMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3;
+ a_BlockMeta = ((yaw >= -90) && (yaw < 90)) ? 2 : 3;
return true;
}
if (
@@ -56,12 +56,12 @@ public:
(Area.GetRelBlockType(2, 0, 1) == E_BLOCK_CHEST)
)
{
- a_BlockMeta = (rot < 0) ? 4 : 5;
+ a_BlockMeta = (yaw < 0) ? 4 : 5;
return true;
}
// Single chest, get meta from rotation only
- a_BlockMeta = RotationToMetaData(rot);
+ a_BlockMeta = RotationToMetaData(yaw);
return true;
}
@@ -80,7 +80,7 @@ public:
return;
}
- double rot = a_Player->GetRotation();
+ double rot = a_Player->GetYaw(); // FIXME: Rename rot to yaw
// Choose meta from player rotation, choose only between 2 or 3
NIBBLETYPE NewMeta = ((rot >= -90) && (rot < 90)) ? 2 : 3;
if (
diff --git a/src/Blocks/BlockComparator.h b/src/Blocks/BlockComparator.h
index e7e18bac9..5a8e54eda 100644
--- a/src/Blocks/BlockComparator.h
+++ b/src/Blocks/BlockComparator.h
@@ -53,7 +53,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockDoor.h b/src/Blocks/BlockDoor.h
index 03a79d47d..1e86446dd 100644
--- a/src/Blocks/BlockDoor.h
+++ b/src/Blocks/BlockDoor.h
@@ -42,7 +42,7 @@ public:
}
a_BlockType = m_BlockType;
- a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
+ a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockDropSpenser.h b/src/Blocks/BlockDropSpenser.h
index b7f20825d..ce9cc0c5d 100644
--- a/src/Blocks/BlockDropSpenser.h
+++ b/src/Blocks/BlockDropSpenser.h
@@ -31,7 +31,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for dispenser placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch());
+ a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
} ;
diff --git a/src/Blocks/BlockEnderchest.h b/src/Blocks/BlockEnderchest.h
index 50d8e38e0..b648248d0 100644
--- a/src/Blocks/BlockEnderchest.h
+++ b/src/Blocks/BlockEnderchest.h
@@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockFenceGate.h b/src/Blocks/BlockFenceGate.h
index 6423a7cb0..779f12ee1 100644
--- a/src/Blocks/BlockFenceGate.h
+++ b/src/Blocks/BlockFenceGate.h
@@ -25,7 +25,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
+ a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}
@@ -33,7 +33,7 @@ public:
virtual void OnUse(cWorld * a_World, cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) override
{
NIBBLETYPE OldMetaData = a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
- NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetRotation());
+ NIBBLETYPE NewMetaData = PlayerYawToMetaData(a_Player->GetYaw());
OldMetaData ^= 4; // Toggle the gate
if ((OldMetaData & 1) == (NewMetaData & 1))
{
diff --git a/src/Blocks/BlockFurnace.h b/src/Blocks/BlockFurnace.h
index 5b067d7b7..693eac331 100644
--- a/src/Blocks/BlockFurnace.h
+++ b/src/Blocks/BlockFurnace.h
@@ -35,7 +35,7 @@ public:
a_BlockType = m_BlockType;
// FIXME: Do not use cPiston class for furnace placement!
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), 0);
+ a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), 0);
return true;
}
diff --git a/src/Blocks/BlockGlowstone.h b/src/Blocks/BlockGlowstone.h
index 5f0d95dee..6c198efc4 100644
--- a/src/Blocks/BlockGlowstone.h
+++ b/src/Blocks/BlockGlowstone.h
@@ -20,8 +20,8 @@ public:
virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override
{
// Reset meta to 0
- // TODO: More drops?
- a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, 1, 0));
+ MTRand r1;
+ a_Pickups.push_back(cItem(E_ITEM_GLOWSTONE_DUST, (char)(2 + r1.randInt(2)), 0));
}
} ;
diff --git a/src/Blocks/BlockLever.h b/src/Blocks/BlockLever.h
index 15fe2071c..5b0c89127 100644
--- a/src/Blocks/BlockLever.h
+++ b/src/Blocks/BlockLever.h
@@ -20,7 +20,7 @@ public:
// Flip the ON bit on/off using the XOR bitwise operation
NIBBLETYPE Meta = (a_World->GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) ^ 0x08);
- a_World->SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta);
+ a_World->SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_LEVER, Meta); // SetMeta doesn't work for unpowering levers, so setblock
a_World->BroadcastSoundEffect("random.click", a_BlockX * 8, a_BlockY * 8, a_BlockZ * 8, 0.5f, (Meta & 0x08) ? 0.6f : 0.5f);
}
diff --git a/src/Blocks/BlockPiston.cpp b/src/Blocks/BlockPiston.cpp
index 3e1ca1d15..88259d96e 100644
--- a/src/Blocks/BlockPiston.cpp
+++ b/src/Blocks/BlockPiston.cpp
@@ -60,7 +60,7 @@ bool cBlockPistonHandler::GetPlacementBlockTypeMeta(
)
{
a_BlockType = m_BlockType;
- a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetRotation(), a_Player->GetPitch());
+ a_BlockMeta = cPiston::RotationPitchToMetaData(a_Player->GetYaw(), a_Player->GetPitch());
return true;
}
diff --git a/src/Blocks/BlockPumpkin.h b/src/Blocks/BlockPumpkin.h
index 724241935..5187f24eb 100644
--- a/src/Blocks/BlockPumpkin.h
+++ b/src/Blocks/BlockPumpkin.h
@@ -86,7 +86,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = PlayerYawToMetaData(a_Player->GetRotation());
+ a_BlockMeta = PlayerYawToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockRedstone.h b/src/Blocks/BlockRedstone.h
index 1bd9995f2..5ffb77fb6 100644
--- a/src/Blocks/BlockRedstone.h
+++ b/src/Blocks/BlockRedstone.h
@@ -20,7 +20,7 @@ public:
virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override
{
- return ((a_RelY > 0) && g_BlockIsTorchPlaceable[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]);
+ return ((a_RelY > 0) && g_BlockFullyOccupiesVoxel[a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ)]);
}
diff --git a/src/Blocks/BlockRedstoneRepeater.h b/src/Blocks/BlockRedstoneRepeater.h
index 1fcddd4f8..713664659 100644
--- a/src/Blocks/BlockRedstoneRepeater.h
+++ b/src/Blocks/BlockRedstoneRepeater.h
@@ -25,7 +25,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
diff --git a/src/Blocks/BlockStairs.h b/src/Blocks/BlockStairs.h
index fa378e4b5..e463612f5 100644
--- a/src/Blocks/BlockStairs.h
+++ b/src/Blocks/BlockStairs.h
@@ -26,7 +26,7 @@ public:
) override
{
a_BlockType = m_BlockType;
- a_BlockMeta = RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = RotationToMetaData(a_Player->GetYaw());
switch (a_BlockFace)
{
case BLOCK_FACE_TOP: break;
diff --git a/src/Blocks/BlockTorch.h b/src/Blocks/BlockTorch.h
index 9e543dfd7..faba9c4f5 100644
--- a/src/Blocks/BlockTorch.h
+++ b/src/Blocks/BlockTorch.h
@@ -98,7 +98,7 @@ public:
static bool CanBePlacedOn(BLOCKTYPE a_BlockType, char a_BlockFace)
{
- if ( !g_BlockIsTorchPlaceable[a_BlockType] )
+ if ( !g_BlockFullyOccupiesVoxel[a_BlockType] )
{
return (a_BlockFace == BLOCK_FACE_TOP); // Allow placement only when torch upright (for glass, etc.); exceptions won't even be sent by client, no need to handle
}
@@ -127,7 +127,7 @@ public:
{
return i;
}
- else if ((g_BlockIsTorchPlaceable[BlockInQuestion]) && (i != BLOCK_FACE_BOTTOM))
+ else if ((g_BlockFullyOccupiesVoxel[BlockInQuestion]) && (i != BLOCK_FACE_BOTTOM))
{
// Otherwise, if block in that direction is torch placeable and we haven't gotten to it via the bottom face, return that face
return i;
@@ -161,7 +161,7 @@ public:
// No need to check for upright orientation, it was done when the torch was placed
return true;
}
- else if ( !g_BlockIsTorchPlaceable[BlockInQuestion] )
+ else if ( !g_BlockFullyOccupiesVoxel[BlockInQuestion] )
{
return false;
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 853138769..275099540 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,11 +1,7 @@
-cmake_minimum_required (VERSION 2.6)
+cmake_minimum_required (VERSION 2.8.2)
project (MCServer)
-if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++03")
-endif()
-
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/")
include_directories (SYSTEM "${PROJECT_SOURCE_DIR}/../lib/jsoncpp/include")
@@ -25,12 +21,34 @@ if (NOT MSVC)
list(REMOVE_ITEM SOURCE "${PROJECT_SOURCE_DIR}/StackWalker.cpp" "${PROJECT_SOURCE_DIR}/LeakFinder.cpp")
+ # If building a windows version, but not using MSVC, add the resources directly to the makefile:
+ if (WIN32)
+ FILE(GLOB ResourceFiles
+ "Resources/*.rc"
+ )
+ list(APPEND SOURCE "${ResourceFiles}")
+ endif()
+
+
else ()
+ # Generate the Bindings if they don't exist:
+ if (NOT EXISTS "${PROJECT_SOURCE_DIR}/Bindings/Bindings.cpp")
+ message("Bindings.cpp not found, generating now")
+ set(tolua_executable ${PROJECT_SOURCE_DIR}/Bindings/tolua++.exe)
+ execute_process(
+ COMMAND ${tolua_executable} -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg
+ WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/Bindings
+ )
+ endif()
+
+ # Add all subfolders as solution-folders:
+ list(APPEND FOLDERS "Resources")
function(includefolder PATH)
FILE(GLOB FOLDER_FILES
"${PATH}/*.cpp"
"${PATH}/*.h"
+ "${PATH}/*.rc"
)
source_group("${PATH}" FILES ${FOLDER_FILES})
endfunction(includefolder)
@@ -59,25 +77,31 @@ else ()
SET_SOURCE_FILES_PROPERTIES(
"StackWalker.cpp LeakFinder.h" PROPERTIES COMPILE_FLAGS "/Yc\"Globals.h\""
)
+ list(APPEND SOURCE "Resources/MCServer.rc")
endif()
-
set(EXECUTABLE MCServer)
add_executable(${EXECUTABLE} ${SOURCE})
-set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer)
-if (MSVC)
- # MSVC generator adds a "Debug" or "Release" postfixes to the EXECUTABLE_OUTPUT_PATH, we need to cancel them:
- SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES PREFIX "../")
- SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES IMPORT_PREFIX "../")
-endif()
+# Output the executable into the $/MCServer folder, so that it has access to external resources:
+set(EXECUTABLE_OUTPUT_PATH ${CMAKE_SOURCE_DIR}/MCServer)
+SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES
+ RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_SOURCE_DIR}/MCServer
+ RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_SOURCE_DIR}/MCServer
+ RUNTIME_OUTPUT_DIRECTORY_DEBUGPROFILE ${CMAKE_SOURCE_DIR}/MCServer
+ RUNTIME_OUTPUT_DIRECTORY_RELEASEPROFILE ${CMAKE_SOURCE_DIR}/MCServer
+)
# Make the debug executable have a "_debug" suffix
SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES DEBUG_POSTFIX "_debug")
+# Make the profiled executables have a "_profile" postfix
+SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES DEBUGPROFILE_POSTFIX "_debug_profile")
+SET_TARGET_PROPERTIES(${EXECUTABLE} PROPERTIES RELEASEPROFILE_POSTFIX "_profile")
+
# Precompiled headers (2nd part)
if (MSVC)
diff --git a/src/Chunk.cpp b/src/Chunk.cpp
index fb26e983d..0735c8144 100644
--- a/src/Chunk.cpp
+++ b/src/Chunk.cpp
@@ -1743,7 +1743,14 @@ bool cChunk::AddClient(cClientHandle* a_Client)
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr )
{
- LOGD("cChunk: Entity #%d (%s) at [%i, %i, %i] spawning for player \"%s\"", (*itr)->GetUniqueID(), (*itr)->GetClass(), m_PosX, m_PosY, m_PosZ, a_Client->GetUsername().c_str());
+ /*
+ // DEBUG:
+ LOGD("cChunk: Entity #%d (%s) at [%i, %i, %i] spawning for player \"%s\"",
+ (*itr)->GetUniqueID(), (*itr)->GetClass(),
+ m_PosX, m_PosY, m_PosZ,
+ a_Client->GetUsername().c_str()
+ );
+ */
(*itr)->SpawnOn(*a_Client);
}
return true;
@@ -1768,7 +1775,13 @@ void cChunk::RemoveClient( cClientHandle* a_Client )
{
for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr )
{
- LOGD("chunk [%i, %i] destroying entity #%i for player \"%s\"", m_PosX, m_PosZ, (*itr)->GetUniqueID(), a_Client->GetUsername().c_str() );
+ /*
+ // DEBUG:
+ LOGD("chunk [%i, %i] destroying entity #%i for player \"%s\"",
+ m_PosX, m_PosZ,
+ (*itr)->GetUniqueID(), a_Client->GetUsername().c_str()
+ );
+ */
a_Client->SendDestroyEntity(*(*itr));
}
}
diff --git a/src/ChunkDef.h b/src/ChunkDef.h
index 7d727a4d4..d1288994c 100644
--- a/src/ChunkDef.h
+++ b/src/ChunkDef.h
@@ -10,6 +10,7 @@
#pragma once
#include "Vector3i.h"
+#include "BiomeDef.h"
@@ -57,97 +58,6 @@ typedef unsigned char HEIGHTTYPE;
-
-
-// tolua_begin
-/** Biome IDs
-The first batch corresponds to the clientside biomes, used by MineCraft.
-BiomeIDs over 255 are used by MCServer internally and are translated to MC biomes before sending them to client
-*/
-enum EMCSBiome
-{
- biOcean = 0,
- biPlains = 1,
- biDesert = 2,
- biExtremeHills = 3,
- biForest = 4,
- biTaiga = 5,
- biSwampland = 6,
- biRiver = 7,
- biHell = 8, // same as Nether
- biNether = 8,
- biSky = 9, // same as biEnd
- biEnd = 9,
- biFrozenOcean = 10,
- biFrozenRiver = 11,
- biIcePlains = 12,
- biTundra = 12, // same as Ice Plains
- biIceMountains = 13,
- biMushroomIsland = 14,
- biMushroomShore = 15,
- biBeach = 16,
- biDesertHills = 17,
- biForestHills = 18,
- biTaigaHills = 19,
- biExtremeHillsEdge = 20,
- biJungle = 21,
- biJungleHills = 22,
-
- // Release 1.7 biomes:
- biJungleEdge = 23,
- biDeepOcean = 24,
- biStoneBeach = 25,
- biColdBeach = 26,
- biBirchForest = 27,
- biBirchForestHills = 28,
- biRoofedForest = 29,
- biColdTaiga = 30,
- biColdTaigaHills = 31,
- biMegaTaiga = 32,
- biMegaTaigaHills = 33,
- biExtremeHillsPlus = 34,
- biSavanna = 35,
- biSavannaPlateau = 36,
- biMesa = 37,
- biMesaPlateauF = 38,
- biMesaPlateau = 39,
-
- // Automatically capture the maximum consecutive biome value into biMaxBiome:
- biNumBiomes, // True number of biomes, since they are zero-based
- biMaxBiome = biNumBiomes - 1, // The maximum biome value
-
- // Add this number to the biomes to get the variant
- biVariant = 128,
-
- // Release 1.7 biome variants:
- biSunflowerPlains = 129,
- biDesertM = 130,
- biExtremeHillsM = 131,
- biFlowerForest = 132,
- biTaigaM = 133,
- biSwamplandM = 134,
- biIcePlainsSpikes = 140,
- biJungleM = 149,
- biJungleEdgeM = 151,
- biBirchForestM = 155,
- biBirchForestHillsM = 156,
- biRoofedForestM = 157,
- biColdTaigaM = 158,
- biMegaSpruceTaiga = 160,
- biMegaSpruceTaigaHills = 161,
- biExtremeHillsPlusM = 162,
- biSavannaM = 163,
- biSavannaPlateauM = 164,
- biMesaBryce = 165,
- biMesaPlateauFM = 166,
- biMesaPlateauM = 167,
-} ;
-
-// tolua_end
-
-
-
-
/// Constants used throughout the code, useful typedefs and utility functions
class cChunkDef
{
@@ -610,8 +520,10 @@ public:
// Illegal in C++03: typedef std::list< cCoordWithData<X> > cCoordWithDataList<X>;
typedef cCoordWithData<int> cCoordWithInt;
+typedef cCoordWithData<BLOCKTYPE> cCoordWithBlock;
typedef std::list<cCoordWithInt> cCoordWithIntList;
typedef std::vector<cCoordWithInt> cCoordWithIntVector;
+typedef std::vector<cCoordWithBlock> cCoordWithBlockVector;
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 8125acb47..c8513d516 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -629,6 +629,17 @@ void cClientHandle::HandleLeftClick(int a_BlockX, int a_BlockY, int a_BlockZ, ch
return;
}
+ case DIG_STATUS_DROP_STACK:
+ {
+ if (PlgMgr->CallHookPlayerTossingItem(*m_Player))
+ {
+ // A plugin doesn't agree with the tossing. The plugin itself is responsible for handling the consequences (possible inventory mismatch)
+ return;
+ }
+ m_Player->TossItem(false, 64); // Toss entire slot - if there aren't enough items, the maximum will be ejected
+ return;
+ }
+
default:
{
ASSERT(!"Unhandled DIG_STATUS");
@@ -1026,7 +1037,7 @@ void cClientHandle::HandlePlayerLook(float a_Rotation, float a_Pitch, bool a_IsO
return;
}
- m_Player->SetRotation (a_Rotation);
+ m_Player->SetYaw (a_Rotation);
m_Player->SetHeadYaw (a_Rotation);
m_Player->SetPitch (a_Pitch);
m_Player->SetTouchGround(a_IsOnGround);
@@ -1058,7 +1069,7 @@ void cClientHandle::HandlePlayerMoveLook(double a_PosX, double a_PosY, double a_
m_Player->SetStance (a_Stance);
m_Player->SetTouchGround(a_IsOnGround);
m_Player->SetHeadYaw (a_Rotation);
- m_Player->SetRotation (a_Rotation);
+ m_Player->SetYaw (a_Rotation);
m_Player->SetPitch (a_Pitch);
}
@@ -1978,6 +1989,15 @@ void cClientHandle::SendPlayerSpawn(const cPlayer & a_Player)
+void cClientHandle::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+{
+ m_Protocol->SendPluginMessage(a_Channel, a_Message);
+}
+
+
+
+
+
void cClientHandle::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
m_Protocol->SendRemoveEntityEffect(a_Entity, a_EffectID);
diff --git a/src/ClientHandle.h b/src/ClientHandle.h
index bc17df780..da2704b72 100644
--- a/src/ClientHandle.h
+++ b/src/ClientHandle.h
@@ -120,6 +120,7 @@ public:
void SendPlayerMoveLook (void);
void SendPlayerPosition (void);
void SendPlayerSpawn (const cPlayer & a_Player);
+ void SendPluginMessage (const AString & a_Channel, const AString & a_Message); // Exported in ManualBindings.cpp
void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID);
void SendRespawn (void);
void SendExperience (void);
@@ -170,7 +171,13 @@ public:
void HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem);
void HandleDisconnect (const AString & a_Reason);
void HandleEntityAction (int a_EntityID, char a_ActionID);
+
+ /** Called when the protocol handshake has been received (for protocol versions that support it;
+ otherwise the first instant when a username is received).
+ Returns true if the player is to be let in, false if they were disconnected
+ */
bool HandleHandshake (const AString & a_Username);
+
void HandleKeepAlive (int a_KeepAliveID);
void HandleLeftClick (int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, char a_Status);
void HandlePing (void);
diff --git a/src/Defines.h b/src/Defines.h
index 534802d55..7a86f499e 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -41,8 +41,8 @@ extern bool g_BlockRequiresSpecialTool[256];
/// Is this block solid (player cannot walk through)?
extern bool g_BlockIsSolid[256];
-/// Can torches be placed on this block?
-extern bool g_BlockIsTorchPlaceable[256];
+/// Does this block fully occupy it's voxel - is it a 'full' block?
+extern bool g_BlockFullyOccupiesVoxel[256];
/// Experience Orb setup
enum
@@ -85,6 +85,7 @@ enum
DIG_STATUS_STARTED = 0,
DIG_STATUS_CANCELLED = 1,
DIG_STATUS_FINISHED = 2,
+ DIG_STATUS_DROP_STACK= 3,
DIG_STATUS_DROP_HELD = 4,
DIG_STATUS_SHOOT_EAT = 5,
} ;
@@ -563,34 +564,6 @@ namespace ItemCategory
}
}
-
-
-
-
-/// Returns true if the biome has no downfall - deserts and savannas
-inline bool IsBiomeNoDownfall(EMCSBiome a_Biome)
-{
- switch (a_Biome)
- {
- case biDesert:
- case biDesertHills:
- case biDesertM:
- case biSavanna:
- case biSavannaM:
- case biSavannaPlateau:
- case biSavannaPlateauM:
- case biNether:
- case biEnd:
- {
- return true;
- }
- default:
- {
- return false;
- }
- }
-}
-
// tolua_end
diff --git a/src/Entities/Entity.cpp b/src/Entities/Entity.cpp
index 8a74c9da4..565c78dfd 100644
--- a/src/Entities/Entity.cpp
+++ b/src/Entities/Entity.cpp
@@ -75,13 +75,16 @@ cEntity::~cEntity()
{
ASSERT(!m_World->HasEntity(m_UniqueID)); // Before deleting, the entity needs to have been removed from the world
+ /*
+ // DEBUG:
LOGD("Deleting entity %d at pos {%.2f, %.2f, %.2f} ~ [%d, %d]; ptr %p",
m_UniqueID,
m_Pos.x, m_Pos.y, m_Pos.z,
(int)(m_Pos.x / cChunkDef::Width), (int)(m_Pos.z / cChunkDef::Width),
this
);
-
+ */
+
if (m_AttachedTo != NULL)
{
Detach();
@@ -138,9 +141,13 @@ bool cEntity::Initialize(cWorld * a_World)
return false;
}
+ /*
+ // DEBUG:
LOGD("Initializing entity #%d (%s) at {%.02f, %.02f, %.02f}",
m_UniqueID, GetClass(), m_Pos.x, m_Pos.y, m_Pos.z
);
+ */
+
m_IsInitialized = true;
m_World = a_World;
m_World->AddEntity(this);
@@ -256,16 +263,16 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
-void cEntity::SetRotationFromSpeed(void)
+void cEntity::SetYawFromSpeed(void)
{
const double EPS = 0.0000001;
if ((abs(m_Speed.x) < EPS) && (abs(m_Speed.z) < EPS))
{
// atan2() may overflow or is undefined, pick any number
- SetRotation(0);
+ SetYaw(0);
return;
}
- SetRotation(atan2(m_Speed.x, m_Speed.z) * 180 / PI);
+ SetYaw(atan2(m_Speed.x, m_Speed.z) * 180 / PI);
}
@@ -321,7 +328,10 @@ void cEntity::DoTakeDamage(TakeDamageInfo & a_TDI)
m_Health = 0;
}
- AddSpeed(a_TDI.Knockback * 2);
+ if (IsMob() || IsPlayer()) // Knockback for only players and mobs
+ {
+ AddSpeed(a_TDI.Knockback * 2);
+ }
m_World->BroadcastEntityStatus(*this, ENTITY_STATUS_HURT);
@@ -614,9 +624,12 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
m_bOnGround = true;
+ /*
+ // DEBUG:
LOGD("Entity #%d (%s) is inside a block at {%d, %d, %d}",
m_UniqueID, GetClass(), BlockX, BlockY, BlockZ
);
+ */
}
if (!m_bOnGround)
@@ -626,11 +639,6 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
fallspeed = m_Gravity * a_Dt / 3; // Fall 3x slower in water.
}
- else if (IsBlockRail(BlockBelow) && IsMinecart()) // Rails aren't solid, except for Minecarts
- {
- fallspeed = 0;
- m_bOnGround = true;
- }
else if (BlockIn == E_BLOCK_COBWEB)
{
NextSpeed.y *= 0.05; // Reduce overall falling speed
@@ -645,41 +653,18 @@ void cEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
}
else
{
- if (IsMinecart())
+ // Friction
+ if (NextSpeed.SqrLength() > 0.0004f)
{
- if (!IsBlockRail(BlockBelow))
+ NextSpeed.x *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.x) < 0.05)
{
- // Friction if minecart is off track, otherwise, Minecart.cpp handles this
- if (NextSpeed.SqrLength() > 0.0004f)
- {
- NextSpeed.x *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.x) < 0.05)
- {
- NextSpeed.x = 0;
- }
- NextSpeed.z *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.z) < 0.05)
- {
- NextSpeed.z = 0;
- }
- }
+ NextSpeed.x = 0;
}
- }
- else
- {
- // Friction for non-minecarts
- if (NextSpeed.SqrLength() > 0.0004f)
+ NextSpeed.z *= 0.7f / (1 + a_Dt);
+ if (fabs(NextSpeed.z) < 0.05)
{
- NextSpeed.x *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.x) < 0.05)
- {
- NextSpeed.x = 0;
- }
- NextSpeed.z *= 0.7f / (1 + a_Dt);
- if (fabs(NextSpeed.z) < 0.05)
- {
- NextSpeed.z = 0;
- }
+ NextSpeed.z = 0;
}
}
}
@@ -1104,9 +1089,11 @@ void cEntity::AttachTo(cEntity * a_AttachTo)
// Already attached to that entity, nothing to do here
return;
}
-
- // Detach from any previous entity:
- Detach();
+ if (m_AttachedTo != NULL)
+ {
+ // Detach from any previous entity:
+ Detach();
+ }
// Attach to the new entity:
m_AttachedTo = a_AttachTo;
diff --git a/src/Entities/Entity.h b/src/Entities/Entity.h
index 2ba1b303d..91463bfd6 100644
--- a/src/Entities/Entity.h
+++ b/src/Entities/Entity.h
@@ -154,8 +154,7 @@ public:
double GetPosX (void) const { return m_Pos.x; }
double GetPosY (void) const { return m_Pos.y; }
double GetPosZ (void) const { return m_Pos.z; }
- const Vector3d & GetRot (void) const { return m_Rot; }
- double GetRotation (void) const { return m_Rot.x; } // OBSOLETE, use GetYaw() instead
+ const Vector3d & GetRot (void) const { return m_Rot; } // OBSOLETE, use individual GetYaw(), GetPitch, GetRoll() components
double GetYaw (void) const { return m_Rot.x; }
double GetPitch (void) const { return m_Rot.y; }
double GetRoll (void) const { return m_Rot.z; }
@@ -177,8 +176,7 @@ public:
void SetPosZ (double a_PosZ);
void SetPosition(double a_PosX, double a_PosY, double a_PosZ);
void SetPosition(const Vector3d & a_Pos) { SetPosition(a_Pos.x, a_Pos.y, a_Pos.z); }
- void SetRot (const Vector3f & a_Rot);
- void SetRotation(double a_Rotation) { SetYaw(a_Rotation); } // OBSOLETE, use SetYaw() instead
+ void SetRot (const Vector3f & a_Rot); // OBSOLETE, use individual SetYaw(), SetPitch(), SetRoll() components
void SetYaw (double a_Yaw);
void SetPitch (double a_Pitch);
void SetRoll (double a_Roll);
@@ -223,7 +221,7 @@ public:
void SetGravity(float a_Gravity) { m_Gravity = a_Gravity; }
/// Sets the rotation to match the speed vector (entity goes "face-forward")
- void SetRotationFromSpeed(void);
+ void SetYawFromSpeed(void);
/// Sets the pitch to match the speed vector (entity gies "face-forward")
void SetPitchFromSpeed(void);
@@ -327,7 +325,7 @@ public:
void AttachTo(cEntity * a_AttachTo);
/// Detaches from the currently attached entity, if any
- void Detach(void);
+ virtual void Detach(void);
/// Makes sure head yaw is not over the specified range.
void WrapHeadYaw();
diff --git a/src/Entities/Minecart.cpp b/src/Entities/Minecart.cpp
index f75e23d8b..d0d384481 100644
--- a/src/Entities/Minecart.cpp
+++ b/src/Entities/Minecart.cpp
@@ -2,6 +2,7 @@
// Minecart.cpp
// Implements the cMinecart class representing a minecart in the world
+// Handles physics when a minecart is on any type of rail (overrides simulator in Entity.cpp)
// Indiana Jones!
#include "Globals.h"
@@ -10,6 +11,10 @@
#include "../ClientHandle.h"
#include "../Chunk.h"
#include "Player.h"
+#include "../BoundingBox.h"
+
+#define MAX_SPEED 8
+#define MAX_SPEED_NEGATIVE -MAX_SPEED
@@ -18,11 +23,15 @@
cMinecart::cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z) :
super(etMinecart, a_X, a_Y, a_Z, 0.98, 0.7),
m_Payload(a_Payload),
- m_LastDamage(0)
+ m_LastDamage(0),
+ m_DetectorRailPosition(0, 0, 0),
+ m_bIsOnDetectorRail(false)
{
SetMass(20.f);
SetMaxHealth(6);
SetHealth(6);
+ SetWidth(1.2);
+ SetHeight(0.9);
}
@@ -45,6 +54,7 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
}
}
a_ClientHandle.SendSpawnVehicle(*this, 10, SubType); // 10 = Minecarts, SubType = What type of Minecart
+ a_ClientHandle.SendEntityMetadata(*this);
}
@@ -53,6 +63,11 @@ void cMinecart::SpawnOn(cClientHandle & a_ClientHandle)
void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
{
+ if (IsDestroyed()) // Mainly to stop detector rails triggering again after minecart is dead
+ {
+ return;
+ }
+
int PosY = (int)floor(GetPosY());
if ((PosY <= 0) || (PosY >= cChunkDef::Height))
{
@@ -70,286 +85,513 @@ void cMinecart::HandlePhysics(float a_Dt, cChunk & a_Chunk)
// Inside an unloaded chunk, bail out all processing
return;
}
- BLOCKTYPE BelowType = Chunk->GetBlock(RelPosX, PosY - 1, RelPosZ);
- BLOCKTYPE InsideType = Chunk->GetBlock(RelPosX, PosY, RelPosZ);
- if (IsBlockRail(BelowType))
+ BLOCKTYPE InsideType;
+ NIBBLETYPE InsideMeta;
+ Chunk->GetBlockTypeMeta(RelPosX, PosY, RelPosZ, InsideType, InsideMeta);
+
+ if (!IsBlockRail(InsideType))
{
- HandleRailPhysics(a_Dt, *Chunk);
+ Chunk->GetBlockTypeMeta(RelPosX, PosY + 1, RelPosZ, InsideType, InsideMeta); // When an descending minecart hits a flat rail, it goes through the ground; check for this
+ if (IsBlockRail(InsideType)) AddPosY(1); // Push cart upwards
}
- else
+
+ if (IsBlockRail(InsideType))
{
- if (IsBlockRail(InsideType))
+ bool WasDetectorRail = false;
+ SnapToRail(InsideMeta);
+
+ switch (InsideType)
{
- SetPosY(PosY + 1);
- HandleRailPhysics(a_Dt, *Chunk);
+ case E_BLOCK_RAIL: HandleRailPhysics(InsideMeta, a_Dt); break;
+ case E_BLOCK_ACTIVATOR_RAIL: break;
+ case E_BLOCK_POWERED_RAIL: HandlePoweredRailPhysics(InsideMeta); break;
+ case E_BLOCK_DETECTOR_RAIL:
+ {
+ HandleDetectorRailPhysics(InsideMeta, a_Dt);
+ WasDetectorRail = true;
+ break;
+ }
+ default: VERIFY(!"Unhandled rail type despite checking if block was rail!"); break;
}
- else
+
+ AddPosition(GetSpeed() * (a_Dt / 1000)); // Commit changes; as we use our own engine when on rails, this needs to be done, whereas it is normally in Entity.cpp
+
+ if (m_bIsOnDetectorRail && !WasDetectorRail)
{
- super::HandlePhysics(a_Dt, *Chunk);
- BroadcastMovementUpdate();
+ m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
+ m_bIsOnDetectorRail = false;
}
}
+ else
+ {
+ // Not on rail, default physics
+ SetPosY(floor(GetPosY()) + 0.35); // HandlePhysics overrides this if minecart can fall, else, it is to stop ground clipping minecart bottom when off-rail
+ super::HandlePhysics(a_Dt, *Chunk);
+ }
+
+ // Broadcast positioning changes to client
+ BroadcastMovementUpdate();
}
-static const double MAX_SPEED = 8;
-static const double MAX_SPEED_NEGATIVE = (0 - MAX_SPEED);
-
-void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
+void cMinecart::HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
{
-
- super::HandlePhysics(a_Dt, a_Chunk); // Main physics handling
-
/*
NOTE: Please bear in mind that taking away from negatives make them even more negative,
adding to negatives make them positive, etc.
*/
- // Get block meta below the cart
- int RelPosX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width;
- int RelPosZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width;
- NIBBLETYPE BelowMeta = a_Chunk.GetMeta(RelPosX, (int)floor(GetPosY() - 1), RelPosZ);
- double SpeedX = GetSpeedX(), SpeedY = GetSpeedY(), SpeedZ = GetSpeedZ(); // Get current speed
-
- switch (BelowMeta)
+ switch (a_RailMeta)
{
case E_META_RAIL_ZM_ZP: // NORTHSOUTH
{
- SetRotation(270);
- SpeedY = 0; // Don't move vertically as on ground
- SpeedX = 0; // Correct diagonal movement from curved rails
+ SetYaw(270);
+ SetPosY(floor(GetPosY()) + 0.55);
+ SetSpeedY(0); // Don't move vertically as on ground
+ SetSpeedX(0); // Correct diagonal movement from curved rails
+
+ if (TestBlockCollision(a_RailMeta)) return;
- if (SpeedZ != 0) // Don't do anything if cart is stationary
+ if (GetSpeedZ() != 0) // Don't do anything if cart is stationary
{
- if (SpeedZ > 0)
+ if (GetSpeedZ() > 0)
{
// Going SOUTH, slow down
- SpeedZ = SpeedZ - 0.1;
+ AddSpeedZ(-0.1);
}
else
{
// Going NORTH, slow down
- SpeedZ = SpeedZ + 0.1;
+ AddSpeedZ(0.1);
}
}
break;
}
-
case E_META_RAIL_XM_XP: // EASTWEST
{
- SetRotation(180);
- SpeedY = 0;
- SpeedZ = 0;
+ SetYaw(180);
+ SetPosY(floor(GetPosY()) + 0.55);
+ SetSpeedY(0);
+ SetSpeedZ(0);
+
+ if (TestBlockCollision(a_RailMeta)) return;
- if (SpeedX != 0)
+ if (GetSpeedX() != 0)
{
- if (SpeedX > 0)
+ if (GetSpeedX() > 0)
{
- SpeedX = SpeedX - 0.1;
+ AddSpeedX(-0.1);
}
else
{
- SpeedX = SpeedX + 0.1;
+ AddSpeedX(0.1);
}
}
break;
}
-
case E_META_RAIL_ASCEND_ZM: // ASCEND NORTH
{
- SetRotation(270);
- SetPosY(floor(GetPosY()) + 0.2); // It seems it doesn't work without levitation :/
- SpeedX = 0;
+ SetYaw(270);
+ SetSpeedX(0);
- if (SpeedZ >= 0)
+ if (GetSpeedZ() >= 0)
{
// SpeedZ POSITIVE, going SOUTH
- if (SpeedZ <= MAX_SPEED) // Speed limit
+ if (GetSpeedZ() <= MAX_SPEED) // Speed limit
{
- SpeedZ = SpeedZ + 0.5; // Speed up
- SpeedY = (0 - SpeedZ); // Downward movement is negative (0 minus positive numbers is negative)
- }
- else
- {
- SpeedZ = MAX_SPEED; // Enforce speed limit
- SpeedY = (0 - SpeedZ);
+ AddSpeedZ(0.5); // Speed up
+ SetSpeedY(-GetSpeedZ()); // Downward movement is negative (0 minus positive numbers is negative)
}
}
else
{
// SpeedZ NEGATIVE, going NORTH
- SpeedZ = SpeedZ + 0.4; // Slow down
- SpeedY = (0 - SpeedZ); // Upward movement is positive (0 minus negative number is positive number)
+ AddSpeedZ(1); // Slow down
+ SetSpeedY(-GetSpeedZ()); // Upward movement is positive (0 minus negative number is positive number)
}
break;
}
-
case E_META_RAIL_ASCEND_ZP: // ASCEND SOUTH
{
- SetRotation(270);
- SetPosY(floor(GetPosY()) + 0.2);
- SpeedX = 0;
+ SetYaw(270);
+ SetSpeedX(0);
- if (SpeedZ > 0)
+ if (GetSpeedZ() > 0)
{
// SpeedZ POSITIVE, going SOUTH
- SpeedZ = SpeedZ - 0.4; // Slow down
- SpeedY = SpeedZ; // Upward movement positive
+ AddSpeedZ(-1); // Slow down
+ SetSpeedY(GetSpeedZ()); // Upward movement positive
}
else
{
- if (SpeedZ >= MAX_SPEED_NEGATIVE) // Speed limit
+ if (GetSpeedZ() >= MAX_SPEED_NEGATIVE) // Speed limit
{
// SpeedZ NEGATIVE, going NORTH
- SpeedZ = SpeedZ - 0.5; // Speed up
- SpeedY = SpeedZ; // Downward movement negative
- }
- else
- {
- SpeedZ = MAX_SPEED_NEGATIVE; // Enforce speed limit
- SpeedY = SpeedZ;
+ AddSpeedZ(-0.5); // Speed up
+ SetSpeedY(GetSpeedZ()); // Downward movement negative
}
}
break;
}
-
case E_META_RAIL_ASCEND_XM: // ASCEND EAST
{
- SetRotation(180);
- SetPosY(floor(GetPosY()) + 0.2);
- SpeedZ = 0;
+ SetYaw(180);
+ SetSpeedZ(0);
- if (SpeedX >= 0)
+ if (GetSpeedX() >= 0)
{
- if (SpeedX <= MAX_SPEED)
- {
- SpeedX = SpeedX + 0.5;
- SpeedY = (0 - SpeedX);
- }
- else
+ if (GetSpeedX() <= MAX_SPEED)
{
- SpeedX = MAX_SPEED;
- SpeedY = (0 - SpeedX);
+ AddSpeedX(0.5);
+ SetSpeedY(-GetSpeedX());
}
}
else
{
- SpeedX = SpeedX + 0.4;
- SpeedY = (0 - SpeedX);
+ AddSpeedX(1);
+ SetSpeedY(-GetSpeedX());
}
break;
}
-
case E_META_RAIL_ASCEND_XP: // ASCEND WEST
{
- SetRotation(180);
- SetPosY(floor(GetPosY()) + 0.2);
- SpeedZ = 0;
+ SetYaw(180);
+ SetSpeedZ(0);
- if (SpeedX > 0)
+ if (GetSpeedX() > 0)
{
- SpeedX = SpeedX - 0.4;
- SpeedY = SpeedX;
+ AddSpeedX(-1);
+ SetSpeedY(GetSpeedX());
}
else
{
- if (SpeedX >= MAX_SPEED_NEGATIVE)
+ if (GetSpeedX() >= MAX_SPEED_NEGATIVE)
{
- SpeedX = SpeedX - 0.5;
- SpeedY = SpeedX;
- }
- else
- {
- SpeedX = MAX_SPEED_NEGATIVE;
- SpeedY = SpeedX;
+ AddSpeedX(-0.5);
+ SetSpeedY(GetSpeedX());
}
}
break;
}
-
case E_META_RAIL_CURVED_ZM_XM: // Ends pointing NORTH and WEST
{
- SetRotation(315); // Set correct rotation server side
- SetPosY(floor(GetPosY()) + 0.2); // Levitate dat cart
+ SetYaw(315); // Set correct rotation server side
+ SetPosY(floor(GetPosY()) + 0.55); // Levitate dat cart
+
+ if (TestBlockCollision(a_RailMeta)) return;
- if (SpeedZ > 0) // Cart moving south
+ if (GetSpeedZ() > 0) // Cart moving south
{
- SpeedX = (0 - SpeedZ); // Diagonally move southwest (which will make cart hit a southwest rail)
+ int OldX = (int)floor(GetPosX());
+ AddSpeedX(-GetSpeedZ() + 0.5); // See below
+ AddPosX(-GetSpeedZ() * (a_Dt / 1000)); // Diagonally move southwest (which will make cart hit a southwest rail)
+ // If we are already at southwest rail, set Z speed to zero as we can be moving so fast, MCS doesn't tick fast enough to active the handle for the rail...
+ // ...and so we derail unexpectedly.
+ if (GetPosX() <= OldX - 1) SetSpeedZ(0);
}
- else if (SpeedX > 0) // Cart moving east
+ else if (GetSpeedX() > 0) // Cart moving east
{
- SpeedZ = (0 - SpeedX); // Diagonally move northeast
+ int OldZ = (int)floor(GetPosZ());
+ AddSpeedZ(-GetSpeedX() + 0.5);
+ AddPosZ(-GetSpeedX() * (a_Dt / 1000)); // Diagonally move northeast
+ if (GetPosZ() <= OldZ - 1) SetSpeedX(0);
}
break;
}
-
case E_META_RAIL_CURVED_ZM_XP: // Curved NORTH EAST
{
- SetRotation(225);
- SetPosY(floor(GetPosY()) + 0.2);
+ SetYaw(225);
+ SetPosY(floor(GetPosY()) + 0.55);
+
+ if (TestBlockCollision(a_RailMeta)) return;
- if (SpeedZ > 0)
+ if (GetSpeedZ() > 0)
{
- SpeedX = SpeedZ;
+ int OldX = (int)floor(GetPosX());
+ AddSpeedX(GetSpeedZ() - 0.5);
+ AddPosX(GetSpeedZ() * (a_Dt / 1000));
+ if (GetPosX() >= OldX + 1) SetSpeedZ(0);
}
- else if (SpeedX < 0)
+ else if (GetSpeedX() < 0)
{
- SpeedZ = SpeedX;
+ int OldZ = (int)floor(GetPosZ());
+ AddSpeedZ(GetSpeedX() + 0.5);
+ AddPosZ(GetSpeedX() * (a_Dt / 1000));
+ if (GetPosZ() <= OldZ - 1) SetSpeedX(0);
}
break;
}
-
case E_META_RAIL_CURVED_ZP_XM: // Curved SOUTH WEST
{
- SetRotation(135);
- SetPosY(floor(GetPosY()) + 0.2);
+ SetYaw(135);
+ SetPosY(floor(GetPosY()) + 0.55);
- if (SpeedZ < 0)
+ if (TestBlockCollision(a_RailMeta)) return;
+
+ if (GetSpeedZ() < 0)
{
- SpeedX = SpeedZ;
+ int OldX = (int)floor(GetPosX());
+ AddSpeedX(GetSpeedZ() + 0.5);
+ AddPosX(GetSpeedZ() * (a_Dt / 1000));
+ if (GetPosX() <= OldX - 1) SetSpeedZ(0);
}
- else if (SpeedX > 0)
+ else if (GetSpeedX() > 0)
{
- SpeedZ = SpeedX;
+ int OldZ = (int)floor(GetPosZ());
+ AddSpeedZ(GetSpeedX() - 0.5);
+ AddPosZ(GetSpeedX() * (a_Dt / 1000));
+ if (GetPosZ() >= OldZ + 1) SetSpeedX(0);
}
break;
}
-
case E_META_RAIL_CURVED_ZP_XP: // Curved SOUTH EAST
{
- SetRotation(45);
- SetPosY(floor(GetPosY()) + 0.2);
+ SetYaw(45);
+ SetPosY(floor(GetPosY()) + 0.55);
+
+ if (TestBlockCollision(a_RailMeta)) return;
- if (SpeedZ < 0)
+ if (GetSpeedZ() < 0)
{
- SpeedX = (0 - SpeedZ);
+ int OldX = (int)floor(GetPosX());
+ AddSpeedX(-GetSpeedZ() - 0.5);
+ AddPosX(-GetSpeedZ() * (a_Dt / 1000));
+ if (GetPosX() >= OldX + 1) SetSpeedZ(0);
}
- else if (SpeedX < 0)
+ else if (GetSpeedX() < 0)
{
- SpeedZ = (0 - SpeedX);
+ int OldZ = (int)floor(GetPosZ());
+ AddSpeedZ(-GetSpeedX() - 0.5);
+ AddPosZ(-GetSpeedX() * (a_Dt / 1000));
+ if (GetPosZ() >= OldZ + 1) SetSpeedX(0);
}
break;
}
-
default:
{
ASSERT(!"Unhandled rail meta!"); // Dun dun DUN!
break;
}
}
+}
- // Set speed to speed variables
- SetSpeedX(SpeedX);
- SetSpeedY(SpeedY);
- SetSpeedZ(SpeedZ);
- // Broadcast position to client
- BroadcastMovementUpdate();
+
+void cMinecart::HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta)
+{
+ // Initialise to 'slow down' values
+ int AccelDecelSpeed = -1;
+ int AccelDecelNegSpeed = 1;
+
+ if ((a_RailMeta & 0x8) == 0x8)
+ {
+ // Rail powered - set variables to 'speed up' values
+ AccelDecelSpeed = 1;
+ AccelDecelNegSpeed = -1;
+ }
+
+ switch (a_RailMeta & 0x07)
+ {
+ case E_META_RAIL_ZM_ZP: // NORTHSOUTH
+ {
+ SetYaw(270);
+ SetPosY(floor(GetPosY()) + 0.55);
+ SetSpeedY(0);
+ SetSpeedX(0);
+
+ if (TestBlockCollision(a_RailMeta)) return;
+
+ if (GetSpeedZ() != 0)
+ {
+ if (GetSpeedZ() > 0)
+ {
+ AddSpeedZ(AccelDecelNegSpeed);
+ }
+ else
+ {
+ AddSpeedZ(AccelDecelSpeed);
+ }
+ }
+ break;
+ }
+ case E_META_RAIL_XM_XP: // EASTWEST
+ {
+ SetYaw(180);
+ SetPosY(floor(GetPosY()) + 0.55);
+ SetSpeedY(0);
+ SetSpeedZ(0);
+
+ if (TestBlockCollision(a_RailMeta)) return;
+
+ if (GetSpeedX() != 0)
+ {
+ if (GetSpeedX() > 0)
+ {
+ AddSpeedX(AccelDecelSpeed);
+ }
+ else
+ {
+ AddSpeedX(AccelDecelNegSpeed);
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+
+
+
+void cMinecart::HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt)
+{
+ m_bIsOnDetectorRail = true;
+ m_DetectorRailPosition = Vector3i((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
+
+ m_World->SetBlockMeta(m_DetectorRailPosition, a_RailMeta | 0x08);
+
+ HandleRailPhysics(a_RailMeta & 0x07, a_Dt);
+}
+
+
+
+
+
+void cMinecart::SnapToRail(NIBBLETYPE a_RailMeta)
+{
+ switch (a_RailMeta)
+ {
+ case E_META_RAIL_ASCEND_XM:
+ case E_META_RAIL_ASCEND_XP:
+ case E_META_RAIL_XM_XP:
+ {
+ SetSpeedZ(0);
+ SetPosZ(floor(GetPosZ()) + 0.5);
+ break;
+ }
+ case E_META_RAIL_ASCEND_ZM:
+ case E_META_RAIL_ASCEND_ZP:
+ case E_META_RAIL_ZM_ZP:
+ {
+ SetSpeedX(0);
+ SetPosX(floor(GetPosX()) + 0.5);
+ break;
+ }
+ default: break;
+ }
+}
+
+
+
+
+
+bool cMinecart::TestBlockCollision(NIBBLETYPE a_RailMeta)
+{
+ switch (a_RailMeta)
+ {
+ case E_META_RAIL_ZM_ZP:
+ {
+ if (GetSpeedZ() > 0)
+ {
+ BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ()));
+ if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ {
+ // We could try to detect a block in front based purely on coordinates, but xoft made a bounding box system - why not use? :P
+ cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)ceil(GetPosZ())), 0.5, 1);
+ cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
+
+ if (bbBlock.DoesIntersect(bbMinecart))
+ {
+ SetSpeed(0, 0, 0);
+ SetPosZ(floor(GetPosZ()) + 0.4);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1);
+ if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ {
+ cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) - 1), 0.5, 1);
+ cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ() - 1), GetWidth() / 2, GetHeight());
+
+ if (bbBlock.DoesIntersect(bbMinecart))
+ {
+ SetSpeed(0, 0, 0);
+ SetPosZ(floor(GetPosZ()) + 0.65);
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ case E_META_RAIL_XM_XP:
+ {
+ if (GetSpeedX() > 0)
+ {
+ BLOCKTYPE Block = m_World->GetBlock((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ {
+ cBoundingBox bbBlock(Vector3d((int)ceil(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
+ cBoundingBox bbMinecart(Vector3d(GetPosX(), floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
+
+ if (bbBlock.DoesIntersect(bbMinecart))
+ {
+ SetSpeed(0, 0, 0);
+ SetPosX(floor(GetPosX()) + 0.4);
+ return true;
+ }
+ }
+ }
+ else
+ {
+ BLOCKTYPE Block = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ if (!IsBlockRail(Block) && g_BlockIsSolid[Block])
+ {
+ cBoundingBox bbBlock(Vector3d((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ())), 0.5, 1);
+ cBoundingBox bbMinecart(Vector3d(GetPosX() - 1, floor(GetPosY()), GetPosZ()), GetWidth() / 2, GetHeight());
+
+ if (bbBlock.DoesIntersect(bbMinecart))
+ {
+ SetSpeed(0, 0, 0);
+ SetPosX(floor(GetPosX()) + 0.65);
+ return true;
+ }
+ }
+ }
+ break;
+ }
+ case E_META_RAIL_CURVED_ZM_XM:
+ case E_META_RAIL_CURVED_ZM_XP:
+ case E_META_RAIL_CURVED_ZP_XM:
+ case E_META_RAIL_CURVED_ZP_XP:
+ {
+ BLOCKTYPE BlockXM = m_World->GetBlock((int)floor(GetPosX()) - 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ BLOCKTYPE BlockXP = m_World->GetBlock((int)floor(GetPosX()) + 1, (int)floor(GetPosY()), (int)floor(GetPosZ()));
+ BLOCKTYPE BlockZM = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
+ BLOCKTYPE BlockZP = m_World->GetBlock((int)floor(GetPosX()), (int)floor(GetPosY()), (int)floor(GetPosZ()) + 1);
+ if (
+ (!IsBlockRail(BlockXM) && g_BlockIsSolid[BlockXM]) ||
+ (!IsBlockRail(BlockXP) && g_BlockIsSolid[BlockXP]) ||
+ (!IsBlockRail(BlockZM) && g_BlockIsSolid[BlockZM]) ||
+ (!IsBlockRail(BlockZP) && g_BlockIsSolid[BlockZP])
+ )
+ {
+ SetSpeed(0, 0, 0);
+ SetPosition((int)floor(GetPosX()) + 0.5, GetPosY(), (int)floor(GetPosZ()) + 0.5);
+ return true;
+ }
+ break;
+ }
+ default: break;
+ }
+ return false;
}
@@ -358,6 +600,14 @@ void cMinecart::HandleRailPhysics(float a_Dt, cChunk & a_Chunk)
void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
{
+ if (TDI.Attacker->IsPlayer() && ((cPlayer *)TDI.Attacker)->IsGameModeCreative())
+ {
+ Destroy();
+ TDI.FinalDamage = GetMaxHealth(); // Instant hit for creative
+ super::DoTakeDamage(TDI);
+ return; // No drops for creative
+ }
+
m_LastDamage = TDI.FinalDamage;
super::DoTakeDamage(TDI);
@@ -365,7 +615,7 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
if (GetHealth() <= 0)
{
- Destroy(true);
+ Destroy();
cItems Drops;
switch (m_Payload)
@@ -410,11 +660,25 @@ void cMinecart::DoTakeDamage(TakeDamageInfo & TDI)
+void cMinecart::Destroyed()
+{
+ if (m_bIsOnDetectorRail)
+ {
+ m_World->SetBlock(m_DetectorRailPosition.x, m_DetectorRailPosition.y, m_DetectorRailPosition.z, E_BLOCK_DETECTOR_RAIL, m_World->GetBlockMeta(m_DetectorRailPosition) & 0x07);
+ }
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-// cEmptyMinecart:
+// cRideableMinecart:
-cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) :
- super(mpNone, a_X, a_Y, a_Z)
+cRideableMinecart::cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height) :
+ super(mpNone, a_X, a_Y, a_Z),
+ m_Content(a_Content),
+ m_Height(a_Height)
{
}
@@ -422,7 +686,7 @@ cEmptyMinecart::cEmptyMinecart(double a_X, double a_Y, double a_Z) :
-void cEmptyMinecart::OnRightClicked(cPlayer & a_Player)
+void cRideableMinecart::OnRightClicked(cPlayer & a_Player)
{
if (m_Attachee != NULL)
{
@@ -489,7 +753,8 @@ void cMinecartWithChest::OnRightClicked(cPlayer & a_Player)
cMinecartWithFurnace::cMinecartWithFurnace(double a_X, double a_Y, double a_Z) :
super(mpFurnace, a_X, a_Y, a_Z),
- m_IsFueled(false)
+ m_IsFueled(false),
+ m_FueledTimeLeft(-1)
{
}
@@ -505,8 +770,12 @@ void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
{
a_Player.GetInventory().RemoveOneEquippedItem();
}
-
+ if (!m_IsFueled) // We don't want to change the direction by right clicking it.
+ {
+ AddSpeed(a_Player.GetLookVector().x, 0, a_Player.GetLookVector().z);
+ }
m_IsFueled = true;
+ m_FueledTimeLeft = m_FueledTimeLeft + 600; // The minecart will be active 600 more ticks.
m_World->BroadcastEntityMetadata(*this);
}
}
@@ -515,6 +784,32 @@ void cMinecartWithFurnace::OnRightClicked(cPlayer & a_Player)
+void cMinecartWithFurnace::Tick(float a_Dt, cChunk & a_Chunk)
+{
+ super::Tick(a_Dt, a_Chunk);
+
+ if (m_IsFueled)
+ {
+ m_FueledTimeLeft--;
+ if (m_FueledTimeLeft < 0)
+ {
+ m_IsFueled = false;
+ m_World->BroadcastEntityMetadata(*this);
+ return;
+ }
+
+ if (GetSpeed().Length() > 6)
+ {
+ return;
+ }
+ AddSpeed(GetSpeed() / 4);
+ }
+}
+
+
+
+
+
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cMinecartWithTNT:
diff --git a/src/Entities/Minecart.h b/src/Entities/Minecart.h
index b1b48be4e..874d0204e 100644
--- a/src/Entities/Minecart.h
+++ b/src/Entities/Minecart.h
@@ -51,17 +51,38 @@ public:
virtual void SpawnOn(cClientHandle & a_ClientHandle) override;
virtual void HandlePhysics(float a_Dt, cChunk & a_Chunk) override;
virtual void DoTakeDamage(TakeDamageInfo & TDI) override;
+ virtual void Destroyed() override;
int LastDamage(void) const { return m_LastDamage; }
- void HandleRailPhysics(float a_Dt, cChunk & a_Chunk);
ePayload GetPayload(void) const { return m_Payload; }
protected:
ePayload m_Payload;
+ int m_LastDamage;
+ Vector3i m_DetectorRailPosition;
+ bool m_bIsOnDetectorRail;
cMinecart(ePayload a_Payload, double a_X, double a_Y, double a_Z);
- int m_LastDamage;
+ /** Handles physics on normal rails
+ For each tick, slow down on flat rails, speed up or slow down on ascending/descending rails (depending on direction), and turn on curved rails
+ */
+ void HandleRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt);
+
+ /** Handles powered rail physics
+ Each tick, speed up or slow down cart, depending on metadata of rail (powered or not)
+ */
+ void HandlePoweredRailPhysics(NIBBLETYPE a_RailMeta);
+
+ /** Handles detector rail activation
+ Activates detector rails when a minecart is on them. Calls HandleRailPhysics() for physics simulations
+ */
+ void HandleDetectorRailPhysics(NIBBLETYPE a_RailMeta, float a_Dt);
+
+ /** Snaps a minecart to a rail's axis, resetting its speed */
+ void SnapToRail(NIBBLETYPE a_RailMeta);
+ /** Tests is a solid block is in front of a cart, and stops the cart (and returns true) if so; returns false if no obstruction*/
+ bool TestBlockCollision(NIBBLETYPE a_RailMeta);
} ;
@@ -69,18 +90,24 @@ protected:
-class cEmptyMinecart :
+class cRideableMinecart :
public cMinecart
{
typedef cMinecart super;
public:
- CLASS_PROTODEF(cEmptyMinecart);
+ CLASS_PROTODEF(cRideableMinecart);
- cEmptyMinecart(double a_X, double a_Y, double a_Z);
+ cRideableMinecart(double a_X, double a_Y, double a_Z, const cItem & a_Content, int a_Height);
+ const cItem & GetContent(void) const {return m_Content;}
+ int GetBlockHeight(void) const {return m_Height;}
// cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override;
+protected:
+
+ cItem m_Content;
+ int m_Height;
} ;
@@ -130,10 +157,18 @@ public:
// cEntity overrides:
virtual void OnRightClicked(cPlayer & a_Player) override;
- bool IsFueled (void) const { return m_IsFueled; }
+ virtual void Tick(float a_Dt, cChunk & a_Chunk) override;
+
+ // Set functions.
+ void SetIsFueled(bool a_IsFueled, int a_FueledTimeLeft = -1) {m_IsFueled = a_IsFueled; m_FueledTimeLeft = a_FueledTimeLeft;}
+
+ // Get functions.
+ int GetFueledTimeLeft(void) const {return m_FueledTimeLeft; }
+ bool IsFueled (void) const {return m_IsFueled;}
private:
+ int m_FueledTimeLeft;
bool m_IsFueled;
} ;
diff --git a/src/Entities/Player.cpp b/src/Entities/Player.cpp
index bc92790aa..c1f2456eb 100644
--- a/src/Entities/Player.cpp
+++ b/src/Entities/Player.cpp
@@ -1382,16 +1382,21 @@ void cPlayer::TossItem(
cItem DroppedItem(GetInventory().GetEquippedItem());
if (!DroppedItem.IsEmpty())
{
- if (GetInventory().RemoveOneEquippedItem())
+ char NewAmount = a_Amount;
+ if (NewAmount > GetInventory().GetEquippedItem().m_ItemCount)
{
- DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again
- Drops.push_back(DroppedItem);
+ NewAmount = GetInventory().GetEquippedItem().m_ItemCount; // Drop only what's there
}
+
+ GetInventory().GetHotbarGrid().ChangeSlotCount(GetInventory().GetEquippedSlotNum() /* Returns hotbar subslot, which HotbarGrid takes */, -a_Amount);
+
+ DroppedItem.m_ItemCount = NewAmount;
+ Drops.push_back(DroppedItem);
}
}
}
double vX = 0, vY = 0, vZ = 0;
- EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY);
+ EulerToVector(-GetYaw(), GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
m_World->SpawnItemPickups(Drops, GetPosX(), GetEyeHeight(), GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player
}
@@ -1523,7 +1528,7 @@ bool cPlayer::LoadFromDisk()
Json::Value & JSON_PlayerRotation = root["rotation"];
if (JSON_PlayerRotation.size() == 3)
{
- SetRotation ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
+ SetYaw ((float)JSON_PlayerRotation[(unsigned int)0].asDouble());
SetPitch ((float)JSON_PlayerRotation[(unsigned int)1].asDouble());
SetRoll ((float)JSON_PlayerRotation[(unsigned int)2].asDouble());
}
@@ -1586,7 +1591,7 @@ bool cPlayer::SaveToDisk()
JSON_PlayerPosition.append(Json::Value(GetPosZ()));
Json::Value JSON_PlayerRotation;
- JSON_PlayerRotation.append(Json::Value(GetRotation()));
+ JSON_PlayerRotation.append(Json::Value(GetYaw()));
JSON_PlayerRotation.append(Json::Value(GetPitch()));
JSON_PlayerRotation.append(Json::Value(GetRoll()));
@@ -1884,3 +1889,33 @@ void cPlayer::ApplyFoodExhaustionFromMovement()
+
+void cPlayer::Detach()
+{
+ super::Detach();
+ int PosX = (int)floor(GetPosX());
+ int PosY = (int)floor(GetPosY());
+ int PosZ = (int)floor(GetPosZ());
+
+ // Search for a position within an area to teleport player after detachment
+ // Position must be solid land, and occupied by a nonsolid block
+ // If nothing found, player remains where they are
+ for (int x = PosX - 2; x <= (PosX + 2); ++x)
+ {
+ for (int y = PosY; y <= (PosY + 3); ++y)
+ {
+ for (int z = PosZ - 2; z <= (PosZ + 2); ++z)
+ {
+ if (!g_BlockIsSolid[m_World->GetBlock(x, y, z)] && g_BlockIsSolid[m_World->GetBlock(x, y - 1, z)])
+ {
+ TeleportToCoords(x, y, z);
+ return;
+ }
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/src/Entities/Player.h b/src/Entities/Player.h
index f9ce950ba..bf3ca08e8 100644
--- a/src/Entities/Player.h
+++ b/src/Entities/Player.h
@@ -350,6 +350,8 @@ public:
virtual bool IsCrouched (void) const { return m_IsCrouched; }
virtual bool IsSprinting(void) const { return m_IsSprinting; }
virtual bool IsRclking (void) const { return IsEating(); }
+
+ virtual void Detach(void);
protected:
typedef std::map< std::string, bool > PermissionMap;
diff --git a/src/Entities/ProjectileEntity.cpp b/src/Entities/ProjectileEntity.cpp
index 9e5069ba6..12ce9a303 100644
--- a/src/Entities/ProjectileEntity.cpp
+++ b/src/Entities/ProjectileEntity.cpp
@@ -206,7 +206,7 @@ cProjectileEntity::cProjectileEntity(eKind a_Kind, cEntity * a_Creator, const Ve
m_IsInGround(false)
{
SetSpeed(a_Speed);
- SetRotationFromSpeed();
+ SetYawFromSpeed();
SetPitchFromSpeed();
}
@@ -350,7 +350,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
NewSpeed.y += m_Gravity / 20;
NewSpeed *= TracerCallback.GetSlowdownCoeff();
SetSpeed(NewSpeed);
- SetRotationFromSpeed();
+ SetYawFromSpeed();
SetPitchFromSpeed();
// DEBUG:
@@ -358,7 +358,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
m_UniqueID,
GetPosX(), GetPosY(), GetPosZ(),
GetSpeedX(), GetSpeedY(), GetSpeedZ(),
- GetRotation(), GetPitch()
+ GetYaw(), GetPitch()
);
}
@@ -369,7 +369,7 @@ void cProjectileEntity::HandlePhysics(float a_Dt, cChunk & a_Chunk)
void cProjectileEntity::SpawnOn(cClientHandle & a_Client)
{
// Default spawning - use the projectile kind to spawn an object:
- a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetRotation()), ANGLE_TO_PROTO(GetPitch()));
+ a_Client.SendSpawnObject(*this, m_ProjectileKind, 12, ANGLE_TO_PROTO(GetYaw()), ANGLE_TO_PROTO(GetPitch()));
a_Client.SendEntityMetadata(*this);
}
@@ -402,11 +402,11 @@ cArrowEntity::cArrowEntity(cEntity * a_Creator, double a_X, double a_Y, double a
{
SetSpeed(a_Speed);
SetMass(0.1);
- SetRotationFromSpeed();
+ SetYawFromSpeed();
SetPitchFromSpeed();
LOGD("Created arrow %d with speed {%.02f, %.02f, %.02f} and rot {%.02f, %.02f}",
m_UniqueID, GetSpeedX(), GetSpeedY(), GetSpeedZ(),
- GetRotation(), GetPitch()
+ GetYaw(), GetPitch()
);
}
diff --git a/src/Generating/ChunkGenerator.cpp b/src/Generating/ChunkGenerator.cpp
index 126a896af..baa5b76b8 100644
--- a/src/Generating/ChunkGenerator.cpp
+++ b/src/Generating/ChunkGenerator.cpp
@@ -2,13 +2,11 @@
#include "Globals.h"
#include "ChunkGenerator.h"
-#include "../World.h"
#include "inifile/iniFile.h"
-#include "../Root.h"
-#include "../Bindings/PluginManager.h"
#include "ChunkDesc.h"
#include "ComposableGenerator.h"
#include "Noise3DGenerator.h"
+#include "../MersenneTwister.h"
@@ -29,8 +27,9 @@ const unsigned int QUEUE_SKIP_LIMIT = 500;
cChunkGenerator::cChunkGenerator(void) :
super("cChunkGenerator"),
- m_World(NULL),
- m_Generator(NULL)
+ m_Generator(NULL),
+ m_PluginInterface(NULL),
+ m_ChunkSink(NULL)
{
}
@@ -47,10 +46,12 @@ cChunkGenerator::~cChunkGenerator()
-bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile)
+bool cChunkGenerator::Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile)
{
+ m_PluginInterface = &a_PluginInterface;
+ m_ChunkSink = &a_ChunkSink;
+
MTRand rnd;
- m_World = a_World;
m_Seed = a_IniFile.GetValueSetI("Seed", "Seed", rnd.randInt());
AString GeneratorName = a_IniFile.GetValueSet("Generator", "Generator", "Composable");
@@ -73,7 +74,7 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile)
return false;
}
- m_Generator->Initialize(a_World, a_IniFile);
+ m_Generator->Initialize(a_IniFile);
return super::Start();
}
@@ -237,14 +238,14 @@ void cChunkGenerator::Execute(void)
}
// Hack for regenerating chunks: if Y != 0, the chunk is considered invalid, even if it has its data set
- if ((coords.m_ChunkY == 0) && m_World->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ))
+ if ((coords.m_ChunkY == 0) && m_ChunkSink->IsChunkValid(coords.m_ChunkX, coords.m_ChunkZ))
{
LOGD("Chunk [%d, %d] already generated, skipping generation", coords.m_ChunkX, coords.m_ChunkZ);
// Already generated, ignore request
continue;
}
- if (SkipEnabled && !m_World->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ))
+ if (SkipEnabled && !m_ChunkSink->HasChunkAnyClients(coords.m_ChunkX, coords.m_ChunkZ))
{
LOGWARNING("Chunk generator overloaded, skipping chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ);
continue;
@@ -253,9 +254,6 @@ void cChunkGenerator::Execute(void)
LOGD("Generating chunk [%d, %d, %d]", coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ);
DoGenerate(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ);
- // Save the chunk right after generating, so that we don't have to generate it again on next run
- m_World->GetStorage().QueueSaveChunk(coords.m_ChunkX, coords.m_ChunkY, coords.m_ChunkZ);
-
NumChunksGenerated++;
} // while (!bStop)
}
@@ -265,27 +263,20 @@ void cChunkGenerator::Execute(void)
void cChunkGenerator::DoGenerate(int a_ChunkX, int a_ChunkY, int a_ChunkZ)
{
+ ASSERT(m_PluginInterface != NULL);
+ ASSERT(m_ChunkSink != NULL);
+
cChunkDesc ChunkDesc(a_ChunkX, a_ChunkZ);
- cRoot::Get()->GetPluginManager()->CallHookChunkGenerating(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc);
+ m_PluginInterface->CallHookChunkGenerating(ChunkDesc);
m_Generator->DoGenerate(a_ChunkX, a_ChunkZ, ChunkDesc);
- cRoot::Get()->GetPluginManager()->CallHookChunkGenerated(m_World, a_ChunkX, a_ChunkZ, &ChunkDesc);
+ m_PluginInterface->CallHookChunkGenerated(ChunkDesc);
#ifdef _DEBUG
// Verify that the generator has produced valid data:
ChunkDesc.VerifyHeightmap();
#endif
- cChunkDef::BlockNibbles BlockMetas;
- ChunkDesc.CompressBlockMetas(BlockMetas);
-
- m_World->SetChunkData(
- a_ChunkX, a_ChunkZ,
- ChunkDesc.GetBlockTypes(), BlockMetas,
- NULL, NULL, // We don't have lighting, chunk will be lighted when needed
- &ChunkDesc.GetHeightMap(), &ChunkDesc.GetBiomeMap(),
- ChunkDesc.GetEntities(), ChunkDesc.GetBlockEntities(),
- true
- );
+ m_ChunkSink->OnChunkGenerated(ChunkDesc);
}
@@ -304,9 +295,8 @@ cChunkGenerator::cGenerator::cGenerator(cChunkGenerator & a_ChunkGenerator) :
-void cChunkGenerator::cGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile)
+void cChunkGenerator::cGenerator::Initialize(cIniFile & a_IniFile)
{
- m_World = a_World;
UNUSED(a_IniFile);
}
@@ -319,7 +309,7 @@ EMCSBiome cChunkGenerator::cGenerator::GetBiomeAt(int a_BlockX, int a_BlockZ)
cChunkDef::BiomeMap Biomes;
int Y = 0;
int ChunkX, ChunkZ;
- cWorld::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, Y, ChunkZ);
+ cChunkDef::AbsoluteToRelative(a_BlockX, Y, a_BlockZ, ChunkX, ChunkZ);
GenerateBiomes(ChunkX, ChunkZ, Biomes);
return cChunkDef::GetBiome(Biomes, a_BlockX, a_BlockZ);
}
diff --git a/src/Generating/ChunkGenerator.h b/src/Generating/ChunkGenerator.h
index 2d3bb8082..9b2d9eb3c 100644
--- a/src/Generating/ChunkGenerator.h
+++ b/src/Generating/ChunkGenerator.h
@@ -26,7 +26,6 @@ If the generator queue is overloaded, the generator skips chunks with no clients
// fwd:
-class cWorld;
class cIniFile;
class cChunkDesc;
@@ -40,7 +39,7 @@ class cChunkGenerator :
typedef cIsThread super;
public:
- /// The interface that a class has to implement to become a generator
+ /** The interface that a class has to implement to become a generator */
class cGenerator
{
public:
@@ -48,7 +47,7 @@ public:
virtual ~cGenerator() {} ; // Force a virtual destructor
/// Called to initialize the generator on server startup.
- virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile);
+ virtual void Initialize(cIniFile & a_IniFile);
/// Generates the biomes for the specified chunk (directly, not in a separate thread). Used by the world loader if biomes failed loading.
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) = 0;
@@ -61,14 +60,59 @@ public:
protected:
cChunkGenerator & m_ChunkGenerator;
- cWorld * m_World;
+ } ;
+
+
+ /** The interface through which the plugins are called for their OnChunkGenerating / OnChunkGenerated hooks. */
+ class cPluginInterface
+ {
+ public:
+ // Force a virtual destructor
+ virtual ~cPluginInterface() {}
+
+ /** Called when the chunk is about to be generated.
+ The generator may be partly or fully overriden by the implementation
+ */
+ virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) = 0;
+
+ /** Called after the chunk is generated, before it is handed to the chunk sink.
+ a_ChunkDesc contains the generated chunk data. Implementation may modify this data.
+ */
+ virtual void CallHookChunkGenerated(cChunkDesc & a_ChunkDesc) = 0;
+ } ;
+
+
+ /** The interface through which the generated chunks are handed to the cWorld or whoever created us. */
+ class cChunkSink
+ {
+ public:
+ // Force a virtual destructor
+ virtual ~cChunkSink() {}
+
+ /** Called after the chunk has been generated
+ The interface may store the chunk, send it over network, whatever.
+ The chunk is not expected to be modified, but the generator will survive if the implementation
+ changes the data within. All changes are ignored, though.
+ */
+ virtual void OnChunkGenerated(cChunkDesc & a_ChunkDesc) = 0;
+
+ /** Called just before the chunk generation is started,
+ to verify that it hasn't been generated in the meantime.
+ If this callback returns true, the chunk is not generated.
+ */
+ virtual bool IsChunkValid(int a_ChunkX, int a_ChunkZ) = 0;
+
+ /** Called when the generator is overloaded to skip chunks that are no longer needed.
+ If this callback returns false, the chunk is not generated.
+ */
+ virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) = 0;
} ;
cChunkGenerator (void);
~cChunkGenerator();
- bool Start(cWorld * a_World, cIniFile & a_IniFile);
+ bool Start(cPluginInterface & a_PluginInterface, cChunkSink & a_ChunkSink, cIniFile & a_IniFile);
void Stop(void);
/// Queues the chunk for generation; removes duplicate requests
@@ -91,8 +135,6 @@ public:
private:
- cWorld * m_World;
-
int m_Seed;
cCriticalSection m_CS;
@@ -101,6 +143,13 @@ private:
cEvent m_evtRemoved; ///< Set when an item is removed from the queue
cGenerator * m_Generator; ///< The actual generator engine used to generate chunks
+
+ /** The plugin interface that may modify the generated chunks */
+ cPluginInterface * m_PluginInterface;
+
+ /** The destination where the generated chunks are sent */
+ cChunkSink * m_ChunkSink;
+
// cIsThread override:
virtual void Execute(void) override;
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index 9817b6654..b01f84627 100644
--- a/src/Generating/ComposableGenerator.cpp
+++ b/src/Generating/ComposableGenerator.cpp
@@ -28,11 +28,88 @@
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cTerrainCompositionGen:
+cTerrainCompositionGen * cTerrainCompositionGen::CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed)
+{
+ AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
+ if (CompoGenName.empty())
+ {
+ LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\".");
+ CompoGenName = "Biomal";
+ a_IniFile.SetValue("Generator", "CompositionGen", CompoGenName);
+ }
+
+ cTerrainCompositionGen * res = NULL;
+ if (NoCaseCompare(CompoGenName, "sameblock") == 0)
+ {
+ res = new cCompoGenSameBlock;
+ }
+ else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0)
+ {
+ res = new cCompoGenDebugBiomes;
+ }
+ else if (NoCaseCompare(CompoGenName, "classic") == 0)
+ {
+ res = new cCompoGenClassic;
+ }
+ else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
+ {
+ res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
+ }
+ else if (NoCaseCompare(CompoGenName, "end") == 0)
+ {
+ res = new cEndGen(a_Seed);
+ }
+ else if (NoCaseCompare(CompoGenName, "nether") == 0)
+ {
+ res = new cCompoGenNether(a_Seed);
+ }
+ else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
+ {
+ res = new cNoise3DComposable(a_Seed);
+ }
+ else if (NoCaseCompare(CompoGenName, "biomal") == 0)
+ {
+ res = new cCompoGenBiomal(a_Seed);
+
+ /*
+ // Performance-testing:
+ LOGINFO("Measuring performance of cCompoGenBiomal...");
+ clock_t BeginTick = clock();
+ for (int x = 0; x < 500; x++)
+ {
+ cChunkDesc Desc(200 + x * 8, 200 + x * 8);
+ a_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap());
+ a_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap());
+ res->ComposeTerrain(Desc);
+ }
+ clock_t Duration = clock() - BeginTick;
+ LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
+ //*/
+ }
+ else
+ {
+ LOGWARN("Unknown CompositionGen \"%s\", using \"Biomal\" instead.", CompoGenName.c_str());
+ a_IniFile.DeleteValue("Generator", "CompositionGen");
+ a_IniFile.SetValue("Generator", "CompositionGen", "Biomal");
+ return CreateCompositionGen(a_IniFile, a_BiomeGen, a_HeightGen, a_Seed);
+ }
+ ASSERT(res != NULL);
+
+ // Read the settings from the ini file:
+ res->InitializeCompoGen(a_IniFile);
+
+ return res;
+}
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cComposableGenerator:
+
cComposableGenerator::cComposableGenerator(cChunkGenerator & a_ChunkGenerator) :
super(a_ChunkGenerator),
m_BiomeGen(NULL),
@@ -80,9 +157,9 @@ cComposableGenerator::~cComposableGenerator()
-void cComposableGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile)
+void cComposableGenerator::Initialize(cIniFile & a_IniFile)
{
- super::Initialize(a_World, a_IniFile);
+ super::Initialize(a_IniFile);
InitBiomeGen(a_IniFile);
InitHeightGen(a_IniFile);
@@ -173,60 +250,8 @@ void cComposableGenerator::InitBiomeGen(cIniFile & a_IniFile)
void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
{
- AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
- if (HeightGenName.empty())
- {
- LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\".");
- HeightGenName = "Biomal";
- }
-
- int Seed = m_ChunkGenerator.GetSeed();
bool CacheOffByDefault = false;
- if (NoCaseCompare(HeightGenName, "flat") == 0)
- {
- m_HeightGen = new cHeiGenFlat;
- CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
- }
- else if (NoCaseCompare(HeightGenName, "classic") == 0)
- {
- m_HeightGen = new cHeiGenClassic(Seed);
- }
- else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
- {
- m_HeightGen = new cDistortedHeightmap(Seed, *m_BiomeGen);
- }
- else if (NoCaseCompare(HeightGenName, "End") == 0)
- {
- m_HeightGen = new cEndGen(Seed);
- }
- else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
- {
- m_HeightGen = new cNoise3DComposable(Seed);
- }
- else // "biomal" or <not found>
- {
- if (NoCaseCompare(HeightGenName, "biomal") != 0)
- {
- LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
- }
- m_HeightGen = new cHeiGenBiomal(Seed, *m_BiomeGen);
-
- /*
- // Performance-testing:
- LOGINFO("Measuring performance of cHeiGenBiomal...");
- clock_t BeginTick = clock();
- for (int x = 0; x < 500; x++)
- {
- cChunkDef::HeightMap Heights;
- m_HeightGen->GenHeightMap(x * 5, x * 5, Heights);
- }
- clock_t Duration = clock() - BeginTick;
- LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
- //*/
- }
-
- // Read the settings:
- m_HeightGen->InitializeHeightGen(a_IniFile);
+ m_HeightGen = cTerrainHeightGen::CreateHeightGen(a_IniFile, *m_BiomeGen, m_ChunkGenerator.GetSeed(), CacheOffByDefault);
// Add a cache, if requested:
int CacheSize = a_IniFile.GetValueSetI("Generator", "HeightGenCacheSize", CacheOffByDefault ? 0 : 64);
@@ -251,67 +276,7 @@ void cComposableGenerator::InitHeightGen(cIniFile & a_IniFile)
void cComposableGenerator::InitCompositionGen(cIniFile & a_IniFile)
{
- int Seed = m_ChunkGenerator.GetSeed();
- AString CompoGenName = a_IniFile.GetValueSet("Generator", "CompositionGen", "");
- if (CompoGenName.empty())
- {
- LOGWARN("[Generator] CompositionGen value not set in world.ini, using \"Biomal\".");
- CompoGenName = "Biomal";
- }
- if (NoCaseCompare(CompoGenName, "sameblock") == 0)
- {
- m_CompositionGen = new cCompoGenSameBlock;
- }
- else if (NoCaseCompare(CompoGenName, "debugbiomes") == 0)
- {
- m_CompositionGen = new cCompoGenDebugBiomes;
- }
- else if (NoCaseCompare(CompoGenName, "classic") == 0)
- {
- m_CompositionGen = new cCompoGenClassic;
- }
- else if (NoCaseCompare(CompoGenName, "DistortedHeightmap") == 0)
- {
- m_CompositionGen = new cDistortedHeightmap(Seed, *m_BiomeGen);
- }
- else if (NoCaseCompare(CompoGenName, "end") == 0)
- {
- m_CompositionGen = new cEndGen(Seed);
- }
- else if (NoCaseCompare(CompoGenName, "nether") == 0)
- {
- m_CompositionGen = new cCompoGenNether(Seed);
- }
- else if (NoCaseCompare(CompoGenName, "Noise3D") == 0)
- {
- m_CompositionGen = new cNoise3DComposable(m_ChunkGenerator.GetSeed());
- }
- else
- {
- if (NoCaseCompare(CompoGenName, "biomal") != 0)
- {
- LOGWARN("Unknown CompositionGen \"%s\", using \"biomal\" instead.", CompoGenName.c_str());
- }
- m_CompositionGen = new cCompoGenBiomal(Seed);
-
- /*
- // Performance-testing:
- LOGINFO("Measuring performance of cCompoGenBiomal...");
- clock_t BeginTick = clock();
- for (int x = 0; x < 500; x++)
- {
- cChunkDesc Desc(200 + x * 8, 200 + x * 8);
- m_BiomeGen->GenBiomes(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetBiomeMap());
- m_HeightGen->GenHeightMap(Desc.GetChunkX(), Desc.GetChunkZ(), Desc.GetHeightMap());
- m_CompositionGen->ComposeTerrain(Desc);
- }
- clock_t Duration = clock() - BeginTick;
- LOGINFO("CompositionGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
- //*/
- }
-
- // Read the settings from the ini file:
- m_CompositionGen->InitializeCompoGen(a_IniFile);
+ m_CompositionGen = cTerrainCompositionGen::CreateCompositionGen(a_IniFile, *m_BiomeGen, *m_HeightGen, m_ChunkGenerator.GetSeed());
int CompoGenCacheSize = a_IniFile.GetValueSetI("Generator", "CompositionGenCacheSize", 64);
if (CompoGenCacheSize > 1)
@@ -402,15 +367,16 @@ void cComposableGenerator::InitStructureGens(cIniFile & a_IniFile)
void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
{
int Seed = m_ChunkGenerator.GetSeed();
- AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
+ eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
+ AString Finishers = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
AStringVector Str = StringSplitAndTrim(Finishers, ",");
for (AStringVector::const_iterator itr = Str.begin(); itr != Str.end(); ++itr)
{
// Finishers, alpha-sorted:
if (NoCaseCompare(*itr, "BottomLava") == 0)
{
- int DefaultBottomLavaLevel = (m_World->GetDimension() == dimNether) ? 30 : 10;
+ int DefaultBottomLavaLevel = (Dimension == dimNether) ? 30 : 10;
int BottomLavaLevel = a_IniFile.GetValueSetI("Generator", "BottomLavaLevel", DefaultBottomLavaLevel);
m_FinishGens.push_back(new cFinishGenBottomLava(BottomLavaLevel));
}
@@ -424,7 +390,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
}
else if (NoCaseCompare(*itr, "LavaSprings") == 0)
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, *m_World));
+ m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_LAVA, a_IniFile, Dimension));
}
else if (NoCaseCompare(*itr, "Lilypads") == 0)
{
@@ -448,7 +414,7 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
}
else if (NoCaseCompare(*itr, "WaterSprings") == 0)
{
- m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, *m_World));
+ m_FinishGens.push_back(new cFinishGenFluidSprings(Seed, E_BLOCK_WATER, a_IniFile, Dimension));
}
} // for itr - Str[]
}
diff --git a/src/Generating/ComposableGenerator.h b/src/Generating/ComposableGenerator.h
index 732f64303..29add0636 100644
--- a/src/Generating/ComposableGenerator.h
+++ b/src/Generating/ComposableGenerator.h
@@ -50,7 +50,7 @@ public:
virtual void InitializeBiomeGen(cIniFile & a_IniFile) {}
/// Creates the correct BiomeGen descendant based on the ini file settings and the seed provided.
- /// a_CacheOffByDefault gets set to whether the cache should be enabled by default
+ /// a_CacheOffByDefault gets set to whether the cache should be disabled by default
/// Used in BiomeVisualiser, too.
/// Implemented in BioGen.cpp!
static cBiomeGen * CreateBiomeGen(cIniFile & a_IniFile, int a_Seed, bool & a_CacheOffByDefault);
@@ -77,6 +77,13 @@ public:
/// Reads parameters from the ini file, prepares generator for use.
virtual void InitializeHeightGen(cIniFile & a_IniFile) {}
+
+ /** Creates the correct TerrainHeightGen descendant based on the ini file settings and the seed provided.
+ a_BiomeGen is the underlying biome generator, some height generators may depend on it to generate more biomes
+ a_CacheOffByDefault gets set to whether the cache should be disabled by default
+ Implemented in HeiGen.cpp!
+ */
+ static cTerrainHeightGen * CreateHeightGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault);
} ;
@@ -97,6 +104,12 @@ public:
/// Reads parameters from the ini file, prepares generator for use.
virtual void InitializeCompoGen(cIniFile & a_IniFile) {}
+
+ /** Creates the correct TerrainCompositionGen descendant based on the ini file settings and the seed provided.
+ a_BiomeGen is the underlying biome generator, some composition generators may depend on it to generate more biomes
+ a_HeightGen is the underlying height generator, some composition generators may depend on it providing additional values
+ */
+ static cTerrainCompositionGen * CreateCompositionGen(cIniFile & a_IniFile, cBiomeGen & a_BiomeGen, cTerrainHeightGen & a_HeightGen, int a_Seed);
} ;
@@ -149,7 +162,7 @@ public:
cComposableGenerator(cChunkGenerator & a_ChunkGenerator);
virtual ~cComposableGenerator();
- virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile) override;
+ virtual void Initialize(cIniFile & a_IniFile) override;
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
diff --git a/src/Generating/FinishGen.cpp b/src/Generating/FinishGen.cpp
index 4ac6ff0f3..02045f76a 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -72,7 +72,7 @@ void cFinishGenNetherClumpFoliage::GenFinish(cChunkDesc & a_ChunkDesc)
PosX = (int) floor(16 / Val1);
}
- // Calculate PosZ
+ // Calculate PosZ
if (Val2 <= 1)
{
PosZ = (int) floor(Val2 * 16);
@@ -640,7 +640,7 @@ void cFinishGenPreSimulator::StationarizeFluid(
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cFinishGenFluidSprings:
-cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, const cWorld & a_World) :
+cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension) :
m_Noise(a_Seed + a_Fluid * 100), // Need to take fluid into account, otherwise water and lava springs generate next to each other
m_HeightDistribution(255),
m_Fluid(a_Fluid)
@@ -649,7 +649,7 @@ cFinishGenFluidSprings::cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cI
AString SectionName = IsWater ? "WaterSprings" : "LavaSprings";
AString DefaultHeightDistribution;
int DefaultChance = 0;
- switch (a_World.GetDimension())
+ switch (a_Dimension)
{
case dimNether:
{
diff --git a/src/Generating/FinishGen.h b/src/Generating/FinishGen.h
index a444721f8..2e5732929 100644
--- a/src/Generating/FinishGen.h
+++ b/src/Generating/FinishGen.h
@@ -51,9 +51,9 @@ class cFinishGenNetherClumpFoliage :
public cFinishGen
{
public:
- cFinishGenNetherClumpFoliage(int a_Seed) :
+ cFinishGenNetherClumpFoliage(int a_Seed) :
m_Noise(a_Seed),
- m_Seed(a_Seed)
+ m_Seed(a_Seed)
{
}
@@ -187,7 +187,7 @@ class cFinishGenFluidSprings :
public cFinishGen
{
public:
- cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, const cWorld & a_World);
+ cFinishGenFluidSprings(int a_Seed, BLOCKTYPE a_Fluid, cIniFile & a_IniFile, eDimension a_Dimension);
protected:
diff --git a/src/Generating/HeiGen.cpp b/src/Generating/HeiGen.cpp
index 2bf641089..10710b4a1 100644
--- a/src/Generating/HeiGen.cpp
+++ b/src/Generating/HeiGen.cpp
@@ -7,6 +7,9 @@
#include "HeiGen.h"
#include "../LinearUpscale.h"
#include "inifile/iniFile.h"
+#include "DistortedHeightmap.h"
+#include "EndGen.h"
+#include "Noise3DGenerator.h"
@@ -14,6 +17,77 @@
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cTerrainHeightGen:
+
+cTerrainHeightGen * cTerrainHeightGen::CreateHeightGen(cIniFile &a_IniFile, cBiomeGen & a_BiomeGen, int a_Seed, bool & a_CacheOffByDefault)
+{
+ AString HeightGenName = a_IniFile.GetValueSet("Generator", "HeightGen", "");
+ if (HeightGenName.empty())
+ {
+ LOGWARN("[Generator] HeightGen value not set in world.ini, using \"Biomal\".");
+ HeightGenName = "Biomal";
+ }
+
+ a_CacheOffByDefault = false;
+ cTerrainHeightGen * res = NULL;
+ if (NoCaseCompare(HeightGenName, "flat") == 0)
+ {
+ res = new cHeiGenFlat;
+ a_CacheOffByDefault = true; // We're generating faster than a cache would retrieve data
+ }
+ else if (NoCaseCompare(HeightGenName, "classic") == 0)
+ {
+ res = new cHeiGenClassic(a_Seed);
+ }
+ else if (NoCaseCompare(HeightGenName, "DistortedHeightmap") == 0)
+ {
+ res = new cDistortedHeightmap(a_Seed, a_BiomeGen);
+ }
+ else if (NoCaseCompare(HeightGenName, "End") == 0)
+ {
+ res = new cEndGen(a_Seed);
+ }
+ else if (NoCaseCompare(HeightGenName, "Noise3D") == 0)
+ {
+ res = new cNoise3DComposable(a_Seed);
+ }
+ else if (NoCaseCompare(HeightGenName, "biomal") == 0)
+ {
+ res = new cHeiGenBiomal(a_Seed, a_BiomeGen);
+
+ /*
+ // Performance-testing:
+ LOGINFO("Measuring performance of cHeiGenBiomal...");
+ clock_t BeginTick = clock();
+ for (int x = 0; x < 500; x++)
+ {
+ cChunkDef::HeightMap Heights;
+ res->GenHeightMap(x * 5, x * 5, Heights);
+ }
+ clock_t Duration = clock() - BeginTick;
+ LOGINFO("HeightGen for 500 chunks took %d ticks (%.02f sec)", Duration, (double)Duration / CLOCKS_PER_SEC);
+ //*/
+ }
+ else
+ {
+ // No match found, force-set the default and retry
+ LOGWARN("Unknown HeightGen \"%s\", using \"Biomal\" instead.", HeightGenName.c_str());
+ a_IniFile.DeleteValue("Generator", "HeightGen");
+ a_IniFile.SetValue("Generator", "HeightGen", "Biomal");
+ return CreateHeightGen(a_IniFile, a_BiomeGen, a_Seed, a_CacheOffByDefault);
+ }
+
+ // Read the settings:
+ res->InitializeHeightGen(a_IniFile);
+
+ return res;
+}
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cHeiGenFlat:
void cHeiGenFlat::GenHeightMap(int a_ChunkX, int a_ChunkZ, cChunkDef::HeightMap & a_HeightMap)
diff --git a/src/Generating/Noise3DGenerator.cpp b/src/Generating/Noise3DGenerator.cpp
index 2511bb656..afa40c647 100644
--- a/src/Generating/Noise3DGenerator.cpp
+++ b/src/Generating/Noise3DGenerator.cpp
@@ -150,10 +150,8 @@ cNoise3DGenerator::~cNoise3DGenerator()
-void cNoise3DGenerator::Initialize(cWorld * a_World, cIniFile & a_IniFile)
+void cNoise3DGenerator::Initialize(cIniFile & a_IniFile)
{
- m_World = a_World;
-
// Params:
m_SeaLevel = a_IniFile.GetValueSetI("Generator", "Noise3DSeaLevel", 62);
m_HeightAmplification = (NOISE_DATATYPE)a_IniFile.GetValueSetF("Generator", "Noise3DHeightAmplification", 0);
diff --git a/src/Generating/Noise3DGenerator.h b/src/Generating/Noise3DGenerator.h
index 0d211cddc..42f61a854 100644
--- a/src/Generating/Noise3DGenerator.h
+++ b/src/Generating/Noise3DGenerator.h
@@ -24,7 +24,7 @@ public:
cNoise3DGenerator(cChunkGenerator & a_ChunkGenerator);
virtual ~cNoise3DGenerator();
- virtual void Initialize(cWorld * a_World, cIniFile & a_IniFile) override;
+ virtual void Initialize(cIniFile & a_IniFile) override;
virtual void GenerateBiomes(int a_ChunkX, int a_ChunkZ, cChunkDef::BiomeMap & a_BiomeMap) override;
virtual void DoGenerate(int a_ChunkX, int a_ChunkZ, cChunkDesc & a_ChunkDesc) override;
diff --git a/src/Globals.h b/src/Globals.h
index f886ba2d0..d2080b8eb 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -233,6 +233,7 @@ public:
// Common headers (part 2, with macros):
#include "ChunkDef.h"
+#include "BiomeDef.h"
#include "BlockID.h"
#include "Entities/Effects.h"
diff --git a/src/Inventory.cpp b/src/Inventory.cpp
index a7f77cf6d..0e1cedc85 100644
--- a/src/Inventory.cpp
+++ b/src/Inventory.cpp
@@ -83,7 +83,7 @@ int cInventory::HowManyCanFit(const cItem & a_ItemStack, int a_BeginSlotNum, int
{
NumLeft -= MaxStack;
}
- else if (Slot.IsStackableWith(a_ItemStack))
+ else if (Slot.IsEqual(a_ItemStack))
{
NumLeft -= MaxStack - Slot.m_ItemCount;
}
diff --git a/src/Item.cpp b/src/Item.cpp
index a44515019..9170006b6 100644
--- a/src/Item.cpp
+++ b/src/Item.cpp
@@ -91,28 +91,6 @@ bool cItem::DamageItem(short a_Amount)
-bool cItem::IsStackableWith(const cItem & a_OtherStack) const
-{
- if (a_OtherStack.m_ItemType != m_ItemType)
- {
- return false;
- }
- if (a_OtherStack.m_ItemDamage != m_ItemDamage)
- {
- return false;
- }
- if (a_OtherStack.m_Enchantments != m_Enchantments)
- {
- return false;
- }
-
- return true;
-}
-
-
-
-
-
bool cItem::IsFullStack(void) const
{
return (m_ItemCount >= ItemHandler(m_ItemType)->GetMaxStackSize());
@@ -153,6 +131,14 @@ void cItem::GetJson(Json::Value & a_OutValue) const
{
a_OutValue["ench"] = Enchantments;
}
+ if (!IsCustomNameEmpty())
+ {
+ a_OutValue["Name"] = m_CustomName;
+ }
+ if (!IsLoreEmpty())
+ {
+ a_OutValue["Lore"] = m_Lore;
+ }
}
}
@@ -169,6 +155,8 @@ void cItem::FromJson(const Json::Value & a_Value)
m_ItemDamage = (short)a_Value.get("Health", -1 ).asInt();
m_Enchantments.Clear();
m_Enchantments.AddFromString(a_Value.get("ench", "").asString());
+ m_CustomName = a_Value.get("Name", "").asString();
+ m_Lore = a_Value.get("Lore", "").asString();
}
}
diff --git a/src/Item.h b/src/Item.h
index 64a30ade1..727965112 100644
--- a/src/Item.h
+++ b/src/Item.h
@@ -36,7 +36,9 @@ public:
cItem(void) :
m_ItemType(E_ITEM_EMPTY),
m_ItemCount(0),
- m_ItemDamage(0)
+ m_ItemDamage(0),
+ m_CustomName(""),
+ m_Lore("")
{
}
@@ -46,12 +48,16 @@ public:
short a_ItemType,
char a_ItemCount = 1,
short a_ItemDamage = 0,
- const AString & a_Enchantments = ""
+ const AString & a_Enchantments = "",
+ const AString & a_CustomName = "",
+ const AString & a_Lore = ""
) :
m_ItemType (a_ItemType),
m_ItemCount (a_ItemCount),
m_ItemDamage (a_ItemDamage),
- m_Enchantments(a_Enchantments)
+ m_Enchantments(a_Enchantments),
+ m_CustomName (a_CustomName),
+ m_Lore (a_Lore)
{
if (!IsValidItem(m_ItemType))
{
@@ -69,7 +75,9 @@ public:
m_ItemType (a_CopyFrom.m_ItemType),
m_ItemCount (a_CopyFrom.m_ItemCount),
m_ItemDamage (a_CopyFrom.m_ItemDamage),
- m_Enchantments(a_CopyFrom.m_Enchantments)
+ m_Enchantments(a_CopyFrom.m_Enchantments),
+ m_CustomName (a_CopyFrom.m_CustomName),
+ m_Lore (a_CopyFrom.m_Lore)
{
}
@@ -80,6 +88,8 @@ public:
m_ItemCount = 0;
m_ItemDamage = 0;
m_Enchantments.Clear();
+ m_CustomName = "";
+ m_Lore = "";
}
@@ -96,13 +106,16 @@ public:
return ((m_ItemType <= 0) || (m_ItemCount <= 0));
}
-
+ /* Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored!
+ */
bool IsEqual(const cItem & a_Item) const
{
return (
IsSameType(a_Item) &&
(m_ItemDamage == a_Item.m_ItemDamage) &&
- (m_Enchantments == a_Item.m_Enchantments)
+ (m_Enchantments == a_Item.m_Enchantments) &&
+ (m_CustomName == a_Item.m_CustomName) &&
+ (m_Lore == a_Item.m_Lore)
);
}
@@ -111,7 +124,16 @@ public:
{
return (m_ItemType == a_Item.m_ItemType) || (IsEmpty() && a_Item.IsEmpty());
}
-
+
+
+ bool IsBothNameAndLoreEmpty(void) const
+ {
+ return (m_CustomName.empty() && m_Lore.empty());
+ }
+
+
+ bool IsCustomNameEmpty(void) const { return (m_CustomName.empty()); }
+ bool IsLoreEmpty(void) const { return (m_Lore.empty()); }
/// Returns a copy of this item with m_ItemCount set to 1. Useful to preserve enchantments etc. on stacked items
cItem CopyOne(void) const;
@@ -127,9 +149,6 @@ public:
inline bool IsDamageable(void) const { return (GetMaxDamage() > 0); }
- /// Returns true if this itemstack can stack with the specified stack (types match, enchantments etc.) ItemCounts are ignored!
- bool IsStackableWith(const cItem & a_OtherStack) const;
-
/// Returns true if the item is stacked up to its maximum stacking.
bool IsFullStack(void) const;
@@ -155,6 +174,8 @@ public:
short m_ItemType;
char m_ItemCount;
short m_ItemDamage;
+ AString m_CustomName;
+ AString m_Lore;
cEnchantments m_Enchantments;
};
// tolua_end
diff --git a/src/ItemGrid.cpp b/src/ItemGrid.cpp
index d2e6b1c69..e8b58695f 100644
--- a/src/ItemGrid.cpp
+++ b/src/ItemGrid.cpp
@@ -226,7 +226,7 @@ int cItemGrid::HowManyCanFit(const cItem & a_ItemStack, bool a_AllowNewStacks)
NumLeft -= MaxStack;
}
}
- else if (m_Slots[i].IsStackableWith(a_ItemStack))
+ else if (m_Slots[i].IsEqual(a_ItemStack))
{
NumLeft -= MaxStack - m_Slots[i].m_ItemCount;
}
@@ -275,7 +275,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit
(a_PrioritarySlot != -1) &&
(
m_Slots[a_PrioritarySlot].IsEmpty() ||
- m_Slots[a_PrioritarySlot].IsStackableWith(a_ItemStack)
+ m_Slots[a_PrioritarySlot].IsEqual(a_ItemStack)
)
)
{
@@ -285,7 +285,7 @@ int cItemGrid::AddItem(cItem & a_ItemStack, bool a_AllowNewStacks, int a_Priorit
// Scan existing stacks:
for (int i = m_NumSlots - 1; i >= 0; i--)
{
- if (m_Slots[i].IsStackableWith(a_ItemStack))
+ if (m_Slots[i].IsEqual(a_ItemStack))
{
NumLeft -= AddItemToSlot(a_ItemStack, i, NumLeft, MaxStack);
}
@@ -438,7 +438,7 @@ int cItemGrid::HowManyItems(const cItem & a_Item)
int res = 0;
for (int i = 0; i < m_NumSlots; i++)
{
- if (m_Slots[i].IsStackableWith(a_Item))
+ if (m_Slots[i].IsEqual(a_Item))
{
res += m_Slots[i].m_ItemCount;
}
diff --git a/src/Items/ItemBed.h b/src/Items/ItemBed.h
index ab4182eea..9b7c8bff8 100644
--- a/src/Items/ItemBed.h
+++ b/src/Items/ItemBed.h
@@ -37,7 +37,7 @@ public:
return false;
}
- a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockBedHandler::RotationToMetaData(a_Player->GetYaw());
// Check if there is empty space for the foot section:
Vector3i Direction = cBlockBedHandler::MetaDataToDirection(a_BlockMeta);
diff --git a/src/Items/ItemComparator.h b/src/Items/ItemComparator.h
index 3fbb7603d..3a5d1d200 100644
--- a/src/Items/ItemComparator.h
+++ b/src/Items/ItemComparator.h
@@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = E_BLOCK_INACTIVE_COMPARATOR;
- a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
} ;
diff --git a/src/Items/ItemMinecart.h b/src/Items/ItemMinecart.h
index f8eb31a49..4071f8c60 100644
--- a/src/Items/ItemMinecart.h
+++ b/src/Items/ItemMinecart.h
@@ -60,7 +60,7 @@ public:
cMinecart * Minecart = NULL;
switch (m_ItemType)
{
- case E_ITEM_MINECART: Minecart = new cEmptyMinecart (x, y, z); break;
+ case E_ITEM_MINECART: Minecart = new cRideableMinecart (x, y, z, cItem(), 1); break;
case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (x, y, z); break;
case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (x, y, z); break;
case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (x, y, z); break;
diff --git a/src/Items/ItemRedstoneDust.h b/src/Items/ItemRedstoneDust.h
index 38bf00ba6..de90c8075 100644
--- a/src/Items/ItemRedstoneDust.h
+++ b/src/Items/ItemRedstoneDust.h
@@ -27,7 +27,7 @@ public:
BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta
) override
{
- if (!g_BlockIsTorchPlaceable[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]) // Some solid blocks, such as cocoa beans, are not suitable for dust
+ if (!g_BlockFullyOccupiesVoxel[a_World->GetBlock(a_BlockX, a_BlockY - 1, a_BlockZ)]) // Some solid blocks, such as cocoa beans, are not suitable for dust
{
return false;
}
diff --git a/src/Items/ItemRedstoneRepeater.h b/src/Items/ItemRedstoneRepeater.h
index f69f24eb8..e71c8e672 100644
--- a/src/Items/ItemRedstoneRepeater.h
+++ b/src/Items/ItemRedstoneRepeater.h
@@ -30,7 +30,7 @@ public:
) override
{
a_BlockType = E_BLOCK_REDSTONE_REPEATER_OFF;
- a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockRedstoneRepeaterHandler::RepeaterRotationToMetaData(a_Player->GetYaw());
return true;
}
} ;
diff --git a/src/Items/ItemSign.h b/src/Items/ItemSign.h
index 5ccd79e29..8c134ab83 100644
--- a/src/Items/ItemSign.h
+++ b/src/Items/ItemSign.h
@@ -34,7 +34,7 @@ public:
{
if (a_BlockFace == BLOCK_FACE_TOP)
{
- a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetRotation());
+ a_BlockMeta = cBlockSignHandler::RotationToMetaData(a_Player->GetYaw());
a_BlockType = E_BLOCK_SIGN_POST;
}
else
diff --git a/src/Log.cpp b/src/Log.cpp
index a0de4531b..2d6be0f59 100644
--- a/src/Log.cpp
+++ b/src/Log.cpp
@@ -147,11 +147,11 @@ void cLog::Log(const char * a_Format, va_list argList)
-void cLog::Log(const char* a_Format, ...)
+void cLog::Log(const char * a_Format, ...)
{
va_list argList;
va_start(argList, a_Format);
- Log( a_Format, argList );
+ Log(a_Format, argList);
va_end(argList);
}
@@ -159,9 +159,9 @@ void cLog::Log(const char* a_Format, ...)
-void cLog::SimpleLog(const char* a_String)
+void cLog::SimpleLog(const char * a_String)
{
- Log("%s", a_String );
+ Log("%s", a_String);
}
diff --git a/src/Log.h b/src/Log.h
index d00022c6f..cba248dae 100644
--- a/src/Log.h
+++ b/src/Log.h
@@ -14,11 +14,11 @@ private:
public:
cLog(const AString & a_FileName);
~cLog();
- void Log(const char* a_Format, va_list argList );
- void Log(const char* a_Format, ...);
+ void Log(const char * a_Format, va_list argList);
+ void Log(const char * a_Format, ...);
// tolua_begin
- void SimpleLog(const char* a_String);
- void OpenLog( const char* a_FileName );
+ void SimpleLog(const char * a_String);
+ void OpenLog(const char * a_FileName);
void CloseLog();
void ClearLog();
static cLog* GetInstance();
diff --git a/src/MCServer.vcproj.user b/src/MCServer.vcproj.user
new file mode 100644
index 000000000..b17909f71
--- /dev/null
+++ b/src/MCServer.vcproj.user
@@ -0,0 +1,167 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<VisualStudioUserFile
+ ProjectType="Visual C++"
+ Version="9,00"
+ ShowAllFiles="false"
+ >
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory="..\MCServer"
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor="0"
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ <Configuration
+ Name="DebugProfile|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory="..\MCServer"
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor="0"
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ <Configuration
+ Name="MinSizeRel|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory="..\MCServer"
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor="0"
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory="..\MCServer"
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor="0"
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ <Configuration
+ Name="ReleaseProfile|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory="..\MCServer"
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ Remote="1"
+ RemoteMachine="ASAGA"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor="0"
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ <Configuration
+ Name="RelWithDebInfo|Win32"
+ >
+ <DebugSettings
+ Command="$(TargetPath)"
+ WorkingDirectory="..\MCServer"
+ CommandArguments=""
+ Attach="false"
+ DebuggerType="3"
+ RemoteCommand=""
+ HttpUrl=""
+ PDBPath=""
+ SQLDebugging=""
+ Environment=""
+ EnvironmentMerge="true"
+ DebuggerFlavor="0"
+ MPIRunCommand=""
+ MPIRunArguments=""
+ MPIRunWorkingDirectory=""
+ ApplicationCommand=""
+ ApplicationArguments=""
+ ShimCommand=""
+ MPIAcceptMode=""
+ MPIAcceptFilter=""
+ />
+ </Configuration>
+ </Configurations>
+</VisualStudioUserFile>
diff --git a/src/Mobs/Monster.cpp b/src/Mobs/Monster.cpp
index 76df76633..98b6c1d28 100644
--- a/src/Mobs/Monster.cpp
+++ b/src/Mobs/Monster.cpp
@@ -208,7 +208,7 @@ void cMonster::Tick(float a_Dt, cChunk & a_Chunk)
Distance.Normalize();
VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch );
SetHeadYaw (Rotation);
- SetRotation( Rotation );
+ SetYaw( Rotation );
SetPitch( -Pitch );
}
diff --git a/src/OSSupport/BlockingTCPLink.cpp b/src/OSSupport/BlockingTCPLink.cpp
index 55454a4b5..08aec0c65 100644
--- a/src/OSSupport/BlockingTCPLink.cpp
+++ b/src/OSSupport/BlockingTCPLink.cpp
@@ -7,17 +7,6 @@
-#ifdef _WIN32
- #define MSG_NOSIGNAL (0)
-#endif
-#ifdef __MACH__
- #define MSG_NOSIGNAL (0)
-#endif
-
-
-
-
-
cBlockingTCPLink::cBlockingTCPLink(void)
{
}
diff --git a/src/OSSupport/Socket.cpp b/src/OSSupport/Socket.cpp
index f25f800c2..8ea5d8320 100644
--- a/src/OSSupport/Socket.cpp
+++ b/src/OSSupport/Socket.cpp
@@ -72,10 +72,6 @@ void cSocket::CloseSocket()
#else // _WIN32
- if (shutdown(m_Socket, SHUT_RDWR) != 0)//SD_BOTH);
- {
- LOGWARN("Error on shutting down socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str());
- }
if (close(m_Socket) != 0)
{
LOGWARN("Error closing socket %d (%s): %s", m_Socket, m_IPString.c_str(), GetLastErrorString().c_str());
@@ -368,7 +364,7 @@ int cSocket::Receive(char* a_Buffer, unsigned int a_Length, unsigned int a_Flags
int cSocket::Send(const char * a_Buffer, unsigned int a_Length)
{
- return send(m_Socket, a_Buffer, a_Length, 0);
+ return send(m_Socket, a_Buffer, a_Length, MSG_NOSIGNAL);
}
diff --git a/src/OSSupport/Socket.h b/src/OSSupport/Socket.h
index 81bfd28fc..b86560de8 100644
--- a/src/OSSupport/Socket.h
+++ b/src/OSSupport/Socket.h
@@ -5,6 +5,18 @@
+// Windows and MacOSX don't have the MSG_NOSIGNAL flag
+#if ( \
+ defined(_WIN32) || \
+ (defined(__APPLE__) && defined(__MACH__)) \
+)
+ #define MSG_NOSIGNAL (0)
+#endif
+
+
+
+
+
class cSocket
{
public:
diff --git a/src/Protocol/Protocol.h b/src/Protocol/Protocol.h
index fdbffb3e9..3293da32c 100644
--- a/src/Protocol/Protocol.h
+++ b/src/Protocol/Protocol.h
@@ -87,6 +87,7 @@ public:
virtual void SendPlayerMoveLook (void) = 0;
virtual void SendPlayerPosition (void) = 0;
virtual void SendPlayerSpawn (const cPlayer & a_Player) = 0;
+ virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) = 0;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) = 0;
virtual void SendRespawn (void) = 0;
virtual void SendExperience (void) = 0;
diff --git a/src/Protocol/Protocol125.cpp b/src/Protocol/Protocol125.cpp
index e49dd43ff..323a13992 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -354,8 +354,8 @@ void cProtocol125::SendEntityLook(const cEntity & a_Entity)
cCSLock Lock(m_CSPacket);
WriteByte(PACKET_ENT_LOOK);
WriteInt (a_Entity.GetUniqueID());
- WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@@ -423,8 +423,8 @@ void cProtocol125::SendEntityRelMoveLook(const cEntity & a_Entity, char a_RelX,
WriteByte(a_RelX);
WriteByte(a_RelY);
WriteByte(a_RelZ);
- WriteByte((char)((a_Entity.GetRotation() / 360.f) * 256));
- WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetYaw() / 360.f) * 256));
+ WriteByte((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
@@ -664,7 +664,7 @@ void cProtocol125::SendPlayerMoveLook(void)
WriteDouble(Player->GetStance() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosY() + 0.03); // Add a small amount so that the player doesn't start inside a block
WriteDouble(Player->GetPosZ());
- WriteFloat ((float)(Player->GetRotation()));
+ WriteFloat ((float)(Player->GetYaw()));
WriteFloat ((float)(Player->GetPitch()));
WriteBool (Player->IsOnGround());
Flush();
@@ -694,8 +694,8 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
- WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
Flush();
}
@@ -704,6 +704,20 @@ void cProtocol125::SendPlayerSpawn(const cPlayer & a_Player)
+void cProtocol125::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+{
+ cCSLock Lock(m_CSPacket);
+ WriteByte(PACKET_PLUGIN_MESSAGE);
+ WriteString(a_Channel);
+ WriteShort((short)a_Message.size());
+ SendData(a_Message.data(), a_Message.size());
+ Flush();
+}
+
+
+
+
+
void cProtocol125::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
cCSLock Lock(m_CSPacket);
@@ -850,7 +864,7 @@ void cProtocol125::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
- WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
+ WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256));
WriteInt (a_VehicleSubType);
if (a_VehicleSubType != 0)
{
@@ -883,7 +897,7 @@ void cProtocol125::SendTeleportEntity(const cEntity & a_Entity)
WriteInt ((int)(floor(a_Entity.GetPosX() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosY() * 32)));
WriteInt ((int)(floor(a_Entity.GetPosZ() * 32)));
- WriteByte ((char)((a_Entity.GetRotation() / 360.f) * 256));
+ WriteByte ((char)((a_Entity.GetYaw() / 360.f) * 256));
WriteByte ((char)((a_Entity.GetPitch() / 360.f) * 256));
Flush();
}
diff --git a/src/Protocol/Protocol125.h b/src/Protocol/Protocol125.h
index 0b32137d8..d0e5c9428 100644
--- a/src/Protocol/Protocol125.h
+++ b/src/Protocol/Protocol125.h
@@ -63,6 +63,7 @@ public:
virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerPosition (void) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
+ virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
virtual void SendRespawn (void) override;
virtual void SendExperience (void) override;
diff --git a/src/Protocol/Protocol132.cpp b/src/Protocol/Protocol132.cpp
index 302d1298c..29fbb4bba 100644
--- a/src/Protocol/Protocol132.cpp
+++ b/src/Protocol/Protocol132.cpp
@@ -367,8 +367,8 @@ void cProtocol132::SendPlayerSpawn(const cPlayer & a_Player)
WriteInt ((int)(a_Player.GetPosX() * 32));
WriteInt ((int)(a_Player.GetPosY() * 32));
WriteInt ((int)(a_Player.GetPosZ() * 32));
- WriteByte ((char)((a_Player.GetRot().x / 360.f) * 256));
- WriteByte ((char)((a_Player.GetRot().y / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetYaw() / 360.f) * 256));
+ WriteByte ((char)((a_Player.GetPitch() / 360.f) * 256));
WriteShort (HeldItem.IsEmpty() ? 0 : HeldItem.m_ItemType);
// Player metadata: just use a default metadata value, since the client doesn't like starting without any metadata:
WriteByte (0); // Index 0, byte (flags)
@@ -421,8 +421,8 @@ void cProtocol132::SendSpawnMob(const cMonster & a_Mob)
WriteInt (a_Mob.GetUniqueID());
WriteByte (a_Mob.GetMobType());
WriteVectorI((Vector3i)(a_Mob.GetPosition() * 32));
- WriteByte ((Byte)((a_Mob.GetRotation() / 360.f) * 256));
- WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
+ WriteByte ((Byte)((a_Mob.GetYaw() / 360.f) * 256));
+ WriteByte ((Byte)((a_Mob.GetPitch() / 360.f) * 256));
WriteByte ((Byte)((a_Mob.GetHeadYaw() / 360.f) * 256));
WriteShort ((short)(a_Mob.GetSpeedX() * 400));
WriteShort ((short)(a_Mob.GetSpeedY() * 400));
diff --git a/src/Protocol/Protocol14x.cpp b/src/Protocol/Protocol14x.cpp
index 926fe6ee8..127ce9d4b 100644
--- a/src/Protocol/Protocol14x.cpp
+++ b/src/Protocol/Protocol14x.cpp
@@ -250,7 +250,7 @@ void cProtocol146::SendSpawnVehicle(const cEntity & a_Vehicle, char a_VehicleTyp
WriteInt ((int)(a_Vehicle.GetPosY() * 32));
WriteInt ((int)(a_Vehicle.GetPosZ() * 32));
WriteByte ((Byte)((a_Vehicle.GetPitch() / 360.f) * 256));
- WriteByte ((Byte)((a_Vehicle.GetRotation() / 360.f) * 256));
+ WriteByte ((Byte)((a_Vehicle.GetYaw() / 360.f) * 256));
WriteInt (a_VehicleSubType);
if (a_VehicleSubType != 0)
{
diff --git a/src/Protocol/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 8ec5dec29..5b3a79555 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -121,7 +121,7 @@ void cProtocol172::SendBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, cha
void cProtocol172::SendBlockBreakAnim(int a_EntityID, int a_BlockX, int a_BlockY, int a_BlockZ, char a_Stage)
{
- cPacketizer Pkt(*this, 0x24); // Block Break Animation packet
+ cPacketizer Pkt(*this, 0x25); // Block Break Animation packet
Pkt.WriteInt(a_EntityID);
Pkt.WriteInt(a_BlockX);
Pkt.WriteInt(a_BlockY);
@@ -216,8 +216,23 @@ void cProtocol172::SendDestroyEntity(const cEntity & a_Entity)
void cProtocol172::SendDisconnect(const AString & a_Reason)
{
- cPacketizer Pkt(*this, 0x40);
- Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
+ switch (m_State)
+ {
+ case 2:
+ {
+ // During login:
+ cPacketizer Pkt(*this, 0);
+ Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
+ break;
+ }
+ case 3:
+ {
+ // In-game:
+ cPacketizer Pkt(*this, 0x40);
+ Pkt.WriteString(Printf("{\"text\":\"%s\"}", EscapeString(a_Reason).c_str()));
+ break;
+ }
+ }
}
@@ -628,6 +643,18 @@ void cProtocol172::SendPlayerSpawn(const cPlayer & a_Player)
+void cProtocol172::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+{
+ cPacketizer Pkt(*this, 0x3f);
+ Pkt.WriteString(a_Channel);
+ Pkt.WriteShort((short)a_Message.size());
+ Pkt.WriteBuf(a_Message.data(), a_Message.size());
+}
+
+
+
+
+
void cProtocol172::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
cPacketizer Pkt(*this, 0x1E);
@@ -1010,11 +1037,31 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
return;
}
- HandlePacket(bb, PacketType);
+ if (!HandlePacket(bb, PacketType))
+ {
+ // Unknown packet, already been reported, but without the length. Log the length here:
+ LOGWARNING("Unhandled packet: type 0x%x, state %d, length %u", PacketType, m_State, PacketLen);
+
+ #ifdef _DEBUG
+ // Dump the packet contents into the log:
+ bb.ResetRead();
+ AString Packet;
+ bb.ReadAll(Packet);
+ Packet.resize(Packet.size() - 1); // Drop the final NUL pushed there for over-read detection
+ AString Out;
+ CreateHexDump(Out, Packet.data(), (int)Packet.size(), 24);
+ LOGD("Packet contents:\n%s", Out.c_str());
+ #endif // _DEBUG
+
+ return;
+ }
if (bb.GetReadableSpace() != 1)
{
// Read more or less than packet length, report as error
+ LOGWARNING("Protocol 1.7: Wrong number of bytes read for packet 0x%x, state %d. Read %u bytes, packet contained %u bytes",
+ PacketType, m_State, bb.GetUsedSpace() - bb.GetReadableSpace(), PacketLen
+ );
ASSERT(!"Read wrong number of bytes!");
m_Client->PacketError(PacketType);
}
@@ -1024,7 +1071,7 @@ void cProtocol172::AddReceivedData(const char * a_Data, int a_Size)
-void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
+bool cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
{
switch (m_State)
{
@@ -1033,8 +1080,8 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
// Status
switch (a_PacketType)
{
- case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return;
- case 0x01: HandlePacketStatusPing (a_ByteBuffer); return;
+ case 0x00: HandlePacketStatusRequest(a_ByteBuffer); return true;
+ case 0x01: HandlePacketStatusPing (a_ByteBuffer); return true;
}
break;
}
@@ -1044,8 +1091,8 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
// Login
switch (a_PacketType)
{
- case 0x00: HandlePacketLoginStart (a_ByteBuffer); return;
- case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return;
+ case 0x00: HandlePacketLoginStart (a_ByteBuffer); return true;
+ case 0x01: HandlePacketLoginEncryptionResponse(a_ByteBuffer); return true;
}
break;
}
@@ -1055,36 +1102,54 @@ void cProtocol172::HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType)
// Game
switch (a_PacketType)
{
- case 0x00: HandlePacketKeepAlive (a_ByteBuffer); return;
- case 0x01: HandlePacketChatMessage (a_ByteBuffer); return;
- case 0x02: HandlePacketUseEntity (a_ByteBuffer); return;
- case 0x03: HandlePacketPlayer (a_ByteBuffer); return;
- case 0x04: HandlePacketPlayerPos (a_ByteBuffer); return;
- case 0x05: HandlePacketPlayerLook (a_ByteBuffer); return;
- case 0x06: HandlePacketPlayerPosLook (a_ByteBuffer); return;
- case 0x07: HandlePacketBlockDig (a_ByteBuffer); return;
- case 0x08: HandlePacketBlockPlace (a_ByteBuffer); return;
- case 0x09: HandlePacketSlotSelect (a_ByteBuffer); return;
- case 0x0a: HandlePacketAnimation (a_ByteBuffer); return;
- case 0x0b: HandlePacketEntityAction (a_ByteBuffer); return;
- case 0x0c: HandlePacketSteerVehicle (a_ByteBuffer); return;
- case 0x0d: HandlePacketWindowClose (a_ByteBuffer); return;
- case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return;
+ case 0x00: HandlePacketKeepAlive (a_ByteBuffer); return true;
+ case 0x01: HandlePacketChatMessage (a_ByteBuffer); return true;
+ case 0x02: HandlePacketUseEntity (a_ByteBuffer); return true;
+ case 0x03: HandlePacketPlayer (a_ByteBuffer); return true;
+ case 0x04: HandlePacketPlayerPos (a_ByteBuffer); return true;
+ case 0x05: HandlePacketPlayerLook (a_ByteBuffer); return true;
+ case 0x06: HandlePacketPlayerPosLook (a_ByteBuffer); return true;
+ case 0x07: HandlePacketBlockDig (a_ByteBuffer); return true;
+ case 0x08: HandlePacketBlockPlace (a_ByteBuffer); return true;
+ case 0x09: HandlePacketSlotSelect (a_ByteBuffer); return true;
+ case 0x0a: HandlePacketAnimation (a_ByteBuffer); return true;
+ case 0x0b: HandlePacketEntityAction (a_ByteBuffer); return true;
+ case 0x0c: HandlePacketSteerVehicle (a_ByteBuffer); return true;
+ case 0x0d: HandlePacketWindowClose (a_ByteBuffer); return true;
+ case 0x0e: HandlePacketWindowClick (a_ByteBuffer); return true;
case 0x0f: // Confirm transaction - not used in MCS
- case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return;
- case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return;
- case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return;
- case 0x14: HandlePacketTabComplete (a_ByteBuffer); return;
- case 0x15: HandlePacketClientSettings (a_ByteBuffer); return;
- case 0x16: HandlePacketClientStatus (a_ByteBuffer); return;
- case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return;
+ case 0x10: HandlePacketCreativeInventoryAction(a_ByteBuffer); return true;
+ case 0x12: HandlePacketUpdateSign (a_ByteBuffer); return true;
+ case 0x13: HandlePacketPlayerAbilities (a_ByteBuffer); return true;
+ case 0x14: HandlePacketTabComplete (a_ByteBuffer); return true;
+ case 0x15: HandlePacketClientSettings (a_ByteBuffer); return true;
+ case 0x16: HandlePacketClientStatus (a_ByteBuffer); return true;
+ case 0x17: HandlePacketPluginMessage (a_ByteBuffer); return true;
}
break;
}
+ default:
+ {
+ // Received a packet in an unknown state, report:
+ LOGWARNING("Received a packet in an unknown protocol state %d. Ignoring further packets.", m_State);
+
+ // Cannot kick the client - we don't know this state and thus the packet number for the kick packet
+
+ // Switch to a state when all further packets are silently ignored:
+ m_State = 255;
+ return false;
+ }
+ case 255:
+ {
+ // This is the state used for "not processing packets anymore" when we receive a bad packet from a client.
+ // Do not output anything (the caller will do that for us), just return failure
+ return false;
+ }
} // switch (m_State)
- // Unknown packet type, report to the client:
+ // Unknown packet type, report to the ClientHandle:
m_Client->PacketUnknown(a_PacketType);
+ return false;
}
@@ -1144,6 +1209,12 @@ void cProtocol172::HandlePacketLoginStart(cByteBuffer & a_ByteBuffer)
// TODO: Protocol encryption should be set up here if not localhost / auth
+ if (!m_Client->HandleHandshake(Username))
+ {
+ // The client is not welcome here, they have been sent a Kick packet already
+ return;
+ }
+
// Send login success:
{
cPacketizer Pkt(*this, 0x02); // Login success packet
@@ -1614,7 +1685,7 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
return;
}
- // Load enchantments from the NBT:
+ // Load enchantments and custom display names from the NBT data:
for (int tag = NBT.GetFirstChild(NBT.GetRoot()); tag >= 0; tag = NBT.GetNextSibling(tag))
{
if (
@@ -1627,6 +1698,27 @@ void cProtocol172::ParseItemMetadata(cItem & a_Item, const AString & a_Metadata)
{
a_Item.m_Enchantments.ParseFromNBT(NBT, tag);
}
+ else if ((NBT.GetType(tag) == TAG_Compound) && (NBT.GetName(tag) == "display")) // Custom name and lore tag
+ {
+ for (int displaytag = NBT.GetFirstChild(tag); displaytag >= 0; displaytag = NBT.GetNextSibling(displaytag))
+ {
+ if ((NBT.GetType(displaytag) == TAG_String) && (NBT.GetName(displaytag) == "Name")) // Custon name tag
+ {
+ a_Item.m_CustomName = NBT.GetString(displaytag);
+ }
+ else if ((NBT.GetType(displaytag) == TAG_List) && (NBT.GetName(displaytag) == "Lore")) // Lore tag
+ {
+ AString Lore;
+
+ for (int loretag = NBT.GetFirstChild(displaytag); loretag >= 0; loretag = NBT.GetNextSibling(loretag)) // Loop through array of strings
+ {
+ AppendPrintf(Lore, "%s`", NBT.GetString(loretag).c_str()); // Append the lore with a newline, used internally by MCS to display a new line in the client; don't forget to c_str ;)
+ }
+
+ a_Item.m_Lore = Lore;
+ }
+ }
+ }
}
}
@@ -1678,16 +1770,45 @@ void cProtocol172::cPacketizer::WriteItem(const cItem & a_Item)
WriteByte (a_Item.m_ItemCount);
WriteShort(a_Item.m_ItemDamage);
- if (a_Item.m_Enchantments.IsEmpty())
+ if (a_Item.m_Enchantments.IsEmpty() && a_Item.IsBothNameAndLoreEmpty())
{
WriteShort(-1);
return;
}
- // Send the enchantments:
+ // Send the enchantments and custom names:
cFastNBTWriter Writer;
- const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
- a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
+ if (!a_Item.m_Enchantments.IsEmpty())
+ {
+ const char * TagName = (a_Item.m_ItemType == E_ITEM_BOOK) ? "StoredEnchantments" : "ench";
+ a_Item.m_Enchantments.WriteToNBTCompound(Writer, TagName);
+ }
+ if (!a_Item.IsBothNameAndLoreEmpty())
+ {
+ Writer.BeginCompound("display");
+ if (!a_Item.IsCustomNameEmpty())
+ {
+ Writer.AddString("Name", a_Item.m_CustomName.c_str());
+ }
+ if (!a_Item.IsLoreEmpty())
+ {
+ Writer.BeginList("Lore", TAG_String);
+
+ AStringVector Decls = StringSplit(a_Item.m_Lore, "`");
+ for (AStringVector::const_iterator itr = Decls.begin(), end = Decls.end(); itr != end; ++itr)
+ {
+ if (itr->empty())
+ {
+ // The decl is empty (two `s), ignore
+ continue;
+ }
+ Writer.AddString("", itr->c_str());
+ }
+
+ Writer.EndList();
+ }
+ Writer.EndCompound();
+ }
Writer.Finish();
AString Compressed;
CompressStringGZIP(Writer.GetResult().data(), Writer.GetResult().size(), Compressed);
@@ -1769,8 +1890,23 @@ void cProtocol172::cPacketizer::WriteEntityMetadata(const cEntity & a_Entity)
WriteInt(1); // Shaking direction, doesn't seem to affect anything
WriteByte(0x73);
WriteFloat((float)(((const cMinecart &)a_Entity).LastDamage() + 10)); // Damage taken / shake effect multiplyer
-
- if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
+
+ if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpNone)
+ {
+ cRideableMinecart & RideableMinecart = ((cRideableMinecart &)a_Entity);
+ if (!RideableMinecart.GetContent().IsEmpty())
+ {
+ WriteByte(0x54);
+ int Content = RideableMinecart.GetContent().m_ItemType;
+ Content |= RideableMinecart.GetContent().m_ItemDamage << 8;
+ WriteInt(Content);
+ WriteByte(0x55);
+ WriteInt(RideableMinecart.GetBlockHeight());
+ WriteByte(0x56);
+ WriteByte(1);
+ }
+ }
+ else if (((cMinecart &)a_Entity).GetPayload() == cMinecart::mpFurnace)
{
WriteByte(0x10);
WriteByte(((const cMinecartWithFurnace &)a_Entity).IsFueled() ? 1 : 0);
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 23ff2365d..07dba834b 100644
--- a/src/Protocol/Protocol17x.h
+++ b/src/Protocol/Protocol17x.h
@@ -86,6 +86,7 @@ public:
virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerPosition (void) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
+ virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
virtual void SendRespawn (void) override;
virtual void SendSoundEffect (const AString & a_SoundName, int a_SrcX, int a_SrcY, int a_SrcZ, float a_Volume, float a_Pitch) override; // a_Src coords are Block * 8
@@ -221,8 +222,10 @@ protected:
/// Adds the received (unencrypted) data to m_ReceivedData, parses complete packets
void AddReceivedData(const char * a_Data, int a_Size);
- /// Reads and handles the packet. The packet length and type have already been read.
- void HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType);
+ /** Reads and handles the packet. The packet length and type have already been read.
+ Returns true if the packet was understood, false if it was an unknown packet
+ */
+ bool HandlePacket(cByteBuffer & a_ByteBuffer, UInt32 a_PacketType);
// Packet handlers while in the Status state (m_State == 1):
void HandlePacketStatusPing (cByteBuffer & a_ByteBuffer);
diff --git a/src/Protocol/ProtocolRecognizer.cpp b/src/Protocol/ProtocolRecognizer.cpp
index e2ea0e6e5..a21f4f042 100644
--- a/src/Protocol/ProtocolRecognizer.cpp
+++ b/src/Protocol/ProtocolRecognizer.cpp
@@ -476,6 +476,16 @@ void cProtocolRecognizer::SendPlayerSpawn(const cPlayer & a_Player)
+void cProtocolRecognizer::SendPluginMessage(const AString & a_Channel, const AString & a_Message)
+{
+ ASSERT(m_Protocol != NULL);
+ m_Protocol->SendPluginMessage(a_Channel, a_Message);
+}
+
+
+
+
+
void cProtocolRecognizer::SendRemoveEntityEffect(const cEntity & a_Entity, int a_EffectID)
{
ASSERT(m_Protocol != NULL);
diff --git a/src/Protocol/ProtocolRecognizer.h b/src/Protocol/ProtocolRecognizer.h
index fbcf59f3b..e94f4cde8 100644
--- a/src/Protocol/ProtocolRecognizer.h
+++ b/src/Protocol/ProtocolRecognizer.h
@@ -98,6 +98,7 @@ public:
virtual void SendPlayerMoveLook (void) override;
virtual void SendPlayerPosition (void) override;
virtual void SendPlayerSpawn (const cPlayer & a_Player) override;
+ virtual void SendPluginMessage (const AString & a_Channel, const AString & a_Message) override;
virtual void SendRemoveEntityEffect (const cEntity & a_Entity, int a_EffectID) override;
virtual void SendRespawn (void) override;
virtual void SendExperience (void) override;
diff --git a/src/Resources/MCServer.rc b/src/Resources/MCServer.rc
new file mode 100644
index 000000000..e0fbbea5d
--- /dev/null
+++ b/src/Resources/MCServer.rc
@@ -0,0 +1,17 @@
+// Generated by ResEdit 1.5.11
+// Copyright (C) 2006-2012
+// http://www.resedit.net
+
+#include <windows.h>
+#include <commctrl.h>
+#include <richedit.h>
+#include "resource_MCServer.h"
+
+
+
+
+//
+// Icon resources
+//
+LANGUAGE 9, SUBLANG_DEFAULT
+IDI_ICON1 ICON "icon.ico"
diff --git a/src/Resources/icon.ico b/src/Resources/icon.ico
new file mode 100644
index 000000000..4024523a1
--- /dev/null
+++ b/src/Resources/icon.ico
Binary files differ
diff --git a/src/Resources/icon_128.png b/src/Resources/icon_128.png
new file mode 100644
index 000000000..87d939a04
--- /dev/null
+++ b/src/Resources/icon_128.png
Binary files differ
diff --git a/src/Resources/icon_256.png b/src/Resources/icon_256.png
new file mode 100644
index 000000000..9a77a490f
--- /dev/null
+++ b/src/Resources/icon_256.png
Binary files differ
diff --git a/src/Resources/resource_MCServer.h b/src/Resources/resource_MCServer.h
new file mode 100644
index 000000000..42f6c4eaf
--- /dev/null
+++ b/src/Resources/resource_MCServer.h
@@ -0,0 +1,5 @@
+#ifndef IDC_STATIC
+#define IDC_STATIC (-1)
+#endif
+
+#define IDI_ICON1 101
diff --git a/src/Server.h b/src/Server.h
index d79417fb0..703a7077e 100644
--- a/src/Server.h
+++ b/src/Server.h
@@ -107,7 +107,7 @@ public: // tolua_export
/// Notifies the server that a player is being destroyed; the server uses this to adjust the number of players
void PlayerDestroying(const cPlayer * a_Player);
- /* Returns base64 encoded favicon data (obtained from favicon.png) */
+ /** Returns base64 encoded favicon data (obtained from favicon.png) */
const AString & GetFaviconData(void) const { return m_FaviconData; }
CryptoPP::RSA::PrivateKey & GetPrivateKey(void) { return m_PrivateKey; }
diff --git a/src/Simulator/RedstoneSimulator.cpp b/src/Simulator/RedstoneSimulator.cpp
index f65908729..469680098 100644
--- a/src/Simulator/RedstoneSimulator.cpp
+++ b/src/Simulator/RedstoneSimulator.cpp
@@ -44,83 +44,46 @@ void cRedstoneSimulator::AddBlock(int a_BlockX, int a_BlockY, int a_BlockZ, cChu
int RelX = a_BlockX - a_Chunk->GetPosX() * cChunkDef::Width;
int RelZ = a_BlockZ - a_Chunk->GetPosZ() * cChunkDef::Width;
+
+ BLOCKTYPE Block;
+ NIBBLETYPE Meta;
+ a_Chunk->GetBlockTypeMeta(RelX, a_BlockY, RelZ, Block, Meta);
- if (!IsAllowedBlock(a_Chunk->GetBlock(RelX, a_BlockY, RelZ)))
- {
- return;
- }
-
- // Check for duplicates:
- cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
- for (cRedstoneSimulatorChunkData::const_iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
- {
- if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ))
- {
- return;
- }
- }
-
- ChunkData.push_back(cCoordWithInt(RelX, a_BlockY, RelZ));
-}
-
-
-
-
-
-void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
-{
- cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
- if (ChunkData.empty())
- {
- return;
- }
-
- int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
- int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
+ // Every time a block is changed (AddBlock called), we want to go through all lists and check to see if the coordiantes stored within are still valid
+ // Checking only when a block is changed, as opposed to every tick, also improves performance
- // Check to see if PoweredBlocks have invalid items (source is air or unpowered)
- for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end();)
+ for (PoweredBlocksList::iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
{
- int RelX = itr->a_SourcePos.x - a_ChunkX * cChunkDef::Width;
- int RelZ = itr->a_SourcePos.z - a_ChunkZ * cChunkDef::Width;
- int DestRelX = itr->a_BlockPos.x - a_ChunkX * cChunkDef::Width;
- int DestRelZ = itr->a_BlockPos.z - a_ChunkZ * cChunkDef::Width;
-
- BLOCKTYPE SourceBlockType;
- NIBBLETYPE SourceBlockMeta;
- BLOCKTYPE DestBlockType;
- if (
- !a_Chunk->UnboundedRelGetBlock(RelX, itr->a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta) ||
- !a_Chunk->UnboundedRelGetBlockType(DestRelX, itr->a_BlockPos.y, DestRelZ, DestBlockType)
- )
+ if (!itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{
continue;
}
- if (SourceBlockType != itr->a_SourceBlock)
+ if (!IsPotentialSource(Block))
{
- LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past block type mismatch", ItemToFullString(itr->a_SourceBlock).c_str());
- itr = m_PoweredBlocks.erase(itr);
+ LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list as it no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_PoweredBlocks.erase(itr);
+ break;
}
else if (
// Changeable sources
- ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
- ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
- ((SourceBlockType == E_BLOCK_DETECTOR_RAIL) && (SourceBlockMeta & 0x08) == 0x08) ||
- (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta))) ||
- (((SourceBlockType == E_BLOCK_STONE_PRESSURE_PLATE) || (SourceBlockType == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (SourceBlockMeta == 0))
+ ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
+ ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
+ ((Block == E_BLOCK_DETECTOR_RAIL) && (Meta & 0x08) == 0) ||
+ (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta))) ||
+ (((Block == E_BLOCK_STONE_PRESSURE_PLATE) || (Block == E_BLOCK_WOODEN_PRESSURE_PLATE)) && (Meta == 0))
)
{
- LOGD("cRedstoneSimulator: Erased block %s from powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str());
- itr = m_PoweredBlocks.erase(itr);
+ LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_PoweredBlocks.erase(itr);
+ break;
}
- else if (SourceBlockType == E_BLOCK_DAYLIGHT_SENSOR)
+ else if (Block == E_BLOCK_DAYLIGHT_SENSOR)
{
if (!a_Chunk->IsLightValid())
{
- m_World.QueueLightChunk(a_ChunkX, a_ChunkZ);
- ++itr;
- continue;
+ m_World.QueueLightChunk(a_Chunk->GetPosX(), a_Chunk->GetPosZ());
+ break;
}
else
{
@@ -130,126 +93,125 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
if (a_Chunk->GetTimeAlteredLight(SkyLight) <= 8) // Could use SkyLight - m_World.GetSkyDarkness();
{
LOGD("cRedstoneSimulator: Erased daylight sensor from powered blocks list due to insufficient light level");
- itr = m_PoweredBlocks.erase(itr);
- }
- else
- {
- ++itr;
- continue;
+ m_PoweredBlocks.erase(itr);
+ break;
}
}
}
- else if ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (DestBlockType == E_BLOCK_REDSTONE_WIRE))
+ }
+
+ for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
+ {
+ if (itr->a_SourcePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{
- // It is simply not allowed that a wire powers another wire, presuming that data here is sane and a dest and source are beside each other
- LOGD("cRedstoneSimulator: Erased redstone wire from powered blocks list because its source was also wire");
- itr = m_PoweredBlocks.erase(itr);
+ if (!IsPotentialSource(Block))
+ {
+ LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer connected to a source", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_LinkedPoweredBlocks.erase(itr);
+ break;
+ }
+ else if (
+ // Things that can send power through a block but which depends on meta
+ ((Block == E_BLOCK_REDSTONE_WIRE) && (Meta == 0)) ||
+ ((Block == E_BLOCK_LEVER) && !IsLeverOn(Meta)) ||
+ (((Block == E_BLOCK_STONE_BUTTON) || (Block == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(Meta)))
+ )
+ {
+ LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list due to present/past metadata mismatch", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_LinkedPoweredBlocks.erase(itr);
+ break;
+ }
}
- else
+ else if (itr->a_MiddlePos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{
- ++itr;
+ if (!IsViableMiddleBlock(Block))
+ {
+ LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from linked powered blocks list as it is no longer powered through a valid middle block", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_LinkedPoweredBlocks.erase(itr);
+ break;
+ }
}
}
- // Check to see if LinkedPoweredBlocks have invalid items: source, block powered through, or power destination block has changed
- for (LinkedBlocksList::iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end();)
+ for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end(); ++itr)
{
- int RelX = itr->a_SourcePos.x - a_ChunkX * cChunkDef::Width;
- int RelZ = itr->a_SourcePos.z - a_ChunkZ * cChunkDef::Width;
- int MidRelX = itr->a_MiddlePos.x - a_ChunkX * cChunkDef::Width;
- int MidRelZ = itr->a_MiddlePos.z - a_ChunkZ * cChunkDef::Width;
-
- BLOCKTYPE SourceBlockType;
- NIBBLETYPE SourceBlockMeta;
- BLOCKTYPE MiddleBlockType;
- if (
- !a_Chunk->UnboundedRelGetBlock(RelX, itr->a_SourcePos.y, RelZ, SourceBlockType, SourceBlockMeta) ||
- !a_Chunk->UnboundedRelGetBlockType(MidRelX, itr->a_MiddlePos.y, MidRelZ, MiddleBlockType)
- )
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{
continue;
}
- if (SourceBlockType != itr->a_SourceBlock)
- {
- LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past block type mismatch", ItemToFullString(itr->a_SourceBlock).c_str());
- itr = m_LinkedPoweredBlocks.erase(itr);
- }
- else if (MiddleBlockType != itr->a_MiddleBlock)
- {
- LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past middle block mismatch", ItemToFullString(itr->a_SourceBlock).c_str());
- itr = m_LinkedPoweredBlocks.erase(itr);
- }
- else if (
- // Things that can send power through a block but which depends on meta
- ((SourceBlockType == E_BLOCK_REDSTONE_WIRE) && (SourceBlockMeta == 0)) ||
- ((SourceBlockType == E_BLOCK_LEVER) && !IsLeverOn(SourceBlockMeta)) ||
- (((SourceBlockType == E_BLOCK_STONE_BUTTON) || (SourceBlockType == E_BLOCK_WOODEN_BUTTON)) && (!IsButtonOn(SourceBlockMeta)))
- )
+ if (!IsAllowedBlock(Block))
{
- LOGD("cRedstoneSimulator: Erased block %s from linked powered blocks list due to present/past metadata mismatch", ItemToFullString(itr->a_SourceBlock).c_str());
- itr = m_LinkedPoweredBlocks.erase(itr);
- }
- else
- {
- ++itr;
+ LOGD("cRedstoneSimulator: Erased block @ {%i, %i, %i} from toggleable simulated list as it is no longer redstone", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z);
+ m_SimulatedPlayerToggleableBlocks.erase(itr);
+ break;
}
}
- for (SimulatedPlayerToggleableList::iterator itr = m_SimulatedPlayerToggleableBlocks.begin(); itr != m_SimulatedPlayerToggleableBlocks.end();)
+ for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end(); ++itr)
{
- int RelX = itr->a_BlockPos.x - a_ChunkX * cChunkDef::Width;
- int RelZ = itr->a_BlockPos.z - a_ChunkZ * cChunkDef::Width;
-
- BLOCKTYPE SourceBlockType;
- if (!a_Chunk->UnboundedRelGetBlockType(RelX, itr->a_BlockPos.y, RelZ, SourceBlockType))
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ)))
{
continue;
}
- else if (!IsAllowedBlock(SourceBlockType))
+
+ if ((Block != E_BLOCK_REDSTONE_REPEATER_ON) && (Block != E_BLOCK_REDSTONE_REPEATER_OFF))
{
- LOGD("cRedstoneSimulator: Erased block %s from toggleable simulated list as block is no longer redstone", ItemToFullString(SourceBlockType).c_str());
- itr = m_SimulatedPlayerToggleableBlocks.erase(itr);
+ m_RepeatersDelayList.erase(itr);
+ break;
}
- else
+ }
+
+ cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
+ for (cRedstoneSimulatorChunkData::iterator itr = ChunkData.begin(); itr != ChunkData.end(); ++itr)
+ {
+ if ((itr->x == RelX) && (itr->y == a_BlockY) && (itr->z == RelZ)) // We are at an entry matching the current (changed) block
{
- ++itr;
+ if (!IsAllowedBlock(Block))
+ {
+ ChunkData.erase(itr); // The new blocktype is not redstone; it must be removed from this list
+ }
+ else
+ {
+ itr->Data = Block; // Update block information
+ }
+ return;
}
}
- for (RepeatersDelayList::iterator itr = m_RepeatersDelayList.begin(); itr != m_RepeatersDelayList.end();)
+ if (!IsAllowedBlock(Block))
{
- int RelX = itr->a_BlockPos.x - a_ChunkX * cChunkDef::Width;
- int RelZ = itr->a_BlockPos.z - a_ChunkZ * cChunkDef::Width;
+ return;
+ }
- BLOCKTYPE SourceBlockType;
- if (!a_Chunk->UnboundedRelGetBlockType(RelX, itr->a_BlockPos.y, RelZ, SourceBlockType))
- {
- continue;
- }
+ ChunkData.push_back(cCoordWithBlock(RelX, a_BlockY, RelZ, Block));
+}
- if ((SourceBlockType != E_BLOCK_REDSTONE_REPEATER_ON) && (SourceBlockType != E_BLOCK_REDSTONE_REPEATER_OFF))
- {
- itr = m_RepeatersDelayList.erase(itr);
- continue;
- }
- ++itr;
- }
- for (cRedstoneSimulatorChunkData::iterator dataitr = ChunkData.begin(), end = ChunkData.end(); dataitr != end;)
+
+
+void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, cChunk * a_Chunk)
+{
+ // We still attempt to simulate all blocks in the chunk every tick, because of outside influence that needs to be taken into account
+ // For example, repeaters need to be ticked, pressure plates checked for entities, daylight sensor checked for light changes, etc.
+ // The easiest way to make this more efficient is probably just to reduce code within the handlers that put too much strain on server, like getting or setting blocks
+ // A marking dirty system might be a TODO for later on, perhaps
+
+ cRedstoneSimulatorChunkData & ChunkData = a_Chunk->GetRedstoneSimulatorData();
+ if (ChunkData.empty())
{
- BLOCKTYPE BlockType = a_Chunk->GetBlock(dataitr->x, dataitr->y, dataitr->z);
- if (!IsAllowedBlock(BlockType))
- {
- dataitr = ChunkData.erase(dataitr);
- continue;
- }
+ return;
+ }
+
+ int BaseX = a_Chunk->GetPosX() * cChunkDef::Width;
+ int BaseZ = a_Chunk->GetPosZ() * cChunkDef::Width;
- // PoweredBlock and LinkedPoweredBlock list was fine, now to the actual handling
+ for (cRedstoneSimulatorChunkData::const_iterator dataitr = ChunkData.begin(); dataitr != ChunkData.end(); ++dataitr)
+ {
int a_X = BaseX + dataitr->x;
int a_Z = BaseZ + dataitr->z;
- switch (BlockType)
+ switch (dataitr->Data)
{
case E_BLOCK_BLOCK_OF_REDSTONE: HandleRedstoneBlock(a_X, dataitr->y, a_Z); break;
case E_BLOCK_LEVER: HandleRedstoneLever(a_X, dataitr->y, a_Z); break;
@@ -262,19 +224,19 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
{
- HandleRedstoneTorch(a_X, dataitr->y, a_Z, BlockType);
+ HandleRedstoneTorch(a_X, dataitr->y, a_Z, dataitr->Data);
break;
}
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_WOODEN_BUTTON:
{
- HandleRedstoneButton(a_X, dataitr->y, a_Z, BlockType);
+ HandleRedstoneButton(a_X, dataitr->y, a_Z, dataitr->Data);
break;
}
case E_BLOCK_REDSTONE_REPEATER_OFF:
case E_BLOCK_REDSTONE_REPEATER_ON:
{
- HandleRedstoneRepeater(a_X, dataitr->y, a_Z, BlockType);
+ HandleRedstoneRepeater(a_X, dataitr->y, a_Z, dataitr->Data);
break;
}
case E_BLOCK_PISTON:
@@ -286,7 +248,7 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON:
{
- HandleRedstoneLamp(a_X, dataitr->y, a_Z, BlockType);
+ HandleRedstoneLamp(a_X, dataitr->y, a_Z, dataitr->Data);
break;
}
case E_BLOCK_DISPENSER:
@@ -305,18 +267,16 @@ void cRedstoneSimulator::SimulateChunk(float a_Dt, int a_ChunkX, int a_ChunkZ, c
case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_POWERED_RAIL:
{
- HandleRail(a_X, dataitr->y, a_Z, BlockType);
+ HandleRail(a_X, dataitr->y, a_Z, dataitr->Data);
break;
}
case E_BLOCK_WOODEN_PRESSURE_PLATE:
case E_BLOCK_STONE_PRESSURE_PLATE:
{
- HandlePressurePlate(a_X, dataitr->y, a_Z, BlockType);
+ HandlePressurePlate(a_X, dataitr->y, a_Z, dataitr->Data);
break;
}
}
-
- ++dataitr;
}
}
@@ -487,7 +447,7 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl
};
// Check to see if directly beside a power source
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
+ if (IsWirePowered(a_BlockX, a_BlockY, a_BlockZ))
{
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 15); // Maximum power
}
@@ -545,7 +505,7 @@ void cRedstoneSimulator::HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_Bl
// transferring power to other wires around.
// However, self not directly powered anymore, so source must have been removed,
// therefore, self must be set to meta zero
- m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0);
+ m_World.SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_REDSTONE_WIRE, 0); // SetMeta & WakeUpSims doesn't seem to work here, so SetBlock
return; // No need to process block power sets because self not powered
}
else
@@ -693,7 +653,7 @@ void cRedstoneSimulator::HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int
// Apparently, incrementing ticks only works reliably here, and not in SimChunk;
// With a world with lots of redstone, the repeaters simply do not delay
// I am confounded to say why. Perhaps optimisation failure.
- LOGD("Incremented a repeater @ %i %i %i | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
+ LOGD("Incremented a repeater @ {%i %i %i} | Elapsed ticks: %i | Target delay: %i", itr->a_BlockPos.x, itr->a_BlockPos.y, itr->a_BlockPos.z, itr->a_ElapsedTicks, itr->a_DelayTicks);
itr->a_ElapsedTicks++;
}
}
@@ -781,48 +741,20 @@ void cRedstoneSimulator::HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ)
void cRedstoneSimulator::HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ)
{
- if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x08) == 0x08)
+ if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ))
{
- // Block position is located at top half of door
- // Is Y - 1 both within world boundaries, a door block, and the bottom half of a door?
- // The bottom half stores the open/closed information
- if (
- (a_BlockY - 1 >= 0) &&
- ((m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_WOODEN_DOOR) || (m_World.GetBlock(a_BlockX, a_BlockY, a_BlockZ) == E_BLOCK_IRON_DOOR)) &&
- (m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ & 0x08) == 0)
- )
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, true))
{
- if ((m_World.GetBlockMeta(a_BlockX, a_BlockY - 1, a_BlockZ) & 0x04) == 0) // Closed door?
- {
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open
- {
- cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ);
- }
- }
- else // Opened door
- {
- if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so
- {
- cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ);
- }
- }
+ cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ);
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, true);
}
}
else
{
- if ((m_World.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ) & 0x04) == 0) // Closed door?
- {
- if (AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Powered? If so, toggle open
- {
- cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ);
- }
- }
- else // Opened door
+ if (!AreCoordsSimulated(a_BlockX, a_BlockY, a_BlockZ, false))
{
- if (!AreCoordsPowered(a_BlockX, a_BlockY, a_BlockZ)) // Unpowered? Close if so
- {
- cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ);
- }
+ cBlockDoorHandler::ChangeDoor(&m_World, a_BlockX, a_BlockY, a_BlockZ);
+ SetPlayerToggleableBlockAsSimulated(a_BlockX, a_BlockY, a_BlockZ, false);
}
}
}
@@ -970,6 +902,7 @@ void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_B
else
{
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
+ m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
}
break;
}
@@ -1032,6 +965,7 @@ void cRedstoneSimulator::HandlePressurePlate(int a_BlockX, int a_BlockY, int a_B
else
{
m_World.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, 0x0);
+ m_World.WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ);
}
break;
}
@@ -1188,6 +1122,33 @@ bool cRedstoneSimulator::IsPistonPowered(int a_BlockX, int a_BlockY, int a_Block
+bool cRedstoneSimulator::IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ)
+{
+ for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
+ {
+ return true;
+ }
+ }
+
+ for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr)
+ {
+ if (!itr->a_BlockPos.Equals(Vector3i(a_BlockX, a_BlockY, a_BlockZ))) { continue; }
+
+ if (m_World.GetBlock(itr->a_SourcePos) != E_BLOCK_REDSTONE_WIRE)
+ {
+ return true;
+ }
+ }
+ return false; // Source was in front of the piston's front face
+}
+
+
+
+
bool cRedstoneSimulator::AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered)
{
@@ -1333,11 +1294,6 @@ void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_Block
// Don't set air, fixes some bugs (wires powering themselves)
return;
}
- if ((Block == E_BLOCK_REDSTONE_WIRE) && (a_SourceBlock == E_BLOCK_REDSTONE_WIRE))
- {
- // Wires cannot power themselves normally, instead, the wire handler will manually set meta
- return;
- }
for (PoweredBlocksList::const_iterator itr = m_PoweredBlocks.begin(); itr != m_PoweredBlocks.end(); ++itr) // Check powered list
{
@@ -1354,7 +1310,6 @@ void cRedstoneSimulator::SetBlockPowered(int a_BlockX, int a_BlockY, int a_Block
sPoweredBlocks RC;
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
- RC.a_SourceBlock = a_SourceBlock;
m_PoweredBlocks.push_back(RC);
}
@@ -1379,11 +1334,6 @@ void cRedstoneSimulator::SetBlockLinkedPowered(
{
return;
}
- if ((a_SourceBlock == E_BLOCK_REDSTONE_WIRE) && (DestBlock == E_BLOCK_REDSTONE_WIRE))
- {
- // Wires cannot power another wire through a block
- return;
- }
for (LinkedBlocksList::const_iterator itr = m_LinkedPoweredBlocks.begin(); itr != m_LinkedPoweredBlocks.end(); ++itr) // Check linked powered list
{
@@ -1402,8 +1352,6 @@ void cRedstoneSimulator::SetBlockLinkedPowered(
RC.a_BlockPos = Vector3i(a_BlockX, a_BlockY, a_BlockZ);
RC.a_MiddlePos = Vector3i(a_MiddleX, a_MiddleY, a_MiddleZ);
RC.a_SourcePos = Vector3i(a_SourceX, a_SourceY, a_SourceZ);
- RC.a_SourceBlock = a_SourceBlock;
- RC.a_MiddleBlock = a_MiddleBlock;
m_LinkedPoweredBlocks.push_back(RC);
}
diff --git a/src/Simulator/RedstoneSimulator.h b/src/Simulator/RedstoneSimulator.h
index 1080c3f81..63a5be3d3 100644
--- a/src/Simulator/RedstoneSimulator.h
+++ b/src/Simulator/RedstoneSimulator.h
@@ -4,7 +4,7 @@
#include "Simulator.h"
/// Per-chunk data for the simulator, specified individual chunks to simulate; 'Data' is not used
-typedef cCoordWithIntList cRedstoneSimulatorChunkData;
+typedef cCoordWithBlockVector cRedstoneSimulatorChunkData;
@@ -39,7 +39,6 @@ private:
{
Vector3i a_BlockPos; // Position of powered block
Vector3i a_SourcePos; // Position of source powering the block at a_BlockPos
- BLOCKTYPE a_SourceBlock; // The source block type (for pistons pushing away sources and replacing with non source etc.)
};
struct sLinkedPoweredBlocks // Define structure of the indirectly powered blocks list (i.e. repeaters powering through a block to the block at the other side)
@@ -47,8 +46,6 @@ private:
Vector3i a_BlockPos;
Vector3i a_MiddlePos;
Vector3i a_SourcePos;
- BLOCKTYPE a_SourceBlock;
- BLOCKTYPE a_MiddleBlock;
};
struct sSimulatedPlayerToggleableList
@@ -81,102 +78,89 @@ private:
// In addition to being non-performant, it would stop the player from actually breaking said device
/* ====== SOURCES ====== */
- /// <summary>Handles the redstone torch</summary>
+ /** Handles the redstone torch */
void HandleRedstoneTorch(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
- /// <summary>Handles the redstone block</summary>
+ /** Handles the redstone block */
void HandleRedstoneBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles levers</summary>
+ /** Handles levers */
void HandleRedstoneLever(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles buttons</summary>
+ /** Handles buttons */
void HandleRedstoneButton(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType);
- /// <summary>Handles daylight sensors</summary>
+ /** Handles daylight sensors */
void HandleDaylightSensor(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles pressure plates</summary>
+ /** Handles pressure plates */
void HandlePressurePlate(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
/* ==================== */
/* ====== CARRIERS ====== */
- /// <summary>Handles redstone wire</summary>
+ /** Handles redstone wire */
void HandleRedstoneWire(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles repeaters</summary>
+ /** Handles repeaters */
void HandleRedstoneRepeater(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
/* ====================== */
/* ====== DEVICES ====== */
- /// <summary>Handles pistons</summary>
+ /** Handles pistons */
void HandlePiston(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles dispensers and droppers</summary>
+ /** Handles dispensers and droppers */
void HandleDropSpenser(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles TNT (exploding)</summary>
+ /** Handles TNT (exploding) */
void HandleTNT(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles redstone lamps</summary>
+ /** Handles redstone lamps */
void HandleRedstoneLamp(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyState);
- /// <summary>Handles doords</summary>
+ /** Handles doords */
void HandleDoor(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles activator, detector, and powered rails</summary>
+ /** Handles activator, detector, and powered rails */
void HandleRail(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_MyType);
- /// <summary>Handles trapdoors</summary>
+ /** Handles trapdoors */
void HandleTrapdoor(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Handles noteblocks</summary>
+ /** Handles noteblocks */
void HandleNoteBlock(int a_BlockX, int a_BlockY, int a_BlockZ);
/* ===================== */
/* ====== Helper functions ====== */
- /// <summary>Marks a block as powered</summary>
+ /** Marks a block as powered */
void SetBlockPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock);
- /// <summary>Marks a block as being powered through another block</summary>
+ /** Marks a block as being powered through another block */
void SetBlockLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, int a_MiddleX, int a_MiddleY, int a_MiddleZ, int a_SourceX, int a_SourceY, int a_SourceZ, BLOCKTYPE a_SourceBlock, BLOCKTYPE a_MiddeBlock);
- /// <summary>Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back</summary>
+ /** Marks a block as simulated, who should not be simulated further unless their power state changes, to accomodate a player manually toggling the block without triggering the simulator toggling it back */
void SetPlayerToggleableBlockAsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool WasLastStatePowered);
- /// <summary>Marks the second block in a direction as linked powered</summary>
+ /** Marks the second block in a direction as linked powered */
void SetDirectionLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ, char a_Direction, BLOCKTYPE a_SourceBlock);
- /// <summary>Marks all blocks immediately surrounding a coordinate as powered</summary>
+ /** Marks all blocks immediately surrounding a coordinate as powered */
void SetAllDirsAsPowered(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_SourceBlock);
- /// <summary>Queues a repeater to be powered or unpowered</summary>
+ /** Queues a repeater to be powered or unpowered */
void QueueRepeaterPowerChange(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta, short a_ElapsedTicks, bool ShouldPowerOn);
- /// <summary>Returns if a coordinate is powered or linked powered</summary>
+ /** Returns if a coordinate is powered or linked powered */
bool AreCoordsPowered(int a_BlockX, int a_BlockY, int a_BlockZ) { return AreCoordsDirectlyPowered(a_BlockX, a_BlockY, a_BlockZ) || AreCoordsLinkedPowered(a_BlockX, a_BlockY, a_BlockZ); }
- /// <summary>Returns if a coordinate is in the directly powered blocks list</summary>
+ /** Returns if a coordinate is in the directly powered blocks list */
bool AreCoordsDirectlyPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Returns if a coordinate is in the indirectly powered blocks list</summary>
+ /** Returns if a coordinate is in the indirectly powered blocks list */
bool AreCoordsLinkedPowered(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Returns if a coordinate was marked as simulated (for blocks toggleable by players)</summary>
+ /** Returns if a coordinate was marked as simulated (for blocks toggleable by players) */
bool AreCoordsSimulated(int a_BlockX, int a_BlockY, int a_BlockZ, bool IsCurrentStatePowered);
- /// <summary>Returns if a repeater is powered</summary>
+ /** Returns if a repeater is powered */
bool IsRepeaterPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
- /// <summary>Returns if a piston is powered</summary>
+ /** Returns if a piston is powered */
bool IsPistonPowered(int a_BlockX, int a_BlockY, int a_BlockZ, NIBBLETYPE a_Meta);
+ /** Returns if a wire is powered
+ The only diffence between this and a normal AreCoordsPowered is that this function checks for a wire powering another wire
+ */
+ bool IsWirePowered(int a_BlockX, int a_BlockY, int a_BlockZ);
- /// <summary>Returns if lever metadata marks it as emitting power</summary>
+
+ /** Returns if lever metadata marks it as emitting power */
bool IsLeverOn(NIBBLETYPE a_BlockMeta);
- /// <summary>Returns if button metadata marks it as emitting power</summary>
+ /** Returns if button metadata marks it as emitting power */
bool IsButtonOn(NIBBLETYPE a_BlockMeta);
/* ============================== */
/* ====== Misc Functions ====== */
- /// <summary>Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation</summary>
- inline static bool IsViableMiddleBlock(BLOCKTYPE Block)
- {
- if (!g_BlockIsSolid[Block]) { return false; }
+ /** Returns if a block is viable to be the MiddleBlock of a SetLinkedPowered operation */
+ inline static bool IsViableMiddleBlock(BLOCKTYPE Block) { return g_BlockFullyOccupiesVoxel[Block]; }
- switch (Block)
- {
- // Add SOLID but not viable middle blocks here
- case E_BLOCK_PISTON:
- case E_BLOCK_PISTON_EXTENSION:
- case E_BLOCK_STICKY_PISTON:
- case E_BLOCK_REDSTONE_REPEATER_ON:
- case E_BLOCK_REDSTONE_REPEATER_OFF:
- case E_BLOCK_DAYLIGHT_SENSOR:
- {
- return false;
- }
- default: return true;
- }
- }
-
- /// <summary>Returns if a block is a mechanism (something that accepts power and does something)</summary>
+ /** Returns if a block is a mechanism (something that accepts power and does something) */
inline static bool IsMechanism(BLOCKTYPE Block)
{
switch (Block)
@@ -205,16 +189,16 @@ private:
}
}
- /// <summary>Returns if a block has the potential to output power</summary>
+ /** Returns if a block has the potential to output power */
inline static bool IsPotentialSource(BLOCKTYPE Block)
{
switch (Block)
{
+ case E_BLOCK_DETECTOR_RAIL:
case E_BLOCK_DAYLIGHT_SENSOR:
case E_BLOCK_WOODEN_BUTTON:
case E_BLOCK_STONE_BUTTON:
case E_BLOCK_REDSTONE_WIRE:
- case E_BLOCK_REDSTONE_TORCH_OFF:
case E_BLOCK_REDSTONE_TORCH_ON:
case E_BLOCK_LEVER:
case E_BLOCK_REDSTONE_REPEATER_ON:
@@ -227,7 +211,7 @@ private:
}
}
- /// <summary>Returns if a block is any sort of redstone device</summary>
+ /** Returns if a block is any sort of redstone device */
inline static bool IsRedstone(BLOCKTYPE Block)
{
switch (Block)
@@ -248,6 +232,7 @@ private:
case E_BLOCK_LEVER:
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
case E_BLOCK_NOTE_BLOCK:
+ case E_BLOCK_POWERED_RAIL:
case E_BLOCK_REDSTONE_LAMP_OFF:
case E_BLOCK_REDSTONE_LAMP_ON:
case E_BLOCK_REDSTONE_REPEATER_OFF:
diff --git a/src/StringCompression.cpp b/src/StringCompression.cpp
index e15058840..5b9a3bb0a 100644
--- a/src/StringCompression.cpp
+++ b/src/StringCompression.cpp
@@ -11,7 +11,7 @@
/// Compresses a_Data into a_Compressed; returns Z_XXX error constants same as zlib's compress2()
-int CompressString(const char * a_Data, int a_Length, AString & a_Compressed)
+int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor)
{
uLongf CompressedSize = compressBound(a_Length);
@@ -19,7 +19,7 @@ int CompressString(const char * a_Data, int a_Length, AString & a_Compressed)
// It saves us one allocation and one memcpy of the entire compressed data
// It may not work on some STL implementations! (Confirmed working on MSVC 2008 & 2010)
a_Compressed.resize(CompressedSize);
- int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, Z_DEFAULT_COMPRESSION);
+ int errorcode = compress2( (Bytef*)a_Compressed.data(), &CompressedSize, (const Bytef*)a_Data, a_Length, a_Factor);
if (errorcode != Z_OK)
{
return errorcode;
diff --git a/src/StringCompression.h b/src/StringCompression.h
index 459e8f568..3f4e12d2d 100644
--- a/src/StringCompression.h
+++ b/src/StringCompression.h
@@ -10,7 +10,7 @@
/// Compresses a_Data into a_Compressed using ZLIB; returns Z_XXX error constants same as zlib's compress2()
-extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed);
+extern int CompressString(const char * a_Data, int a_Length, AString & a_Compressed, int a_Factor);
/// Uncompresses a_Data into a_Uncompressed; returns Z_XXX error constants same as zlib's decompress()
extern int UncompressString(const char * a_Data, int a_Length, AString & a_Uncompressed, int a_UncompressedSize);
diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp
index 0b38297ef..0dbd41c12 100644
--- a/src/StringUtils.cpp
+++ b/src/StringUtils.cpp
@@ -18,27 +18,40 @@
-AString & AppendVPrintf(AString & str, const char *format, va_list args)
+AString & AppendVPrintf(AString & str, const char * format, va_list args)
{
ASSERT(format != NULL);
char buffer[2048];
size_t len;
+ #ifdef va_copy
+ va_list argsCopy;
+ va_copy(argsCopy, args);
+ #else
+ #define argsCopy args
+ #endif
#ifdef _MSC_VER
// MS CRT provides secure printf that doesn't behave like in the C99 standard
- if ((len = _vsnprintf_s(buffer, ARRAYCOUNT(buffer), _TRUNCATE, format, args)) != -1)
+ if ((len = _vsnprintf_s(buffer, ARRAYCOUNT(buffer), _TRUNCATE, format, argsCopy)) != -1)
#else // _MSC_VER
- if ((len = vsnprintf(buffer, ARRAYCOUNT(buffer), format, args)) < ARRAYCOUNT(buffer))
+ if ((len = vsnprintf(buffer, ARRAYCOUNT(buffer), format, argsCopy)) < ARRAYCOUNT(buffer))
#endif // else _MSC_VER
{
// The result did fit into the static buffer
+ #ifdef va_copy
+ va_end(argsCopy);
+ #endif
str.append(buffer, len);
return str;
}
+ #ifdef va_copy
+ va_end(argsCopy);
+ #endif
- // The result did not fit into the static buffer
+ // The result did not fit into the static buffer, use a dynamic buffer:
#ifdef _MSC_VER
// for MS CRT, we need to calculate the result length
+ // MS doesn't have va_copy() and does nod need it at all
len = _vscprintf(format, args);
if (len == -1)
{
@@ -47,13 +60,19 @@ AString & AppendVPrintf(AString & str, const char *format, va_list args)
#endif // _MSC_VER
// Allocate a buffer and printf into it:
+ #ifdef va_copy
+ va_copy(argsCopy, args);
+ #endif
std::vector<char> Buffer(len + 1);
#ifdef _MSC_VER
- vsprintf_s((char *)&(Buffer.front()), Buffer.size(), format, args);
+ vsprintf_s((char *)&(Buffer.front()), Buffer.size(), format, argsCopy);
#else // _MSC_VER
- vsnprintf((char *)&(Buffer.front()), Buffer.size(), format, args);
+ vsnprintf((char *)&(Buffer.front()), Buffer.size(), format, argsCopy);
#endif // else _MSC_VER
str.append(&(Buffer.front()), Buffer.size() - 1);
+ #ifdef va_copy
+ va_end(argsCopy);
+ #endif
return str;
}
@@ -89,7 +108,7 @@ AString Printf(const char * format, ...)
-AString & AppendPrintf(AString &str, const char *format, ...)
+AString & AppendPrintf(AString &str, const char * format, ...)
{
va_list args;
va_start(args, format);
diff --git a/src/StringUtils.h b/src/StringUtils.h
index 2373f3843..dfbfc2a75 100644
--- a/src/StringUtils.h
+++ b/src/StringUtils.h
@@ -21,7 +21,7 @@ typedef std::list<AString> AStringList;
-/// Add the formated string to the existing data in the string
+/** Add the formated string to the existing data in the string */
extern AString & AppendVPrintf(AString & str, const char * format, va_list args);
/// Output the formatted text into the string
diff --git a/src/UI/SlotArea.cpp b/src/UI/SlotArea.cpp
index a721e6b7e..bfcad3d92 100644
--- a/src/UI/SlotArea.cpp
+++ b/src/UI/SlotArea.cpp
@@ -85,10 +85,10 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
{
if (DraggingItem.m_ItemType <= 0) // Empty-handed?
{
+ DraggingItem = Slot.CopyOne(); // Obtain copy of slot to preserve lore, enchantments, etc.
+
DraggingItem.m_ItemCount = (char)(((float)Slot.m_ItemCount) / 2.f + 0.5f);
Slot.m_ItemCount -= DraggingItem.m_ItemCount;
- DraggingItem.m_ItemType = Slot.m_ItemType;
- DraggingItem.m_ItemDamage = Slot.m_ItemDamage;
if (Slot.m_ItemCount <= 0)
{
@@ -101,9 +101,12 @@ void cSlotArea::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickA
cItemHandler * Handler = ItemHandler(Slot.m_ItemType);
if ((DraggingItem.m_ItemCount > 0) && (Slot.m_ItemCount < Handler->GetMaxStackSize()))
{
- Slot.m_ItemType = DraggingItem.m_ItemType;
- Slot.m_ItemCount++;
- Slot.m_ItemDamage = DraggingItem.m_ItemDamage;
+ char OldSlotCount = Slot.m_ItemCount;
+
+ Slot = DraggingItem.CopyOne(); // See above
+ OldSlotCount++;
+ Slot.m_ItemCount = OldSlotCount;
+
DraggingItem.m_ItemCount--;
}
if (DraggingItem.m_ItemCount <= 0)
@@ -226,7 +229,7 @@ void cSlotArea::DistributeStack(cItem & a_ItemStack, cPlayer & a_Player, bool a_
for (int i = 0; i < m_NumSlots; i++)
{
const cItem * Slot = GetSlot(i, a_Player);
- if (!Slot->IsStackableWith(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
+ if (!Slot->IsEqual(a_ItemStack) && (!Slot->IsEmpty() || a_KeepEmptySlots))
{
// Different items
continue;
@@ -265,7 +268,7 @@ bool cSlotArea::CollectItemsToHand(cItem & a_Dragging, cPlayer & a_Player, bool
for (int i = 0; i < NumSlots; i++)
{
const cItem & SlotItem = *GetSlot(i, a_Player);
- if (!SlotItem.IsStackableWith(a_Dragging))
+ if (!SlotItem.IsEqual(a_Dragging))
{
continue;
}
@@ -908,7 +911,7 @@ void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End)
} // for i - itr->second[]
double vX = 0, vY = 0, vZ = 0;
- EulerToVector(-a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY);
+ EulerToVector(-a_Player.GetYaw(), a_Player.GetPitch(), vZ, vX, vY);
vY = -vY * 2 + 1.f;
a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because player created
}
diff --git a/src/UI/Window.cpp b/src/UI/Window.cpp
index ee75921d1..3ffeff7a0 100644
--- a/src/UI/Window.cpp
+++ b/src/UI/Window.cpp
@@ -642,7 +642,7 @@ int cWindow::DistributeItemToSlots(cPlayer & a_Player, const cItem & a_Item, int
Area->SetSlot(LocalSlotNum, a_Player, ToStore);
NumDistributed += ToStore.m_ItemCount;
}
- else if (AtSlot.IsStackableWith(a_Item))
+ else if (AtSlot.IsEqual(a_Item))
{
// Occupied, add and cap at MaxStack:
int CanStore = std::min(a_NumToEachSlot, (int)MaxStack - AtSlot.m_ItemCount);
diff --git a/src/World.cpp b/src/World.cpp
index 39300d419..3e7c0ef74 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -10,11 +10,13 @@
#include "Root.h"
#include "inifile/iniFile.h"
#include "ChunkMap.h"
+#include "Generating/ChunkDesc.h"
#include "OSSupport/Timer.h"
// Entities (except mobs):
#include "Entities/ExpOrb.h"
#include "Entities/FallingBlock.h"
+#include "Entities/Minecart.h"
#include "Entities/Pickup.h"
#include "Entities/Player.h"
#include "Entities/TNTEntity.h"
@@ -229,6 +231,7 @@ cWorld::cWorld(const AString & a_WorldName) :
m_WorldName(a_WorldName),
m_IniFileName(m_WorldName + "/world.ini"),
m_StorageSchema("Default"),
+ m_StorageCompressionFactor(6),
m_IsSpawnExplicitlySet(false),
m_WorldAgeSecs(0),
m_TimeOfDaySecs(0),
@@ -238,6 +241,7 @@ cWorld::cWorld(const AString & a_WorldName) :
m_SkyDarkness(0),
m_Weather(eWeather_Sunny),
m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :)
+ m_GeneratorCallbacks(*this),
m_TickThread(*this)
{
LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str());
@@ -509,6 +513,7 @@ void cWorld::Start(void)
}
m_StorageSchema = IniFile.GetValueSet ("Storage", "Schema", m_StorageSchema);
+ m_StorageCompressionFactor = IniFile.GetValueSetI ("Storage", "CompressionFactor", m_StorageCompressionFactor);
m_MaxCactusHeight = IniFile.GetValueSetI("Plants", "MaxCactusHeight", 3);
m_MaxSugarcaneHeight = IniFile.GetValueSetI("Plants", "MaxSugarcaneHeight", 3);
m_IsCactusBonemealable = IniFile.GetValueSetB("Plants", "IsCactusBonemealable", false);
@@ -582,8 +587,8 @@ void cWorld::Start(void)
m_SimulatorManager->RegisterSimulator(m_RedstoneSimulator, 1);
m_Lighting.Start(this);
- m_Storage.Start(this, m_StorageSchema);
- m_Generator.Start(this, IniFile);
+ m_Storage.Start(this, m_StorageSchema, m_StorageCompressionFactor );
+ m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile);
m_ChunkSender.Start(this);
m_TickThread.Start();
@@ -688,6 +693,7 @@ void cWorld::Tick(float a_Dt, int a_LastTickDurationMSec)
TickClients(a_Dt);
TickQueuedBlocks();
TickQueuedTasks();
+ TickScheduledTasks();
GetSimulatorManager()->Simulate(a_Dt);
@@ -859,6 +865,31 @@ void cWorld::TickQueuedTasks(void)
} // for itr - m_Tasks[]
}
+void cWorld::TickScheduledTasks()
+{
+ ScheduledTaskList Tasks;
+ // Make a copy of the tasks to avoid deadlocks on accessing m_Tasks
+ {
+ cCSLock Lock(m_CSScheduledTasks);
+ ScheduledTaskList::iterator itr = m_ScheduledTasks.begin();
+ while (itr != m_ScheduledTasks.end() && (*itr)->Ticks > 0)
+ {
+ Tasks.push_back(m_ScheduledTasks.front());
+ m_ScheduledTasks.pop_front();
+ }
+ for(;itr != m_ScheduledTasks.end(); itr++)
+ {
+ (*itr)->Ticks--;
+ }
+ }
+
+ // Execute and delete each task:
+ for (ScheduledTaskList::iterator itr = Tasks.begin(), end = Tasks.end(); itr != end; ++itr)
+ {
+ (*itr)->Run(*this);
+ delete *itr;
+ } // for itr - m_Tasks[]
+}
@@ -1645,6 +1676,29 @@ int cWorld::SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward)
+int cWorld::SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content, int a_BlockHeight)
+{
+ cMinecart * Minecart;
+ switch (a_MinecartType)
+ {
+ case E_ITEM_MINECART: Minecart = new cRideableMinecart (a_X, a_Y, a_Z, a_Content, a_BlockHeight); break;
+ case E_ITEM_CHEST_MINECART: Minecart = new cMinecartWithChest (a_X, a_Y, a_Z); break;
+ case E_ITEM_FURNACE_MINECART: Minecart = new cMinecartWithFurnace (a_X, a_Y, a_Z); break;
+ case E_ITEM_MINECART_WITH_TNT: Minecart = new cMinecartWithTNT (a_X, a_Y, a_Z); break;
+ case E_ITEM_MINECART_WITH_HOPPER: Minecart = new cMinecartWithHopper (a_X, a_Y, a_Z); break;
+ default:
+ {
+ return -1;
+ }
+ } // switch (a_MinecartType)
+ Minecart->Initialize(this);
+ return Minecart->GetUniqueID();
+}
+
+
+
+
+
void cWorld::SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff)
{
UNUSED(a_InitialVelocityCoeff);
@@ -2569,6 +2623,19 @@ void cWorld::QueueTask(cTask * a_Task)
m_Tasks.push_back(a_Task);
}
+void cWorld::ScheduleTask(cScheduledTask * a_Task)
+{
+ cCSLock Lock(m_CSScheduledTasks);
+ for(ScheduledTaskList::iterator itr = m_ScheduledTasks.begin(); itr != m_ScheduledTasks.end(); itr++)
+ {
+ if((*itr)->Ticks >= a_Task->Ticks)
+ {
+ m_ScheduledTasks.insert(itr, a_Task);
+ return;
+ }
+ }
+ m_ScheduledTasks.push_back(a_Task);
+}
@@ -2843,3 +2910,77 @@ void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World)
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// cWorld::cChunkGeneratorCallbacks:
+
+cWorld::cChunkGeneratorCallbacks::cChunkGeneratorCallbacks(cWorld & a_World) :
+ m_World(&a_World)
+{
+}
+
+
+
+
+
+void cWorld::cChunkGeneratorCallbacks::OnChunkGenerated(cChunkDesc & a_ChunkDesc)
+{
+ cChunkDef::BlockNibbles BlockMetas;
+ a_ChunkDesc.CompressBlockMetas(BlockMetas);
+
+ m_World->SetChunkData(
+ a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(),
+ a_ChunkDesc.GetBlockTypes(), BlockMetas,
+ NULL, NULL, // We don't have lighting, chunk will be lighted when needed
+ &a_ChunkDesc.GetHeightMap(), &a_ChunkDesc.GetBiomeMap(),
+ a_ChunkDesc.GetEntities(), a_ChunkDesc.GetBlockEntities(),
+ true
+ );
+
+ // Save the chunk right after generating, so that we don't have to generate it again on next run
+ m_World->GetStorage().QueueSaveChunk(a_ChunkDesc.GetChunkX(), 0, a_ChunkDesc.GetChunkZ());
+}
+
+
+
+
+
+bool cWorld::cChunkGeneratorCallbacks::IsChunkValid(int a_ChunkX, int a_ChunkZ)
+{
+ return m_World->IsChunkValid(a_ChunkX, a_ChunkZ);
+}
+
+
+
+
+
+bool cWorld::cChunkGeneratorCallbacks::HasChunkAnyClients(int a_ChunkX, int a_ChunkZ)
+{
+ return m_World->HasChunkAnyClients(a_ChunkX, a_ChunkZ);
+}
+
+
+
+
+
+void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerating(cChunkDesc & a_ChunkDesc)
+{
+ cPluginManager::Get()->CallHookChunkGenerating(
+ m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc
+ );
+}
+
+
+
+
+
+void cWorld::cChunkGeneratorCallbacks::CallHookChunkGenerated (cChunkDesc & a_ChunkDesc)
+{
+ cPluginManager::Get()->CallHookChunkGenerated(
+ m_World, a_ChunkDesc.GetChunkX(), a_ChunkDesc.GetChunkZ(), &a_ChunkDesc
+ );
+}
+
+
+
+
+
diff --git a/src/World.h b/src/World.h
index f90ddd90f..ef74a65c7 100644
--- a/src/World.h
+++ b/src/World.h
@@ -82,7 +82,18 @@ public:
virtual void Run(cWorld & a_World) = 0;
} ;
+ /// A common ancestor for all scheduled tasks queued onto the tick thread
+ class cScheduledTask
+ {
+ public:
+ cScheduledTask(const int a_Ticks) : Ticks(a_Ticks) {};
+ virtual ~cScheduledTask() {};
+ virtual void Run(cWorld & a_World) = 0;
+ int Ticks;
+ };
+
typedef std::vector<cTask *> cTasks;
+ typedef std::list<cScheduledTask *> ScheduledTaskList;
class cTaskSaveAllChunks :
public cTask
@@ -363,6 +374,9 @@ public:
/// Spawns an falling block entity at the given position. It returns the UniqueID of the spawned falling block.
int SpawnFallingBlock(int a_X, int a_Y, int a_Z, BLOCKTYPE BlockType, NIBBLETYPE BlockMeta);
+ /// Spawns an minecart at the given coordinates.
+ int SpawnMinecart(double a_X, double a_Y, double a_Z, int a_MinecartType, const cItem & a_Content = cItem(), int a_BlockHeight = 1);
+
/// Spawns an experience orb at the given location with the given reward. It returns the UniqueID of the spawned experience orb.
int SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward);
@@ -533,6 +547,9 @@ public:
/// Queues a task onto the tick thread. The task object will be deleted once the task is finished
void QueueTask(cTask * a_Task); // Exported in ManualBindings.cpp
+
+ // Queues a task onto the tick thread. The task object will be deleted once the task is finished
+ void ScheduleTask(cScheduledTask * a_Task);
/// Returns the number of chunks loaded
int GetNumChunks() const; // tolua_export
@@ -636,6 +653,27 @@ private:
virtual void Execute(void) override;
} ;
+
+ /** Implementation of the callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
+ class cChunkGeneratorCallbacks :
+ public cChunkGenerator::cChunkSink,
+ public cChunkGenerator::cPluginInterface
+ {
+ cWorld * m_World;
+
+ // cChunkSink overrides:
+ virtual void OnChunkGenerated (cChunkDesc & a_ChunkDesc) override;
+ virtual bool IsChunkValid (int a_ChunkX, int a_ChunkZ) override;
+ virtual bool HasChunkAnyClients(int a_ChunkX, int a_ChunkZ) override;
+
+ // cPluginInterface overrides:
+ virtual void CallHookChunkGenerating(cChunkDesc & a_ChunkDesc) override;
+ virtual void CallHookChunkGenerated (cChunkDesc & a_ChunkDesc) override;
+
+ public:
+ cChunkGeneratorCallbacks(cWorld & a_World);
+ } ;
+
AString m_WorldName;
AString m_IniFileName;
@@ -643,6 +681,8 @@ private:
/// Name of the storage schema used to load and save chunks
AString m_StorageSchema;
+ int m_StorageCompressionFactor;
+
/// The dimension of the world, used by the client to provide correct lighting scheme
eDimension m_Dimension;
@@ -714,6 +754,9 @@ private:
cChunkGenerator m_Generator;
+ /** The callbacks that the ChunkGenerator uses to store new chunks and interface to plugins */
+ cChunkGeneratorCallbacks m_GeneratorCallbacks;
+
cChunkSender m_ChunkSender;
cLightingThread m_Lighting;
cTickThread m_TickThread;
@@ -721,9 +764,16 @@ private:
/// Guards the m_Tasks
cCriticalSection m_CSTasks;
+ /// Guards the m_ScheduledTasks
+ cCriticalSection m_CSScheduledTasks;
+
/// Tasks that have been queued onto the tick thread; guarded by m_CSTasks
cTasks m_Tasks;
+ /// Tasks that have been queued to be executed on the tick thread at some number of ticks in
+ /// the future; guarded by m_CSScheduledTasks
+ ScheduledTaskList m_ScheduledTasks;
+
/// Guards m_Clients
cCriticalSection m_CSClients;
@@ -751,6 +801,9 @@ private:
/// Executes all tasks queued onto the tick thread
void TickQueuedTasks(void);
+ /// Executes all tasks queued onto the tick thread
+ void TickScheduledTasks(void);
+
/// Ticks all clients that are in this world
void TickClients(float a_Dt);
diff --git a/src/WorldStorage/NBTChunkSerializer.cpp b/src/WorldStorage/NBTChunkSerializer.cpp
index e5043de1f..e1205f2be 100644
--- a/src/WorldStorage/NBTChunkSerializer.cpp
+++ b/src/WorldStorage/NBTChunkSerializer.cpp
@@ -257,7 +257,7 @@ void cNBTChunkSerializer::AddBasicEntity(cEntity * a_Entity, const AString & a_C
m_Writer.AddDouble("", a_Entity->GetSpeedZ());
m_Writer.EndList();
m_Writer.BeginList("Rotation", TAG_Double);
- m_Writer.AddDouble("", a_Entity->GetRotation());
+ m_Writer.AddDouble("", a_Entity->GetYaw());
m_Writer.AddDouble("", a_Entity->GetPitch());
m_Writer.EndList();
}
diff --git a/src/WorldStorage/WSSAnvil.cpp b/src/WorldStorage/WSSAnvil.cpp
index 8605930b6..16513cd1b 100644
--- a/src/WorldStorage/WSSAnvil.cpp
+++ b/src/WorldStorage/WSSAnvil.cpp
@@ -58,8 +58,9 @@ Since only the header is actually in the memory, this number can be high, but st
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWSSAnvil:
-cWSSAnvil::cWSSAnvil(cWorld * a_World) :
- super(a_World)
+cWSSAnvil::cWSSAnvil(cWorld * a_World, int a_CompressionFactor) :
+ super(a_World),
+ m_CompressionFactor(a_CompressionFactor)
{
// Create a level.dat file for mapping tools, if it doesn't already exist:
AString fnam;
@@ -272,7 +273,7 @@ bool cWSSAnvil::SaveChunkToData(const cChunkCoords & a_Chunk, AString & a_Data)
}
Writer.Finish();
- CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data);
+ CompressString(Writer.GetResult().data(), Writer.GetResult().size(), a_Data, m_CompressionFactor);
return true;
}
@@ -1150,7 +1151,7 @@ void cWSSAnvil::LoadFallingBlockFromNBT(cEntityList & a_Entities, const cParsedN
void cWSSAnvil::LoadMinecartRFromNBT(cEntityList & a_Entities, const cParsedNBT & a_NBT, int a_TagIdx)
{
- std::auto_ptr<cEmptyMinecart> Minecart(new cEmptyMinecart(0, 0, 0));
+ std::auto_ptr<cRideableMinecart> Minecart(new cRideableMinecart(0, 0, 0, cItem(), 1)); // TODO: Load the block and the height
if (!LoadEntityBaseFromNBT(*Minecart.get(), a_NBT, a_TagIdx))
{
return;
@@ -1891,7 +1892,7 @@ bool cWSSAnvil::LoadEntityBaseFromNBT(cEntity & a_Entity, const cParsedNBT & a_N
{
return false;
}
- a_Entity.SetRotation(Rotation[0]);
+ a_Entity.SetYaw(Rotation[0]);
a_Entity.SetRoll (Rotation[1]);
return true;
diff --git a/src/WorldStorage/WSSAnvil.h b/src/WorldStorage/WSSAnvil.h
index 0a7406267..e66e63b08 100644
--- a/src/WorldStorage/WSSAnvil.h
+++ b/src/WorldStorage/WSSAnvil.h
@@ -47,7 +47,7 @@ class cWSSAnvil :
public:
- cWSSAnvil(cWorld * a_World);
+ cWSSAnvil(cWorld * a_World, int a_CompressionFactor);
virtual ~cWSSAnvil();
protected:
@@ -89,6 +89,8 @@ protected:
cCriticalSection m_CS;
cMCAFiles m_Files; // a MRU cache of MCA files
+
+ int m_CompressionFactor;
/// Gets chunk data from the correct file; locks file CS as needed
bool GetChunkData(const cChunkCoords & a_Chunk, AString & a_Data);
diff --git a/src/WorldStorage/WSSCompact.cpp b/src/WorldStorage/WSSCompact.cpp
index e2556b96e..ea17a8ec1 100644
--- a/src/WorldStorage/WSSCompact.cpp
+++ b/src/WorldStorage/WSSCompact.cpp
@@ -193,7 +193,7 @@ cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkCoords & a_Chunk)
// Load it anew:
AString FileName;
Printf(FileName, "%s/X%i_Z%i.pak", m_World->GetName().c_str(), LayerX, LayerZ );
- cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ);
+ cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ, m_CompressionFactor);
if (f == NULL)
{
return NULL;
@@ -399,8 +399,9 @@ void cWSSCompact::LoadEntitiesFromJson(Json::Value & a_Value, cEntityList & a_En
return; \
}
-cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ) :
+cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor) :
m_FileName(a_FileName),
+ m_CompressionFactor(a_CompressionFactor),
m_LayerX(a_LayerX),
m_LayerZ(a_LayerZ),
m_NumDirty(0),
@@ -648,7 +649,7 @@ void cWSSCompact::cPAKFile::UpdateChunk1To2()
// Re-compress data
AString CompressedData;
{
- int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData);
+ int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData,m_CompressionFactor);
if (errorcode != Z_OK)
{
LOGERROR("Error %d compressing data for chunk [%d, %d]",
@@ -786,7 +787,7 @@ void cWSSCompact::cPAKFile::UpdateChunk2To3()
// Re-compress data
AString CompressedData;
{
- int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData);
+ int errorcode = CompressString(Converted.data(), Converted.size(), CompressedData, m_CompressionFactor);
if (errorcode != Z_OK)
{
LOGERROR("Error %d compressing data for chunk [%d, %d]",
@@ -939,7 +940,7 @@ bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkCoords & a_Chunk, cWorld
// Compress the data:
AString CompressedData;
- int errorcode = CompressString(Data.data(), Data.size(), CompressedData);
+ int errorcode = CompressString(Data.data(), Data.size(), CompressedData, m_CompressionFactor);
if ( errorcode != Z_OK )
{
LOGERROR("Error %i compressing data for chunk [%d, %d, %d]", errorcode, a_Chunk.m_ChunkX, a_Chunk.m_ChunkY, a_Chunk.m_ChunkZ);
diff --git a/src/WorldStorage/WSSCompact.h b/src/WorldStorage/WSSCompact.h
index 3223a986e..64b8d7f31 100644
--- a/src/WorldStorage/WSSCompact.h
+++ b/src/WorldStorage/WSSCompact.h
@@ -53,7 +53,7 @@ class cWSSCompact :
public cWSSchema
{
public:
- cWSSCompact(cWorld * a_World) : cWSSchema(a_World) {}
+ cWSSCompact(cWorld * a_World, int a_CompressionFactor) : cWSSchema(a_World), m_CompressionFactor(a_CompressionFactor) {}
virtual ~cWSSCompact();
protected:
@@ -74,7 +74,7 @@ protected:
{
public:
- cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ);
+ cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ, int a_CompressionFactor);
~cPAKFile();
bool GetChunkData(const cChunkCoords & a_Chunk, int & a_UncompressedSize, AString & a_Data);
@@ -95,6 +95,7 @@ protected:
protected:
AString m_FileName;
+ int m_CompressionFactor;
int m_LayerX;
int m_LayerZ;
@@ -119,6 +120,8 @@ protected:
cCriticalSection m_CS;
cPAKFiles m_PAKFiles; // A MRU cache of PAK files
+ int m_CompressionFactor;
+
/// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache
cPAKFile * LoadPAKFile(const cChunkCoords & a_Chunk);
diff --git a/src/WorldStorage/WorldStorage.cpp b/src/WorldStorage/WorldStorage.cpp
index 6aec525a8..711c8612f 100644
--- a/src/WorldStorage/WorldStorage.cpp
+++ b/src/WorldStorage/WorldStorage.cpp
@@ -68,11 +68,11 @@ cWorldStorage::~cWorldStorage()
-bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName)
+bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor )
{
m_World = a_World;
m_StorageSchemaName = a_StorageSchemaName;
- InitSchemas();
+ InitSchemas(a_StorageCompressionFactor);
return super::Start();
}
@@ -197,11 +197,11 @@ void cWorldStorage::UnqueueSave(const cChunkCoords & a_Chunk)
-void cWorldStorage::InitSchemas(void)
+void cWorldStorage::InitSchemas(int a_StorageCompressionFactor)
{
// The first schema added is considered the default
- m_Schemas.push_back(new cWSSAnvil (m_World));
- m_Schemas.push_back(new cWSSCompact (m_World));
+ m_Schemas.push_back(new cWSSAnvil (m_World,a_StorageCompressionFactor));
+ m_Schemas.push_back(new cWSSCompact (m_World,a_StorageCompressionFactor));
m_Schemas.push_back(new cWSSForgetful(m_World));
// Add new schemas here
diff --git a/src/WorldStorage/WorldStorage.h b/src/WorldStorage/WorldStorage.h
index 06cae1717..bb189b6c9 100644
--- a/src/WorldStorage/WorldStorage.h
+++ b/src/WorldStorage/WorldStorage.h
@@ -76,7 +76,7 @@ public:
void UnqueueLoad(int a_ChunkX, int a_ChunkY, int a_ChunkZ);
void UnqueueSave(const cChunkCoords & a_Chunk);
- bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args
+ bool Start(cWorld * a_World, const AString & a_StorageSchemaName, int a_StorageCompressionFactor); // Hide the cIsThread's Start() method, we need to provide args
void Stop(void); // Hide the cIsThread's Stop() method, we need to signal the event
void WaitForFinish(void);
void WaitForLoadQueueEmpty(void);
@@ -126,7 +126,7 @@ protected:
/// The one storage schema used for saving
cWSSchema * m_SaveSchema;
- void InitSchemas(void);
+ void InitSchemas(int a_StorageCompressionFactor);
virtual void Execute(void) override;
diff --git a/src/main.cpp b/src/main.cpp
index 0620e0f0e..340149e0b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -47,9 +47,20 @@ void NonCtrlHandler(int a_Signal)
case SIGSEGV:
{
std::signal(SIGSEGV, SIG_DFL);
- LOGWARN("Segmentation fault; MCServer has crashed :(");
+ LOGERROR(" D: | MCServer has encountered an error and needs to close");
+ LOGERROR("Details | SIGSEGV: Segmentation fault");
exit(EXIT_FAILURE);
}
+ case SIGABRT:
+ #ifdef SIGABRT_COMPAT
+ case SIGABRT_COMPAT:
+ #endif
+ {
+ std::signal(a_Signal, SIG_DFL);
+ LOGERROR(" D: | MCServer has encountered an error and needs to close");
+ LOGERROR("Details | SIGABRT: Server self-terminated due to an internal fault");
+ break;
+ }
case SIGTERM:
{
std::signal(SIGTERM, SIG_IGN); // Server is shutting down, wait for it...