1
0
Fork 0

Revert "Replace ItemCallbacks with lambdas (#3948)"

This reverts commit 496c337cdf.
This commit is contained in:
LogicParrot 2017-09-02 10:45:06 +03:00 committed by Alexander Harkness
parent 700bbdabf5
commit 49c443896d
67 changed files with 1832 additions and 874 deletions

View File

@ -1,4 +1,4 @@

// LuaState.cpp // LuaState.cpp
// Implements the cLuaState class representing the wrapper over lua_State *, provides associated helper functions // Implements the cLuaState class representing the wrapper over lua_State *, provides associated helper functions

View File

@ -1,4 +1,4 @@

// LuaState.h // LuaState.h
// Declares the cLuaState class representing the wrapper over lua_State *, provides associated helper functions // Declares the cLuaState class representing the wrapper over lua_State *, provides associated helper functions

View File

@ -54,15 +54,22 @@ cLuaWindow::~cLuaWindow()
m_Contents.RemoveListener(*this); m_Contents.RemoveListener(*this);
// Close open lua window from players, to avoid dangling pointers // Close open lua window from players, to avoid dangling pointers
cRoot::Get()->ForEachPlayer([this](cPlayer & a_Player) class cPlayerCallback : public cPlayerListCallback
{
virtual bool Item(cPlayer * a_Player)
{ {
if (a_Player.GetWindow() == this) if (a_Player->GetWindow() == m_LuaWindow)
{ {
a_Player.CloseWindow(false); a_Player->CloseWindow(false);
} }
return false; return false;
} }
); cLuaWindow * m_LuaWindow;
public:
cPlayerCallback(cLuaWindow & a_LuaWindow) { m_LuaWindow = &a_LuaWindow; }
} PlayerCallback(*this);
cRoot::Get()->ForEachPlayer(PlayerCallback);
// Must delete slot areas now, because they are referencing this->m_Contents and would try to access it in cWindow's // Must delete slot areas now, because they are referencing this->m_Contents and would try to access it in cWindow's
// destructor, when the member is already gone. // destructor, when the member is already gone.

View File

@ -1,4 +1,4 @@

// LuaWindow.h // LuaWindow.h
// Declares the cLuaWindow class representing a virtual window that plugins may create and open for the player // Declares the cLuaWindow class representing a virtual window that plugins may create and open for the player
@ -9,14 +9,13 @@
#pragma once #pragma once
#include <functional>
#include "LuaState.h" #include "LuaState.h"
#include "../UI/Window.h" #include "../UI/Window.h"
#include "../ItemGrid.h" #include "../ItemGrid.h"
class cPlayer; class cPlayer;
using cPlayerListCallback = std::function<bool(cPlayer &)>; typedef cItemCallback<cPlayer> cPlayerListCallback;
/** A window that has been created by a Lua plugin and is handled entirely by that plugin /** A window that has been created by a Lua plugin and is handled entirely by that plugin

View File

@ -1483,29 +1483,44 @@ static int tolua_cPluginManager_CallPlugin(lua_State * tolua_S)
} }
// Call the destination plugin using a plugin callback: // Call the destination plugin using a plugin callback:
int NumReturns = 0; class cCallback :
auto PluginCallback = [&](cPlugin & a_Plugin) public cPluginManager::cPluginCallback
{
public:
int m_NumReturns;
cCallback(const AString & a_FunctionName, cLuaState & a_SrcLuaState) :
m_NumReturns(0),
m_FunctionName(a_FunctionName),
m_SrcLuaState(a_SrcLuaState)
{ {
if (!a_Plugin.IsLoaded()) }
protected:
const AString & m_FunctionName;
cLuaState & m_SrcLuaState;
virtual bool Item(cPlugin * a_Plugin) override
{
if (!a_Plugin->IsLoaded())
{ {
return false; return false;
} }
NumReturns = static_cast<cPluginLua &>(a_Plugin).CallFunctionFromForeignState( m_NumReturns = static_cast<cPluginLua *>(a_Plugin)->CallFunctionFromForeignState(
FunctionName, L, 4, lua_gettop(L) m_FunctionName, m_SrcLuaState, 4, lua_gettop(m_SrcLuaState)
); );
return true; return true;
}; }
} Callback(FunctionName, L);
if (!cPluginManager::Get()->DoWithPlugin(PluginName, PluginCallback)) if (!cPluginManager::Get()->DoWithPlugin(PluginName, Callback))
{ {
return 0; return 0;
} }
if (NumReturns < 0) if (Callback.m_NumReturns < 0)
{ {
// The call has failed, there are zero return values. Do NOT return negative number (Lua considers that a "yield") // The call has failed, there are zero return values. Do NOT return negative number (Lua considers that a "yield")
return 0; return 0;
} }
return NumReturns; return Callback.m_NumReturns;
} }
@ -3228,29 +3243,42 @@ static int tolua_cRoot_DoWithPlayerByUUID(lua_State * tolua_S)
return 0; return 0;
} }
class cCallback :
public cPlayerListCallback
{
public:
cCallback(cLuaState & a_LuaState) :
m_LuaState(a_LuaState)
{
}
virtual bool Item(cPlayer * a_Player) override
{
bool ret = false;
m_LuaState.Call(m_FnRef, a_Player, cLuaState::Return, ret);
return ret;
}
cLuaState & m_LuaState;
cLuaState::cRef m_FnRef;
} Callback(L);
// Get parameters: // Get parameters:
cRoot * Self; cRoot * Self;
cUUID PlayerUUID; cUUID PlayerUUID;
cLuaState::cRef FnRef; L.GetStackValues(1, Self, PlayerUUID, Callback.m_FnRef);
L.GetStackValues(1, Self, PlayerUUID, FnRef);
if (PlayerUUID.IsNil()) if (PlayerUUID.IsNil())
{ {
return L.ApiParamError("Expected a non-nil UUID for parameter #1"); return L.ApiParamError("Expected a non-nil UUID for parameter #1");
} }
if (!FnRef.IsValid()) if (!Callback.m_FnRef.IsValid())
{ {
return L.ApiParamError("Expected a valid callback function for parameter #2"); return L.ApiParamError("Expected a valid callback function for parameter #2");
} }
// Call the function: // Call the function:
bool res = Self->DoWithPlayerByUUID(PlayerUUID, [&](cPlayer & a_Player) bool res = Self->DoWithPlayerByUUID(PlayerUUID, Callback);
{
bool ret = false;
L.Call(FnRef, &a_Player, cLuaState::Return, ret);
return ret;
}
);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);

View File

@ -1,4 +1,4 @@

// ManualBindings.h // ManualBindings.h
// Declares the cManualBindings class used as a namespace for functions exported to the Lua API manually // Declares the cManualBindings class used as a namespace for functions exported to the Lua API manually
@ -57,7 +57,7 @@ public:
template < template <
class Ty1, class Ty1,
class Ty2, class Ty2,
bool (Ty1::*DoWithFn)(const AString &, const std::function<bool(Ty2 &)> &) bool (Ty1::*DoWithFn)(const AString &, cItemCallback<Ty2> &)
> >
static int DoWith(lua_State * tolua_S) static int DoWith(lua_State * tolua_S)
{ {
@ -89,14 +89,28 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2");
} }
// Call the DoWith function: class cLuaCallback : public cItemCallback<Ty2>
bool res = (Self->*DoWithFn)(ItemName, [&](Ty2 & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{
}
private:
virtual bool Item(Ty2 * a_Item) override
{ {
bool ret = false; bool ret = false;
L.Call(FnRef, &a_Item, cLuaState::Return, ret); m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret);
return ret; return ret;
} }
); cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
} Callback(L, FnRef);
// Call the DoWith function:
bool res = (Self->*DoWithFn)(ItemName, Callback);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);
@ -111,7 +125,7 @@ public:
template < template <
class Ty1, class Ty1,
class Ty2, class Ty2,
bool (Ty1::*DoWithFn)(const AString &, const std::function<bool(Ty2 &)> &) bool (Ty1::*DoWithFn)(const AString &, cItemCallback<Ty2> &)
> >
static int StaticDoWith(lua_State * tolua_S) static int StaticDoWith(lua_State * tolua_S)
{ {
@ -138,14 +152,28 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2");
} }
// Call the DoWith function: class cLuaCallback : public cItemCallback<Ty2>
bool res = (Ty1::Get()->*DoWithFn)(ItemName, [&](Ty2 & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{
}
private:
virtual bool Item(Ty2 * a_Item) override
{ {
bool ret = false; bool ret = false;
L.Call(FnRef, &a_Item, cLuaState::Return, ret); m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret);
return ret; return ret;
} }
); cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
} Callback(L, FnRef);
// Call the DoWith function:
bool res = (Ty1::Get()->*DoWithFn)(ItemName, Callback);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);
@ -159,7 +187,7 @@ public:
template < template <
class Ty1, class Ty1,
class Ty2, class Ty2,
bool (Ty1::*DoWithFn)(UInt32, const std::function<bool(Ty2 &)> &) bool (Ty1::*DoWithFn)(UInt32, cItemCallback<Ty2> &)
> >
static int DoWithID(lua_State * tolua_S) static int DoWithID(lua_State * tolua_S)
{ {
@ -187,14 +215,28 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2");
} }
// Call the DoWith function: class cLuaCallback : public cItemCallback<Ty2>
bool res = (Self->*DoWithFn)(ItemID, [&](Ty2 & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{
}
private:
virtual bool Item(Ty2 * a_Item) override
{ {
bool ret = false; bool ret = false;
L.Call(FnRef, &a_Item, cLuaState::Return, ret); m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret);
return ret; return ret;
} }
); cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
} Callback(L, FnRef);
// Call the DoWith function:
bool res = (Self->*DoWithFn)(ItemID, Callback);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);
@ -209,7 +251,7 @@ public:
template < template <
class SELF, class SELF,
class ITEM, class ITEM,
bool (SELF::*DoWithFn)(int, int, int, const std::function<bool(ITEM &)> &) bool (SELF::*DoWithFn)(int, int, int, cItemCallback<ITEM> &)
> >
static int DoWithXYZ(lua_State * tolua_S) static int DoWithXYZ(lua_State * tolua_S)
{ {
@ -240,14 +282,28 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #5"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #5");
} }
// Call the DoWith function: class cLuaCallback : public cItemCallback<ITEM>
bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, [&](ITEM & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{
}
private:
virtual bool Item(ITEM * a_Item) override
{ {
bool ret = false; bool ret = false;
L.Call(FnRef, &a_Item, cLuaState::Return, ret); m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret);
return ret; return ret;
} }
); cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
} Callback(L, FnRef);
// Call the DoWith function:
bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, Callback);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);
@ -262,7 +318,7 @@ public:
template < template <
class SELF, class SELF,
class ITEM, class ITEM,
bool (SELF::*DoWithFn)(int, int, int, const std::function<bool(ITEM &)> &), bool (SELF::*DoWithFn)(int, int, int, cItemCallback<ITEM> &),
bool (SELF::*CoordCheckFn)(int, int, int) const bool (SELF::*CoordCheckFn)(int, int, int) const
> >
static int DoWithXYZ(lua_State * tolua_S) static int DoWithXYZ(lua_State * tolua_S)
@ -300,14 +356,28 @@ public:
).c_str()); ).c_str());
} }
// Call the DoWith function: class cLuaCallback : public cItemCallback<ITEM>
bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, [&](ITEM & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{
}
private:
virtual bool Item(ITEM * a_Item) override
{ {
bool ret = false; bool ret = false;
L.Call(FnRef, &a_Item, cLuaState::Return, ret); m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret);
return ret; return ret;
} }
); cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
} Callback(L, FnRef);
// Call the DoWith function:
bool res = (Self->*DoWithFn)(BlockX, BlockY, BlockZ, Callback);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);
@ -321,7 +391,7 @@ public:
template < template <
class Ty1, class Ty1,
class Ty2, class Ty2,
bool (Ty1::*ForEachFn)(int, int, const std::function<bool(Ty2 &)> &) bool (Ty1::*ForEachFn)(int, int, cItemCallback<Ty2> &)
> >
static int ForEachInChunk(lua_State * tolua_S) static int ForEachInChunk(lua_State * tolua_S)
{ {
@ -351,14 +421,28 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #4"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #4");
} }
// Call the DoWith function: class cLuaCallback : public cItemCallback<Ty2>
bool res = (Self->*ForEachFn)(ChunkX, ChunkZ, [&](Ty2 & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{
}
private:
virtual bool Item(Ty2 * a_Item) override
{ {
bool ret = false; bool ret = false;
L.Call(FnRef, &a_Item, cLuaState::Return, ret); m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, ret);
return ret; return ret;
} }
); cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
} Callback(L, FnRef);
// Call the DoWith function:
bool res = (Self->*ForEachFn)(ChunkX, ChunkZ, Callback);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);
@ -372,7 +456,7 @@ public:
template < template <
class Ty1, class Ty1,
class Ty2, class Ty2,
bool (Ty1::*ForEachFn)(const cBoundingBox &, const std::function<bool(Ty2 &)> &) bool (Ty1::*ForEachFn)(const cBoundingBox &, cItemCallback<Ty2> &)
> >
static int ForEachInBox(lua_State * tolua_S) static int ForEachInBox(lua_State * tolua_S)
{ {
@ -404,19 +488,36 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #2");
} }
bool res = (Self->*ForEachFn)(*Box, [&](Ty2 & a_Item) // Callback wrapper for the Lua function:
class cLuaCallback : public cItemCallback<Ty2>
{
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FuncRef) :
m_LuaState(a_LuaState),
m_FnRef(a_FuncRef)
{ {
bool ret = false; }
if (!L.Call(FnRef, &a_Item, cLuaState::Return, ret))
private:
cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
// cItemCallback<Ty2> overrides:
virtual bool Item(Ty2 * a_Item) override
{
bool res = false;
if (!m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res))
{ {
LOGWARNING("Failed to call Lua callback"); LOGWARNING("Failed to call Lua callback");
L.LogStackTrace(); m_LuaState.LogStackTrace();
return true; // Abort enumeration return true; // Abort enumeration
} }
return ret; return res;
} }
); } Callback(L, FnRef);
bool res = (Self->*ForEachFn)(*Box, Callback);
// Push the result as the return value: // Push the result as the return value:
L.Push(res); L.Push(res);
@ -430,7 +531,7 @@ public:
template < template <
class Ty1, class Ty1,
class Ty2, class Ty2,
bool (Ty1::*ForEachFn)(const std::function<bool(Ty2 &)> &) bool (Ty1::*ForEachFn)(cItemCallback<Ty2> &)
> >
static int ForEach(lua_State * tolua_S) static int ForEach(lua_State * tolua_S)
{ {
@ -457,14 +558,29 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #1"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #1");
} }
// Call the enumeration: class cLuaCallback : public cItemCallback<Ty2>
bool res = (Self->*ForEachFn)([&](Ty2 & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{ {
bool ret = false; // By default continue the enumeration
L.Call(FnRef, &a_Item, cLuaState::Return, ret);
return ret;
} }
);
private:
cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
virtual bool Item(Ty2 * a_Item) override
{
bool res = false; // By default continue the enumeration
m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res);
return res;
}
} Callback(L, FnRef);
// Call the enumeration:
bool res = (Self->*ForEachFn)(Callback);
// Push the return value: // Push the return value:
L.Push(res); L.Push(res);
@ -479,7 +595,7 @@ public:
template < template <
class Ty1, class Ty1,
class Ty2, class Ty2,
bool (Ty1::*ForEachFn)(const std::function<bool(Ty2 &)> &) bool (Ty1::*ForEachFn)(cItemCallback<Ty2> &)
> >
static int StaticForEach(lua_State * tolua_S) static int StaticForEach(lua_State * tolua_S)
{ {
@ -500,14 +616,29 @@ public:
return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #1"); return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a valid callback function for parameter #1");
} }
// Call the enumeration: class cLuaCallback : public cItemCallback<Ty2>
bool res = (Ty1::Get()->*ForEachFn)([&](Ty2 & a_Item) {
public:
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
m_LuaState(a_LuaState),
m_FnRef(a_FnRef)
{ {
bool ret = false; // By default continue the enumeration
L.Call(FnRef, &a_Item, cLuaState::Return, ret);
return ret;
} }
);
private:
cLuaState & m_LuaState;
cLuaState::cRef & m_FnRef;
virtual bool Item(Ty2 * a_Item) override
{
bool res = false; // By default continue the enumeration
m_LuaState.Call(m_FnRef, a_Item, cLuaState::Return, res);
return res;
}
} Callback(L, FnRef);
// Call the enumeration:
bool res = (Ty1::Get()->*ForEachFn)(Callback);
// Push the return value: // Push the return value:
L.Push(res); L.Push(res);

View File

@ -1,4 +1,4 @@

// ManualBindings_World.cpp // ManualBindings_World.cpp
// Implements the manual Lua API bindings for the cWorld class // Implements the manual Lua API bindings for the cWorld class
@ -237,10 +237,10 @@ static int tolua_cWorld_DoWithPlayerByUUID(lua_State * tolua_S)
} }
// Call the function: // Call the function:
bool res = Self->DoWithPlayerByUUID(PlayerUUID, [&](cPlayer & a_Player) bool res = Self->DoWithPlayerByUUID(PlayerUUID, [&](cPlayer * a_Player)
{ {
bool ret = false; bool ret = false;
L.Call(FnRef, &a_Player, cLuaState::Return, ret); L.Call(FnRef, a_Player, cLuaState::Return, ret);
return ret; return ret;
} }
); );

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "PluginManager.h" #include "PluginManager.h"
@ -1993,14 +1993,14 @@ bool cPluginManager::IsValidHookType(int a_HookType)
bool cPluginManager::DoWithPlugin(const AString & a_PluginName, const cPluginCallback & a_Callback) bool cPluginManager::DoWithPlugin(const AString & a_PluginName, cPluginCallback & a_Callback)
{ {
// TODO: Implement locking for plugins // TODO: Implement locking for plugins
for (auto & plugin: m_Plugins) for (auto & plugin: m_Plugins)
{ {
if (plugin->GetName() == a_PluginName) if (plugin->GetName() == a_PluginName)
{ {
return a_Callback(*plugin); return a_Callback.Item(plugin.get());
} }
} }
return false; return false;
@ -2010,12 +2010,12 @@ bool cPluginManager::DoWithPlugin(const AString & a_PluginName, const cPluginCal
bool cPluginManager::ForEachPlugin(const cPluginCallback & a_Callback) bool cPluginManager::ForEachPlugin(cPluginCallback & a_Callback)
{ {
// TODO: Implement locking for plugins // TODO: Implement locking for plugins
for (auto & plugin: m_Plugins) for (auto & plugin: m_Plugins)
{ {
if (a_Callback(*plugin)) if (a_Callback.Item(plugin.get()))
{ {
return false; return false;
} }

View File

@ -1,9 +1,8 @@

#pragma once #pragma once
#include "Defines.h" #include "Defines.h"
#include <functional>
@ -195,7 +194,7 @@ public:
/** The interface used for enumerating and extern-calling plugins */ /** The interface used for enumerating and extern-calling plugins */
using cPluginCallback = std::function<bool(cPlugin &)>; typedef cItemCallback<cPlugin> cPluginCallback;
typedef std::list<cPlugin *> PluginList; typedef std::list<cPlugin *> PluginList;
@ -373,18 +372,18 @@ public:
/** Calls the specified callback with the plugin object of the specified plugin. /** Calls the specified callback with the plugin object of the specified plugin.
Returns false if plugin not found, otherwise returns the value that the callback has returned. */ Returns false if plugin not found, otherwise returns the value that the callback has returned. */
bool DoWithPlugin(const AString & a_PluginName, const cPluginCallback & a_Callback); bool DoWithPlugin(const AString & a_PluginName, cPluginCallback & a_Callback);
/** Calls the specified callback for each plugin in m_Plugins. /** Calls the specified callback for each plugin in m_Plugins.
Returns true if all plugins have been reported, false if the callback has aborted the enumeration by returning true. */ Returns true if all plugins have been reported, false if the callback has aborted the enumeration by returning true. */
bool ForEachPlugin(const cPluginCallback & a_Callback); bool ForEachPlugin(cPluginCallback & a_Callback);
/** Returns the name of the folder (cPlugin::GetFolderName()) from which the specified plugin was loaded. */ /** Returns the name of the folder (cPlugin::GetFolderName()) from which the specified plugin was loaded. */
AString GetPluginFolderName(const AString & a_PluginName); // tolua_export AString GetPluginFolderName(const AString & a_PluginName); // tolua_export
/** Returns the path where individual plugins' folders are expected. /** Returns the path where individual plugins' folders are expected.
The path doesn't end in a slash. */ The path doesn't end in a slash. */
static AString GetPluginsPath(void) { return FILE_IO_PREFIX "Plugins"; } // tolua_export static AString GetPluginsPath(void) { return FILE_IO_PREFIX + AString("Plugins"); } // tolua_export
private: private:
friend class cRoot; friend class cRoot;

View File

@ -1,4 +1,4 @@

// BlockArea.cpp // BlockArea.cpp
// NOTE: compile.sh checks for this file in order to determine if this is the Cuberite folder. // NOTE: compile.sh checks for this file in order to determine if this is the Cuberite folder.
@ -2239,7 +2239,7 @@ int cBlockArea::MakeIndex(int a_RelX, int a_RelY, int a_RelZ) const
bool cBlockArea::DoWithBlockEntityRelAt(int a_RelX, int a_RelY, int a_RelZ, const cBlockEntityCallback & a_Callback) bool cBlockArea::DoWithBlockEntityRelAt(int a_RelX, int a_RelY, int a_RelZ, cItemCallback<cBlockEntity> & a_Callback)
{ {
ASSERT(IsValidRelCoords(a_RelX, a_RelY, a_RelZ)); ASSERT(IsValidRelCoords(a_RelX, a_RelY, a_RelZ));
if (!HasBlockEntities()) if (!HasBlockEntities())
@ -2252,14 +2252,14 @@ bool cBlockArea::DoWithBlockEntityRelAt(int a_RelX, int a_RelY, int a_RelZ, cons
{ {
return false; return false;
} }
return a_Callback(*itr->second); return a_Callback.Item(itr->second);
} }
bool cBlockArea::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback) bool cBlockArea::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cItemCallback<cBlockEntity> & a_Callback)
{ {
return DoWithBlockEntityRelAt(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Callback); return DoWithBlockEntityRelAt(a_BlockX - m_Origin.x, a_BlockY - m_Origin.y, a_BlockZ - m_Origin.z, a_Callback);
} }
@ -2268,7 +2268,7 @@ bool cBlockArea::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
bool cBlockArea::ForEachBlockEntity(const cBlockEntityCallback & a_Callback) bool cBlockArea::ForEachBlockEntity(cItemCallback<cBlockEntity> & a_Callback)
{ {
if (!HasBlockEntities()) if (!HasBlockEntities())
{ {
@ -2276,7 +2276,7 @@ bool cBlockArea::ForEachBlockEntity(const cBlockEntityCallback & a_Callback)
} }
for (auto & keyPair: *m_BlockEntities) for (auto & keyPair: *m_BlockEntities)
{ {
if (a_Callback(*keyPair.second)) if (a_Callback.Item(keyPair.second))
{ {
return false; return false;
} }

View File

@ -1,4 +1,4 @@

// BlockArea.h // BlockArea.h
// Interfaces to the cBlockArea object representing an area of block data that can be queried from cWorld and then accessed again without further queries // Interfaces to the cBlockArea object representing an area of block data that can be queried from cWorld and then accessed again without further queries
@ -17,14 +17,13 @@
#include "ForEachChunkProvider.h" #include "ForEachChunkProvider.h"
#include "ChunkDataCallback.h" #include "ChunkDataCallback.h"
#include "Cuboid.h" #include "Cuboid.h"
#include <functional>
// fwd: // fwd:
class cCuboid; class cCuboid;
using cBlockEntityCallback = std::function<bool(cBlockEntity &)>;
@ -377,18 +376,18 @@ public:
/** Calls the callback for the block entity at the specified coords. /** Calls the callback for the block entity at the specified coords.
Returns false if there is no block entity at those coords, or the block area doesn't have baBlockEntities. Returns false if there is no block entity at those coords, or the block area doesn't have baBlockEntities.
Returns the value that the callback has returned if there is a block entity. */ Returns the value that the callback has returned if there is a block entity. */
bool DoWithBlockEntityRelAt(int a_RelX, int a_RelY, int a_RelZ, const cBlockEntityCallback & a_Callback); bool DoWithBlockEntityRelAt(int a_RelX, int a_RelY, int a_RelZ, cItemCallback<cBlockEntity> & a_Callback);
/** Calls the callback for the block entity at the specified coords. /** Calls the callback for the block entity at the specified coords.
Returns false if there is no block entity at those coords. Returns false if there is no block entity at those coords.
Returns the value that the callback has returned if there is a block entity. */ Returns the value that the callback has returned if there is a block entity. */
bool DoWithBlockEntityAt (int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback); bool DoWithBlockEntityAt (int a_BlockX, int a_BlockY, int a_BlockZ, cItemCallback<cBlockEntity> & a_Callback);
/** Calls the callback for all the block entities. /** Calls the callback for all the block entities.
If the callback returns true, aborts the enumeration and returns false. If the callback returns true, aborts the enumeration and returns false.
If the callback returns true, continues with the next BE. If the callback returns true, continues with the next BE.
Returns true if all block entities have been enumerated (including the case when there is none or the area is without baBlockEntities). */ Returns true if all block entities have been enumerated (including the case when there is none or the area is without baBlockEntities). */
bool ForEachBlockEntity(const cBlockEntityCallback & a_Callback); bool ForEachBlockEntity(cItemCallback<cBlockEntity> & a_Callback);
/** Direct read-only access to block entities. */ /** Direct read-only access to block entities. */
const cBlockEntities & GetBlockEntities(void) const { ASSERT(HasBlockEntities()); return *m_BlockEntities; } const cBlockEntities & GetBlockEntities(void) const { ASSERT(HasBlockEntities()); return *m_BlockEntities; }

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "BeaconEntity.h" #include "BeaconEntity.h"
@ -195,21 +195,33 @@ void cBeaconEntity::UpdateBeacon(void)
GetWindow()->SetProperty(0, m_BeaconLevel); GetWindow()->SetProperty(0, m_BeaconLevel);
} }
Vector3d BeaconPosition(m_PosX, m_PosY, m_PosZ); class cPlayerCallback :
GetWorld()->ForEachPlayer([=](cPlayer & a_Player) public cPlayerListCallback
{
public:
cPlayerCallback(Vector3d a_Position):
m_Position(a_Position)
{ {
Vector3d Distance = BeaconPosition - a_Player.GetPosition(); }
virtual bool Item(cPlayer * a_Player)
{
Vector3d Distance = m_Position - a_Player->GetPosition();
if ( if (
(std::abs(Distance.y) <= 14) && (std::abs(Distance.y) <= 14) &&
(std::abs(Distance.x) <= 20) && (std::abs(Distance.x) <= 20) &&
(std::abs(Distance.z) <= 20) (std::abs(Distance.z) <= 20)
) )
{ {
a_Player.AwardAchievement(eStatistic::achFullBeacon); a_Player->AwardAchievement(eStatistic::achFullBeacon);
} }
return false; return false;
} }
);
private:
Vector3d m_Position;
} PlayerCallback(Vector3d(m_PosX, m_PosY, m_PosZ));
GetWorld()->ForEachPlayer(PlayerCallback);
} }
} }
@ -237,28 +249,46 @@ void cBeaconEntity::GiveEffects(void)
SecondaryEffect = m_SecondaryEffect; SecondaryEffect = m_SecondaryEffect;
} }
Vector3d BeaconPosition(m_PosX, m_PosY, m_PosZ); class cPlayerCallback : public cPlayerListCallback
GetWorld()->ForEachPlayer([=](cPlayer & a_Player) {
int m_Radius;
Vector3d m_Position;
cEntityEffect::eType m_PrimaryEffect, m_SecondaryEffect;
short m_EffectLevel;
virtual bool Item(cPlayer * a_Player)
{ {
auto PlayerPosition = a_Player.GetPosition(); Vector3d PlayerPosition = Vector3d(a_Player->GetPosition());
if (PlayerPosition.y > BeaconPosition.y) if (PlayerPosition.y > m_Position.y)
{ {
PlayerPosition.y = BeaconPosition.y; PlayerPosition.y = m_Position.y;
} }
// TODO: Vanilla minecraft uses an AABB check instead of a radius one // TODO: Vanilla minecraft uses an AABB check instead of a radius one
if ((PlayerPosition - BeaconPosition).Length() <= Radius) if ((PlayerPosition - m_Position).Length() <= m_Radius)
{ {
a_Player.AddEntityEffect(m_PrimaryEffect, 180, EffectLevel); a_Player->AddEntityEffect(m_PrimaryEffect, 180, m_EffectLevel);
if (m_SecondaryEffect != cEntityEffect::effNoEffect) if (m_SecondaryEffect != cEntityEffect::effNoEffect)
{ {
a_Player.AddEntityEffect(m_SecondaryEffect, 180, 0); a_Player->AddEntityEffect(m_SecondaryEffect, 180, 0);
} }
} }
return false; return false;
} }
);
public:
cPlayerCallback(int a_Radius, Vector3d a_Position, cEntityEffect::eType a_PrimaryEffect, cEntityEffect::eType a_SecondaryEffect, short a_EffectLevel):
m_Radius(a_Radius),
m_Position(a_Position),
m_PrimaryEffect(a_PrimaryEffect),
m_SecondaryEffect(a_SecondaryEffect),
m_EffectLevel(a_EffectLevel)
{
}
} PlayerCallback(Radius, Vector3d(m_PosX, m_PosY, m_PosZ), m_PrimaryEffect, SecondaryEffect, EffectLevel);
GetWorld()->ForEachPlayer(PlayerCallback);
} }

View File

@ -138,18 +138,33 @@ bool cChestEntity::UsedBy(cPlayer * a_Player)
void cChestEntity::ScanNeighbours() void cChestEntity::ScanNeighbours()
{ {
// Callback for finding neighbouring chest: // Callback for finding neighbouring chest:
auto FindNeighbour = [this](cChestEntity & a_Chest) class cFindNeighbour :
public cChestCallback
{ {
if (a_Chest.GetBlockType() != m_BlockType) public:
cChestEntity * m_Neighbour;
BLOCKTYPE m_ChestType;
cFindNeighbour(BLOCKTYPE a_ChestType) :
m_Neighbour(nullptr),
m_ChestType(a_ChestType)
{ {
// Neighboring block is not the same type of chest
return true;
} }
m_Neighbour = &a_Chest;
return false; virtual bool Item(cChestEntity * a_Chest) override
{
if (a_Chest->GetBlockType() != m_ChestType)
{
// Neighboring block is not the same type of chest
return true;
}
m_Neighbour = a_Chest;
return false;
}
}; };
// Scan horizontally adjacent blocks for any neighbouring chest of the same type: // Scan horizontally adjacent blocks for any neighbouring chest of the same type:
cFindNeighbour FindNeighbour(m_BlockType);
if ( if (
m_World->DoWithChestAt(m_PosX - 1, m_PosY, m_PosZ, FindNeighbour) || m_World->DoWithChestAt(m_PosX - 1, m_PosY, m_PosZ, FindNeighbour) ||
m_World->DoWithChestAt(m_PosX + 1, m_PosY, m_PosZ, FindNeighbour) || m_World->DoWithChestAt(m_PosX + 1, m_PosY, m_PosZ, FindNeighbour) ||
@ -157,6 +172,7 @@ void cChestEntity::ScanNeighbours()
m_World->DoWithChestAt(m_PosX, m_PosY, m_PosZ + 1, FindNeighbour) m_World->DoWithChestAt(m_PosX, m_PosY, m_PosZ + 1, FindNeighbour)
) )
{ {
m_Neighbour = FindNeighbour.m_Neighbour;
m_Neighbour->m_Neighbour = this; m_Neighbour->m_Neighbour = this;
// Force neighbour's window shut. Does Mojang server do this or should a double window open? // Force neighbour's window shut. Does Mojang server do this or should a double window open?
m_Neighbour->DestroyWindow(); m_Neighbour->DestroyWindow();

View File

@ -193,7 +193,8 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
{ {
UNUSED(a_CurrentTick); UNUSED(a_CurrentTick);
class cHopperPickupSearchCallback class cHopperPickupSearchCallback :
public cEntityCallback
{ {
public: public:
cHopperPickupSearchCallback(const Vector3i & a_Pos, cItemGrid & a_Contents) : cHopperPickupSearchCallback(const Vector3i & a_Pos, cItemGrid & a_Contents) :
@ -203,20 +204,22 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
{ {
} }
bool operator () (cEntity & a_Entity) virtual bool Item(cEntity * a_Entity) override
{ {
if (!a_Entity.IsPickup()) ASSERT(a_Entity != nullptr);
if (!a_Entity->IsPickup())
{ {
return false; return false;
} }
Vector3f EntityPos = a_Entity.GetPosition(); Vector3f EntityPos = a_Entity->GetPosition();
Vector3f BlockPos(m_Pos.x + 0.5f, static_cast<float>(m_Pos.y) + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards Vector3f BlockPos(m_Pos.x + 0.5f, static_cast<float>(m_Pos.y) + 1, m_Pos.z + 0.5f); // One block above hopper, and search from center outwards
double Distance = (EntityPos - BlockPos).Length(); double Distance = (EntityPos - BlockPos).Length();
if (Distance < 0.5) if (Distance < 0.5)
{ {
if (TrySuckPickupIn(static_cast<cPickup &>(a_Entity))) if (TrySuckPickupIn(static_cast<cPickup *>(a_Entity)))
{ {
return false; return false;
} }
@ -225,9 +228,9 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
return false; return false;
} }
bool TrySuckPickupIn(cPickup & a_Pickup) bool TrySuckPickupIn(cPickup * a_Pickup)
{ {
cItem & Item = a_Pickup.GetItem(); cItem & Item = a_Pickup->GetItem();
for (int i = 0; i < ContentsWidth * ContentsHeight; i++) for (int i = 0; i < ContentsWidth * ContentsHeight; i++)
{ {
@ -235,7 +238,7 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
{ {
m_bFoundPickupsAbove = true; m_bFoundPickupsAbove = true;
m_Contents.SetSlot(i, Item); m_Contents.SetSlot(i, Item);
a_Pickup.Destroy(); // Kill pickup a_Pickup->Destroy(); // Kill pickup
return true; return true;
} }
@ -249,7 +252,7 @@ bool cHopperEntity::MovePickupsIn(cChunk & a_Chunk, Int64 a_CurrentTick)
if (Item.IsEmpty()) if (Item.IsEmpty())
{ {
a_Pickup.Destroy(); // Kill pickup if all items were added a_Pickup->Destroy(); // Kill pickup if all items were added
} }
return true; return true;
} }

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "MobSpawnerEntity.h" #include "MobSpawnerEntity.h"
@ -138,36 +138,47 @@ void cMobSpawnerEntity::SpawnEntity(void)
return; return;
} }
auto MobType = m_Entity; class cCallback : public cChunkCallback
bool EntitiesSpawned = m_World->DoWithChunk(GetChunkX(), GetChunkZ(), [&](cChunk & a_Chunk) {
public:
cCallback(int a_RelX, int a_RelY, int a_RelZ, eMonsterType a_MobType, int a_NearbyEntitiesNum) :
m_RelX(a_RelX),
m_RelY(a_RelY),
m_RelZ(a_RelZ),
m_MobType(a_MobType),
m_NearbyEntitiesNum(a_NearbyEntitiesNum)
{
}
virtual bool Item(cChunk * a_Chunk)
{ {
auto & Random = GetRandomProvider(); auto & Random = GetRandomProvider();
bool HaveSpawnedEntity = false; bool EntitiesSpawned = false;
for (size_t i = 0; i < 4; i++) for (size_t i = 0; i < 4; i++)
{ {
if (NearbyEntities >= 6) if (m_NearbyEntitiesNum >= 6)
{ {
break; break;
} }
int RelX = m_RelX + static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0); int RelX = m_RelX + static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0);
int RelY = m_PosY + Random.RandInt(-1, 1); int RelY = m_RelY + Random.RandInt(-1, 1);
int RelZ = m_RelZ + static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0); int RelZ = m_RelZ + static_cast<int>((Random.RandReal<double>() - Random.RandReal<double>()) * 4.0);
cChunk * Chunk = a_Chunk.GetRelNeighborChunkAdjustCoords(RelX, RelZ); cChunk * Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(RelX, RelZ);
if ((Chunk == nullptr) || !Chunk->IsValid()) if ((Chunk == nullptr) || !Chunk->IsValid())
{ {
continue; continue;
} }
EMCSBiome Biome = Chunk->GetBiomeAt(RelX, RelZ); EMCSBiome Biome = Chunk->GetBiomeAt(RelX, RelZ);
if (cMobSpawner::CanSpawnHere(Chunk, RelX, RelY, RelZ, MobType, Biome)) if (cMobSpawner::CanSpawnHere(Chunk, RelX, RelY, RelZ, m_MobType, Biome))
{ {
double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX; double PosX = Chunk->GetPosX() * cChunkDef::Width + RelX;
double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ; double PosZ = Chunk->GetPosZ() * cChunkDef::Width + RelZ;
auto Monster = cMonster::NewMonsterFromType(MobType); auto Monster = cMonster::NewMonsterFromType(m_MobType);
if (Monster == nullptr) if (Monster == nullptr)
{ {
continue; continue;
@ -177,7 +188,7 @@ void cMobSpawnerEntity::SpawnEntity(void)
Monster->SetYaw(Random.RandReal(360.0f)); Monster->SetYaw(Random.RandReal(360.0f));
if (Chunk->GetWorld()->SpawnMobFinalize(std::move(Monster)) != cEntity::INVALID_ID) if (Chunk->GetWorld()->SpawnMobFinalize(std::move(Monster)) != cEntity::INVALID_ID)
{ {
HaveSpawnedEntity = true; EntitiesSpawned = true;
Chunk->BroadcastSoundParticleEffect( Chunk->BroadcastSoundParticleEffect(
EffectID::PARTICLE_MOBSPAWN, EffectID::PARTICLE_MOBSPAWN,
static_cast<int>(PosX * 8.0), static_cast<int>(PosX * 8.0),
@ -185,15 +196,19 @@ void cMobSpawnerEntity::SpawnEntity(void)
static_cast<int>(PosZ * 8.0), static_cast<int>(PosZ * 8.0),
0 0
); );
NearbyEntities++; m_NearbyEntitiesNum++;
} }
} }
} }
return EntitiesSpawned; return EntitiesSpawned;
} }
); protected:
int m_RelX, m_RelY, m_RelZ;
eMonsterType m_MobType;
int m_NearbyEntitiesNum;
} Callback(m_RelX, m_PosY, m_RelZ, m_Entity, NearbyEntities);
if (EntitiesSpawned) if (m_World->DoWithChunk(GetChunkX(), GetChunkZ(), Callback))
{ {
ResetTimer(); ResetTimer();
} }

View File

@ -1,12 +1,12 @@

// BlockBed.cpp // BlockBed.cpp
#include "Globals.h" #include "Globals.h"
#include "BlockBed.h" #include "BlockBed.h"
#include "BroadcastInterface.h" #include "BroadcastInterface.h"
#include "Entities/../World.h"
#include "Entities/Player.h" #include "Entities/Player.h"
#include "../World.h"
#include "../BoundingBox.h" #include "../BoundingBox.h"
#include "../Mobs/Monster.h" #include "../Mobs/Monster.h"
#include "../BlockEntities/BedEntity.h" #include "../BlockEntities/BedEntity.h"
@ -53,6 +53,66 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
class cFindMobs :
public cEntityCallback
{
virtual bool Item(cEntity * a_Entity) override
{
return (
(a_Entity->GetEntityType() == cEntity::etMonster) &&
(static_cast<cMonster*>(a_Entity)->GetMobFamily() == cMonster::mfHostile)
);
}
};
class cTimeFastForwardTester :
public cPlayerListCallback
{
virtual bool Item(cPlayer * a_Player) override
{
if (!a_Player->IsInBed())
{
return true;
}
return false;
}
};
class cPlayerBedStateUnsetter :
public cPlayerListCallback
{
public:
cPlayerBedStateUnsetter(Vector3i a_Position, cChunkInterface & a_ChunkInterface) :
m_Position(a_Position),
m_ChunkInterface(a_ChunkInterface)
{
}
virtual bool Item(cPlayer * a_Player) override
{
cBlockBedHandler::SetBedOccupationState(m_ChunkInterface, a_Player->GetLastBedPos(), false);
a_Player->SetIsInBed(false);
return false;
}
private:
Vector3i m_Position;
cChunkInterface & m_ChunkInterface;
};
bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ) bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace, int a_CursorX, int a_CursorY, int a_CursorZ)
{ {
if (a_WorldInterface.GetDimension() != dimOverworld) if (a_WorldInterface.GetDimension() != dimOverworld)
@ -73,14 +133,7 @@ bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
} }
else else
{ {
auto FindMobs = [](cEntity & a_Entity) cFindMobs FindMobs;
{
return (
(a_Entity.GetEntityType() == cEntity::etMonster) &&
(static_cast<cMonster&>(a_Entity).GetMobFamily() == cMonster::mfHostile)
);
};
if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs)) if (!a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(a_Player.GetPosition() - Vector3i(0, 5, 0), 8, 10), FindMobs))
{ {
a_Player.SendMessageFailure("You may not rest now, there are monsters nearby"); a_Player.SendMessageFailure("You may not rest now, there are monsters nearby");
@ -111,24 +164,11 @@ bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
a_Player.SetIsInBed(true); a_Player.SetIsInBed(true);
a_Player.SendMessageSuccess("Home position set successfully"); a_Player.SendMessageSuccess("Home position set successfully");
auto TimeFastForwardTester = [](cPlayer & a_OtherPlayer) cTimeFastForwardTester Tester;
if (a_WorldInterface.ForEachPlayer(Tester))
{ {
if (!a_OtherPlayer.IsInBed()) cPlayerBedStateUnsetter Unsetter(Vector3i(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z), a_ChunkInterface);
{ a_WorldInterface.ForEachPlayer(Unsetter);
return true;
}
return false;
};
if (a_WorldInterface.ForEachPlayer(TimeFastForwardTester))
{
a_WorldInterface.ForEachPlayer([&](cPlayer & a_OtherPlayer)
{
cBlockBedHandler::SetBedOccupationState(a_ChunkInterface, a_OtherPlayer.GetLastBedPos(), false);
a_OtherPlayer.SetIsInBed(false);
return false;
}
);
a_WorldInterface.SetTimeOfDay(0); a_WorldInterface.SetTimeOfDay(0);
a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x0b); // Clear the "occupied" bit of the bed's block a_ChunkInterface.SetBlockMeta(a_BlockX, a_BlockY, a_BlockZ, Meta & 0x0b); // Clear the "occupied" bit of the bed's block
} }
@ -144,12 +184,25 @@ bool cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange) void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWorldInterface & a_WorldInterface, cPlayer & a_Player, const sSetBlock & a_BlockChange)
{ {
a_Player.GetWorld()->DoWithBedAt(a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(), [&](cBedEntity & a_Bed) class cBedColor :
public cBedCallback
{
public:
short m_Color;
cBedColor(short a_Color) :
m_Color(a_Color)
{ {
a_Bed.SetColor(a_Player.GetEquippedItem().m_ItemDamage); }
virtual bool Item(cBedEntity * a_Bed) override
{
a_Bed->SetColor(m_Color);
return true; return true;
} }
); };
cBedColor BedCallback(a_Player.GetEquippedItem().m_ItemDamage);
a_Player.GetWorld()->DoWithBedAt(a_BlockChange.GetX(), a_BlockChange.GetY(), a_BlockChange.GetZ(), BedCallback);
} }
@ -158,12 +211,19 @@ void cBlockBedHandler::OnPlacedByPlayer(cChunkInterface & a_ChunkInterface, cWor
void cBlockBedHandler::ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ) void cBlockBedHandler::ConvertToPickups(cWorldInterface & a_WorldInterface, cItems & a_Pickups, NIBBLETYPE a_BlockMeta, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
short Color = E_META_WOOL_RED; class cBedColor :
a_WorldInterface.DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBedEntity & a_Bed) public cBedCallback
{
public:
short m_Color = E_META_WOOL_RED;
virtual bool Item(cBedEntity * a_Bed) override
{ {
Color = a_Bed.GetColor(); m_Color = a_Bed->GetColor();
return true; return true;
} }
); };
a_Pickups.Add(cItem(E_ITEM_BED, 1, Color)); cBedColor BedCallback;
a_WorldInterface.DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, BedCallback);
a_Pickups.Add(cItem(E_ITEM_BED, 1, BedCallback.m_Color));
} }

View File

@ -30,32 +30,36 @@ public:
return; return;
} }
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [](cBlockEntity & a_BlockEntity) class cCallback : public cBlockEntityCallback
{
virtual bool Item(cBlockEntity * a_BlockEntity)
{ {
if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) if (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)
{ {
return false; return false;
} }
auto & MobHeadEntity = static_cast<cMobHeadEntity&>(a_BlockEntity); cMobHeadEntity * MobHeadEntity = static_cast<cMobHeadEntity*>(a_BlockEntity);
cItems Pickups; cItems Pickups;
Pickups.Add(E_ITEM_HEAD, 1, static_cast<short>(MobHeadEntity.GetType())); Pickups.Add(E_ITEM_HEAD, 1, static_cast<short>(MobHeadEntity->GetType()));
auto & r1 = GetRandomProvider(); auto & r1 = GetRandomProvider();
// Mid-block position first // Mid-block position first
double MicroX, MicroY, MicroZ; double MicroX, MicroY, MicroZ;
MicroX = MobHeadEntity.GetPosX() + 0.5; MicroX = MobHeadEntity->GetPosX() + 0.5;
MicroY = MobHeadEntity.GetPosY() + 0.5; MicroY = MobHeadEntity->GetPosY() + 0.5;
MicroZ = MobHeadEntity.GetPosZ() + 0.5; MicroZ = MobHeadEntity->GetPosZ() + 0.5;
// Add random offset second // Add random offset second
MicroX += r1.RandReal<double>(-0.5, 0.5); MicroX += r1.RandReal<double>(-0.5, 0.5);
MicroZ += r1.RandReal<double>(-0.5, 0.5); MicroZ += r1.RandReal<double>(-0.5, 0.5);
MobHeadEntity.GetWorld()->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ); MobHeadEntity->GetWorld()->SpawnItemPickups(Pickups, MicroX, MicroY, MicroZ);
return false; return false;
} }
); } Callback;
a_WorldInterface.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
} }
virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override virtual ColourID GetMapBaseColourID(NIBBLETYPE a_Meta) override

View File

@ -1,18 +1,15 @@

#pragma once #pragma once
#include <functional>
#include "../Mobs/MonsterTypes.h" #include "../Mobs/MonsterTypes.h"
class cBedEntity;
class cBlockEntity; typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
class cBroadcastInterface; class cBroadcastInterface;
class cItems; class cItems;
class cPlayer; class cPlayer;
using cBedCallback = std::function<bool(cBedEntity &)>;
using cBlockEntityCallback = std::function<bool(cBlockEntity &)>;
using cPlayerListCallback = std::function<bool(cPlayer &)>;
@ -31,10 +28,7 @@ public:
virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) = 0; virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) = 0;
virtual bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCallback & a_Callback) = 0; virtual bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback) = 0;
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback) = 0;
/** Spawns item pickups for each item in the list. May compress pickups if too many entities: */ /** Spawns item pickups for each item in the list. May compress pickups if too many entities: */
virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) = 0; virtual void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false) = 0;
@ -52,16 +46,19 @@ public:
Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */ Returns the UniqueID of the spawned experience orb, or cEntity::INVALID_ID on failure. */
virtual UInt32 SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0; virtual UInt32 SpawnExperienceOrb(double a_X, double a_Y, double a_Z, int a_Reward) = 0;
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) = 0;
/** Sends the block on those coords to the player */ /** Sends the block on those coords to the player */
virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0; virtual void SendBlockTo(int a_BlockX, int a_BlockY, int a_BlockZ, cPlayer & a_Player) = 0;
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
virtual bool ForEachPlayer(const cPlayerListCallback & a_Callback) = 0; virtual bool ForEachPlayer(cItemCallback<cPlayer> & a_Callback) = 0;
/** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox. /** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Returns true if all entities processed, false if the callback aborted by returning true. Returns true if all entities processed, false if the callback aborted by returning true.
If any chunk in the box is missing, ignores the entities in that chunk silently. */ If any chunk in the box is missing, ignores the entities in that chunk silently. */
virtual bool ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallback & a_Callback) = 0; virtual bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback) = 0;
virtual void SetTimeOfDay(int a_TimeOfDay) = 0; virtual void SetTimeOfDay(int a_TimeOfDay) = 0;

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#ifndef _WIN32 #ifndef _WIN32
@ -2114,12 +2114,17 @@ bool cChunk::HasEntity(UInt32 a_EntityID)
bool cChunk::ForEachEntity(const cEntityCallback & a_Callback) bool cChunk::ForEachEntity(cEntityCallback & a_Callback)
{ {
// The entity list is locked by the parent chunkmap's CS // The entity list is locked by the parent chunkmap's CS
for (const auto & Entity : m_Entities) for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2)
{ {
if (Entity->IsTicking() && a_Callback(*Entity)) ++itr2;
if (!(*itr)->IsTicking())
{
continue;
}
if (a_Callback.Item(itr->get()))
{ {
return false; return false;
} }
@ -2131,22 +2136,23 @@ bool cChunk::ForEachEntity(const cEntityCallback & a_Callback)
bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallback & a_Callback) bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback)
{ {
// The entity list is locked by the parent chunkmap's CS // The entity list is locked by the parent chunkmap's CS
for (const auto & Entity : m_Entities) for (auto itr = m_Entities.begin(), itr2 = itr; itr != m_Entities.end(); itr = itr2)
{ {
if (!Entity->IsTicking()) ++itr2;
if (!(*itr)->IsTicking())
{ {
continue; continue;
} }
cBoundingBox EntBox(Entity->GetPosition(), Entity->GetWidth() / 2, Entity->GetHeight()); cBoundingBox EntBox((*itr)->GetPosition(), (*itr)->GetWidth() / 2, (*itr)->GetHeight());
if (!EntBox.DoesIntersect(a_Box)) if (!EntBox.DoesIntersect(a_Box))
{ {
// The entity is not in the specified box // The entity is not in the specified box
continue; continue;
} }
if (a_Callback(*Entity)) if (a_Callback.Item(itr->get()))
{ {
return false; return false;
} }
@ -2158,14 +2164,23 @@ bool cChunk::ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallbac
bool cChunk::DoWithEntityByID(UInt32 a_EntityID, const cEntityCallback & a_Callback, bool & a_CallbackResult) bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult)
{
return DoWithEntityByID(a_EntityID, std::bind(&cEntityCallback::Item, &a_Callback, std::placeholders::_1), a_CallbackResult);
}
bool cChunk::DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback, bool & a_CallbackResult)
{ {
// The entity list is locked by the parent chunkmap's CS // The entity list is locked by the parent chunkmap's CS
for (const auto & Entity : m_Entities) for (const auto & Entity : m_Entities)
{ {
if ((Entity->GetUniqueID() == a_EntityID) && (Entity->IsTicking())) if ((Entity->GetUniqueID() == a_EntityID) && (Entity->IsTicking()))
{ {
a_CallbackResult = a_Callback(*Entity); a_CallbackResult = a_Callback(Entity.get());
return true; return true;
} }
} // for itr - m_Entitites[] } // for itr - m_Entitites[]
@ -2177,7 +2192,7 @@ bool cChunk::DoWithEntityByID(UInt32 a_EntityID, const cEntityCallback & a_Callb
template <class tyEntity, BLOCKTYPE... tBlocktype> template <class tyEntity, BLOCKTYPE... tBlocktype>
bool cChunk::GenericForEachBlockEntity(const std::function<bool(tyEntity &)> & a_Callback) bool cChunk::GenericForEachBlockEntity(cItemCallback<tyEntity>& a_Callback)
{ {
// The blockentity list is locked by the parent chunkmap's CS // The blockentity list is locked by the parent chunkmap's CS
for (auto & KeyPair : m_BlockEntities) for (auto & KeyPair : m_BlockEntities)
@ -2188,7 +2203,7 @@ bool cChunk::GenericForEachBlockEntity(const std::function<bool(tyEntity &)> & a
(IsOneOf<tBlocktype...>(Block->GetBlockType())) (IsOneOf<tBlocktype...>(Block->GetBlockType()))
) )
{ {
if (a_Callback(*static_cast<tyEntity *>(Block))) if (a_Callback.Item(static_cast<tyEntity *>(Block)))
{ {
return false; return false;
} }
@ -2201,7 +2216,7 @@ bool cChunk::GenericForEachBlockEntity(const std::function<bool(tyEntity &)> & a
bool cChunk::ForEachBlockEntity(const cBlockEntityCallback & a_Callback) bool cChunk::ForEachBlockEntity(cBlockEntityCallback & a_Callback)
{ {
return GenericForEachBlockEntity<cBlockEntity>(a_Callback); return GenericForEachBlockEntity<cBlockEntity>(a_Callback);
} }
@ -2210,7 +2225,7 @@ bool cChunk::ForEachBlockEntity(const cBlockEntityCallback & a_Callback)
bool cChunk::ForEachBrewingstand(const cBrewingstandCallback & a_Callback) bool cChunk::ForEachBrewingstand(cBrewingstandCallback & a_Callback)
{ {
return GenericForEachBlockEntity<cBrewingstandEntity, return GenericForEachBlockEntity<cBrewingstandEntity,
E_BLOCK_BREWING_STAND E_BLOCK_BREWING_STAND
@ -2221,7 +2236,7 @@ bool cChunk::ForEachBrewingstand(const cBrewingstandCallback & a_Callback)
bool cChunk::ForEachChest(const cChestCallback & a_Callback) bool cChunk::ForEachChest(cChestCallback & a_Callback)
{ {
return GenericForEachBlockEntity<cChestEntity, return GenericForEachBlockEntity<cChestEntity,
E_BLOCK_CHEST E_BLOCK_CHEST
@ -2232,7 +2247,7 @@ bool cChunk::ForEachChest(const cChestCallback & a_Callback)
bool cChunk::ForEachDispenser(const cDispenserCallback & a_Callback) bool cChunk::ForEachDispenser(cDispenserCallback & a_Callback)
{ {
return GenericForEachBlockEntity<cDispenserEntity, return GenericForEachBlockEntity<cDispenserEntity,
E_BLOCK_DISPENSER E_BLOCK_DISPENSER
@ -2243,7 +2258,7 @@ bool cChunk::ForEachDispenser(const cDispenserCallback & a_Callback)
bool cChunk::ForEachDropper(const cDropperCallback & a_Callback) bool cChunk::ForEachDropper(cDropperCallback & a_Callback)
{ {
return GenericForEachBlockEntity<cDropperEntity, return GenericForEachBlockEntity<cDropperEntity,
E_BLOCK_DROPPER E_BLOCK_DROPPER
@ -2254,7 +2269,7 @@ bool cChunk::ForEachDropper(const cDropperCallback & a_Callback)
bool cChunk::ForEachDropSpenser(const cDropSpenserCallback & a_Callback) bool cChunk::ForEachDropSpenser(cDropSpenserCallback & a_Callback)
{ {
return GenericForEachBlockEntity<cDropSpenserEntity, return GenericForEachBlockEntity<cDropSpenserEntity,
E_BLOCK_DISPENSER, E_BLOCK_DISPENSER,
@ -2266,7 +2281,7 @@ bool cChunk::ForEachDropSpenser(const cDropSpenserCallback & a_Callback)
bool cChunk::ForEachFurnace(const cFurnaceCallback & a_Callback) bool cChunk::ForEachFurnace(cFurnaceCallback & a_Callback)
{ {
return GenericForEachBlockEntity<cFurnaceEntity, return GenericForEachBlockEntity<cFurnaceEntity,
E_BLOCK_FURNACE, E_BLOCK_FURNACE,
@ -2279,7 +2294,7 @@ bool cChunk::ForEachFurnace(const cFurnaceCallback & a_Callback)
template <class tyEntity, BLOCKTYPE... tBlocktype> template <class tyEntity, BLOCKTYPE... tBlocktype>
bool cChunk::GenericDoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const std::function<bool(tyEntity &)> & a_Callback) bool cChunk::GenericDoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cItemCallback<tyEntity>& a_Callback)
{ {
// The blockentity list is locked by the parent chunkmap's CS // The blockentity list is locked by the parent chunkmap's CS
cBlockEntity * Block = GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ); cBlockEntity * Block = GetBlockEntity(a_BlockX, a_BlockY, a_BlockZ);
@ -2294,14 +2309,14 @@ bool cChunk::GenericDoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ
{ {
return false; // Not any of the given tBlocktypes return false; // Not any of the given tBlocktypes
} }
return !a_Callback(*static_cast<tyEntity *>(Block)); return !a_Callback.Item(static_cast<tyEntity *>(Block));
} }
bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback) bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cBlockEntity>(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return GenericDoWithBlockEntityAt<cBlockEntity>(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -2309,7 +2324,7 @@ bool cChunk::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const
bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBeaconCallback & a_Callback) bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cBeaconEntity, return GenericDoWithBlockEntityAt<cBeaconEntity,
E_BLOCK_BEACON E_BLOCK_BEACON
@ -2319,7 +2334,7 @@ bool cChunk::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBea
bool cChunk::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCallback & a_Callback) bool cChunk::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cBedEntity, return GenericDoWithBlockEntityAt<cBedEntity,
E_BLOCK_BED E_BLOCK_BED
@ -2329,7 +2344,7 @@ bool cChunk::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCal
bool cChunk::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBrewingstandCallback & a_Callback) bool cChunk::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cBrewingstandEntity, return GenericDoWithBlockEntityAt<cBrewingstandEntity,
E_BLOCK_BREWING_STAND E_BLOCK_BREWING_STAND
@ -2340,7 +2355,7 @@ bool cChunk::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cons
bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChestCallback & a_Callback) bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cChestEntity, return GenericDoWithBlockEntityAt<cChestEntity,
E_BLOCK_CHEST, E_BLOCK_CHEST,
@ -2352,7 +2367,7 @@ bool cChunk::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChes
bool cChunk::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDispenserCallback & a_Callback) bool cChunk::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cDispenserEntity, return GenericDoWithBlockEntityAt<cDispenserEntity,
E_BLOCK_DISPENSER E_BLOCK_DISPENSER
@ -2363,7 +2378,7 @@ bool cChunk::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const c
bool cChunk::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropperCallback & a_Callback) bool cChunk::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cDropperEntity, return GenericDoWithBlockEntityAt<cDropperEntity,
E_BLOCK_DROPPER E_BLOCK_DROPPER
@ -2374,7 +2389,7 @@ bool cChunk::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDr
bool cChunk::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropSpenserCallback & a_Callback) bool cChunk::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cDropSpenserEntity, return GenericDoWithBlockEntityAt<cDropSpenserEntity,
E_BLOCK_DISPENSER, E_BLOCK_DISPENSER,
@ -2386,7 +2401,7 @@ bool cChunk::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const
bool cChunk::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFurnaceCallback & a_Callback) bool cChunk::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cFurnaceEntity, return GenericDoWithBlockEntityAt<cFurnaceEntity,
E_BLOCK_FURNACE, E_BLOCK_FURNACE,
@ -2398,7 +2413,7 @@ bool cChunk::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFu
bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cNoteBlockCallback & a_Callback) bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cNoteEntity, return GenericDoWithBlockEntityAt<cNoteEntity,
E_BLOCK_NOTE_BLOCK E_BLOCK_NOTE_BLOCK
@ -2409,7 +2424,7 @@ bool cChunk::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const c
bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cCommandBlockCallback & a_Callback) bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cCommandBlockEntity, return GenericDoWithBlockEntityAt<cCommandBlockEntity,
E_BLOCK_COMMAND_BLOCK E_BLOCK_COMMAND_BLOCK
@ -2420,7 +2435,7 @@ bool cChunk::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cons
bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMobHeadCallback & a_Callback) bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cMobHeadEntity, return GenericDoWithBlockEntityAt<cMobHeadEntity,
E_BLOCK_HEAD E_BLOCK_HEAD
@ -2431,7 +2446,7 @@ bool cChunk::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMo
bool cChunk::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFlowerPotCallback & a_Callback) bool cChunk::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{ {
return GenericDoWithBlockEntityAt<cFlowerPotEntity, return GenericDoWithBlockEntityAt<cFlowerPotEntity,
E_BLOCK_FLOWER_POT E_BLOCK_FLOWER_POT

View File

@ -1,4 +1,4 @@

#pragma once #pragma once
#include "Entities/Entity.h" #include "Entities/Entity.h"
@ -37,7 +37,18 @@ class cMobCensus;
class cMobSpawner; class cMobSpawner;
class cSetChunkData; class cSetChunkData;
typedef std::list<cClientHandle *> cClientHandleList; typedef std::list<cClientHandle *> cClientHandleList;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBeaconEntity> cBeaconCallback;
typedef cItemCallback<cBedEntity> cBedCallback;
typedef cItemCallback<cBrewingstandEntity> cBrewingstandCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
// A convenience macro for calling GetChunkAndRelByAbsolute. // A convenience macro for calling GetChunkAndRelByAbsolute.
#define PREPARE_REL_AND_CHUNK(Position, OriginalChunk) cChunk * Chunk; Vector3i Rel; bool RelSuccess = (OriginalChunk).GetChunkAndRelByAbsolute(Position, &Chunk, Rel); #define PREPARE_REL_AND_CHUNK(Position, OriginalChunk) cChunk * Chunk; Vector3i Rel; bool RelSuccess = (OriginalChunk).GetChunkAndRelByAbsolute(Position, &Chunk, Rel);
@ -247,86 +258,87 @@ public:
bool HasEntity(UInt32 a_EntityID); bool HasEntity(UInt32 a_EntityID);
/** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */ /** Calls the callback for each entity; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntity(const cEntityCallback & a_Callback); // Lua-accessible bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox. /** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Returns true if all entities processed, false if the callback aborted by returning true. */ Returns true if all entities processed, false if the callback aborted by returning true. */
bool ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallback & a_Callback); // Lua-accessible bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */ /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found. */
bool DoWithEntityByID(UInt32 a_EntityID, const cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback, bool & a_CallbackResult); // Lua-accessible
bool DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback, bool & a_CallbackResult); // Lambda version
/** Calls the callback for each tyEntity; returns true if all block entities processed, false if the callback aborted by returning true /** Calls the callback for each tyEntity; returns true if all block entities processed, false if the callback aborted by returning true
tBlocktypes are all blocktypes convertible to tyEntity which are to be called. If no block type is given the callback is called for every block entity tBlocktypes are all blocktypes convertible to tyEntity which are to be called. If no block type is given the callback is called for every block entity
Accessible only from within Chunk.cpp */ Accessible only from within Chunk.cpp */
template <class tyEntity, BLOCKTYPE... tBlocktype> template <class tyEntity, BLOCKTYPE... tBlocktype>
bool GenericForEachBlockEntity(const std::function<bool(tyEntity &)> & a_Callback); bool GenericForEachBlockEntity(cItemCallback<tyEntity>& a_Callback);
/** Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true */ /** Calls the callback for each block entity; returns true if all block entities processed, false if the callback aborted by returning true */
bool ForEachBlockEntity(const cBlockEntityCallback & a_Callback); // Lua-accessible bool ForEachBlockEntity(cBlockEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback for each brewingstand; returns true if all brewingstands processed, false if the callback aborted by returning true */ /** Calls the callback for each brewingstand; returns true if all brewingstands processed, false if the callback aborted by returning true */
bool ForEachBrewingstand(const cBrewingstandCallback & a_Callback); // Lua-accessible bool ForEachBrewingstand(cBrewingstandCallback & a_Callback); // Lua-accessible
/** Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true */ /** Calls the callback for each chest; returns true if all chests processed, false if the callback aborted by returning true */
bool ForEachChest(const cChestCallback & a_Callback); // Lua-accessible bool ForEachChest(cChestCallback & a_Callback); // Lua-accessible
/** Calls the callback for each dispenser; returns true if all dispensers processed, false if the callback aborted by returning true */ /** Calls the callback for each dispenser; returns true if all dispensers processed, false if the callback aborted by returning true */
bool ForEachDispenser(const cDispenserCallback & a_Callback); bool ForEachDispenser(cDispenserCallback & a_Callback);
/** Calls the callback for each dropper; returns true if all droppers processed, false if the callback aborted by returning true */ /** Calls the callback for each dropper; returns true if all droppers processed, false if the callback aborted by returning true */
bool ForEachDropper(const cDropperCallback & a_Callback); bool ForEachDropper(cDropperCallback & a_Callback);
/** Calls the callback for each dropspenser; returns true if all dropspensers processed, false if the callback aborted by returning true */ /** Calls the callback for each dropspenser; returns true if all dropspensers processed, false if the callback aborted by returning true */
bool ForEachDropSpenser(const cDropSpenserCallback & a_Callback); bool ForEachDropSpenser(cDropSpenserCallback & a_Callback);
/** Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true */ /** Calls the callback for each furnace; returns true if all furnaces processed, false if the callback aborted by returning true */
bool ForEachFurnace(const cFurnaceCallback & a_Callback); // Lua-accessible bool ForEachFurnace(cFurnaceCallback & a_Callback); // Lua-accessible
/** Calls the callback for the tyEntity at the specified coords; returns false if there's no such block entity at those coords, true if found /** Calls the callback for the tyEntity at the specified coords; returns false if there's no such block entity at those coords, true if found
tBlocktype is a list of the blocktypes to be called. If no BLOCKTYPE template arguments are given the callback is called for any block entity tBlocktype is a list of the blocktypes to be called. If no BLOCKTYPE template arguments are given the callback is called for any block entity
Accessible only from within Chunk.cpp */ Accessible only from within Chunk.cpp */
template <class tyEntity, BLOCKTYPE... tBlocktype> template <class tyEntity, BLOCKTYPE... tBlocktype>
bool GenericDoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const std::function<bool(tyEntity &)> & a_Callback); bool GenericDoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cItemCallback<tyEntity>& a_Callback);
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback); // Lua-acessible bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible
/** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBeaconCallback & a_Callback); // Lua-acessible bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible
/** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */ /** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */
bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBrewingstandCallback & a_Callback); // Lua-acessible bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback); // Lua-acessible
/** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */ /** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */
bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCallback & a_Callback); // Lua-acessible bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback); // Lua-acessible
/** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChestCallback & a_Callback); // Lua-acessible bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */ /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDispenserCallback & a_Callback); bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback);
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */ /** Calls the callback for the dispenser at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */
bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropperCallback & a_Callback); bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback);
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */ /** Calls the callback for the dispenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */
bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropSpenserCallback & a_Callback); bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback);
/** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */ /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFurnaceCallback & a_Callback); // Lua-accessible bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible
/** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */ /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cNoteBlockCallback & a_Callback); bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback);
/** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cCommandBlockCallback & a_Callback); bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback);
/** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMobHeadCallback & a_Callback); bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback);
/** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */ /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFlowerPotCallback & a_Callback); bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback);
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Lua-accessible

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "ChunkMap.h" #include "ChunkMap.h"
@ -731,7 +731,7 @@ bool cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i
bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, const cChunkCallback & a_Callback) bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, a_ChunkZ);
@ -739,15 +739,30 @@ bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, const cChunkCallback & a
{ {
return false; return false;
} }
return a_Callback(*Chunk); return a_Callback.Item(Chunk);
} }
bool cChunkMap::DoWithChunkAt(Vector3i a_BlockPos, const cChunkCallback & a_Callback) bool cChunkMap::DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(a_BlockPos.x, a_BlockPos.z, ChunkX, ChunkZ); cChunkDef::BlockToChunk(a_BlockPos.x, a_BlockPos.z, ChunkX, ChunkZ);
return DoWithChunk(ChunkX, ChunkZ, a_Callback); struct cCallBackWrapper : cChunkCallback
{
cCallBackWrapper(std::function<bool(cChunk &)> a_InnerCallback) :
m_Callback(a_InnerCallback)
{
}
virtual bool Item(cChunk * a_Chunk)
{
return m_Callback(*a_Chunk);
}
private:
std::function<bool(cChunk &)> m_Callback;
} callback(a_Callback);
return DoWithChunk(ChunkX, ChunkZ, callback);
} }
@ -1583,7 +1598,7 @@ OwnedEntity cChunkMap::RemoveEntity(cEntity & a_Entity)
bool cChunkMap::ForEachEntity(const cEntityCallback & a_Callback) bool cChunkMap::ForEachEntity(cEntityCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
for (const auto & Chunk : m_Chunks) for (const auto & Chunk : m_Chunks)
@ -1600,7 +1615,7 @@ bool cChunkMap::ForEachEntity(const cEntityCallback & a_Callback)
bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, const cEntityCallback & a_Callback) bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1615,7 +1630,7 @@ bool cChunkMap::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, const cEntityCa
bool cChunkMap::ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallback & a_Callback) bool cChunkMap::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback)
{ {
// Calculate the chunk range for the box: // Calculate the chunk range for the box:
int MinChunkX = FloorC(a_Box.GetMinX() / cChunkDef::Width); int MinChunkX = FloorC(a_Box.GetMinX() / cChunkDef::Width);
@ -1777,41 +1792,60 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
area.Write(*m_World, bx - ExplosionSizeInt, MinY, bz - ExplosionSizeInt); area.Write(*m_World, bx - ExplosionSizeInt, MinY, bz - ExplosionSizeInt);
} }
Vector3d ExplosionPos{ a_BlockX, a_BlockY, a_BlockZ }; class cTNTDamageCallback :
cBoundingBox bbTNT(ExplosionPos, 0.5, 1); public cEntityCallback
bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2); {
public:
ForEachEntity([&](cEntity & a_Entity) cTNTDamageCallback(cBoundingBox & a_CBBBTNT, Vector3d a_CBExplosionPos, int a_CBExplosionSize) :
m_bbTNT(a_CBBBTNT),
m_ExplosionPos(a_CBExplosionPos),
m_ExplosionSize(a_CBExplosionSize)
{ {
if (a_Entity.IsPickup() && (a_Entity.GetTicksAlive() < 20)) }
virtual bool Item(cEntity * a_Entity) override
{
if (a_Entity->IsPickup() && (a_Entity->GetTicksAlive() < 20))
{ {
// If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned) // If pickup age is smaller than one second, it is invincible (so we don't kill pickups that were just spawned)
return false; return false;
} }
Vector3d DistanceFromExplosion = a_Entity.GetPosition() - ExplosionPos; Vector3d DistanceFromExplosion = a_Entity->GetPosition() - m_ExplosionPos;
if (!a_Entity.IsTNT() && !a_Entity.IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible if (!a_Entity->IsTNT() && !a_Entity->IsFallingBlock()) // Don't apply damage to other TNT entities and falling blocks, they should be invincible
{ {
cBoundingBox bbEntity(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
if (!bbTNT.IsInside(bbEntity)) // If bbEntity is inside bbTNT, not vice versa! if (!m_bbTNT.IsInside(bbEntity)) // If bbEntity is inside bbTNT, not vice versa!
{ {
return false; return false;
} }
// Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit // Ensure that the damage dealt is inversely proportional to the distance to the TNT centre - the closer a player is, the harder they are hit
a_Entity.TakeDamage(dtExplosion, nullptr, static_cast<int>((1 / DistanceFromExplosion.Length()) * 6 * ExplosionSizeInt), 0); a_Entity->TakeDamage(dtExplosion, nullptr, static_cast<int>((1 / DistanceFromExplosion.Length()) * 6 * m_ExplosionSize), 0);
} }
// Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt() // Apply force to entities around the explosion - code modified from World.cpp DoExplosionAt()
DistanceFromExplosion.Normalize(); DistanceFromExplosion.Normalize();
DistanceFromExplosion *= ExplosionSizeInt * ExplosionSizeInt; DistanceFromExplosion *= m_ExplosionSize * m_ExplosionSize;
a_Entity.AddSpeed(DistanceFromExplosion); a_Entity->AddSpeed(DistanceFromExplosion);
return false; return false;
} }
);
protected:
cBoundingBox & m_bbTNT;
Vector3d m_ExplosionPos;
int m_ExplosionSize;
};
cBoundingBox bbTNT(Vector3d(a_BlockX, a_BlockY, a_BlockZ), 0.5, 1);
bbTNT.Expand(ExplosionSizeInt * 2, ExplosionSizeInt * 2, ExplosionSizeInt * 2);
cTNTDamageCallback TNTDamageCallback(bbTNT, Vector3d(a_BlockX, a_BlockY, a_BlockZ), ExplosionSizeInt);
ForEachEntity(TNTDamageCallback);
// Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391): // Wake up all simulators for the area, so that water and lava flows and sand falls into the blasted holes (FS #391):
m_World->GetSimulatorManager()->WakeUpArea(cCuboid( m_World->GetSimulatorManager()->WakeUpArea(cCuboid(
@ -1824,7 +1858,16 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_
bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, const cEntityCallback & a_Callback) bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback)
{
return DoWithEntityByID(a_UniqueID, std::bind(&cEntityCallback::Item, &a_Callback, std::placeholders::_1));
}
bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
bool res = false; bool res = false;
@ -1842,7 +1885,7 @@ bool cChunkMap::DoWithEntityByID(UInt32 a_UniqueID, const cEntityCallback & a_Ca
bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, const cBlockEntityCallback & a_Callback) bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1857,7 +1900,7 @@ bool cChunkMap::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, const cBlo
bool cChunkMap::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, const cBrewingstandCallback & a_Callback) bool cChunkMap::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1872,7 +1915,7 @@ bool cChunkMap::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, const cBr
bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, const cChestCallback & a_Callback) bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1887,7 +1930,7 @@ bool cChunkMap::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, const cChestCall
bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, const cDispenserCallback & a_Callback) bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1902,7 +1945,7 @@ bool cChunkMap::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, const cDispe
bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, const cDropperCallback & a_Callback) bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1917,7 +1960,7 @@ bool cChunkMap::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, const cDropper
bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, const cDropSpenserCallback & a_Callback) bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1932,7 +1975,7 @@ bool cChunkMap::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, const cDro
bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, const cFurnaceCallback & a_Callback) bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ); cChunkPtr Chunk = GetChunkNoGen(a_ChunkX, a_ChunkZ);
@ -1947,7 +1990,7 @@ bool cChunkMap::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, const cFurnace
bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback) bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -1965,7 +2008,7 @@ bool cChunkMap::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, co
bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBeaconCallback & a_Callback) bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -1983,7 +2026,7 @@ bool cChunkMap::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const c
bool cChunkMap::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCallback & a_Callback) bool cChunkMap::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2001,7 +2044,7 @@ bool cChunkMap::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBed
bool cChunkMap::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBrewingstandCallback & a_Callback) bool cChunkMap::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2019,7 +2062,7 @@ bool cChunkMap::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChestCallback & a_Callback) bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2037,7 +2080,7 @@ bool cChunkMap::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cC
bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDispenserCallback & a_Callback) bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2055,7 +2098,7 @@ bool cChunkMap::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cons
bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropperCallback & a_Callback) bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2073,7 +2116,7 @@ bool cChunkMap::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const
bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropSpenserCallback & a_Callback) bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2091,7 +2134,7 @@ bool cChunkMap::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, co
bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFurnaceCallback & a_Callback) bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2108,7 +2151,7 @@ bool cChunkMap::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const
bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cNoteBlockCallback & a_Callback) bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2125,7 +2168,7 @@ bool cChunkMap::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cons
bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cCommandBlockCallback & a_Callback) bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2143,7 +2186,7 @@ bool cChunkMap::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, c
bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMobHeadCallback & a_Callback) bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2161,7 +2204,7 @@ bool cChunkMap::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const
bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFlowerPotCallback & a_Callback) bool cChunkMap::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{ {
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ; int BlockX = a_BlockX, BlockY = a_BlockY, BlockZ = a_BlockZ;
@ -2399,7 +2442,7 @@ bool cChunkMap::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinCh
bool cChunkMap::ForEachLoadedChunk(const std::function<bool(int, int)> & a_Callback) bool cChunkMap::ForEachLoadedChunk(std::function<bool(int, int)> a_Callback)
{ {
cCSLock Lock(m_CSChunks); cCSLock Lock(m_CSChunks);
for (const auto & Chunk : m_Chunks) for (const auto & Chunk : m_Chunks)

View File

@ -1,4 +1,4 @@

// cChunkMap.h // cChunkMap.h
// Interfaces to the cChunkMap class representing the chunk storage for a single world // Interfaces to the cChunkMap class representing the chunk storage for a single world
@ -38,23 +38,25 @@ class cSetChunkData;
class cBoundingBox; class cBoundingBox;
class cDeadlockDetect; class cDeadlockDetect;
typedef std::list<cClientHandle *> cClientHandleList; typedef std::list<cClientHandle *> cClientHandleList;
typedef cChunk * cChunkPtr; typedef cChunk * cChunkPtr;
using cEntityCallback = std::function<bool(cEntity &)>; typedef cItemCallback<cEntity> cEntityCallback;
using cBeaconCallback = std::function<bool(cBeaconEntity &)>; typedef cItemCallback<cBlockEntity> cBlockEntityCallback;
using cBedCallback = std::function<bool(cBedEntity &)>; typedef cItemCallback<cBeaconEntity> cBeaconCallback;
using cBlockEntityCallback = std::function<bool(cBlockEntity &)>; typedef cItemCallback<cBedEntity> cBedCallback;
using cBrewingstandCallback = std::function<bool(cBrewingstandEntity &)>; typedef cItemCallback<cBrewingstandEntity> cBrewingstandCallback;
using cChestCallback = std::function<bool(cChestEntity &)>; typedef cItemCallback<cChestEntity> cChestCallback;
using cChunkCallback = std::function<bool(cChunk &)>; typedef cItemCallback<cDispenserEntity> cDispenserCallback;
using cDispenserCallback = std::function<bool(cDispenserEntity &)>; typedef cItemCallback<cDropperEntity> cDropperCallback;
using cDropperCallback = std::function<bool(cDropperEntity &)>; typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback;
using cDropSpenserCallback = std::function<bool(cDropSpenserEntity &)>; typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
using cFurnaceCallback = std::function<bool(cFurnaceEntity &)>; typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
using cNoteBlockCallback = std::function<bool(cNoteEntity &)>; typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
using cCommandBlockCallback = std::function<bool(cCommandBlockEntity &)>; typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
using cMobHeadCallback = std::function<bool(cMobHeadEntity &)>; typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
using cFlowerPotCallback = std::function<bool(cFlowerPotEntity &)>; typedef cItemCallback<cChunk> cChunkCallback;
typedef std::function<bool (cEntity *)> cLambdaEntityCallback;
@ -104,10 +106,10 @@ public:
bool UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); bool UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z);
/** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */ /** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, const cChunkCallback & a_Callback); bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
/** Calls the callback for the chunk at the block position specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */ /** Calls the callback for the chunk at the block position specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */
bool DoWithChunkAt(Vector3i a_BlockPos, const cChunkCallback & a_Callback); bool DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback);
/** Wakes up simulators for the specified block */ /** Wakes up simulators for the specified block */
void WakeUpSimulators(Vector3i a_Block); void WakeUpSimulators(Vector3i a_Block);
@ -228,101 +230,102 @@ public:
OwnedEntity RemoveEntity(cEntity & a_Entity); OwnedEntity RemoveEntity(cEntity & a_Entity);
/** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntity(const cEntityCallback & a_Callback); // Lua-accessible bool ForEachEntity(cEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */ /** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, const cEntityCallback & a_Callback); // Lua-accessible bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox. /** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Returns true if all entities processed, false if the callback aborted by returning true. Returns true if all entities processed, false if the callback aborted by returning true.
If any chunk in the box is missing, ignores the entities in that chunk silently. */ If any chunk in the box is missing, ignores the entities in that chunk silently. */
bool ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallback & a_Callback); // Lua-accessible bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback); // Lua-accessible
/** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */ /** Destroys and returns a list of blocks destroyed in the explosion at the specified coordinates */
void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected); void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, cVector3iArray & a_BlockAffected);
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param.
Returns true if entity found and callback returned false. */ Returns true if entity found and callback returned false. */
bool DoWithEntityByID(UInt32 a_EntityID, const cEntityCallback & a_Callback); // Lua-accessible bool DoWithEntityByID(UInt32 a_EntityID, cEntityCallback & a_Callback); // Lua-accessible
bool DoWithEntityByID(UInt32 a_EntityID, cLambdaEntityCallback a_Callback); // Lambda version
/** Calls the callback for each block entity in the specified chunk. /** Calls the callback for each block entity in the specified chunk.
Returns true if all block entities processed, false if the callback aborted by returning true. */ Returns true if all block entities processed, false if the callback aborted by returning true. */
bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, const cBlockEntityCallback & a_Callback); // Lua-accessible bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Lua-accessible
/** Calls the callback for brewingstand in the specified chunk. /** Calls the callback for brewingstand in the specified chunk.
Returns true if all brewingstands processed, false if the callback aborted by returning true. */ Returns true if all brewingstands processed, false if the callback aborted by returning true. */
bool ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, const cBrewingstandCallback & a_Callback); // Lua-accessible bool ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback & a_Callback); // Lua-accessible
/** Calls the callback for each chest in the specified chunk. /** Calls the callback for each chest in the specified chunk.
Returns true if all chests processed, false if the callback aborted by returning true. */ Returns true if all chests processed, false if the callback aborted by returning true. */
bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, const cChestCallback & a_Callback); // Lua-accessible bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Lua-accessible
/** Calls the callback for each dispenser in the specified chunk. /** Calls the callback for each dispenser in the specified chunk.
Returns true if all dispensers processed, false if the callback aborted by returning true. */ Returns true if all dispensers processed, false if the callback aborted by returning true. */
bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, const cDispenserCallback & a_Callback); bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
/** Calls the callback for each dropper in the specified chunk. /** Calls the callback for each dropper in the specified chunk.
Returns true if all droppers processed, false if the callback aborted by returning true. */ Returns true if all droppers processed, false if the callback aborted by returning true. */
bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, const cDropperCallback & a_Callback); bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
/** Calls the callback for each dropspenser in the specified chunk. /** Calls the callback for each dropspenser in the specified chunk.
Returns true if all dropspensers processed, false if the callback aborted by returning true. */ Returns true if all dropspensers processed, false if the callback aborted by returning true. */
bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, const cDropSpenserCallback & a_Callback); bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
/** Calls the callback for each furnace in the specified chunk. /** Calls the callback for each furnace in the specified chunk.
Returns true if all furnaces processed, false if the callback aborted by returning true. */ Returns true if all furnaces processed, false if the callback aborted by returning true. */
bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, const cFurnaceCallback & a_Callback); // Lua-accessible bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Lua-accessible
/** Calls the callback for the block entity at the specified coords. /** Calls the callback for the block entity at the specified coords.
Returns false if there's no block entity at those coords, true if found. */ Returns false if there's no block entity at those coords, true if found. */
bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback); // Lua-acessible bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback); // Lua-acessible
/** Calls the callback for the beacon at the specified coords. /** Calls the callback for the beacon at the specified coords.
Returns false if there's no beacon at those coords, true if found. */ Returns false if there's no beacon at those coords, true if found. */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBeaconCallback & a_Callback); // Lua-acessible bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Lua-acessible
/** Calls the callback for the bed at the specified coords. /** Calls the callback for the bed at the specified coords.
Returns false if there's no bed at those coords, true if found. */ Returns false if there's no bed at those coords, true if found. */
bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCallback & a_Callback); // Lua-acessible bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback); // Lua-acessible
/** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */ /** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */
bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBrewingstandCallback & a_Callback); // Lua-acessible bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback); // Lua-acessible
/** Calls the callback for the chest at the specified coords. /** Calls the callback for the chest at the specified coords.
Returns false if there's no chest at those coords, true if found. */ Returns false if there's no chest at those coords, true if found. */
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChestCallback & a_Callback); // Lua-acessible bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Lua-acessible
/** Calls the callback for the dispenser at the specified coords. /** Calls the callback for the dispenser at the specified coords.
Returns false if there's no dispenser at those coords or callback returns true, returns true if found. */ Returns false if there's no dispenser at those coords or callback returns true, returns true if found. */
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDispenserCallback & a_Callback); // Lua-accessible bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Lua-accessible
/** Calls the callback for the dropper at the specified coords. /** Calls the callback for the dropper at the specified coords.
Returns false if there's no dropper at those coords or callback returns true, returns true if found. */ Returns false if there's no dropper at those coords or callback returns true, returns true if found. */
bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropperCallback & a_Callback); // Lua-accessible bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Lua-accessible
/** Calls the callback for the dropspenser at the specified coords. /** Calls the callback for the dropspenser at the specified coords.
Returns false if there's no dropspenser at those coords or callback returns true, returns true if found. */ Returns false if there's no dropspenser at those coords or callback returns true, returns true if found. */
bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropSpenserCallback & a_Callback); // Lua-accessible bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Lua-accessible
/** Calls the callback for the furnace at the specified coords. /** Calls the callback for the furnace at the specified coords.
Returns false if there's no furnace at those coords or callback returns true, returns true if found. */ Returns false if there's no furnace at those coords or callback returns true, returns true if found. */
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFurnaceCallback & a_Callback); // Lua-accessible bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Lua-accessible
/** Calls the callback for the noteblock at the specified coords. /** Calls the callback for the noteblock at the specified coords.
Returns false if there's no noteblock at those coords or callback returns true, returns true if found. */ Returns false if there's no noteblock at those coords or callback returns true, returns true if found. */
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cNoteBlockCallback & a_Callback); // Lua-accessible bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Lua-accessible
/** Calls the callback for the command block at the specified coords. /** Calls the callback for the command block at the specified coords.
Returns false if there's no command block at those coords or callback returns true, returns true if found. */ Returns false if there's no command block at those coords or callback returns true, returns true if found. */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cCommandBlockCallback & a_Callback); // Lua-accessible bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Lua-accessible
/** Calls the callback for the mob head block at the specified coords. /** Calls the callback for the mob head block at the specified coords.
Returns false if there's no mob head block at those coords or callback returns true, returns true if found. */ Returns false if there's no mob head block at those coords or callback returns true, returns true if found. */
bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMobHeadCallback & a_Callback); // Lua-accessible bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Lua-accessible
/** Calls the callback for the flower pot at the specified coords. /** Calls the callback for the flower pot at the specified coords.
Returns false if there's no flower pot at those coords or callback returns true, returns true if found. */ Returns false if there's no flower pot at those coords or callback returns true, returns true if found. */
bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFlowerPotCallback & a_Callback); // Lua-accessible bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback); // Lua-accessible
/** Retrieves the test on the sign at the specified coords. /** Retrieves the test on the sign at the specified coords.
Returns false if there's no sign at those coords, true if found. */ Returns false if there's no sign at those coords, true if found. */
@ -360,7 +363,7 @@ public:
bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback); bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback);
/** Calls the callback for each loaded chunk. Returns true if all chunks have been processed successfully */ /** Calls the callback for each loaded chunk. Returns true if all chunks have been processed successfully */
bool ForEachLoadedChunk(const std::function<bool(int, int)> & a_Callback); bool ForEachLoadedChunk(std::function<bool(int, int)> a_Callback);
/** Writes the block area into the specified coords. Returns true if all chunks have been processed. Prefer cBlockArea::Write() instead. */ /** Writes the block area into the specified coords. Returns true if all chunks have been processed. Prefer cBlockArea::Write() instead. */
bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes); bool WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlockY, int a_MinBlockZ, int a_DataTypes);

View File

@ -1660,9 +1660,9 @@ void cClientHandle::HandleSlotSelected(Int16 a_SlotNum)
void cClientHandle::HandleSpectate(const cUUID & a_PlayerUUID) void cClientHandle::HandleSpectate(const cUUID & a_PlayerUUID)
{ {
m_Player->GetWorld()->DoWithPlayerByUUID(a_PlayerUUID, [=](cPlayer & a_ToSpectate) m_Player->GetWorld()->DoWithPlayerByUUID(a_PlayerUUID, [=](cPlayer * a_ToSpectate)
{ {
m_Player->TeleportToEntity(a_ToSpectate); m_Player->TeleportToEntity(*a_ToSpectate);
return true; return true;
}); });
} }
@ -1734,9 +1734,9 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
// If the player is a spectator, let him spectate // If the player is a spectator, let him spectate
if (m_Player->IsGameModeSpectator() && a_IsLeftClick) if (m_Player->IsGameModeSpectator() && a_IsLeftClick)
{ {
m_Player->GetWorld()->DoWithEntityByID(a_TargetEntityID, [=](cEntity & a_Entity) m_Player->GetWorld()->DoWithEntityByID(a_TargetEntityID, [=](cEntity * a_Entity)
{ {
m_Player->AttachTo(&a_Entity); m_Player->AttachTo(a_Entity);
return true; return true;
}); });
return; return;
@ -1745,18 +1745,20 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
// If it is a right click, call the entity's OnRightClicked() handler: // If it is a right click, call the entity's OnRightClicked() handler:
if (!a_IsLeftClick) if (!a_IsLeftClick)
{ {
cWorld * World = m_Player->GetWorld(); class cRclkEntity : public cEntityCallback
World->DoWithEntityByID(a_TargetEntityID, [=](cEntity & a_Entity) {
cPlayer & m_Player;
virtual bool Item(cEntity * a_Entity) override
{ {
if ( if (
cPluginManager::Get()->CallHookPlayerRightClickingEntity(*m_Player, a_Entity) || cPluginManager::Get()->CallHookPlayerRightClickingEntity(m_Player, *a_Entity) ||
( (
m_Player->IsGameModeSpectator() && // Spectators cannot interact with every entity m_Player.IsGameModeSpectator() && // Spectators cannot interact with every entity
( (
!a_Entity.IsMinecart() || // They can only interact with minecarts !a_Entity->IsMinecart() || // They can only interact with minecarts
( (
(static_cast<cMinecart &>(a_Entity).GetPayload() != cMinecart::mpChest) && // And only if the type matches a minecart with a chest or (reinterpret_cast<cMinecart *>(a_Entity)->GetPayload() != cMinecart::mpChest) && // And only if the type matches a minecart with a chest or
(static_cast<cMinecart &>(a_Entity).GetPayload() != cMinecart::mpHopper) // a minecart with a hopper (reinterpret_cast<cMinecart *>(a_Entity)->GetPayload() != cMinecart::mpHopper) // a minecart with a hopper
) )
) )
) )
@ -1764,34 +1766,52 @@ void cClientHandle::HandleUseEntity(UInt32 a_TargetEntityID, bool a_IsLeftClick)
{ {
return false; return false;
} }
a_Entity.OnRightClicked(*m_Player); a_Entity->OnRightClicked(m_Player);
return false; return false;
} }
); public:
cRclkEntity(cPlayer & a_Player) : m_Player(a_Player) {}
} Callback (*m_Player);
cWorld * World = m_Player->GetWorld();
World->DoWithEntityByID(a_TargetEntityID, Callback);
return; return;
} }
// If it is a left click, attack the entity: // If it is a left click, attack the entity:
m_Player->GetWorld()->DoWithEntityByID(a_TargetEntityID, [=](cEntity & a_Entity) class cDamageEntity : public cEntityCallback
{
public:
cPlayer * m_Me;
cDamageEntity(cPlayer * a_Player) :
m_Me(a_Player)
{ {
if (!a_Entity.GetWorld()->IsPVPEnabled()) }
virtual bool Item(cEntity * a_Entity) override
{
if (!a_Entity->GetWorld()->IsPVPEnabled())
{ {
// PVP is disabled, disallow players hurting other players: // PVP is disabled, disallow players hurting other players:
if (a_Entity.IsPlayer()) if (a_Entity->IsPlayer())
{ {
// Player is hurting another player which is not allowed when PVP is disabled so ignore it // Player is hurting another player which is not allowed when PVP is disabled so ignore it
return true; return true;
} }
} }
a_Entity.TakeDamage(*m_Player); a_Entity->TakeDamage(*m_Me);
m_Player->AddFoodExhaustion(0.3); m_Me->AddFoodExhaustion(0.3);
if (a_Entity.IsPawn()) if (a_Entity->IsPawn())
{ {
m_Player->NotifyNearbyWolves(static_cast<cPawn*>(&a_Entity), true); m_Me->NotifyNearbyWolves(static_cast<cPawn*>(a_Entity), true);
} }
return true; return true;
} }
); } Callback(m_Player);
cWorld * World = m_Player->GetWorld();
World->DoWithEntityByID(a_TargetEntityID, Callback);
} }
@ -1840,8 +1860,17 @@ bool cClientHandle::CheckMultiLogin(const AString & a_Username)
return false; return false;
} }
class cCallback :
public cPlayerListCallback
{
virtual bool Item(cPlayer * a_Player) override
{
return true;
}
} Callback;
// Check if the player is in any World. // Check if the player is in any World.
if (cRoot::Get()->DoWithPlayer(a_Username, [](cPlayer &) { return true; })) if (cRoot::Get()->DoWithPlayer(a_Username, Callback))
{ {
Kick("A player of the username is already logged in"); Kick("A player of the username is already logged in");
return false; return false;

View File

@ -56,12 +56,25 @@ bool cDeadlockDetect::Start(int a_IntervalSec)
m_IntervalSec = a_IntervalSec; m_IntervalSec = a_IntervalSec;
// Read the initial world data: // Read the initial world data:
cRoot::Get()->ForEachWorld([=](cWorld & a_World) class cFillIn :
public cWorldListCallback
{
public:
cFillIn(cDeadlockDetect * a_Detect) :
m_Detect(a_Detect)
{ {
SetWorldAge(a_World.GetName(), a_World.GetWorldAge()); }
virtual bool Item(cWorld * a_World) override
{
m_Detect->SetWorldAge(a_World->GetName(), a_World->GetWorldAge());
return false; return false;
} }
);
protected:
cDeadlockDetect * m_Detect;
} FillIn(this);
cRoot::Get()->ForEachWorld(FillIn);
return super::Start(); return super::Start();
} }
@ -102,12 +115,25 @@ void cDeadlockDetect::Execute(void)
while (!m_ShouldTerminate) while (!m_ShouldTerminate)
{ {
// Check the world ages: // Check the world ages:
cRoot::Get()->ForEachWorld([=](cWorld & a_World) class cChecker :
public cWorldListCallback
{
public:
cChecker(cDeadlockDetect * a_Detect) :
m_Detect(a_Detect)
{ {
CheckWorldAge(a_World.GetName(), a_World.GetWorldAge()); }
protected:
cDeadlockDetect * m_Detect;
virtual bool Item(cWorld * a_World) override
{
m_Detect->CheckWorldAge(a_World->GetName(), a_World->GetWorldAge());
return false; return false;
} }
); } Checker(this);
cRoot::Get()->ForEachWorld(Checker);
std::this_thread::sleep_for(std::chrono::milliseconds(CYCLE_MILLISECONDS)); std::this_thread::sleep_for(std::chrono::milliseconds(CYCLE_MILLISECONDS));
} // while (should run) } // while (should run)

View File

@ -304,22 +304,38 @@ void cEntity::TakeDamage(eDamageType a_DamageType, cEntity * a_Attacker, int a_R
void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_RawDamage, double a_KnockbackAmount) void cEntity::TakeDamage(eDamageType a_DamageType, UInt32 a_AttackerID, int a_RawDamage, double a_KnockbackAmount)
{ {
m_World->DoWithEntityByID(a_AttackerID, [=](cEntity & a_Attacker) class cFindEntity : public cEntityCallback
{
public:
cEntity * m_Entity;
eDamageType m_DamageType;
int m_RawDamage;
double m_KnockbackAmount;
virtual bool Item(cEntity * a_Attacker) override
{ {
cPawn * Attacker; cPawn * Attacker;
if (a_Attacker.IsPawn()) if (a_Attacker->IsPawn())
{ {
Attacker = static_cast<cPawn*>(&a_Attacker); Attacker = static_cast<cPawn*>(a_Attacker);
} }
else else
{ {
Attacker = nullptr; Attacker = nullptr;
} }
TakeDamage(a_DamageType, Attacker, a_RawDamage, a_KnockbackAmount);
m_Entity->TakeDamage(m_DamageType, Attacker, m_RawDamage, m_KnockbackAmount);
return true; return true;
} }
); } Callback;
Callback.m_Entity = this;
Callback.m_DamageType = a_DamageType;
Callback.m_RawDamage = a_RawDamage;
Callback.m_KnockbackAmount = a_KnockbackAmount;
m_World->DoWithEntityByID(a_AttackerID, Callback);
} }
@ -650,7 +666,7 @@ bool cEntity::ArmorCoversAgainst(eDamageType a_DamageType)
int cEntity::GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage) int cEntity::GetEnchantmentCoverAgainst(const cEntity * a_Attacker, eDamageType a_DamageType, int a_Damage)
{ {
int TotalEPF = 0; int TotalEPF = 0.0;
const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() }; const cItem ArmorItems[] = { GetEquippedHelmet(), GetEquippedChestplate(), GetEquippedLeggings(), GetEquippedBoots() };
for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++) for (size_t i = 0; i < ARRAYCOUNT(ArmorItems); i++)

View File

@ -13,7 +13,8 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cFloaterEntityCollisionCallback // cFloaterEntityCollisionCallback
class cFloaterEntityCollisionCallback class cFloaterEntityCollisionCallback :
public cEntityCallback
{ {
public: public:
cFloaterEntityCollisionCallback(cFloater * a_Floater, const Vector3d & a_Pos, const Vector3d & a_NextPos) : cFloaterEntityCollisionCallback(cFloater * a_Floater, const Vector3d & a_Pos, const Vector3d & a_NextPos) :
@ -24,14 +25,14 @@ public:
m_HitEntity(nullptr) m_HitEntity(nullptr)
{ {
} }
bool operator () (cEntity & a_Entity) virtual bool Item(cEntity * a_Entity) override
{ {
if (!a_Entity.IsMob()) // Floaters can only pull mobs not other entities. if (!a_Entity->IsMob()) // Floaters can only pull mobs not other entities.
{ {
return false; return false;
} }
cBoundingBox EntBox(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
double LineCoeff; double LineCoeff;
eBlockFace Face; eBlockFace Face;
@ -46,7 +47,7 @@ public:
{ {
// The entity is closer than anything we've stored so far, replace it as the potential victim // The entity is closer than anything we've stored so far, replace it as the potential victim
m_MinCoeff = LineCoeff; m_MinCoeff = LineCoeff;
m_HitEntity = &a_Entity; m_HitEntity = a_Entity;
} }
// Don't break the enumeration, we want all the entities // Don't break the enumeration, we want all the entities
@ -74,6 +75,32 @@ protected:
////////////////////////////////////////////////////////////////////////////////
// cFloaterCheckEntityExist
class cFloaterCheckEntityExist :
public cEntityCallback
{
public:
cFloaterCheckEntityExist(void) :
m_EntityExists(false)
{
}
bool Item(cEntity * a_Entity) override
{
m_EntityExists = true;
return false;
}
bool DoesExist(void) const { return m_EntityExists; }
protected:
bool m_EntityExists;
} ;
cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, UInt32 a_PlayerID, int a_CountDownTime) : cFloater::cFloater(double a_X, double a_Y, double a_Z, Vector3d a_Speed, UInt32 a_PlayerID, int a_CountDownTime) :
cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2), cEntity(etFloater, a_X, a_Y, a_Z, 0.2, 0.2),
m_BitePos(Vector3d(a_X, a_Y, a_Z)), m_BitePos(Vector3d(a_X, a_Y, a_Z)),
@ -173,16 +200,18 @@ void cFloater::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
} }
} }
if (!m_World->DoWithEntityByID(m_PlayerID, [](cEntity &) { return true; })) // The owner doesn't exist anymore. Destroy the floater entity. cFloaterCheckEntityExist EntityCallback;
m_World->DoWithEntityByID(m_PlayerID, EntityCallback);
if (!EntityCallback.DoesExist()) // The owner doesn't exist anymore. Destroy the floater entity.
{ {
Destroy(true); Destroy(true);
} }
if (m_AttachedMobID != cEntity::INVALID_ID) if (m_AttachedMobID != cEntity::INVALID_ID)
{ {
if (!m_World->DoWithEntityByID(m_AttachedMobID, [](cEntity &) { return true; })) m_World->DoWithEntityByID(m_AttachedMobID, EntityCallback); // The mob the floater was attached to doesn't exist anymore.
if (!EntityCallback.DoesExist())
{ {
// The mob the floater was attached to doesn't exist anymore.
m_AttachedMobID = cEntity::INVALID_ID; m_AttachedMobID = cEntity::INVALID_ID;
} }
} }

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "LeashKnot.h" #include "LeashKnot.h"
@ -38,42 +38,58 @@ void cLeashKnot::OnRightClicked(cPlayer & a_Player)
void cLeashKnot::TiePlayersLeashedMobs(cPlayer & a_Player, bool a_ShouldBroadcast) void cLeashKnot::TiePlayersLeashedMobs(cPlayer & a_Player, bool a_ShouldBroadCast)
{ {
// Check leashed nearby mobs to tie them to this knot // Check leashed nearby mobs to tie them to this knot
// taking world from player (instead from this) because this can be called before entity was initialized class LookForLeasheds : public cEntityCallback
a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8, -4), [&](cEntity & a_Entity) {
public:
cLeashKnot * m_Knot;
cPlayer * m_Player;
bool m_ShouldBroadcast;
LookForLeasheds(cLeashKnot * a_Knot, cPlayer * a_PlayerLeashedTo, bool a_ShouldBroadcast) :
m_Knot(a_Knot),
m_Player(a_PlayerLeashedTo),
m_ShouldBroadcast(a_ShouldBroadcast)
{
}
virtual bool Item(cEntity * a_Entity) override
{ {
// If the entity is not a monster skip it // If the entity is not a monster skip it
if (a_Entity.GetEntityType() != cEntity::eEntityType::etMonster) if (a_Entity->GetEntityType() != cEntity::eEntityType::etMonster)
{ {
return false; return false;
} }
auto & PotentialLeashed = static_cast<cMonster&>(a_Entity); cMonster * PotentialLeashed = static_cast<cMonster*>(a_Entity);
// If can't be leashed skip it // If can't be leashed skip it
if (!PotentialLeashed.CanBeLeashed()) if (!PotentialLeashed->CanBeLeashed())
{ {
return false; return false;
} }
// If it's not leashed to the player skip it // If it's not leashed to the player skip it
if ( if (
!PotentialLeashed.IsLeashed() || !PotentialLeashed->IsLeashed() ||
!PotentialLeashed.GetLeashedTo()->IsPlayer() || !PotentialLeashed->GetLeashedTo()->IsPlayer() ||
(PotentialLeashed.GetLeashedTo()->GetUniqueID() != a_Player.GetUniqueID()) (PotentialLeashed->GetLeashedTo()->GetUniqueID() != m_Player->GetUniqueID())
) )
{ {
return false; return false;
} }
// All conditions met, unleash from player and leash to fence // All conditions met, unleash from player and leash to fence
PotentialLeashed.Unleash(false, false); PotentialLeashed->Unleash(false, false);
PotentialLeashed.LeashTo(*this, a_ShouldBroadcast); PotentialLeashed->LeashTo(*m_Knot, m_ShouldBroadcast);
return false; return false;
} }
); } LookForLeashedsCallback(this, &a_Player, a_ShouldBroadCast);
// taking world from player (instead from this) because this can be called before entity was initialized
a_Player.GetWorld()->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8, -4), LookForLeashedsCallback);
} }
@ -142,19 +158,26 @@ void cLeashKnot::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
cLeashKnot * cLeashKnot::FindKnotAtPos(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos) cLeashKnot * cLeashKnot::FindKnotAtPos(cWorldInterface & a_WorldInterface, Vector3i a_BlockPos)
{ {
cLeashKnot * LeashKnot = nullptr; class LookForKnot : public cEntityCallback
a_WorldInterface.ForEachEntityInBox(cBoundingBox(a_BlockPos, 0.5, 1), [&](cEntity & a_Entity) {
public:
cLeashKnot * m_LeashKnot = nullptr;
virtual bool Item(cEntity * a_Entity) override
{ {
if (a_Entity.IsLeashKnot()) if (a_Entity->IsLeashKnot())
{ {
LeashKnot = static_cast<cLeashKnot *>(&a_Entity); m_LeashKnot = reinterpret_cast<cLeashKnot *>(a_Entity);
return true; return true;
} }
return false; return false;
} }
);
return LeashKnot; } CallbackFindKnot;
a_WorldInterface.ForEachEntityInBox(cBoundingBox(a_BlockPos, 0.5, 1), CallbackFindKnot);
return CallbackFindKnot.m_LeashKnot;
} }

View File

@ -20,7 +20,8 @@
class cMinecartCollisionCallback class cMinecartCollisionCallback :
public cEntityCallback
{ {
public: public:
cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, UInt32 a_UniqueID, UInt32 a_AttacheeUniqueID) : cMinecartCollisionCallback(Vector3d a_Pos, double a_Height, double a_Width, UInt32 a_UniqueID, UInt32 a_AttacheeUniqueID) :
@ -34,31 +35,33 @@ public:
{ {
} }
bool operator () (cEntity & a_Entity) virtual bool Item(cEntity * a_Entity) override
{ {
ASSERT(a_Entity != nullptr);
if ( if (
( (
!a_Entity.IsPlayer() || !a_Entity->IsPlayer() ||
static_cast<cPlayer &>(a_Entity).IsGameModeSpectator() // Spectators doesn't collide with anything reinterpret_cast<cPlayer *>(a_Entity)->IsGameModeSpectator() // Spectators doesn't collide with anything
) && ) &&
!a_Entity.IsMob() && !a_Entity->IsMob() &&
!a_Entity.IsMinecart() && !a_Entity->IsMinecart() &&
!a_Entity.IsBoat() !a_Entity->IsBoat()
) )
{ {
return false; return false;
} }
else if ((a_Entity.GetUniqueID() == m_UniqueID) || (a_Entity.GetUniqueID() == m_AttacheeUniqueID)) else if ((a_Entity->GetUniqueID() == m_UniqueID) || (a_Entity->GetUniqueID() == m_AttacheeUniqueID))
{ {
return false; return false;
} }
cBoundingBox bbEntity(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); cBoundingBox bbEntity(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
cBoundingBox bbMinecart(Vector3d(m_Pos.x, floor(m_Pos.y), m_Pos.z), m_Width / 2, m_Height); cBoundingBox bbMinecart(Vector3d(m_Pos.x, floor(m_Pos.y), m_Pos.z), m_Width / 2, m_Height);
if (bbEntity.DoesIntersect(bbMinecart)) if (bbEntity.DoesIntersect(bbMinecart))
{ {
m_CollidedEntityPos = a_Entity.GetPosition(); m_CollidedEntityPos = a_Entity->GetPosition();
m_DoesIntersect = true; m_DoesIntersect = true;
return true; return true;
} }

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Pawn.h" #include "Pawn.h"
@ -80,37 +80,49 @@ void cPawn::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
Effect->OnTick(*this); Effect->OnTick(*this);
} }
// Spectators cannot push entities around class Pusher : public cEntityCallback
if ((!IsPlayer()) || (!static_cast<cPlayer *>(this)->IsGameModeSpectator()))
{ {
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), GetWidth(), GetHeight()), [=](cEntity & a_Entity) public:
cEntity * m_Pusher;
Pusher(cEntity * a_Pusher) :
m_Pusher(a_Pusher)
{
}
virtual bool Item(cEntity * a_Entity) override
{
if (a_Entity->GetUniqueID() == m_Pusher->GetUniqueID())
{ {
if (a_Entity.GetUniqueID() == GetUniqueID())
{
return false;
}
// we only push other mobs, boats and minecarts
if ((a_Entity.GetEntityType() != etMonster) && (a_Entity.GetEntityType() != etMinecart) && (a_Entity.GetEntityType() != etBoat))
{
return false;
}
// do not push a boat / minecart you're sitting in
if (IsAttachedTo(&a_Entity))
{
return false;
}
Vector3d v3Delta = a_Entity.GetPosition() - GetPosition();
v3Delta.y = 0.0; // we only push sideways
v3Delta *= 1.0 / (v3Delta.Length() + 0.01); // we push harder if we're close
// QUESTION: is there an additional multiplier for this? current shoving seems a bit weak
a_Entity.AddSpeed(v3Delta);
return false; return false;
} }
);
// we only push other mobs, boats and minecarts
if ((a_Entity->GetEntityType() != etMonster) && (a_Entity->GetEntityType() != etMinecart) && (a_Entity->GetEntityType() != etBoat))
{
return false;
}
// do not push a boat / minecart you're sitting in
if (m_Pusher->IsAttachedTo(a_Entity))
{
return false;
}
Vector3d v3Delta = a_Entity->GetPosition() - m_Pusher->GetPosition();
v3Delta.y = 0.0; // we only push sideways
v3Delta *= 1.0 / (v3Delta.Length() + 0.01); // we push harder if we're close
// QUESTION: is there an additional multiplier for this? current shoving seems a bit weak
a_Entity->AddSpeed(v3Delta);
return false;
}
} Callback(this);
// Spectators cannot push entities around
if ((!IsPlayer()) || (!reinterpret_cast<cPlayer *>(this)->IsGameModeSpectator()))
{
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), GetWidth(), GetHeight()), Callback);
} }
super::Tick(a_Dt, a_Chunk); super::Tick(a_Dt, a_Chunk);

View File

@ -17,7 +17,8 @@
class cPickupCombiningCallback class cPickupCombiningCallback :
public cEntityCallback
{ {
public: public:
cPickupCombiningCallback(Vector3d a_Position, cPickup * a_Pickup) : cPickupCombiningCallback(Vector3d a_Position, cPickup * a_Pickup) :
@ -27,21 +28,21 @@ public:
{ {
} }
bool operator () (cEntity & a_Entity) virtual bool Item(cEntity * a_Entity) override
{ {
ASSERT(a_Entity.IsTicking()); ASSERT(a_Entity->IsTicking());
if (!a_Entity.IsPickup() || (a_Entity.GetUniqueID() <= m_Pickup->GetUniqueID()) || !a_Entity.IsOnGround()) if (!a_Entity->IsPickup() || (a_Entity->GetUniqueID() <= m_Pickup->GetUniqueID()) || !a_Entity->IsOnGround())
{ {
return false; return false;
} }
Vector3d EntityPos = a_Entity.GetPosition(); Vector3d EntityPos = a_Entity->GetPosition();
double Distance = (EntityPos - m_Position).Length(); double Distance = (EntityPos - m_Position).Length();
auto & OtherPickup = static_cast<cPickup &>(a_Entity); cPickup * OtherPickup = static_cast<cPickup *>(a_Entity);
cItem & Item = OtherPickup.GetItem(); cItem & Item = OtherPickup->GetItem();
if ((Distance < 1.2) && Item.IsEqual(m_Pickup->GetItem()) && OtherPickup.CanCombine()) if ((Distance < 1.2) && Item.IsEqual(m_Pickup->GetItem()) && OtherPickup->CanCombine())
{ {
short CombineCount = Item.m_ItemCount; short CombineCount = Item.m_ItemCount;
if ((CombineCount + m_Pickup->GetItem().m_ItemCount) > Item.GetMaxStackSize()) if ((CombineCount + m_Pickup->GetItem().m_ItemCount) > Item.GetMaxStackSize())
@ -63,16 +64,16 @@ public:
int DiffX = FloorC(m_Pickup->GetPosX() * 32.0) - FloorC(EntityPos.x * 32.0); int DiffX = FloorC(m_Pickup->GetPosX() * 32.0) - FloorC(EntityPos.x * 32.0);
int DiffY = FloorC(m_Pickup->GetPosY() * 32.0) - FloorC(EntityPos.y * 32.0); int DiffY = FloorC(m_Pickup->GetPosY() * 32.0) - FloorC(EntityPos.y * 32.0);
int DiffZ = FloorC(m_Pickup->GetPosZ() * 32.0) - FloorC(EntityPos.z * 32.0); int DiffZ = FloorC(m_Pickup->GetPosZ() * 32.0) - FloorC(EntityPos.z * 32.0);
a_Entity.GetWorld()->BroadcastEntityRelMove(a_Entity, static_cast<char>(DiffX), static_cast<char>(DiffY), static_cast<char>(DiffZ)); a_Entity->GetWorld()->BroadcastEntityRelMove(*a_Entity, static_cast<char>(DiffX), static_cast<char>(DiffY), static_cast<char>(DiffZ));
/* End of experimental animation */ /* End of experimental animation */
a_Entity.Destroy(); a_Entity->Destroy();
// Reset the timer // Reset the timer
m_Pickup->SetAge(0); m_Pickup->SetAge(0);
} }
else else
{ {
a_Entity.GetWorld()->BroadcastEntityMetadata(a_Entity); a_Entity->GetWorld()->BroadcastEntityMetadata(*a_Entity);
} }
m_FoundMatchingPickup = true; m_FoundMatchingPickup = true;
} }

View File

@ -1005,21 +1005,36 @@ bool cPlayer::DoTakeDamage(TakeDamageInfo & a_TDI)
void cPlayer::NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved) void cPlayer::NotifyNearbyWolves(cPawn * a_Opponent, bool a_IsPlayerInvolved)
{ {
ASSERT(a_Opponent != nullptr); ASSERT(a_Opponent != nullptr);
class LookForWolves : public cEntityCallback
{
public:
cPlayer * m_Player;
cPawn * m_Attacker;
bool m_IsPlayerInvolved;
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16), [&] (cEntity & a_Entity) LookForWolves(cPlayer * a_Me, cPawn * a_MyAttacker, bool a_PlayerInvolved) :
m_Player(a_Me),
m_Attacker(a_MyAttacker),
m_IsPlayerInvolved(a_PlayerInvolved)
{ {
if (a_Entity.IsMob()) }
virtual bool Item(cEntity * a_Entity) override
{
if (a_Entity->IsMob())
{ {
auto & Mob = static_cast<cMonster&>(a_Entity); cMonster * Mob = static_cast<cMonster*>(a_Entity);
if (Mob.GetMobType() == mtWolf) if (Mob->GetMobType() == mtWolf)
{ {
auto & Wolf = static_cast<cWolf&>(Mob); cWolf * Wolf = static_cast<cWolf*>(Mob);
Wolf.ReceiveNearbyFightInfo(GetUUID(), a_Opponent, a_IsPlayerInvolved); Wolf->ReceiveNearbyFightInfo(m_Player->GetUUID(), m_Attacker, m_IsPlayerInvolved);
} }
} }
return false; return false;
} }
); } Callback(this, a_Opponent, a_IsPlayerInvolved);
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 16), Callback);
} }
@ -2417,12 +2432,17 @@ void cPlayer::HandleFloater()
{ {
return; return;
} }
m_World->DoWithEntityByID(m_FloaterID, [](cEntity & a_Entity) class cFloaterCallback :
public cEntityCallback
{
public:
virtual bool Item(cEntity * a_Entity) override
{ {
a_Entity.Destroy(true); a_Entity->Destroy(true);
return true; return true;
} }
); } Callback;
m_World->DoWithEntityByID(m_FloaterID, Callback);
SetIsFishing(false); SetIsFishing(false);
} }
@ -2666,18 +2686,29 @@ bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks)
cWorld * World = GetWorld(); cWorld * World = GetWorld();
// Check to see if any entity intersects any block being placed // Check to see if any entity intersects any block being placed
return !World->ForEachEntityInBox(PlacingBounds, [&](cEntity & a_Entity) class DoesIntersectBlock : public cEntityCallback
{ {
// The distance inside the block the entity can still be. public:
const double EPSILON = 0.0005; const std::vector<cBoundingBox> & m_BoundingBoxes;
if (!a_Entity.DoesPreventBlockPlacement()) // The distance inside the block the entity can still be.
const double EPSILON = 0.0005;
DoesIntersectBlock(const std::vector<cBoundingBox> & a_BoundingBoxes) :
m_BoundingBoxes(a_BoundingBoxes)
{
}
virtual bool Item(cEntity * a_Entity) override
{
if (!a_Entity->DoesPreventBlockPlacement())
{ {
return false; return false;
} }
cBoundingBox EntBox(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
for (auto BlockBox : PlacementBoxes) for (auto BlockBox: m_BoundingBoxes)
{ {
// Put in a little bit of wiggle room // Put in a little bit of wiggle room
BlockBox.Expand(-EPSILON, -EPSILON, -EPSILON); BlockBox.Expand(-EPSILON, -EPSILON, -EPSILON);
if (EntBox.DoesIntersect(BlockBox)) if (EntBox.DoesIntersect(BlockBox))
@ -2687,7 +2718,15 @@ bool cPlayer::DoesPlacingBlocksIntersectEntity(const sSetBlockVector & a_Blocks)
} }
return false; return false;
} }
); } Callback(PlacementBoxes);
// See if any entities in that bounding box collide with anyone
if (!World->ForEachEntityInBox(PlacingBounds, Callback))
{
return true;
}
return false;
} }

View File

@ -126,7 +126,8 @@ protected:
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cProjectileEntityCollisionCallback: // cProjectileEntityCollisionCallback:
class cProjectileEntityCollisionCallback class cProjectileEntityCollisionCallback :
public cEntityCallback
{ {
public: public:
cProjectileEntityCollisionCallback(cProjectileEntity * a_Projectile, const Vector3d & a_Pos, const Vector3d & a_NextPos) : cProjectileEntityCollisionCallback(cProjectileEntity * a_Projectile, const Vector3d & a_Pos, const Vector3d & a_NextPos) :
@ -139,11 +140,11 @@ public:
} }
bool operator () (cEntity & a_Entity) virtual bool Item(cEntity * a_Entity) override
{ {
if ( if (
(&a_Entity == m_Projectile) || // Do not check collisions with self (a_Entity == m_Projectile) || // Do not check collisions with self
(a_Entity.GetUniqueID() == m_Projectile->GetCreatorUniqueID()) // Do not check whoever shot the projectile (a_Entity->GetUniqueID() == m_Projectile->GetCreatorUniqueID()) // Do not check whoever shot the projectile
) )
{ {
// Don't check creator only for the first 5 ticks so that projectiles can collide with the creator // Don't check creator only for the first 5 ticks so that projectiles can collide with the creator
@ -153,7 +154,7 @@ public:
} }
} }
cBoundingBox EntBox(a_Entity.GetPosition(), a_Entity.GetWidth() / 2, a_Entity.GetHeight()); cBoundingBox EntBox(a_Entity->GetPosition(), a_Entity->GetWidth() / 2, a_Entity->GetHeight());
// Instead of colliding the bounding box with another bounding box in motion, we collide an enlarged bounding box with a hairline. // Instead of colliding the bounding box with another bounding box in motion, we collide an enlarged bounding box with a hairline.
// The results should be good enough for our purposes // The results should be good enough for our purposes
@ -167,20 +168,20 @@ public:
} }
if ( if (
!a_Entity.IsMob() && !a_Entity->IsMob() &&
!a_Entity.IsMinecart() && !a_Entity->IsMinecart() &&
( (
!a_Entity.IsPlayer() || !a_Entity->IsPlayer() ||
static_cast<cPlayer &>(a_Entity).IsGameModeSpectator() static_cast<cPlayer *>(a_Entity)->IsGameModeSpectator()
) && ) &&
!a_Entity.IsBoat() !a_Entity->IsBoat()
) )
{ {
// Not an entity that interacts with a projectile // Not an entity that interacts with a projectile
return false; return false;
} }
if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, a_Entity)) if (cPluginManager::Get()->CallHookProjectileHitEntity(*m_Projectile, *a_Entity))
{ {
// A plugin disagreed. // A plugin disagreed.
return false; return false;
@ -190,7 +191,7 @@ public:
{ {
// The entity is closer than anything we've stored so far, replace it as the potential victim // The entity is closer than anything we've stored so far, replace it as the potential victim
m_MinCoeff = LineCoeff; m_MinCoeff = LineCoeff;
m_HitEntity = &a_Entity; m_HitEntity = a_Entity;
} }
// Don't break the enumeration, we want all the entities // Don't break the enumeration, we want all the entities
@ -326,13 +327,20 @@ void cProjectileEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_Hi
// If we were created by a player and we hit a pawn, notify attacking player's wolves // If we were created by a player and we hit a pawn, notify attacking player's wolves
if (a_EntityHit.IsPawn() && (GetCreatorName() != "")) if (a_EntityHit.IsPawn() && (GetCreatorName() != ""))
{ {
auto EntityHit = static_cast<cPawn *>(&a_EntityHit); class cNotifyWolves : public cEntityCallback
m_World->DoWithEntityByID(GetCreatorUniqueID(), [=](cEntity & a_Hitter) {
public:
cPawn * m_EntityHit;
virtual bool Item(cEntity * a_Hitter) override
{ {
static_cast<cPlayer&>(a_Hitter).NotifyNearbyWolves(EntityHit, true); static_cast<cPlayer*>(a_Hitter)->NotifyNearbyWolves(m_EntityHit, true);
return true; return true;
} }
); } Callback;
Callback.m_EntityHit = static_cast<cPawn*>(&a_EntityHit);
m_World->DoWithEntityByID(GetCreatorUniqueID(), Callback);
} }
} }

View File

@ -16,6 +16,60 @@
////////////////////////////////////////////////////////////////////////////////
// cSplashPotionEntityCallback:
/** Used to distribute the splashed potion effect among nearby entities */
class cSplashPotionCallback :
public cEntityCallback
{
public:
/** Creates the callback.
@param a_HitPos The position where the splash potion has splashed
@param a_EntityEffectType The effect type of the potion
@param a_EntityEffect The effect description */
cSplashPotionCallback(const Vector3d & a_HitPos, cEntityEffect::eType a_EntityEffectType, const cEntityEffect & a_EntityEffect) :
m_HitPos(a_HitPos),
m_EntityEffectType(a_EntityEffectType),
m_EntityEffect(a_EntityEffect)
{
}
/** Called by cWorld::ForEachEntity(), adds the stored entity effect to the entity, if it is close enough. */
virtual bool Item(cEntity * a_Entity) override
{
if (!a_Entity->IsPawn())
{
// Not an entity that can take effects
return false;
}
double SplashDistance = (a_Entity->GetPosition() - m_HitPos).Length();
if (SplashDistance >= 20)
{
// Too far away
return false;
}
// y = -0.25x + 1, where x is the distance from the player. Approximation for potion splash.
// TODO: better equation
double Reduction = -0.25 * SplashDistance + 1.0;
Reduction = std::max(Reduction, 0.0);
static_cast<cPawn *>(a_Entity)->AddEntityEffect(m_EntityEffectType, m_EntityEffect.GetDuration(), m_EntityEffect.GetIntensity(), Reduction);
return false;
}
private:
const Vector3d & m_HitPos;
cEntityEffect::eType m_EntityEffectType;
const cEntityEffect & m_EntityEffect;
};
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cSplashPotionEntity: // cSplashPotionEntity:
@ -65,30 +119,8 @@ void cSplashPotionEntity::OnHitEntity(cEntity & a_EntityHit, const Vector3d & a_
void cSplashPotionEntity::Splash(const Vector3d & a_HitPos) void cSplashPotionEntity::Splash(const Vector3d & a_HitPos)
{ {
m_World->ForEachEntity([=](cEntity & a_Entity) cSplashPotionCallback Callback(a_HitPos, m_EntityEffectType, m_EntityEffect);
{ m_World->ForEachEntity(Callback);
if (!a_Entity.IsPawn())
{
// Not an entity that can take effects
return false;
}
double SplashDistance = (a_Entity.GetPosition() - a_HitPos).Length();
if (SplashDistance >= 20)
{
// Too far away
return false;
}
// y = -0.25x + 1, where x is the distance from the player. Approximation for potion splash.
// TODO: better equation
double Reduction = -0.25 * SplashDistance + 1.0;
Reduction = std::max(Reduction, 0.0);
static_cast<cPawn &>(a_Entity).AddEntityEffect(m_EntityEffectType, m_EntityEffect.GetDuration(), m_EntityEffect.GetIntensity(), Reduction);
return false;
}
);
m_World->BroadcastSoundParticleEffect( m_World->BroadcastSoundParticleEffect(
EffectID::PARTICLE_SPLASH_POTION, EffectID::PARTICLE_SPLASH_POTION,

View File

@ -74,12 +74,29 @@ void cThrownEnderPearlEntity::TeleportCreator(const Vector3d & a_HitPos)
return; return;
} }
GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, [=](cPlayer & a_Entity) class cProjectileCreatorCallbackForPlayers : public cPlayerListCallback
{
public:
cProjectileCreatorCallbackForPlayers(cEntity * a_Attacker, Vector3i a_CallbackHitPos) :
m_Attacker(a_Attacker),
m_HitPos(a_CallbackHitPos)
{
}
virtual bool Item(cPlayer * a_Entity) override
{ {
// Teleport the creator here, make them take 5 damage: // Teleport the creator here, make them take 5 damage:
a_Entity.TeleportToCoords(a_HitPos.x, a_HitPos.y + 0.2, a_HitPos.z); a_Entity->TeleportToCoords(m_HitPos.x, m_HitPos.y + 0.2, m_HitPos.z);
a_Entity.TakeDamage(dtEnderPearl, this, 5, 0); a_Entity->TakeDamage(dtEnderPearl, m_Attacker, 5, 0);
return true; return true;
} }
);
private:
cEntity * m_Attacker;
Vector3i m_HitPos;
};
cProjectileCreatorCallbackForPlayers PCCFP(this, a_HitPos);
GetWorld()->FindAndDoWithPlayer(m_CreatorData.m_Name, PCCFP);
} }

View File

@ -416,6 +416,20 @@ template class SizeChecker<UInt8, 1>;
/** A generic interface used mainly in ForEach() functions */
template <typename Type> class cItemCallback
{
public:
virtual ~cItemCallback() {}
/** Called for each item in the internal list; return true to stop the loop, or false to continue enumerating */
virtual bool Item(Type * a_Type) = 0;
} ;
/** Clamp X to the specified range. */ /** Clamp X to the specified range. */
template <typename T> template <typename T>
T Clamp(T a_Value, T a_Min, T a_Max) T Clamp(T a_Value, T a_Min, T a_Max)

View File

@ -20,7 +20,8 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cFloaterCallback // cFloaterCallback
class cFloaterCallback class cFloaterCallback :
public cEntityCallback
{ {
public: public:
cFloaterCallback(void) : cFloaterCallback(void) :
@ -29,14 +30,13 @@ public:
{ {
} }
bool operator () (cEntity & a_Entity) virtual bool Item(cEntity * a_Entity) override
{ {
auto & Floater = static_cast<cFloater &>(a_Entity); m_CanPickup = reinterpret_cast<cFloater *>(a_Entity)->CanPickup();
m_CanPickup = Floater.CanPickup(); m_Pos = Vector3d(a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ());
m_Pos = Floater.GetPosition(); m_BitePos = reinterpret_cast<cFloater *>(a_Entity)->GetBitePos();
m_BitePos = Floater.GetBitePos(); m_AttachedMobID = reinterpret_cast<cFloater *>(a_Entity)->GetAttachedMobID();
m_AttachedMobID = Floater.GetAttachedMobID(); a_Entity->Destroy(true);
Floater.Destroy(true);
return true; return true;
} }
@ -57,6 +57,33 @@ protected:
////////////////////////////////////////////////////////////////////////////////
// cSweepEntityCallback:
class cSweepEntityCallback :
public cEntityCallback
{
public:
cSweepEntityCallback(Vector3d a_PlayerPos) :
m_PlayerPos(a_PlayerPos)
{
}
virtual bool Item(cEntity * a_Entity) override
{
Vector3d Speed = m_PlayerPos - a_Entity->GetPosition();
a_Entity->AddSpeed(Speed);
return true;
}
protected:
Vector3d m_PlayerPos;
} ;
class cItemFishingRodHandler : class cItemFishingRodHandler :
public cItemHandler public cItemHandler
{ {
@ -90,13 +117,8 @@ public:
if (FloaterInfo.IsAttached()) if (FloaterInfo.IsAttached())
{ {
a_World->DoWithEntityByID(FloaterInfo.GetAttachedMobID(), [=](cEntity & a_Entity) cSweepEntityCallback SweepEntity(a_Player->GetPosition());
{ a_World->DoWithEntityByID(FloaterInfo.GetAttachedMobID(), SweepEntity);
Vector3d Speed = a_Player->GetPosition() - a_Entity.GetPosition();
a_Entity.AddSpeed(Speed);
return true;
}
);
} }
else if (FloaterInfo.CanPickup()) else if (FloaterInfo.CanPickup())
{ {

View File

@ -62,30 +62,42 @@ public:
int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace int a_BlockX, int a_BlockY, int a_BlockZ, eBlockFace a_BlockFace
) )
{ {
auto HeadType = static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage);
auto BlockMeta = static_cast<NIBBLETYPE>(a_BlockFace);
// Use a callback to set the properties of the mob head block entity: // Use a callback to set the properties of the mob head block entity:
a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, [&](cBlockEntity & a_BlockEntity) class cCallback : public cBlockEntityCallback
{
cPlayer & m_Player;
eMobHeadType m_HeadType;
NIBBLETYPE m_BlockMeta;
virtual bool Item(cBlockEntity * a_BlockEntity)
{ {
if (a_BlockEntity.GetBlockType() != E_BLOCK_HEAD) if (a_BlockEntity->GetBlockType() != E_BLOCK_HEAD)
{ {
return false; return false;
} }
auto & MobHeadEntity = static_cast<cMobHeadEntity &>(a_BlockEntity); auto MobHeadEntity = static_cast<cMobHeadEntity *>(a_BlockEntity);
int Rotation = 0; int Rotation = 0;
if (BlockMeta == 1) if (m_BlockMeta == 1)
{ {
Rotation = FloorC(a_Player.GetYaw() * 16.0f / 360.0f + 0.5f) & 0x0f; Rotation = FloorC(m_Player.GetYaw() * 16.0f / 360.0f + 0.5f) & 0x0f;
} }
MobHeadEntity.SetType(HeadType); MobHeadEntity->SetType(m_HeadType);
MobHeadEntity.SetRotation(static_cast<eMobHeadRotation>(Rotation)); MobHeadEntity->SetRotation(static_cast<eMobHeadRotation>(Rotation));
MobHeadEntity.GetWorld()->BroadcastBlockEntity(MobHeadEntity.GetPosX(), MobHeadEntity.GetPosY(), MobHeadEntity.GetPosZ()); MobHeadEntity->GetWorld()->BroadcastBlockEntity(MobHeadEntity->GetPosX(), MobHeadEntity->GetPosY(), MobHeadEntity->GetPosZ());
return false; return false;
} }
);
public:
cCallback (cPlayer & a_CBPlayer, eMobHeadType a_HeadType, NIBBLETYPE a_BlockMeta) :
m_Player(a_CBPlayer),
m_HeadType(a_HeadType),
m_BlockMeta(a_BlockMeta)
{}
};
cCallback Callback(a_Player, static_cast<eMobHeadType>(a_EquippedItem.m_ItemDamage), static_cast<NIBBLETYPE>(a_BlockFace));
a_World.DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, Callback);
} }
@ -231,16 +243,24 @@ public:
// If it is a mob head, check the correct head type using the block entity: // If it is a mob head, check the correct head type using the block entity:
if (BlockType == E_BLOCK_HEAD) if (BlockType == E_BLOCK_HEAD)
{ {
bool IsWitherHead = false; class cHeadCallback: public cBlockEntityCallback
a_World.DoWithBlockEntityAt(BlockX, BlockY, BlockZ, [&](cBlockEntity & a_Entity) {
virtual bool Item(cBlockEntity * a_Entity) override
{ {
ASSERT(a_Entity.GetBlockType() == E_BLOCK_HEAD); ASSERT(a_Entity->GetBlockType() == E_BLOCK_HEAD);
auto & MobHead = static_cast<cMobHeadEntity &>(a_Entity); cMobHeadEntity * MobHead = static_cast<cMobHeadEntity *>(a_Entity);
IsWitherHead = (MobHead.GetType() == SKULL_TYPE_WITHER); m_IsWitherHead = (MobHead->GetType() == SKULL_TYPE_WITHER);
return true; return true;
} }
); public:
if (!IsWitherHead) cHeadCallback(void):
m_IsWitherHead(false)
{
}
bool m_IsWitherHead;
} callback;
a_World.DoWithBlockEntityAt(BlockX, BlockY, BlockZ, callback);
if (!callback.m_IsWitherHead)
{ {
return false; return false;
} }
@ -267,18 +287,25 @@ public:
/** Awards the achievement to all players close to the specified point. */ /** Awards the achievement to all players close to the specified point. */
void AwardSpawnWitherAchievement(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ) void AwardSpawnWitherAchievement(cWorld & a_World, int a_BlockX, int a_BlockY, int a_BlockZ)
{ {
Vector3f Pos{ static_cast<float>(a_BlockX), static_cast<float>(a_BlockY), static_cast<float>(a_BlockZ) }; class cPlayerCallback : public cPlayerListCallback
a_World.ForEachPlayer([=](cPlayer & a_Player) {
Vector3f m_Pos;
virtual bool Item(cPlayer * a_Player)
{ {
// If player is close, award achievement: // If player is close, award achievement:
double Dist = (a_Player.GetPosition() - Pos).Length(); double Dist = (a_Player->GetPosition() - m_Pos).Length();
if (Dist < 50.0) if (Dist < 50.0)
{ {
a_Player.AwardAchievement(achSpawnWither); a_Player->AwardAchievement(achSpawnWither);
} }
return false; return false;
} }
);
public:
cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
} PlayerCallback(Vector3f(static_cast<float>(a_BlockX), static_cast<float>(a_BlockY), static_cast<float>(a_BlockZ)));
a_World.ForEachPlayer(PlayerCallback);
} }

View File

@ -199,12 +199,12 @@ bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ,
m_DiffY = m_EndY - m_StartY; m_DiffY = m_EndY - m_StartY;
m_DiffZ = m_EndZ - m_StartZ; m_DiffZ = m_EndZ - m_StartZ;
// The actual trace is handled with ChunkMapCS locked by calling our ChunkCallback for the specified chunk // The actual trace is handled with ChunkMapCS locked by calling our Item() for the specified chunk
int BlockX = FloorC(m_StartX); int BlockX = FloorC(m_StartX);
int BlockZ = FloorC(m_StartZ); int BlockZ = FloorC(m_StartZ);
int ChunkX, ChunkZ; int ChunkX, ChunkZ;
cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ);
return m_World->DoWithChunk(ChunkX, ChunkZ, [this](cChunk & a_Chunk) { return ChunkCallback(&a_Chunk); }); return m_World->DoWithChunk(ChunkX, ChunkZ, *this);
} }
@ -308,7 +308,7 @@ bool cLineBlockTracer::MoveToNextBlock(void)
bool cLineBlockTracer::ChunkCallback(cChunk * a_Chunk) bool cLineBlockTracer::Item(cChunk * a_Chunk)
{ {
ASSERT((m_CurrentY >= 0) && (m_CurrentY < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld() ASSERT((m_CurrentY >= 0) && (m_CurrentY < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld()

View File

@ -18,12 +18,17 @@
// fwd: Chunk.h // fwd: Chunk.h
class cChunk; class cChunk;
// fwd: cChunkMap.h
typedef cItemCallback<cChunk> cChunkCallback;
class cLineBlockTracer : class cLineBlockTracer :
public cBlockTracer public cBlockTracer,
public cChunkCallback
{ {
typedef cBlockTracer super; typedef cBlockTracer super;
@ -104,7 +109,8 @@ protected:
/** Moves m_Current to the next block on the line; returns false if no move is possible (reached the end) */ /** Moves m_Current to the next block on the line; returns false if no move is possible (reached the end) */
bool MoveToNextBlock(void); bool MoveToNextBlock(void);
bool ChunkCallback(cChunk * a_Chunk); // cChunkCallback overrides:
virtual bool Item(cChunk * a_Chunk) override;
} ; } ;

View File

@ -120,17 +120,27 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
int RelX = BlockX - (ChunkX * cChunkDef::Width); int RelX = BlockX - (ChunkX * cChunkDef::Width);
int RelZ = BlockZ - (ChunkZ * cChunkDef::Width); int RelZ = BlockZ - (ChunkZ * cChunkDef::Width);
ASSERT(m_World != nullptr); class cCalculatePixelCb :
public cChunkCallback
{
cMap * m_Map;
ColorID PixelData; int m_RelX, m_RelZ;
m_World->DoWithChunk(ChunkX, ChunkZ, [&](cChunk & a_Chunk)
ColorID m_PixelData;
public:
cCalculatePixelCb(cMap * a_Map, int a_RelX, int a_RelZ)
: m_Map(a_Map), m_RelX(a_RelX), m_RelZ(a_RelZ), m_PixelData(E_BASE_COLOR_TRANSPARENT) {}
virtual bool Item(cChunk * a_Chunk) override
{ {
if (!a_Chunk.IsValid()) if (!a_Chunk->IsValid())
{ {
return false; return false;
} }
if (GetDimension() == dimNether) if (m_Map->GetDimension() == dimNether)
{ {
// TODO 2014-02-22 xdot: Nether maps // TODO 2014-02-22 xdot: Nether maps
@ -141,22 +151,22 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
BLOCKTYPE TargetBlock; BLOCKTYPE TargetBlock;
NIBBLETYPE TargetMeta; NIBBLETYPE TargetMeta;
auto Height = a_Chunk.GetHeight(RelX, RelZ); auto Height = a_Chunk->GetHeight(m_RelX, m_RelZ);
auto ChunkHeight = cChunkDef::Height; auto ChunkHeight = cChunkDef::Height;
a_Chunk.GetBlockTypeMeta(RelX, Height, RelZ, TargetBlock, TargetMeta); a_Chunk->GetBlockTypeMeta(m_RelX, Height, m_RelZ, TargetBlock, TargetMeta);
auto ColourID = BlockHandler(TargetBlock)->GetMapBaseColourID(TargetMeta); auto ColourID = BlockHandler(TargetBlock)->GetMapBaseColourID(TargetMeta);
if (IsBlockWater(TargetBlock)) if (IsBlockWater(TargetBlock))
{ {
ChunkHeight /= 4; ChunkHeight /= 4;
while (((--Height) != -1) && IsBlockWater(a_Chunk.GetBlock(RelX, Height, RelZ))) while (((--Height) != -1) && IsBlockWater(a_Chunk->GetBlock(m_RelX, Height, m_RelZ)))
{ {
continue; continue;
} }
} }
else if (ColourID == 0) else if (ColourID == 0)
{ {
while (((--Height) != -1) && ((ColourID = BlockHandler(a_Chunk.GetBlock(RelX, Height, RelZ))->GetMapBaseColourID(a_Chunk.GetMeta(RelX, Height, RelZ))) == 0)) while (((--Height) != -1) && ((ColourID = BlockHandler(a_Chunk->GetBlock(m_RelX, Height, m_RelZ))->GetMapBaseColourID(a_Chunk->GetMeta(m_RelX, Height, m_RelZ))) == 0))
{ {
continue; continue;
} }
@ -164,12 +174,20 @@ bool cMap::UpdatePixel(unsigned int a_X, unsigned int a_Z)
// Multiply base color ID by 4 and add brightness ID // Multiply base color ID by 4 and add brightness ID
const int BrightnessIDSize = static_cast<int>(BrightnessID.size()); const int BrightnessIDSize = static_cast<int>(BrightnessID.size());
PixelData = ColourID * 4 + BrightnessID[static_cast<size_t>(Clamp<int>((BrightnessIDSize * Height) / ChunkHeight, 0, BrightnessIDSize - 1))]; m_PixelData = ColourID * 4 + BrightnessID[static_cast<size_t>(Clamp<int>((BrightnessIDSize * Height) / ChunkHeight, 0, BrightnessIDSize - 1))];
return false; return false;
} }
);
SetPixel(a_X, a_Z, PixelData); ColorID GetPixelData(void) const
{
return m_PixelData;
}
} CalculatePixelCb(this, RelX, RelZ);
ASSERT(m_World != nullptr);
m_World->DoWithChunk(ChunkX, ChunkZ, CalculatePixelCb);
SetPixel(a_X, a_Z, CalculatePixelCb.GetPixelData());
return true; return true;
} }

View File

@ -1,4 +1,4 @@

// MapManager.cpp // MapManager.cpp
#include "Globals.h" #include "Globals.h"
@ -22,7 +22,7 @@ cMapManager::cMapManager(cWorld * a_World)
bool cMapManager::DoWithMap(UInt32 a_ID, const cMapCallback & a_Callback) bool cMapManager::DoWithMap(UInt32 a_ID, cMapCallback & a_Callback)
{ {
cCSLock Lock(m_CS); cCSLock Lock(m_CS);
cMap * Map = GetMapData(a_ID); cMap * Map = GetMapData(a_ID);
@ -33,7 +33,7 @@ bool cMapManager::DoWithMap(UInt32 a_ID, const cMapCallback & a_Callback)
} }
else else
{ {
a_Callback(*Map); a_Callback.Item(Map);
return true; return true;
} }
} }

View File

@ -1,4 +1,4 @@

// MapManager.h // MapManager.h
@ -11,13 +11,12 @@
#include <functional>
#include "Map.h" #include "Map.h"
using cMapCallback = std::function<bool(cMap &)>; typedef cItemCallback<cMap> cMapCallback;
@ -42,7 +41,7 @@ public:
/** Calls the callback for the map with the specified ID. /** Calls the callback for the map with the specified ID.
Returns true if the map was found and the callback called, false if map not found. Returns true if the map was found and the callback called, false if map not found.
Callback return value is ignored. */ Callback return value is ignored. */
bool DoWithMap(UInt32 a_ID, const cMapCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithMap(UInt32 a_ID, cMapCallback & a_Callback); // Exported in ManualBindings.cpp
/** Ticks each registered map */ /** Ticks each registered map */
void TickMaps(void); void TickMaps(void);

View File

@ -369,7 +369,7 @@ cMonster * cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY,
auto NewMobPtr = newMob.get(); auto NewMobPtr = newMob.get();
if (newMob) if (newMob)
{ {
m_Spawned.push_back(std::move(newMob)); m_Spawned.insert(std::move(newMob));
} }
return NewMobPtr; return NewMobPtr;
} }
@ -390,6 +390,15 @@ void cMobSpawner::NewPack()
cMobSpawner::tSpawnedContainer & cMobSpawner::getSpawned(void)
{
return m_Spawned;
}
bool cMobSpawner::CanSpawnAnything(void) bool cMobSpawner::CanSpawnAnything(void)
{ {
return !m_AllowedTypes.empty(); return !m_AllowedTypes.empty();

View File

@ -37,10 +37,8 @@ public :
// return true if there is at least one allowed type // return true if there is at least one allowed type
bool CanSpawnAnything(void); bool CanSpawnAnything(void);
std::vector<std::unique_ptr<cMonster>> & getSpawned(void) typedef const std::set<std::unique_ptr<cMonster>> tSpawnedContainer;
{ tSpawnedContainer & getSpawned(void);
return m_Spawned;
}
/** Returns true if specified type of mob can spawn on specified block */ /** Returns true if specified type of mob can spawn on specified block */
static bool CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, eMonsterType a_MobType, EMCSBiome a_Biome); static bool CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, eMonsterType a_MobType, EMCSBiome a_Biome);
@ -57,7 +55,7 @@ protected :
std::set<eMonsterType> m_AllowedTypes; std::set<eMonsterType> m_AllowedTypes;
bool m_NewPack; bool m_NewPack;
eMonsterType m_MobType; eMonsterType m_MobType;
std::vector<std::unique_ptr<cMonster>> m_Spawned; std::set<std::unique_ptr<cMonster>> m_Spawned;
} ; } ;

View File

@ -81,16 +81,21 @@ void cCreeper::GetDrops(cItems & a_Drops, cEntity * a_Killer)
a_Killer->IsProjectile() && a_Killer->IsProjectile() &&
((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID() != cEntity::INVALID_ID)) ((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID() != cEntity::INVALID_ID))
{ {
auto ProjectileCreatorCallback = [](cEntity & a_Entity) class cProjectileCreatorCallback : public cEntityCallback
{
public:
cProjectileCreatorCallback(void) {}
virtual bool Item(cEntity * a_Entity) override
{ {
if (a_Entity.IsMob() && ((static_cast<cMonster &>(a_Entity)).GetMobType() == mtSkeleton)) if (a_Entity->IsMob() && ((reinterpret_cast<cMonster *>(a_Entity))->GetMobType() == mtSkeleton))
{ {
return true; return true;
} }
return false; return false;
}; }
} PCC;
if (GetWorld()->DoWithEntityByID(static_cast<cProjectileEntity *>(a_Killer)->GetCreatorUniqueID(), ProjectileCreatorCallback)) if (GetWorld()->DoWithEntityByID((reinterpret_cast<cProjectileEntity *>(a_Killer))->GetCreatorUniqueID(), PCC))
{ {
AddRandomDropItem(a_Drops, 1, 1, static_cast<short>(m_World->GetTickRandomNumber(11) + E_ITEM_FIRST_DISC)); AddRandomDropItem(a_Drops, 1, 1, static_cast<short>(m_World->GetTickRandomNumber(11) + E_ITEM_FIRST_DISC));
} }

View File

@ -10,7 +10,8 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cPlayerLookCheck // cPlayerLookCheck
class cPlayerLookCheck class cPlayerLookCheck :
public cPlayerListCallback
{ {
public: public:
cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) : cPlayerLookCheck(Vector3d a_EndermanPos, int a_SightDistance) :
@ -20,29 +21,29 @@ public:
{ {
} }
bool operator () (cPlayer & a_Player) virtual bool Item(cPlayer * a_Player) override
{ {
// Don't check players who cannot be targeted // Don't check players who cannot be targeted
if (!a_Player.CanMobsTarget()) if (!a_Player->CanMobsTarget())
{ {
return false; return false;
} }
// Don't check players who are more than SightDistance (64) blocks away // Don't check players who are more than SightDistance (64) blocks away
auto Direction = m_EndermanPos - a_Player.GetPosition(); auto Direction = m_EndermanPos - a_Player->GetPosition();
if (Direction.Length() > m_SightDistance) if (Direction.Length() > m_SightDistance)
{ {
return false; return false;
} }
// Don't check if the player has a pumpkin on his head // Don't check if the player has a pumpkin on his head
if (a_Player.GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN) if (a_Player->GetEquippedHelmet().m_ItemType == E_BLOCK_PUMPKIN)
{ {
return false; return false;
} }
// If the player's crosshair is within 5 degrees of the enderman, it counts as looking // If the player's crosshair is within 5 degrees of the enderman, it counts as looking
auto LookVector = a_Player.GetLookVector(); auto LookVector = a_Player->GetLookVector();
auto dot = Direction.Dot(LookVector); auto dot = Direction.Dot(LookVector);
if (dot <= cos(0.09)) // 0.09 rad ~ 5 degrees if (dot <= cos(0.09)) // 0.09 rad ~ 5 degrees
{ {
@ -50,13 +51,13 @@ public:
} }
// TODO: Check if endermen are angered through water in Vanilla // TODO: Check if endermen are angered through water in Vanilla
if (!cLineBlockTracer::LineOfSightTrace(*a_Player.GetWorld(), m_EndermanPos, a_Player.GetPosition(), cLineBlockTracer::losAirWater)) if (!cLineBlockTracer::LineOfSightTrace(*a_Player->GetWorld(), m_EndermanPos, a_Player->GetPosition(), cLineBlockTracer::losAirWater))
{ {
// No direct line of sight // No direct line of sight
return false; return false;
} }
m_Player = &a_Player; m_Player = a_Player;
return true; return true;
} }

View File

@ -90,25 +90,30 @@ void cOcelot::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cOcelot::TickFollowPlayer() void cOcelot::TickFollowPlayer()
{ {
Vector3d OwnerPos; class cCallback :
bool OwnerFlying = false; public cPlayerListCallback
auto Callback = [&](cPlayer & a_Player)
{ {
OwnerPos = a_Player.GetPosition(); virtual bool Item(cPlayer * a_Player) override
OwnerFlying = a_Player.IsFlying(); {
return true; OwnerPos = a_Player->GetPosition();
}; OwnerFlying = a_Player->IsFlying();
return true;
}
public:
Vector3d OwnerPos;
bool OwnerFlying;
} Callback;
if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback)) if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback))
{ {
// The player is present in the world, follow him: // The player is present in the world, follow him:
double Distance = (OwnerPos - GetPosition()).Length(); double Distance = (Callback.OwnerPos - GetPosition()).Length();
if (Distance > 12) if (Distance > 12)
{ {
if (!OwnerFlying) if (!Callback.OwnerFlying)
{ {
OwnerPos.y = FindFirstNonAirBlockPosition(OwnerPos.x, OwnerPos.z); Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z);
TeleportToCoords(OwnerPos.x, OwnerPos.y, OwnerPos.z); TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
} }
} }
if (Distance < 2) if (Distance < 2)
@ -117,9 +122,9 @@ void cOcelot::TickFollowPlayer()
} }
else else
{ {
if (!OwnerFlying) if (!Callback.OwnerFlying)
{ {
MoveToPosition(OwnerPos); MoveToPosition(Callback.OwnerPos);
} }
} }
} }
@ -200,19 +205,27 @@ void cOcelot::SpawnOn(cClientHandle & a_ClientHandle)
class cFindSittingCat :
public cEntityCallback
{
virtual bool Item(cEntity * a_Entity) override
{
return (
(a_Entity->GetEntityType() == cEntity::etMonster) &&
(static_cast<cMonster *>(a_Entity)->GetMobType() == eMonsterType::mtOcelot) &&
(static_cast<cOcelot *>(a_Entity)->IsSitting())
);
}
};
bool cOcelot::IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition) bool cOcelot::IsCatSittingOnBlock(cWorld * a_World, Vector3d a_BlockPosition)
{ {
return a_World->ForEachEntityInBox( cFindSittingCat FindSittingCat;
cBoundingBox(Vector3d(a_BlockPosition.x, a_BlockPosition.y + 1, a_BlockPosition.z), 1), return a_World->ForEachEntityInBox(cBoundingBox(Vector3d(a_BlockPosition.x, a_BlockPosition.y + 1, a_BlockPosition.z), 1), FindSittingCat);
[=](cEntity & a_Entity)
{
return (
(a_Entity.GetEntityType() == cEntity::etMonster) &&
(static_cast<cMonster &>(a_Entity).GetMobType() == eMonsterType::mtOcelot) &&
(static_cast<cOcelot &>(a_Entity).IsSitting())
);
}
);
} }

View File

@ -109,18 +109,23 @@ void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
Vector3f Pos = (GetPosition() + m_LovePartner->GetPosition()) * 0.5; Vector3f Pos = (GetPosition() + m_LovePartner->GetPosition()) * 0.5;
UInt32 BabyID = m_World->SpawnMob(Pos.x, Pos.y, Pos.z, GetMobType(), true); UInt32 BabyID = m_World->SpawnMob(Pos.x, Pos.y, Pos.z, GetMobType(), true);
cPassiveMonster * Baby = nullptr; class cBabyInheritCallback :
public cEntityCallback
m_World->DoWithEntityByID(BabyID, [&](cEntity & a_Entity) {
public:
cPassiveMonster * Baby;
cBabyInheritCallback() : Baby(nullptr) { }
virtual bool Item(cEntity * a_Entity) override
{ {
Baby = static_cast<cPassiveMonster *>(&a_Entity); Baby = static_cast<cPassiveMonster *>(a_Entity);
return true; return true;
} }
); } Callback;
if (Baby != nullptr) m_World->DoWithEntityByID(BabyID, Callback);
if (Callback.Baby != nullptr)
{ {
Baby->InheritFromParents(this, m_LovePartner); Callback.Baby->InheritFromParents(this, m_LovePartner);
} }
m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, GetRandomProvider().RandInt(1, 6)); m_World->SpawnExperienceOrb(Pos.x, Pos.y, Pos.z, GetRandomProvider().RandInt(1, 6));
@ -154,37 +159,49 @@ void cPassiveMonster::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
{ {
if (m_LovePartner == nullptr) if (m_LovePartner == nullptr)
{ {
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8), [=](cEntity & a_Entity) class LookForLover : public cEntityCallback
{
public:
cEntity * m_Me;
LookForLover(cEntity * a_Me) :
m_Me(a_Me)
{
}
virtual bool Item(cEntity * a_Entity) override
{ {
// If the entity is not a monster, don't breed with it // If the entity is not a monster, don't breed with it
// Also, do not self-breed // Also, do not self-breed
if ((a_Entity.GetEntityType() != etMonster) || (&a_Entity == this)) if ((a_Entity->GetEntityType() != etMonster) || (a_Entity == m_Me))
{ {
return false; return false;
} }
auto & Me = static_cast<cPassiveMonster&>(*this); cPassiveMonster * Me = static_cast<cPassiveMonster*>(m_Me);
auto & PotentialPartner = static_cast<cPassiveMonster&>(a_Entity); cPassiveMonster * PotentialPartner = static_cast<cPassiveMonster*>(a_Entity);
// If the potential partner is not of the same species, don't breed with it // If the potential partner is not of the same species, don't breed with it
if (PotentialPartner.GetMobType() != Me.GetMobType()) if (PotentialPartner->GetMobType() != Me->GetMobType())
{ {
return false; return false;
} }
// If the potential partner is not in love // If the potential partner is not in love
// Or they already have a mate, do not breed with them // Or they already have a mate, do not breed with them
if ((!PotentialPartner.IsInLove()) || (PotentialPartner.GetPartner() != nullptr)) if ((!PotentialPartner->IsInLove()) || (PotentialPartner->GetPartner() != nullptr))
{ {
return false; return false;
} }
// All conditions met, let's breed! // All conditions met, let's breed!
PotentialPartner.EngageLoveMode(&Me); PotentialPartner->EngageLoveMode(Me);
Me.EngageLoveMode(&PotentialPartner); Me->EngageLoveMode(PotentialPartner);
return true; return true;
} }
); } Callback(this);
m_World->ForEachEntityInBox(cBoundingBox(GetPosition(), 8, 8, -4), Callback);
} }
m_LoveTimer--; m_LoveTimer--;

View File

@ -101,19 +101,28 @@ void cWither::KilledBy(TakeDamageInfo & a_TDI)
{ {
super::KilledBy(a_TDI); super::KilledBy(a_TDI);
Vector3d Pos = GetPosition(); class cPlayerCallback : public cPlayerListCallback
m_World->ForEachPlayer([=](cPlayer & a_Player) {
Vector3f m_Pos;
virtual bool Item(cPlayer * a_Player)
{ {
// TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one // TODO 2014-05-21 xdot: Vanilla minecraft uses an AABB check instead of a radius one
double Dist = (a_Player.GetPosition() - Pos).Length(); double Dist = (a_Player->GetPosition() - m_Pos).Length();
if (Dist < 50.0) if (Dist < 50.0)
{ {
// If player is close, award achievement // If player is close, award achievement
a_Player.AwardAchievement(achKillWither); a_Player->AwardAchievement(achKillWither);
} }
return false; return false;
} }
);
public:
cPlayerCallback(const Vector3f & a_Pos) : m_Pos(a_Pos) {}
} PlayerCallback(GetPosition());
m_World->ForEachPlayer(PlayerCallback);
} }

View File

@ -80,13 +80,19 @@ void cWolf::NotifyAlliesOfFight(cPawn * a_Opponent)
return; return;
} }
m_NotificationCooldown = 15; m_NotificationCooldown = 15;
class cCallback : public cPlayerListCallback
m_World->DoWithPlayerByUUID(m_OwnerUUID, [=](cPlayer & a_Player) {
virtual bool Item(cPlayer * a_Player) override
{ {
a_Player.NotifyNearbyWolves(a_Opponent, false); a_Player->NotifyNearbyWolves(m_Opponent, false);
return false; return false;
} }
); public:
cPawn * m_Opponent;
} Callback;
Callback.m_Opponent = a_Opponent;
m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback);
} }
bool cWolf::Attack(std::chrono::milliseconds a_Dt) bool cWolf::Attack(std::chrono::milliseconds a_Dt)
@ -341,25 +347,30 @@ void cWolf::Tick(std::chrono::milliseconds a_Dt, cChunk & a_Chunk)
void cWolf::TickFollowPlayer() void cWolf::TickFollowPlayer()
{ {
Vector3d OwnerPos; class cCallback :
bool OwnerFlying; public cPlayerListCallback
auto Callback = [&](cPlayer & a_Player)
{ {
OwnerPos = a_Player.GetPosition(); virtual bool Item(cPlayer * a_Player) override
OwnerFlying = a_Player.IsFlying(); {
return true; OwnerPos = a_Player->GetPosition();
}; OwnerFlying = a_Player->IsFlying();
return true;
}
public:
Vector3d OwnerPos;
bool OwnerFlying;
} Callback;
if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback)) if (m_World->DoWithPlayerByUUID(m_OwnerUUID, Callback))
{ {
// The player is present in the world, follow him: // The player is present in the world, follow him:
double Distance = (OwnerPos - GetPosition()).Length(); double Distance = (Callback.OwnerPos - GetPosition()).Length();
if (Distance > 20) if (Distance > 20)
{ {
if (!OwnerFlying) if (!Callback.OwnerFlying)
{ {
OwnerPos.y = FindFirstNonAirBlockPosition(OwnerPos.x, OwnerPos.z); Callback.OwnerPos.y = FindFirstNonAirBlockPosition(Callback.OwnerPos.x, Callback.OwnerPos.z);
TeleportToCoords(OwnerPos.x, OwnerPos.y, OwnerPos.z); TeleportToCoords(Callback.OwnerPos.x, Callback.OwnerPos.y, Callback.OwnerPos.z);
SetTarget(nullptr); SetTarget(nullptr);
} }
} }
@ -374,9 +385,9 @@ void cWolf::TickFollowPlayer()
{ {
if (GetTarget() == nullptr) if (GetTarget() == nullptr)
{ {
if (!OwnerFlying) if (!Callback.OwnerFlying)
{ {
MoveToPosition(OwnerPos); MoveToPosition(Callback.OwnerPos);
} }
} }
} }

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Root.h" #include "Root.h"
@ -352,16 +352,22 @@ void cRoot::Start(std::unique_ptr<cSettingsRepositoryInterface> a_OverridesRepo)
void cRoot::StopServer() void cRoot::StopServer()
{ {
// Kick all players from the server with custom disconnect message // Kick all players from the server with custom disconnect message
class cPlayerCallback : public cPlayerListCallback
bool SentDisconnect = false; {
cRoot::Get()->ForEachPlayer([&](cPlayer & a_Player) AString m_ShutdownMessage;
virtual bool Item(cPlayer * a_Player)
{ {
a_Player.GetClientHandlePtr()->Kick(m_Server->GetShutdownMessage()); a_Player->GetClientHandlePtr()->Kick(m_ShutdownMessage);
SentDisconnect = true; m_HasSentDisconnect = true;
return false; return false;
} }
); public:
if (SentDisconnect) bool m_HasSentDisconnect;
cPlayerCallback(AString a_ShutdownMessage) : m_ShutdownMessage(a_ShutdownMessage) { m_HasSentDisconnect = false; }
} PlayerCallback(m_Server->GetShutdownMessage());
cRoot::Get()->ForEachPlayer(PlayerCallback);
if (PlayerCallback.m_HasSentDisconnect)
{ {
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
} }
@ -578,13 +584,14 @@ cWorld * cRoot::GetWorld(const AString & a_WorldName)
bool cRoot::ForEachWorld(const cWorldListCallback & a_Callback) bool cRoot::ForEachWorld(cWorldListCallback & a_Callback)
{ {
for (auto & World : m_WorldsByName) for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2)
{ {
if (World.second != nullptr) ++itr2;
if (itr->second != nullptr)
{ {
if (a_Callback(*World.second)) if (a_Callback.Item(itr->second))
{ {
return false; return false;
} }
@ -743,7 +750,7 @@ void cRoot::BroadcastChat(const cCompositeChat & a_Message)
bool cRoot::ForEachPlayer(const cPlayerListCallback & a_Callback) bool cRoot::ForEachPlayer(cPlayerListCallback & a_Callback)
{ {
for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2) for (WorldMap::iterator itr = m_WorldsByName.begin(), itr2 = itr; itr != m_WorldsByName.end(); itr = itr2)
{ {
@ -760,22 +767,20 @@ bool cRoot::ForEachPlayer(const cPlayerListCallback & a_Callback)
bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, const cPlayerListCallback & a_Callback) bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
{ {
class cCallback class cCallback : public cPlayerListCallback
{ {
size_t m_BestRating; size_t m_BestRating;
size_t m_NameLength; size_t m_NameLength;
const AString m_PlayerName; const AString m_PlayerName;
public: virtual bool Item (cPlayer * a_pPlayer)
bool operator () (cPlayer & a_Player)
{ {
size_t Rating = RateCompareString (m_PlayerName, a_Player.GetName()); size_t Rating = RateCompareString (m_PlayerName, a_pPlayer->GetName());
if ((Rating > 0) && (Rating >= m_BestRating)) if ((Rating > 0) && (Rating >= m_BestRating))
{ {
m_BestMatch = a_Player.GetName(); m_BestMatch = a_pPlayer->GetName();
if (Rating > m_BestRating) if (Rating > m_BestRating)
{ {
m_NumMatches = 0; m_NumMatches = 0;
@ -790,6 +795,7 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, const cPlayerListC
return false; return false;
} }
public:
cCallback (const AString & a_CBPlayerName) : cCallback (const AString & a_CBPlayerName) :
m_BestRating(0), m_BestRating(0),
m_NameLength(a_CBPlayerName.length()), m_NameLength(a_CBPlayerName.length()),
@ -814,7 +820,7 @@ bool cRoot::FindAndDoWithPlayer(const AString & a_PlayerName, const cPlayerListC
bool cRoot::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, const cPlayerListCallback & a_Callback) bool cRoot::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback & a_Callback)
{ {
for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr) for (WorldMap::iterator itr = m_WorldsByName.begin(); itr != m_WorldsByName.end(); ++itr)
{ {
@ -830,7 +836,7 @@ bool cRoot::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, const cPlayerListCall
bool cRoot::DoWithPlayer(const AString & a_PlayerName, const cPlayerListCallback & a_Callback) bool cRoot::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
{ {
for (auto World : m_WorldsByName) for (auto World : m_WorldsByName)
{ {
@ -1022,11 +1028,25 @@ int cRoot::GetFurnaceFuelBurnTime(const cItem & a_Fuel)
AStringVector cRoot::GetPlayerTabCompletionMultiWorld(const AString & a_Text) AStringVector cRoot::GetPlayerTabCompletionMultiWorld(const AString & a_Text)
{ {
AStringVector Results; AStringVector Results;
ForEachWorld([&](cWorld & a_World) class cWorldCallback : public cWorldListCallback
{
public:
cWorldCallback(AStringVector & a_Results, const AString & a_Search) :
m_Results(a_Results),
m_Search(a_Search)
{ {
a_World.TabCompleteUserName(a_Text, Results); }
virtual bool Item(cWorld * a_World) override
{
a_World->TabCompleteUserName(m_Search, m_Results);
return false; return false;
} }
); private:
AStringVector & m_Results;
const AString & m_Search;
} WC(Results, a_Text);
Get()->ForEachWorld(WC);
return Results; return Results;
} }

View File

@ -1,11 +1,10 @@

#pragma once #pragma once
#include "Protocol/Authenticator.h" #include "Protocol/Authenticator.h"
#include "Protocol/MojangAPI.h" #include "Protocol/MojangAPI.h"
#include "HTTP/HTTPServer.h" #include "HTTP/HTTPServer.h"
#include "Defines.h" #include "Defines.h"
#include <functional>
#include "RankManager.h" #include "RankManager.h"
@ -28,8 +27,8 @@ class cSettingsRepositoryInterface;
class cDeadlockDetect; class cDeadlockDetect;
class cUUID; class cUUID;
using cPlayerListCallback = std::function<bool(cPlayer &)>; typedef cItemCallback<cPlayer> cPlayerListCallback;
using cWorldListCallback = std::function<bool(cWorld &)>; typedef cItemCallback<cWorld> cWorldListCallback;
namespace Json namespace Json
{ {
@ -77,7 +76,7 @@ public:
// tolua_end // tolua_end
/** Calls the callback for each world; returns true if the callback didn't abort (return true) */ /** Calls the callback for each world; returns true if the callback didn't abort (return true) */
bool ForEachWorld(const cWorldListCallback & a_Callback); // >> Exported in ManualBindings << bool ForEachWorld(cWorldListCallback & a_Callback); // >> Exported in ManualBindings <<
/** Writes chunkstats, for each world and totals, to the output callback */ /** Writes chunkstats, for each world and totals, to the output callback */
void LogChunkStats(cCommandOutputCallback & a_Output); void LogChunkStats(cCommandOutputCallback & a_Output);
@ -137,16 +136,16 @@ public:
void SaveAllChunks(void); // tolua_export void SaveAllChunks(void); // tolua_export
/** Calls the callback for each player in all worlds */ /** Calls the callback for each player in all worlds */
bool ForEachPlayer(const cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool ForEachPlayer(cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/** Finds a player from a partial or complete player name and calls the callback - case-insensitive */ /** Finds a player from a partial or complete player name and calls the callback - case-insensitive */
bool FindAndDoWithPlayer(const AString & a_PlayerName, const cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool FindAndDoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/** Finds the player over his uuid and calls the callback */ /** Finds the player over his uuid and calls the callback */
bool DoWithPlayerByUUID(const cUUID & a_PlayerUUID, const cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/** Finds the player using it's complete username and calls the callback */ /** Finds the player using it's complete username and calls the callback */
bool DoWithPlayer(const AString & a_PlayerName, const cPlayerListCallback & a_Callback); bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback);
/** Send playerlist of all worlds to player */ /** Send playerlist of all worlds to player */
void SendPlayerLists(cPlayer * a_DestPlayer); void SendPlayerLists(cPlayer * a_DestPlayer);

View File

@ -1,4 +1,4 @@

// Scoreboard.cpp // Scoreboard.cpp
// Implementation of a scoreboard that keeps track of specified objectives // Implementation of a scoreboard that keeps track of specified objectives
@ -487,7 +487,7 @@ cObjective * cScoreboard::GetObjectiveIn(eDisplaySlot a_Slot)
bool cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, const cObjectiveCallback & a_Callback) bool cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback & a_Callback)
{ {
cCSLock Lock(m_CSObjectives); cCSLock Lock(m_CSObjectives);
@ -496,7 +496,7 @@ bool cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, const cObjectiv
if (it->second.GetType() == a_Type) if (it->second.GetType() == a_Type)
{ {
// Call callback // Call callback
if (a_Callback(it->second)) if (a_Callback.Item(&it->second))
{ {
return false; return false;
} }
@ -509,14 +509,14 @@ bool cScoreboard::ForEachObjectiveWith(cObjective::eType a_Type, const cObjectiv
bool cScoreboard::ForEachObjective(const cObjectiveCallback & a_Callback) bool cScoreboard::ForEachObjective(cObjectiveCallback & a_Callback)
{ {
cCSLock Lock(m_CSObjectives); cCSLock Lock(m_CSObjectives);
for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it) for (cObjectiveMap::iterator it = m_Objectives.begin(); it != m_Objectives.end(); ++it)
{ {
// Call callback // Call callback
if (a_Callback(it->second)) if (a_Callback.Item(&it->second))
{ {
return false; return false;
} }
@ -528,14 +528,14 @@ bool cScoreboard::ForEachObjective(const cObjectiveCallback & a_Callback)
bool cScoreboard::ForEachTeam(const cTeamCallback & a_Callback) bool cScoreboard::ForEachTeam(cTeamCallback & a_Callback)
{ {
cCSLock Lock(m_CSTeams); cCSLock Lock(m_CSTeams);
for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it) for (cTeamMap::iterator it = m_Teams.begin(); it != m_Teams.end(); ++it)
{ {
// Call callback // Call callback
if (a_Callback(it->second)) if (a_Callback.Item(&it->second))
{ {
return false; return false;
} }

View File

@ -1,4 +1,4 @@

// Scoreboard.h // Scoreboard.h
// Implementation of a scoreboard that keeps track of specified objectives // Implementation of a scoreboard that keeps track of specified objectives
@ -11,15 +11,14 @@
#include <functional>
class cObjective; class cObjective;
class cTeam; class cTeam;
class cWorld; class cWorld;
using cObjectiveCallback = std::function<bool(cObjective &)>; typedef cItemCallback<cObjective> cObjectiveCallback;
using cTeamCallback = std::function<bool(cTeam &)>; typedef cItemCallback<cTeam> cTeamCallback;
@ -267,15 +266,15 @@ public:
/** Execute callback for each objective with the specified type /** Execute callback for each objective with the specified type
Returns true if all objectives processed, false if the callback aborted by returning true. */ Returns true if all objectives processed, false if the callback aborted by returning true. */
bool ForEachObjectiveWith(cObjective::eType a_Type, const cObjectiveCallback & a_Callback); bool ForEachObjectiveWith(cObjective::eType a_Type, cObjectiveCallback & a_Callback);
/** Execute callback for each objective. /** Execute callback for each objective.
Returns true if all objectives have been processed, false if the callback aborted by returning true. */ Returns true if all objectives have been processed, false if the callback aborted by returning true. */
bool ForEachObjective(const cObjectiveCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachObjective(cObjectiveCallback & a_Callback); // Exported in ManualBindings.cpp
/** Execute callback for each team. /** Execute callback for each team.
Returns true if all teams have been processed, false if the callback aborted by returning true. */ Returns true if all teams have been processed, false if the callback aborted by returning true. */
bool ForEachTeam(const cTeamCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachTeam(cTeamCallback & a_Callback); // Exported in ManualBindings.cpp
void SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot); void SetDisplay(cObjective * a_Objective, eDisplaySlot a_Slot);

View File

@ -498,20 +498,26 @@ void cServer::ExecuteConsoleCommand(const AString & a_Cmd, cCommandOutputCallbac
} }
if (split[0] == "destroyentities") if (split[0] == "destroyentities")
{ {
cRoot::Get()->ForEachWorld([](cWorld & a_World) class WorldCallback : public cWorldListCallback
{
virtual bool Item(cWorld * a_World) override
{ {
a_World.ForEachEntity([](cEntity & a_Entity) class EntityCallback : public cEntityCallback
{
virtual bool Item(cEntity * a_Entity) override
{ {
if (!a_Entity.IsPlayer()) if (!a_Entity->IsPlayer())
{ {
a_Entity.Destroy(); a_Entity->Destroy();
} }
return false; return false;
} }
); } EC;
a_World->ForEachEntity(EC);
return false; return false;
} }
); } WC;
cRoot::Get()->ForEachWorld(WC);
a_Output.Out("Destroyed all entities"); a_Output.Out("Destroyed all entities");
a_Output.Finished(); a_Output.Finished();
return; return;

View File

@ -44,12 +44,17 @@ public:
return {}; return {};
} }
a_World.DoWithCommandBlockAt(a_Position.x, a_Position.y, a_Position.z, [](cCommandBlockEntity & a_CommandBlock) class cSetPowerToCommandBlock : public cCommandBlockCallback
{
public:
virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
{ {
a_CommandBlock.Activate(); a_CommandBlock->Activate();
return false; return false;
} }
); } CmdBlockSP;
a_World.DoWithCommandBlockAt(a_Position.x, a_Position.y, a_Position.z, CmdBlockSP);
return {}; return {};
} }

View File

@ -56,12 +56,18 @@ public:
bool WasPoweredPreviously = IsActivated(a_Meta); bool WasPoweredPreviously = IsActivated(a_Meta);
if (IsPoweredNow && !WasPoweredPreviously) if (IsPoweredNow && !WasPoweredPreviously)
{ {
a_World.DoWithDropSpenserAt(a_Position.x, a_Position.y, a_Position.z, [](cDropSpenserEntity & a_DropSpenser) class cSetPowerToDropSpenser :
public cDropSpenserCallback
{
public:
virtual bool Item(cDropSpenserEntity * a_DropSpenser) override
{ {
a_DropSpenser.Activate(); a_DropSpenser->Activate();
return false; return false;
} }
); } DrSpSP;
a_World.DoWithDropSpenserAt(a_Position.x, a_Position.y, a_Position.z, DrSpSP);
} }
// Update the internal dropspenser state if necessary // Update the internal dropspenser state if necessary

View File

@ -45,12 +45,17 @@ public:
return {}; return {};
} }
a_World.DoWithNoteBlockAt(a_Position.x, a_Position.y, a_Position.z, [](cNoteEntity & a_NoteBlock) class cSetPowerToNoteBlock : public cNoteBlockCallback
{
public:
virtual bool Item(cNoteEntity * a_NoteBlock) override
{ {
a_NoteBlock.MakeSound(); a_NoteBlock->MakeSound();
return false; return false;
} }
); } NoteBlockSP;
a_World.DoWithNoteBlockAt(a_Position.x, a_Position.y, a_Position.z, NoteBlockSP);
return {}; return {};
} }

View File

@ -27,37 +27,49 @@ public:
{ {
UNUSED(a_Meta); UNUSED(a_Meta);
unsigned int NumberOfEntities; class cPressurePlateCallback :
bool FoundPlayer; public cEntityCallback
a_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + a_Position, 0.5, 0.5), [&](cEntity & a_Entity) {
public:
cPressurePlateCallback(void) :
m_NumberOfEntities(0),
m_FoundPlayer(false)
{ {
if (a_Entity.IsPlayer()) }
virtual bool Item(cEntity * a_Entity) override
{
if (a_Entity->IsPlayer())
{ {
FoundPlayer = true; m_FoundPlayer = true;
} }
NumberOfEntities++; m_NumberOfEntities++;
return false; return false;
} }
);
unsigned int m_NumberOfEntities;
bool m_FoundPlayer;
} PressurePlateCallback;
a_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + a_Position, 0.5, 0.5), PressurePlateCallback);
switch (a_BlockType) switch (a_BlockType)
{ {
case E_BLOCK_STONE_PRESSURE_PLATE: case E_BLOCK_STONE_PRESSURE_PLATE:
{ {
return (FoundPlayer ? 15 : 0); return (PressurePlateCallback.m_FoundPlayer ? 15 : 0);
} }
case E_BLOCK_WOODEN_PRESSURE_PLATE: case E_BLOCK_WOODEN_PRESSURE_PLATE:
{ {
return (NumberOfEntities != 0 ? 15 : 0); return (PressurePlateCallback.m_NumberOfEntities != 0 ? 15 : 0);
} }
case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_HEAVY_WEIGHTED_PRESSURE_PLATE:
{ {
return std::min(static_cast<unsigned char>(CeilC(NumberOfEntities / 10.f)), static_cast<unsigned char>(15)); return std::min(static_cast<unsigned char>(CeilC(PressurePlateCallback.m_NumberOfEntities / 10.f)), static_cast<unsigned char>(15));
} }
case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE: case E_BLOCK_LIGHT_WEIGHTED_PRESSURE_PLATE:
{ {
return std::min(static_cast<unsigned char>(NumberOfEntities), static_cast<unsigned char>(15)); return std::min(static_cast<unsigned char>(PressurePlateCallback.m_NumberOfEntities), static_cast<unsigned char>(15));
} }
default: default:
{ {

View File

@ -44,12 +44,17 @@ public:
UNUSED(a_Position); UNUSED(a_Position);
UNUSED(a_BlockType); UNUSED(a_BlockType);
UInt8 SignalStrength = 0; class cContainerCallback : public cBlockEntityCallback
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3); {
a_World.DoWithBlockEntityAt(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, [&](cBlockEntity & a_BlockEntity) public:
cContainerCallback() : m_SignalStrength(0)
{
}
virtual bool Item(cBlockEntity * a_BlockEntity) override
{ {
// Skip BlockEntities that don't have slots // Skip BlockEntities that don't have slots
auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(&a_BlockEntity); auto BlockEntityWithItems = dynamic_cast<cBlockEntityWithItems *>(a_BlockEntity);
if (BlockEntityWithItems == nullptr) if (BlockEntityWithItems == nullptr)
{ {
return false; return false;
@ -63,18 +68,23 @@ public:
Fullness += static_cast<float>(Contents.GetSlot(Slot).m_ItemCount) / Contents.GetSlot(Slot).GetMaxStackSize(); Fullness += static_cast<float>(Contents.GetSlot(Slot).m_ItemCount) / Contents.GetSlot(Slot).GetMaxStackSize();
} }
SignalStrength = (Fullness < 0.001 /* container empty? */) ? 0 : static_cast<UInt8>(1 + (Fullness / Contents.GetNumSlots()) * 14); m_SignalStrength = (Fullness < 0.001 /* container empty? */) ? 0 : static_cast<unsigned char>(1 + (Fullness / Contents.GetNumSlots()) * 14);
return false; return false;
} }
);
auto RearPower = SignalStrength; unsigned char m_SignalStrength;
} CCB;
auto RearCoordinate = cBlockComparatorHandler::GetRearCoordinate(a_Position, a_Meta & 0x3);
a_World.DoWithBlockEntityAt(RearCoordinate.x, RearCoordinate.y, RearCoordinate.z, CCB);
auto RearPower = CCB.m_SignalStrength;
auto RearType = a_World.GetBlock(RearCoordinate); auto RearType = a_World.GetBlock(RearCoordinate);
auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType); auto PotentialSourceHandler = cIncrementalRedstoneSimulator::GetComponentHandler(RearType);
if (PotentialSourceHandler != nullptr) if (PotentialSourceHandler != nullptr)
{ {
NIBBLETYPE RearMeta = a_World.GetBlockMeta(RearCoordinate); NIBBLETYPE RearMeta = a_World.GetBlockMeta(RearCoordinate);
RearPower = std::max(SignalStrength, PotentialSourceHandler->GetPowerDeliveredToPosition(a_World, RearCoordinate, RearType, RearMeta, a_Position, a_BlockType)); RearPower = std::max(CCB.m_SignalStrength, PotentialSourceHandler->GetPowerDeliveredToPosition(a_World, RearCoordinate, RearType, RearMeta, a_Position, a_BlockType));
} }
return RearPower; return RearPower;

View File

@ -1,4 +1,4 @@

#pragma once #pragma once
#include "RedstoneHandler.h" #include "RedstoneHandler.h"
@ -28,15 +28,38 @@ public:
UNUSED(a_BlockType); UNUSED(a_BlockType);
UNUSED(a_Meta); UNUSED(a_Meta);
int NumberOfPlayers = 0; class cGetTrappedChestPlayers :
VERIFY(!a_World.DoWithChestAt(a_Position.x, a_Position.y, a_Position.z, [&](cChestEntity & a_Chest) public cItemCallback<cChestEntity>
{
public:
cGetTrappedChestPlayers(void) :
m_NumberOfPlayers(0)
{ {
ASSERT(a_Chest.GetBlockType() == E_BLOCK_TRAPPED_CHEST); }
NumberOfPlayers = a_Chest.GetNumberOfPlayers();
virtual ~cGetTrappedChestPlayers() override
{
}
virtual bool Item(cChestEntity * a_Chest) override
{
ASSERT(a_Chest->GetBlockType() == E_BLOCK_TRAPPED_CHEST);
m_NumberOfPlayers = a_Chest->GetNumberOfPlayers();
return true; return true;
} }
));
return static_cast<unsigned char>(std::min(NumberOfPlayers, 15)); unsigned char GetPowerLevel(void) const
{
return static_cast<unsigned char>(std::min(m_NumberOfPlayers, 15));
}
private:
int m_NumberOfPlayers;
} GTCP;
VERIFY(!a_World.DoWithChestAt(a_Position.x, a_Position.y, a_Position.z, GTCP));
return GTCP.GetPowerLevel();
} }
virtual cVector3iArray Update(cWorld & a_World, const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override virtual cVector3iArray Update(cWorld & a_World, const Vector3i & a_Position, BLOCKTYPE a_BlockType, NIBBLETYPE a_Meta, PoweringData a_PoweringData) const override

View File

@ -39,7 +39,26 @@ public:
if (Type == E_BLOCK_TRIPWIRE) if (Type == E_BLOCK_TRIPWIRE)
{ {
if (!a_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), [](cEntity &) { return true; })) class cTripwireCallback :
public cEntityCallback
{
public:
cTripwireCallback(void) :
m_NumberOfEntities(0),
m_FoundPlayer(false)
{
}
virtual bool Item(cEntity * a_Entity) override
{
return true;
}
unsigned int m_NumberOfEntities;
bool m_FoundPlayer;
} TripwireCallback;
if (!a_World.ForEachEntityInBox(cBoundingBox(Vector3d(0.5, 0, 0.5) + Position, 0.5, 0.5), TripwireCallback))
{ {
FoundActivated = true; FoundActivated = true;
} }

View File

@ -1,4 +1,4 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Window.h" #include "Window.h"
#include "WindowOwner.h" #include "WindowOwner.h"
@ -362,12 +362,12 @@ void cWindow::OwnerDestroyed()
bool cWindow::ForEachPlayer(const cPlayerListCallback & a_Callback) bool cWindow::ForEachPlayer(cItemCallback<cPlayer> & a_Callback)
{ {
cCSLock Lock(m_CS); cCSLock Lock(m_CS);
for (auto & Player : m_OpenedBy) for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr)
{ {
if (a_Callback(*Player)) if (a_Callback.Item(*itr))
{ {
return false; return false;
} }
@ -379,12 +379,12 @@ bool cWindow::ForEachPlayer(const cPlayerListCallback & a_Callback)
bool cWindow::ForEachClient(cClientHandleCallback & a_Callback) bool cWindow::ForEachClient(cItemCallback<cClientHandle> & a_Callback)
{ {
cCSLock Lock(m_CS); cCSLock Lock(m_CS);
for (auto & Player : m_OpenedBy) for (cPlayerList::iterator itr = m_OpenedBy.begin(), end = m_OpenedBy.end(); itr != end; ++itr)
{ {
if (a_Callback(*Player->GetClientHandle())) if (a_Callback.Item((*itr)->GetClientHandle()))
{ {
return false; return false;
} }

View File

@ -1,4 +1,4 @@

// Window.h // Window.h
// Interfaces to the cWindow class representing a UI window for a specific block // Interfaces to the cWindow class representing a UI window for a specific block
@ -9,7 +9,6 @@
#pragma once #pragma once
#include <functional>
#include "../ItemGrid.h" #include "../ItemGrid.h"
@ -32,8 +31,7 @@ class cWorld;
typedef std::list<cPlayer *> cPlayerList; typedef std::list<cPlayer *> cPlayerList;
typedef std::vector<cSlotArea *> cSlotAreas; typedef std::vector<cSlotArea *> cSlotAreas;
using cPlayerListCallback = std::function<bool(cPlayer &)>;
using cClientHandleCallback = std::function<bool(cClientHandle &)>;
@ -153,10 +151,10 @@ public:
void OwnerDestroyed(void); void OwnerDestroyed(void);
/** Calls the callback safely for each player that has this window open; returns true if all players have been enumerated */ /** Calls the callback safely for each player that has this window open; returns true if all players have been enumerated */
bool ForEachPlayer(const cPlayerListCallback & a_Callback); bool ForEachPlayer(cItemCallback<cPlayer> & a_Callback);
/** Calls the callback safely for each client that has this window open; returns true if all clients have been enumerated */ /** Calls the callback safely for each client that has this window open; returns true if all clients have been enumerated */
bool ForEachClient(cClientHandleCallback & a_Callback); bool ForEachClient(cItemCallback<cClientHandle> & a_Callback);
/** Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is distributed! /** Called on shift-clicking to distribute the stack into other areas; Modifies a_ItemStack as it is distributed!
if a_ShouldApply is true, the changes are written into the slots; if a_ShouldApply is true, the changes are written into the slots;

View File

@ -21,6 +21,30 @@ static const char DEFAULT_WEBADMIN_PORTS[] = "8080";
////////////////////////////////////////////////////////////////////////////////
// cPlayerAccum:
/** Helper class - appends all player names together in an HTML list */
class cPlayerAccum :
public cPlayerListCallback
{
virtual bool Item(cPlayer * a_Player) override
{
m_Contents.append("<li>");
m_Contents.append(a_Player->GetName());
m_Contents.append("</li>");
return false;
}
public:
AString m_Contents;
} ;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// cWebadminRequestData // cWebadminRequestData

View File

@ -1,4 +1,4 @@

#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "World.h" #include "World.h"
@ -1117,52 +1117,59 @@ void cWorld::TickMobs(std::chrono::milliseconds a_Dt)
{ {
m_ChunkMap->SpawnMobs(Spawner); m_ChunkMap->SpawnMobs(Spawner);
// do the spawn // do the spawn
for (auto & Mob : Spawner.getSpawned()) for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); ++itr2)
{ {
SpawnMobFinalize(std::move(Mob)); SpawnMobFinalize(std::move(const_cast<std::unique_ptr<cMonster> &>(*itr2)));
} }
} }
} // for i - AllFamilies[] } // for i - AllFamilies[]
} // if (Spawning enabled) } // if (Spawning enabled)
ForEachEntity([=](cEntity & a_Entity) class cCallback : public cEntityCallback
{
virtual bool Item(cEntity * a_Entity) override
{ {
if (!a_Entity.IsMob()) if (!a_Entity->IsMob())
{ {
return false; return false;
} }
if (!a_Entity.IsTicking()) if (!a_Entity->IsTicking())
{ {
return false; return false;
} }
auto & Monster = static_cast<cMonster &>(a_Entity); auto Monster = static_cast<cMonster *>(a_Entity);
ASSERT(Monster.GetParentChunk() != nullptr); // A ticking entity must have a valid parent chunk ASSERT(Monster->GetParentChunk() != nullptr); // A ticking entity must have a valid parent chunk
// Tick close mobs // Tick close mobs
if (Monster.GetParentChunk()->HasAnyClients()) if (Monster->GetParentChunk()->HasAnyClients())
{ {
Monster.Tick(a_Dt, *(a_Entity.GetParentChunk())); Monster->Tick(m_Dt, *(a_Entity->GetParentChunk()));
} }
// Destroy far hostile mobs except if last target was a player // Destroy far hostile mobs except if last target was a player
else if ((Monster.GetMobFamily() == cMonster::eFamily::mfHostile) && !Monster.WasLastTargetAPlayer()) else if ((Monster->GetMobFamily() == cMonster::eFamily::mfHostile) && !Monster->WasLastTargetAPlayer())
{ {
if (Monster.GetMobType() != eMonsterType::mtWolf) if (Monster->GetMobType() != eMonsterType::mtWolf)
{ {
Monster.Destroy(true); Monster->Destroy(true);
} }
else else
{ {
auto & Wolf = static_cast<cWolf &>(Monster); auto Wolf = static_cast<cWolf *>(Monster);
if (Wolf.IsAngry()) if (Wolf->IsAngry())
{ {
Monster.Destroy(true); Monster->Destroy(true);
} }
} }
} }
return false; return false;
} }
); public:
std::chrono::milliseconds m_Dt;
} Callback;
Callback.m_Dt = a_Dt;
ForEachEntity(Callback);
} }
@ -1314,7 +1321,7 @@ void cWorld::WakeUpSimulatorsInArea(const cCuboid & a_Area)
bool cWorld::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, const cBlockEntityCallback & a_Callback) bool cWorld::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback)
{ {
return m_ChunkMap->ForEachBlockEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachBlockEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1323,7 +1330,7 @@ bool cWorld::ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, const cBlockE
bool cWorld::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, const cBrewingstandCallback & a_Callback) bool cWorld::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback & a_Callback)
{ {
return m_ChunkMap->ForEachBrewingstandInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachBrewingstandInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1332,7 +1339,7 @@ bool cWorld::ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, const cBrewi
bool cWorld::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, const cChestCallback & a_Callback) bool cWorld::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback)
{ {
return m_ChunkMap->ForEachChestInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachChestInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1341,7 +1348,7 @@ bool cWorld::ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, const cChestCallbac
bool cWorld::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, const cDispenserCallback & a_Callback) bool cWorld::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback)
{ {
return m_ChunkMap->ForEachDispenserInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachDispenserInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1350,7 +1357,7 @@ bool cWorld::ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, const cDispense
bool cWorld::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, const cDropperCallback & a_Callback) bool cWorld::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback)
{ {
return m_ChunkMap->ForEachDropperInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachDropperInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1359,7 +1366,7 @@ bool cWorld::ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, const cDropperCal
bool cWorld::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, const cDropSpenserCallback & a_Callback) bool cWorld::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback)
{ {
return m_ChunkMap->ForEachDropSpenserInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachDropSpenserInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1368,7 +1375,7 @@ bool cWorld::ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, const cDropSp
bool cWorld::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, const cFurnaceCallback & a_Callback) bool cWorld::ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback)
{ {
return m_ChunkMap->ForEachFurnaceInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachFurnaceInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1423,7 +1430,7 @@ void cWorld::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_Blo
bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback) bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback)
{ {
return m_ChunkMap->DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithBlockEntityAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1432,7 +1439,7 @@ bool cWorld::DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const
bool cWorld::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBeaconCallback & a_Callback) bool cWorld::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback)
{ {
return m_ChunkMap->DoWithBeaconAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithBeaconAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1441,7 +1448,7 @@ bool cWorld::DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBea
bool cWorld::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCallback & a_Callback) bool cWorld::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback)
{ {
return m_ChunkMap->DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithBedAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1450,7 +1457,7 @@ bool cWorld::DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCal
bool cWorld::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBrewingstandCallback & a_Callback) bool cWorld::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback)
{ {
return m_ChunkMap->DoWithBrewingstandAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithBrewingstandAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1459,7 +1466,7 @@ bool cWorld::DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cons
bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChestCallback & a_Callback) bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback)
{ {
return m_ChunkMap->DoWithChestAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithChestAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1468,7 +1475,7 @@ bool cWorld::DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChes
bool cWorld::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDispenserCallback & a_Callback) bool cWorld::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback)
{ {
return m_ChunkMap->DoWithDispenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithDispenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1477,7 +1484,7 @@ bool cWorld::DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const c
bool cWorld::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropperCallback & a_Callback) bool cWorld::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback)
{ {
return m_ChunkMap->DoWithDropperAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithDropperAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1486,7 +1493,7 @@ bool cWorld::DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDr
bool cWorld::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropSpenserCallback & a_Callback) bool cWorld::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback)
{ {
return m_ChunkMap->DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithDropSpenserAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1495,7 +1502,7 @@ bool cWorld::DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const
bool cWorld::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFurnaceCallback & a_Callback) bool cWorld::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback)
{ {
return m_ChunkMap->DoWithFurnaceAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithFurnaceAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1504,7 +1511,7 @@ bool cWorld::DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFu
bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cNoteBlockCallback & a_Callback) bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback)
{ {
return m_ChunkMap->DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithNoteBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1513,7 +1520,7 @@ bool cWorld::DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const c
bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cCommandBlockCallback & a_Callback) bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback)
{ {
return m_ChunkMap->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1522,7 +1529,7 @@ bool cWorld::DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cons
bool cWorld::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMobHeadCallback & a_Callback) bool cWorld::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback)
{ {
return m_ChunkMap->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithMobHeadAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1531,7 +1538,7 @@ bool cWorld::DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMo
bool cWorld::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFlowerPotCallback & a_Callback) bool cWorld::DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback)
{ {
return m_ChunkMap->DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback); return m_ChunkMap->DoWithFlowerPotAt(a_BlockX, a_BlockY, a_BlockZ, a_Callback);
} }
@ -1549,7 +1556,7 @@ bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_
bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, const cChunkCallback & a_Callback) bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback)
{ {
return m_ChunkMap->DoWithChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->DoWithChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -1558,7 +1565,31 @@ bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, const cChunkCallback & a_Ca
bool cWorld::DoWithChunkAt(Vector3i a_BlockPos, const cChunkCallback & a_Callback) bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback)
{
struct cCallBackWrapper : cChunkCallback
{
cCallBackWrapper(std::function<bool(cChunk &)> a_InnerCallback) :
m_Callback(a_InnerCallback)
{
}
virtual bool Item(cChunk * a_Chunk)
{
return m_Callback(*a_Chunk);
}
private:
std::function<bool(cChunk &)> m_Callback;
} callback(a_Callback);
return m_ChunkMap->DoWithChunk(a_ChunkX, a_ChunkZ, callback);
}
bool cWorld::DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback)
{ {
return m_ChunkMap->DoWithChunkAt(a_BlockPos, a_Callback); return m_ChunkMap->DoWithChunkAt(a_BlockPos, a_Callback);
} }
@ -3132,13 +3163,18 @@ bool cWorld::IsPlayerReferencedInWorldOrChunk(cPlayer & a_Player)
bool cWorld::ForEachPlayer(const cPlayerListCallback & a_Callback) bool cWorld::ForEachPlayer(cPlayerListCallback & a_Callback)
{ {
// Calls the callback for each player in the list // Calls the callback for each player in the list
cCSLock Lock(m_CSPlayers); cCSLock Lock(m_CSPlayers);
for (auto & Player : m_Players) for (cPlayerList::iterator itr = m_Players.begin(), itr2 = itr; itr != m_Players.end(); itr = itr2)
{ {
if (Player->IsTicking() && a_Callback(*Player)) ++itr2;
if (!(*itr)->IsTicking())
{
continue;
}
if (a_Callback.Item(*itr))
{ {
return false; return false;
} }
@ -3150,15 +3186,19 @@ bool cWorld::ForEachPlayer(const cPlayerListCallback & a_Callback)
bool cWorld::DoWithPlayer(const AString & a_PlayerName, const cPlayerListCallback & a_Callback) bool cWorld::DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback)
{ {
// Calls the callback for the specified player in the list // Calls the callback for the specified player in the list
cCSLock Lock(m_CSPlayers); cCSLock Lock(m_CSPlayers);
for (auto & Player : m_Players) for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (Player->IsTicking() && (NoCaseCompare(Player->GetName(), a_PlayerName) == 0)) if (!(*itr)->IsTicking())
{ {
a_Callback(*Player); continue;
}
if (NoCaseCompare((*itr)->GetName(), a_PlayerName) == 0)
{
a_Callback.Item(*itr);
return true; return true;
} }
} // for itr - m_Players[] } // for itr - m_Players[]
@ -3169,7 +3209,7 @@ bool cWorld::DoWithPlayer(const AString & a_PlayerName, const cPlayerListCallbac
bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, const cPlayerListCallback & a_Callback) bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback)
{ {
cPlayer * BestMatch = nullptr; cPlayer * BestMatch = nullptr;
size_t BestRating = 0; size_t BestRating = 0;
@ -3196,7 +3236,7 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, const cPlayer
if (BestMatch != nullptr) if (BestMatch != nullptr)
{ {
return a_Callback(*BestMatch); return a_Callback.Item (BestMatch);
} }
return false; return false;
} }
@ -3205,14 +3245,27 @@ bool cWorld::FindAndDoWithPlayer(const AString & a_PlayerNameHint, const cPlayer
bool cWorld::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, const cPlayerListCallback & a_Callback) bool cWorld::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback & a_Callback)
{
return DoWithPlayerByUUID(a_PlayerUUID, std::bind(&cPlayerListCallback::Item, &a_Callback, std::placeholders::_1));
}
bool cWorld::DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cLambdaPlayerCallback a_Callback)
{ {
cCSLock Lock(m_CSPlayers); cCSLock Lock(m_CSPlayers);
for (auto & Player : m_Players) for (cPlayerList::iterator itr = m_Players.begin(); itr != m_Players.end(); ++itr)
{ {
if (Player->IsTicking() && (Player->GetUUID() == a_PlayerUUID)) if (!(*itr)->IsTicking())
{ {
return a_Callback(*Player); continue;
}
if ((*itr)->GetUUID() == a_PlayerUUID)
{
return a_Callback(*itr);
} }
} }
return false; return false;
@ -3280,7 +3333,7 @@ void cWorld::SendPlayerList(cPlayer * a_DestPlayer)
bool cWorld::ForEachEntity(const cEntityCallback & a_Callback) bool cWorld::ForEachEntity(cEntityCallback & a_Callback)
{ {
return m_ChunkMap->ForEachEntity(a_Callback); return m_ChunkMap->ForEachEntity(a_Callback);
} }
@ -3289,7 +3342,7 @@ bool cWorld::ForEachEntity(const cEntityCallback & a_Callback)
bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, const cEntityCallback & a_Callback) bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback)
{ {
return m_ChunkMap->ForEachEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback); return m_ChunkMap->ForEachEntityInChunk(a_ChunkX, a_ChunkZ, a_Callback);
} }
@ -3298,7 +3351,7 @@ bool cWorld::ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, const cEntityCallb
bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallback & a_Callback) bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback)
{ {
return m_ChunkMap->ForEachEntityInBox(a_Box, a_Callback); return m_ChunkMap->ForEachEntityInBox(a_Box, a_Callback);
} }
@ -3307,7 +3360,16 @@ bool cWorld::ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallbac
bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, const cEntityCallback & a_Callback) bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback)
{
return DoWithEntityByID(a_UniqueID, std::bind(&cEntityCallback::Item, &a_Callback, std::placeholders::_1));
}
bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callback)
{ {
// First check the entities-to-add: // First check the entities-to-add:
{ {
@ -3316,7 +3378,7 @@ bool cWorld::DoWithEntityByID(UInt32 a_UniqueID, const cEntityCallback & a_Callb
{ {
if (ent->GetUniqueID() == a_UniqueID) if (ent->GetUniqueID() == a_UniqueID)
{ {
a_Callback(*ent); a_Callback(ent.get());
return true; return true;
} }
} // for ent - m_EntitiesToAdd[] } // for ent - m_EntitiesToAdd[]
@ -3448,12 +3510,20 @@ bool cWorld::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const AStrin
bool cWorld::SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Command) bool cWorld::SetCommandBlockCommand(int a_BlockX, int a_BlockY, int a_BlockZ, const AString & a_Command)
{ {
return DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, [&](cCommandBlockEntity & a_CommandBlock) class cUpdateCommandBlock : public cCommandBlockCallback
{
AString m_Command;
public:
cUpdateCommandBlock(const AString & a_CallbackCommand) : m_Command(a_CallbackCommand) {}
virtual bool Item(cCommandBlockEntity * a_CommandBlock) override
{ {
a_CommandBlock.SetCommand(a_Command); a_CommandBlock->SetCommand(m_Command);
return false; return false;
} }
); } CmdBlockCB (a_Command);
return DoWithCommandBlockAt(a_BlockX, a_BlockY, a_BlockZ, CmdBlockCB);
} }
@ -3548,7 +3618,7 @@ bool cWorld::ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunk
bool cWorld::ForEachLoadedChunk(const std::function<bool(int, int)> & a_Callback) bool cWorld::ForEachLoadedChunk(std::function<bool(int, int)> a_Callback)
{ {
return m_ChunkMap->ForEachLoadedChunk(a_Callback); return m_ChunkMap->ForEachLoadedChunk(a_Callback);
} }
@ -3579,7 +3649,7 @@ void cWorld::QueueSaveAllChunks(void)
void cWorld::QueueTask(std::function<void(cWorld &)> a_Task) void cWorld::QueueTask(std::function<void(cWorld &)> a_Task)
{ {
cCSLock Lock(m_CSTasks); cCSLock Lock(m_CSTasks);
m_Tasks.emplace_back(0, std::move(a_Task)); m_Tasks.emplace_back(0, a_Task);
} }
@ -3593,7 +3663,7 @@ void cWorld::ScheduleTask(int a_DelayTicks, std::function<void (cWorld &)> a_Tas
// Insert the task into the list of scheduled tasks // Insert the task into the list of scheduled tasks
{ {
cCSLock Lock(m_CSTasks); cCSLock Lock(m_CSTasks);
m_Tasks.emplace_back(TargetTick, std::move(a_Task)); m_Tasks.emplace_back(TargetTick, a_Task);
} }
} }

View File

@ -1,4 +1,4 @@

#pragma once #pragma once
#define MAX_PLAYERS 65535 #define MAX_PLAYERS 65535
@ -58,6 +58,21 @@ typedef std::list< std::pair< std::unique_ptr<cPlayer>, cWorld * > > cAwaitingPl
typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr; typedef std::unique_ptr<cSetChunkData> cSetChunkDataPtr;
typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs; typedef std::vector<cSetChunkDataPtr> cSetChunkDataPtrs;
typedef cItemCallback<cPlayer> cPlayerListCallback;
typedef cItemCallback<cEntity> cEntityCallback;
typedef cItemCallback<cBeaconEntity> cBeaconCallback;
typedef cItemCallback<cBrewingstandEntity> cBrewingstandCallback;
typedef cItemCallback<cChestEntity> cChestCallback;
typedef cItemCallback<cDispenserEntity> cDispenserCallback;
typedef cItemCallback<cFurnaceEntity> cFurnaceCallback;
typedef cItemCallback<cNoteEntity> cNoteBlockCallback;
typedef cItemCallback<cCommandBlockEntity> cCommandBlockCallback;
typedef cItemCallback<cMobHeadEntity> cMobHeadCallback;
typedef cItemCallback<cFlowerPotEntity> cFlowerPotCallback;
typedef std::function<bool (cPlayer *)> cLambdaPlayerCallback;
typedef std::function<bool (cEntity *)> cLambdaEntityCallback;
@ -260,20 +275,21 @@ public:
#endif #endif
/** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */ /** Calls the callback for each player in the list; returns true if all players processed, false if the callback aborted by returning true */
virtual bool ForEachPlayer(const cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS << virtual bool ForEachPlayer(cPlayerListCallback & a_Callback) override; // >> EXPORTED IN MANUALBINDINGS <<
/** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found. /** Calls the callback for the player of the given name; returns true if the player was found and the callback called, false if player not found.
Callback return value is ignored. If there are multiple players of the same name, only (random) one is processed by the callback. */ Callback return value is ignored. If there are multiple players of the same name, only (random) one is processed by the callback. */
bool DoWithPlayer(const AString & a_PlayerName, const cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool DoWithPlayer(const AString & a_PlayerName, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
/** Finds a player from a partial or complete player name and calls the callback - case-insensitive */ /** Finds a player from a partial or complete player name and calls the callback - case-insensitive */
bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, const cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool FindAndDoWithPlayer(const AString & a_PlayerNameHint, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
// TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action) // TODO: This interface is dangerous - rewrite to DoWithClosestPlayer(pos, sight, action)
cPlayer * FindClosestPlayer(Vector3d a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true); cPlayer * FindClosestPlayer(Vector3d a_Pos, float a_SightLimit, bool a_CheckLineOfSight = true);
/** Finds the player over his uuid and calls the callback */ /** Finds the player over his uuid and calls the callback */
bool DoWithPlayerByUUID(const cUUID & a_PlayerUUID, const cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS << bool DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cPlayerListCallback & a_Callback); // >> EXPORTED IN MANUALBINDINGS <<
bool DoWithPlayerByUUID(const cUUID & a_PlayerUUID, cLambdaPlayerCallback a_Callback); // Lambda version
void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
@ -286,19 +302,20 @@ public:
bool HasEntity(UInt32 a_UniqueID); bool HasEntity(UInt32 a_UniqueID);
/** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */ /** Calls the callback for each entity in the entire world; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntity(const cEntityCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachEntity(cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */ /** Calls the callback for each entity in the specified chunk; returns true if all entities processed, false if the callback aborted by returning true */
bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, const cEntityCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox. /** Calls the callback for each entity that has a nonempty intersection with the specified boundingbox.
Returns true if all entities processed, false if the callback aborted by returning true. Returns true if all entities processed, false if the callback aborted by returning true.
If any chunk in the box is missing, ignores the entities in that chunk silently. */ If any chunk in the box is missing, ignores the entities in that chunk silently. */
virtual bool ForEachEntityInBox(const cBoundingBox & a_Box, const cEntityCallback & a_Callback) override; // Exported in ManualBindings.cpp virtual bool ForEachEntityInBox(const cBoundingBox & a_Box, cEntityCallback & a_Callback) override; // Exported in ManualBindings.cpp
/** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. /** Calls the callback if the entity with the specified ID is found, with the entity object as the callback param.
Returns true if entity found and callback returned false. */ Returns true if entity found and callback returned false. */
bool DoWithEntityByID(UInt32 a_UniqueID, const cEntityCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithEntityByID(UInt32 a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp
bool DoWithEntityByID(UInt32 a_UniqueID, cLambdaEntityCallback a_Callback); // Lambda version
/** Compares clients of two chunks, calls the callback accordingly */ /** Compares clients of two chunks, calls the callback accordingly */
void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback);
@ -362,7 +379,7 @@ public:
virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) override; virtual bool ForEachChunkInRect(int a_MinChunkX, int a_MaxChunkX, int a_MinChunkZ, int a_MaxChunkZ, cChunkDataCallback & a_Callback) override;
/** Calls the callback for each loaded chunk. Returns true if all chunks have been processed successfully */ /** Calls the callback for each loaded chunk. Returns true if all chunks have been processed successfully */
bool ForEachLoadedChunk(const std::function<bool(int, int)> & a_Callback); bool ForEachLoadedChunk(std::function<bool(int, int)> a_Callback);
// tolua_begin // tolua_begin
@ -499,25 +516,25 @@ public:
inline cRedstoneSimulator * GetRedstoneSimulator(void) { return m_RedstoneSimulator; } inline cRedstoneSimulator * GetRedstoneSimulator(void) { return m_RedstoneSimulator; }
/** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */ /** Calls the callback for each block entity in the specified chunk; returns true if all block entities processed, false if the callback aborted by returning true */
bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, const cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachBlockEntityInChunk(int a_ChunkX, int a_ChunkZ, cBlockEntityCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for each brewingstand in the specified chunk; returns true if all brewingstands processed, false if the callback aborted by returning true */ /** Calls the callback for each brewingstand in the specified chunk; returns true if all brewingstands processed, false if the callback aborted by returning true */
bool ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, const cBrewingstandCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachBrewingstandInChunk(int a_ChunkX, int a_ChunkZ, cBrewingstandCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */ /** Calls the callback for each chest in the specified chunk; returns true if all chests processed, false if the callback aborted by returning true */
bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, const cChestCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachChestInChunk(int a_ChunkX, int a_ChunkZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */ /** Calls the callback for each dispenser in the specified chunk; returns true if all dispensers processed, false if the callback aborted by returning true */
bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, const cDispenserCallback & a_Callback); bool ForEachDispenserInChunk(int a_ChunkX, int a_ChunkZ, cDispenserCallback & a_Callback);
/** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */ /** Calls the callback for each dropper in the specified chunk; returns true if all droppers processed, false if the callback aborted by returning true */
bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, const cDropperCallback & a_Callback); bool ForEachDropperInChunk(int a_ChunkX, int a_ChunkZ, cDropperCallback & a_Callback);
/** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */ /** Calls the callback for each dropspenser in the specified chunk; returns true if all dropspensers processed, false if the callback aborted by returning true */
bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, const cDropSpenserCallback & a_Callback); bool ForEachDropSpenserInChunk(int a_ChunkX, int a_ChunkZ, cDropSpenserCallback & a_Callback);
/** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */ /** Calls the callback for each furnace in the specified chunk; returns true if all furnaces processed, false if the callback aborted by returning true */
bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, const cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp bool ForEachFurnaceInChunk(int a_ChunkX, int a_ChunkZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
/** Does an explosion with the specified strength at the specified coordinates. /** Does an explosion with the specified strength at the specified coordinates.
Executes the HOOK_EXPLODING and HOOK_EXPLODED hooks as part of the processing. Executes the HOOK_EXPLODING and HOOK_EXPLODED hooks as part of the processing.
@ -526,43 +543,43 @@ public:
virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) override; virtual void DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_BlockY, double a_BlockZ, bool a_CanCauseFire, eExplosionSource a_Source, void * a_SourceData) override;
/** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */ /** Calls the callback for the block entity at the specified coords; returns false if there's no block entity at those coords, true if found */
virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBlockEntityCallback & a_Callback) override; // Exported in ManualBindings.cpp virtual bool DoWithBlockEntityAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBlockEntityCallback & a_Callback) override; // Exported in ManualBindings.cpp
/** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */ /** Calls the callback for the beacon at the specified coords; returns false if there's no beacon at those coords, true if found */
bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBeaconCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithBeaconAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBeaconCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */ /** Calls the callback for the bed at the specified coords; returns false if there's no bed at those coords, true if found */
virtual bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBedCallback & a_Callback) override; // Exported in ManualBindings.cpp virtual bool DoWithBedAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBedCallback & a_Callback) override; // Exported in ManualBindings.cpp
/** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */ /** Calls the callback for the brewingstand at the specified coords; returns false if there's no brewingstand at those coords, true if found */
bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cBrewingstandCallback & a_Callback); // Lua-acessible bool DoWithBrewingstandAt(int a_BlockX, int a_BlockY, int a_BlockZ, cBrewingstandCallback & a_Callback); // Lua-acessible
/** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */ /** Calls the callback for the chest at the specified coords; returns false if there's no chest at those coords, true if found */
bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cChestCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithChestAt(int a_BlockX, int a_BlockY, int a_BlockZ, cChestCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */ /** Calls the callback for the dispenser at the specified coords; returns false if there's no dispenser at those coords or callback returns true, returns true if found */
bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithDispenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDispenserCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */ /** Calls the callback for the dropper at the specified coords; returns false if there's no dropper at those coords or callback returns true, returns true if found */
bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropperCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithDropperAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropperCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */ /** Calls the callback for the dropspenser at the specified coords; returns false if there's no dropspenser at those coords or callback returns true, returns true if found */
bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithDropSpenserAt(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */ /** Calls the callback for the furnace at the specified coords; returns false if there's no furnace at those coords or callback returns true, returns true if found */
bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithFurnaceAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */ /** Calls the callback for the noteblock at the specified coords; returns false if there's no noteblock at those coords or callback returns true, returns true if found */
bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithNoteBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cNoteBlockCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */ /** Calls the callback for the command block at the specified coords; returns false if there's no command block at those coords or callback returns true, returns true if found */
bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithCommandBlockAt(int a_BlockX, int a_BlockY, int a_BlockZ, cCommandBlockCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */ /** Calls the callback for the mob head block at the specified coords; returns false if there's no mob head block at those coords or callback returns true, returns true if found */
bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cMobHeadCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithMobHeadAt(int a_BlockX, int a_BlockY, int a_BlockZ, cMobHeadCallback & a_Callback); // Exported in ManualBindings.cpp
/** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */ /** Calls the callback for the flower pot at the specified coords; returns false if there's no flower pot at those coords or callback returns true, returns true if found */
bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, const cFlowerPotCallback & a_Callback); // Exported in ManualBindings.cpp bool DoWithFlowerPotAt(int a_BlockX, int a_BlockY, int a_BlockZ, cFlowerPotCallback & a_Callback); // Exported in ManualBindings.cpp
/** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */ /** Retrieves the test on the sign at the specified coords; returns false if there's no sign at those coords, true if found */
bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp bool GetSignLines (int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_Line1, AString & a_Line2, AString & a_Line3, AString & a_Line4); // Exported in ManualBindings.cpp
@ -570,13 +587,13 @@ public:
/** a_Player is using block entity at [x, y, z], handle that: */ /** a_Player is using block entity at [x, y, z], handle that: */
void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); } // tolua_export void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); } // tolua_export
/** Calls the callback for the chunk specified, with ChunkMapCS locked. /** Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback */
Returns false if the chunk doesn't exist, otherwise returns the same value as the callback */ bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback);
bool DoWithChunk(int a_ChunkX, int a_ChunkZ, const cChunkCallback & a_Callback); bool DoWithChunk(int a_ChunkX, int a_ChunkZ, std::function<bool(cChunk &)> a_Callback);
/** Calls the callback for the chunk at the block position specified, with ChunkMapCS locked. /** Calls the callback for the chunk at the block position specified, with ChunkMapCS locked.
Returns false if the chunk isn't loaded, otherwise returns the same value as the callback */ Returns false if the chunk isn't loaded, otherwise returns the same value as the callback */
bool DoWithChunkAt(Vector3i a_BlockPos, const cChunkCallback & a_Callback); bool DoWithChunkAt(Vector3i a_BlockPos, std::function<bool(cChunk &)> a_Callback);
void GrowTreeImage(const sSetBlockVector & a_Blocks); void GrowTreeImage(const sSetBlockVector & a_Blocks);