summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/Bindings/AllToLua.pkg3
-rw-r--r--src/Bindings/LuaState.cpp54
-rw-r--r--src/Bindings/LuaState.h100
-rw-r--r--src/Bindings/ManualBindings.cpp130
-rw-r--r--src/Bindings/PluginLua.cpp13
-rw-r--r--src/Bindings/tolua++.h6
-rw-r--r--src/Bindings/tolua_base.h128
-rw-r--r--src/BiomeDef.cpp131
-rw-r--r--src/BiomeDef.h107
-rw-r--r--src/BlockID.cpp100
-rw-r--r--src/BlockID.h3
-rw-r--r--src/Blocks/BlockGlowstone.h4
-rw-r--r--src/ChunkDef.h92
-rw-r--r--src/ClientHandle.cpp9
-rw-r--r--src/ClientHandle.h1
-rw-r--r--src/Defines.h28
-rw-r--r--src/Generating/Caves.cpp1
-rw-r--r--src/Generating/ChunkGenerator.cpp48
-rw-r--r--src/Generating/ChunkGenerator.h63
-rw-r--r--src/Generating/CompoGen.cpp17
-rw-r--r--src/Generating/ComposableGenerator.cpp204
-rw-r--r--src/Generating/ComposableGenerator.h17
-rw-r--r--src/Generating/FinishGen.cpp4
-rw-r--r--src/Generating/FinishGen.h2
-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/Protocol/Protocol.h1
-rw-r--r--src/Protocol/Protocol125.cpp14
-rw-r--r--src/Protocol/Protocol125.h1
-rw-r--r--src/Protocol/Protocol17x.cpp12
-rw-r--r--src/Protocol/Protocol17x.h1
-rw-r--r--src/Protocol/ProtocolRecognizer.cpp10
-rw-r--r--src/Protocol/ProtocolRecognizer.h1
-rw-r--r--src/World.cpp78
-rw-r--r--src/World.h24
37 files changed, 844 insertions, 644 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..149c304ed 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;
}
@@ -732,11 +740,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 +974,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 +1024,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..a43d39732 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);
@@ -183,7 +182,7 @@ public:
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 +801,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 +828,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 +850,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..a9368f613 100644
--- a/src/Bindings/ManualBindings.cpp
+++ b/src/Bindings/ManualBindings.cpp
@@ -991,7 +991,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 +1882,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 +1902,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 +1980,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:
@@ -2292,6 +2273,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..eefcd2b09 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))
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/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/BlockID.cpp b/src/BlockID.cpp
index db7551a9a..69a3a817c 100644
--- a/src/BlockID.cpp
+++ b/src/BlockID.cpp
@@ -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 {
diff --git a/src/BlockID.h b/src/BlockID.h
index a6f0e2675..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);
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/ChunkDef.h b/src/ChunkDef.h
index 3df575732..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
{
diff --git a/src/ClientHandle.cpp b/src/ClientHandle.cpp
index 8125acb47..9348a1825 100644
--- a/src/ClientHandle.cpp
+++ b/src/ClientHandle.cpp
@@ -1978,6 +1978,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..297d62d57 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);
diff --git a/src/Defines.h b/src/Defines.h
index 9bbe1055d..cc04d8026 100644
--- a/src/Defines.h
+++ b/src/Defines.h
@@ -563,34 +563,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/Generating/Caves.cpp b/src/Generating/Caves.cpp
index c94113f5c..2571e6b77 100644
--- a/src/Generating/Caves.cpp
+++ b/src/Generating/Caves.cpp
@@ -509,6 +509,7 @@ void cCaveTunnel::ProcessChunk(
case E_BLOCK_GRAVEL:
case E_BLOCK_SAND:
case E_BLOCK_SANDSTONE:
+ case E_BLOCK_SOULSAND:
case E_BLOCK_NETHERRACK:
case E_BLOCK_COAL_ORE:
case E_BLOCK_IRON_ORE:
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/CompoGen.cpp b/src/Generating/CompoGen.cpp
index f929ddc2f..60356fe46 100644
--- a/src/Generating/CompoGen.cpp
+++ b/src/Generating/CompoGen.cpp
@@ -589,7 +589,22 @@ void cCompoGenNether::ComposeTerrain(cChunkDesc & a_ChunkDesc)
for (int y = 0; y < SEGMENT_HEIGHT; y++)
{
int Val = Lo + (Hi - Lo) * y / SEGMENT_HEIGHT;
- a_ChunkDesc.SetBlockType(x, y + Segment, z, (Val < m_Threshold) ? E_BLOCK_NETHERRACK : E_BLOCK_AIR);
+ BLOCKTYPE Block = E_BLOCK_AIR;
+ if (Val < m_Threshold) // Don't calculate if the block should be Netherrack or Soulsand when it's already decided that it's air.
+ {
+ NOISE_DATATYPE NoiseX = ((NOISE_DATATYPE)(BaseX + x)) / 8;
+ NOISE_DATATYPE NoiseY = ((NOISE_DATATYPE)(BaseZ + z)) / 8;
+ NOISE_DATATYPE CompBlock = m_Noise1.CubicNoise3D(NoiseX, (float) (y + Segment) / 2, NoiseY);
+ if (CompBlock < -0.5)
+ {
+ Block = E_BLOCK_SOULSAND;
+ }
+ else
+ {
+ Block = E_BLOCK_NETHERRACK;
+ }
+ }
+ a_ChunkDesc.SetBlockType(x, y + Segment, z, Block);
}
}
diff --git a/src/Generating/ComposableGenerator.cpp b/src/Generating/ComposableGenerator.cpp
index c86568c95..87c4d2c52 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)
@@ -404,13 +369,14 @@ void cComposableGenerator::InitFinishGens(cIniFile & a_IniFile)
int Seed = m_ChunkGenerator.GetSeed();
AString Structures = a_IniFile.GetValueSet("Generator", "Finishers", "SprinkleFoliage,Ice,Snow,Lilypads,BottomLava,DeadBushes,PreSimulator");
+ eDimension Dimension = StringToDimension(a_IniFile.GetValue("General", "Dimension", "Overworld"));
AStringVector Str = StringSplitAndTrim(Structures, ",");
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)
{
@@ -444,7 +410,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 145fe22e0..4915e6818 100644
--- a/src/Generating/FinishGen.cpp
+++ b/src/Generating/FinishGen.cpp
@@ -520,7 +520,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)
@@ -529,7 +529,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 ed7df5909..d89ffed15 100644
--- a/src/Generating/FinishGen.h
+++ b/src/Generating/FinishGen.h
@@ -164,7 +164,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/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..48c085ae5 100644
--- a/src/Protocol/Protocol125.cpp
+++ b/src/Protocol/Protocol125.cpp
@@ -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);
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/Protocol17x.cpp b/src/Protocol/Protocol17x.cpp
index 8ec5dec29..9c46c6843 100644
--- a/src/Protocol/Protocol17x.cpp
+++ b/src/Protocol/Protocol17x.cpp
@@ -628,6 +628,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);
diff --git a/src/Protocol/Protocol17x.h b/src/Protocol/Protocol17x.h
index 23ff2365d..fd6b1fc0f 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
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/World.cpp b/src/World.cpp
index 39300d419..1cf82d641 100644
--- a/src/World.cpp
+++ b/src/World.cpp
@@ -10,6 +10,7 @@
#include "Root.h"
#include "inifile/iniFile.h"
#include "ChunkMap.h"
+#include "Generating/ChunkDesc.h"
#include "OSSupport/Timer.h"
// Entities (except mobs):
@@ -238,6 +239,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());
@@ -583,7 +585,7 @@ void cWorld::Start(void)
m_Lighting.Start(this);
m_Storage.Start(this, m_StorageSchema);
- m_Generator.Start(this, IniFile);
+ m_Generator.Start(m_GeneratorCallbacks, m_GeneratorCallbacks, IniFile);
m_ChunkSender.Start(this);
m_TickThread.Start();
@@ -2843,3 +2845,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..b61708d03 100644
--- a/src/World.h
+++ b/src/World.h
@@ -636,6 +636,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;
@@ -714,6 +735,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;