Merge branch 'master' of https://github.com/mc-server/MCServer
This commit is contained in:
commit
007bac638b
14
.travis.yml
14
.travis.yml
@ -2,7 +2,7 @@ language: cpp
|
|||||||
compiler: clang
|
compiler: clang
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ]; then sudo pip install cpp_coveralls; fi
|
# - if [ "$TRAVIS_MCSERVER_BUILD_TYPE" == "COVERAGE" ]; then sudo pip install cpp_coveralls; fi
|
||||||
|
|
||||||
# g++4.8
|
# g++4.8
|
||||||
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
- sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||||
@ -21,17 +21,17 @@ install:
|
|||||||
# Build MCServer
|
# Build MCServer
|
||||||
script: ./CIbuild.sh
|
script: ./CIbuild.sh
|
||||||
|
|
||||||
after_success:
|
#after_success:
|
||||||
- ./uploadCoverage.sh
|
# - ./uploadCoverage.sh
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
|
- TRAVIS_MCSERVER_BUILD_TYPE=RELEASE MCSERVER_PATH=./MCServer
|
||||||
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG MCSERVER_PATH=./MCServer_debug
|
- TRAVIS_MCSERVER_BUILD_TYPE=DEBUG MCSERVER_PATH=./MCServer_debug
|
||||||
|
|
||||||
matrix:
|
#matrix:
|
||||||
include:
|
# include:
|
||||||
- compiler: gcc
|
# - compiler: gcc
|
||||||
env: TRAVIS_MCSERVER_BUILD_TYPE=COVERAGE MCSERVER_PATH=./MCServer
|
# env: TRAVIS_MCSERVER_BUILD_TYPE=COVERAGE MCSERVER_PATH=./MCServer
|
||||||
|
|
||||||
# Notification Settings
|
# Notification Settings
|
||||||
notifications:
|
notifications:
|
||||||
|
@ -971,7 +971,7 @@ end
|
|||||||
|
|
||||||
--- Writes a list of undocumented objects into a file
|
--- Writes a list of undocumented objects into a file
|
||||||
local function ListUndocumentedObjects(API, UndocumentedHooks)
|
local function ListUndocumentedObjects(API, UndocumentedHooks)
|
||||||
f = io.open("API/_undocumented.lua", "w");
|
local f = io.open("API/_undocumented.lua", "w");
|
||||||
if (f ~= nil) then
|
if (f ~= nil) then
|
||||||
f:write("\n-- This is the list of undocumented API objects, automatically generated by APIDump\n\n");
|
f:write("\n-- This is the list of undocumented API objects, automatically generated by APIDump\n\n");
|
||||||
f:write("g_APIDesc =\n{\n\tClasses =\n\t{\n");
|
f:write("g_APIDesc =\n{\n\tClasses =\n\t{\n");
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer/master.svg?style=flat)](https://travis-ci.org/mc-server/MCServer) [![Coverity Scan Build Status](https://scan.coverity.com/projects/1930/badge.svg)](https://scan.coverity.com/projects/1930) [![weekly tips](http://img.shields.io/gratipay/cuberite_team.svg?style=flat)](http://gratipay.com/cuberite_team) [![tip for next commit](http://tip4commit.com/projects/74.svg)](http://tip4commit.com/projects/74)
|
MCServer [![Build Status](http://img.shields.io/travis/mc-server/MCServer/master.svg?style=flat)](https://travis-ci.org/mc-server/MCServer) [![Coverity Scan Build Status](https://img.shields.io/coverity/scan/1930.svg)](https://scan.coverity.com/projects/1930) [![weekly tips](http://img.shields.io/gratipay/cuberite_team.svg?style=flat)](http://gratipay.com/cuberite_team)
|
||||||
========
|
========
|
||||||
|
|
||||||
MCServer is a Minecraft server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API.
|
MCServer is a Minecraft-compatible multiplayer game server that is written in C++ and designed to be efficient with memory and CPU, as well as having a flexible Lua Plugin API. MCServer is compatible with the vanilla Minecraft client.
|
||||||
|
|
||||||
MCServer can run on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis.
|
MCServer can run on Windows, *nix and Android operating systems. This includes Android phones and tablets as well as Raspberry Pis.
|
||||||
|
|
||||||
We currently support Release 1.7 and 1.8 (not beta) Minecraft protocol versions.
|
We currently support Release 1.7 and 1.8 (not beta) Minecraft protocol versions.
|
||||||
|
|
||||||
|
Subscribe to [the newsletter](http://newsletter.cuberite.org/subscribe.htm) for important updates and project news.
|
||||||
|
|
||||||
Installation
|
Installation
|
||||||
------------
|
------------
|
||||||
Hosted MCServer is available DIY on DigitalOcean: [![Install on DigitalOcean](http://doinstall.bearbin.net/button.svg)](http://doinstall.bearbin.net/install?url=https://github.com/mc-server/MCServer) and [Gamososm](https://gamocosm.com) also offers MCServer support.
|
Hosted MCServer is available DIY on DigitalOcean: [![Install on DigitalOcean](http://doinstall.bearbin.net/button.svg)](http://doinstall.bearbin.net/install?url=https://github.com/mc-server/MCServer) and [Gamososm](https://gamocosm.com) also offers MCServer support.
|
||||||
|
@ -927,6 +927,9 @@ bool cLuaState::CheckParamTable(int a_StartParam, int a_EndParam)
|
|||||||
VERIFY(lua_getstack(m_LuaState, 0, &entry));
|
VERIFY(lua_getstack(m_LuaState, 0, &entry));
|
||||||
VERIFY(lua_getinfo (m_LuaState, "n", &entry));
|
VERIFY(lua_getinfo (m_LuaState, "n", &entry));
|
||||||
AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?");
|
AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != nullptr) ? entry.name : "?");
|
||||||
|
|
||||||
|
BreakIntoDebugger(m_LuaState);
|
||||||
|
|
||||||
tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err);
|
tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err);
|
||||||
return false;
|
return false;
|
||||||
} // for i - Param
|
} // for i - Param
|
||||||
@ -1366,6 +1369,7 @@ int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
|
|||||||
{
|
{
|
||||||
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1));
|
LOGWARNING("LUA: %s", lua_tostring(a_LuaState, -1));
|
||||||
LogStackTrace(a_LuaState, 1);
|
LogStackTrace(a_LuaState, 1);
|
||||||
|
BreakIntoDebugger(a_LuaState);
|
||||||
return 1; // We left the error message on the stack as the return value
|
return 1; // We left the error message on the stack as the return value
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1373,6 +1377,28 @@ int cLuaState::ReportFnCallErrors(lua_State * a_LuaState)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int cLuaState::BreakIntoDebugger(lua_State * a_LuaState)
|
||||||
|
{
|
||||||
|
// Call the BreakIntoDebugger function, if available:
|
||||||
|
lua_getglobal(a_LuaState, "BreakIntoDebugger");
|
||||||
|
if (!lua_isfunction(a_LuaState, -1))
|
||||||
|
{
|
||||||
|
LOGD("LUA: BreakIntoDebugger() not found / not a function");
|
||||||
|
lua_pop(a_LuaState, 1);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
lua_insert(a_LuaState, -2); // Copy the string that has been passed to us
|
||||||
|
LOGD("Calling BreakIntoDebugger()...");
|
||||||
|
lua_call(a_LuaState, 1, 0);
|
||||||
|
LOGD("Returned from BreakIntoDebugger().");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// cLuaState::cRef:
|
// cLuaState::cRef:
|
||||||
|
|
||||||
|
@ -389,6 +389,9 @@ protected:
|
|||||||
|
|
||||||
/** Used as the error reporting function for function calls */
|
/** Used as the error reporting function for function calls */
|
||||||
static int ReportFnCallErrors(lua_State * a_LuaState);
|
static int ReportFnCallErrors(lua_State * a_LuaState);
|
||||||
|
|
||||||
|
/** Tries to break into the MobDebug debugger, if it is installed. */
|
||||||
|
static int BreakIntoDebugger(lua_State * a_LuaState);
|
||||||
} ;
|
} ;
|
||||||
|
|
||||||
|
|
||||||
|
@ -747,39 +747,38 @@ static int tolua_cPluginManager_AddHook(lua_State * tolua_S)
|
|||||||
|
|
||||||
static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S)
|
static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S)
|
||||||
{
|
{
|
||||||
int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */
|
/*
|
||||||
if (NumArgs != 1)
|
Function signature:
|
||||||
|
cPluginManager:Get():ForEachCommand(a_CallbackFn) -> bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Check params:
|
||||||
|
cLuaState L(tolua_S);
|
||||||
|
if (
|
||||||
|
!L.CheckParamUserType(1, "cPluginManager") ||
|
||||||
|
!L.CheckParamFunction(2) ||
|
||||||
|
!L.CheckParamEnd(3)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
LOGWARN("Error in function call 'ForEachCommand': Requires 1 argument, got %i", NumArgs);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr);
|
// Get the params:
|
||||||
if (self == nullptr)
|
cLuaState::cRef FnRef;
|
||||||
{
|
L.GetStackValues(2, FnRef);
|
||||||
LOGWARN("Error in function call 'ForEachCommand': Not called on an object instance");
|
if (!FnRef.IsValid())
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lua_isfunction(tolua_S, 2))
|
|
||||||
{
|
|
||||||
LOGWARN("Error in function call 'ForEachCommand': Expected a function for parameter #1");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
|
|
||||||
if (FuncRef == LUA_REFNIL)
|
|
||||||
{
|
{
|
||||||
LOGWARN("Error in function call 'ForEachCommand': Could not get function reference of parameter #1");
|
LOGWARN("Error in function call 'ForEachCommand': Could not get function reference of parameter #1");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callback for enumerating all commands:
|
||||||
class cLuaCallback : public cPluginManager::cCommandEnumCallback
|
class cLuaCallback : public cPluginManager::cCommandEnumCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cLuaCallback(lua_State * a_LuaState, int a_FuncRef):
|
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
|
||||||
LuaState(a_LuaState),
|
m_LuaState(a_LuaState),
|
||||||
FuncRef(a_FuncRef)
|
m_FnRef(a_FnRef)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,35 +786,16 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S)
|
|||||||
virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override
|
virtual bool Command(const AString & a_Command, const cPlugin * a_Plugin, const AString & a_Permission, const AString & a_HelpString) override
|
||||||
{
|
{
|
||||||
UNUSED(a_Plugin);
|
UNUSED(a_Plugin);
|
||||||
|
bool ret = false;
|
||||||
lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */
|
m_LuaState.Call(m_FnRef, a_Command, a_Permission, a_HelpString, cLuaState::Return, ret);
|
||||||
tolua_pushcppstring(LuaState, a_Command);
|
return ret;
|
||||||
tolua_pushcppstring(LuaState, a_Permission);
|
|
||||||
tolua_pushcppstring(LuaState, a_HelpString);
|
|
||||||
|
|
||||||
int s = lua_pcall(LuaState, 3, 1, 0);
|
|
||||||
if (cLuaState::ReportErrors(LuaState, s))
|
|
||||||
{
|
|
||||||
return true; /* Abort enumeration */
|
|
||||||
}
|
}
|
||||||
|
cLuaState & m_LuaState;
|
||||||
|
cLuaState::cRef & m_FnRef;
|
||||||
|
} Callback(L, FnRef);
|
||||||
|
|
||||||
if (lua_isboolean(LuaState, -1))
|
// Execute and push the returned value:
|
||||||
{
|
L.Push(cPluginManager::Get()->ForEachCommand(Callback));
|
||||||
return (tolua_toboolean(LuaState, -1, 0) > 0);
|
|
||||||
}
|
|
||||||
return false; /* Continue enumeration */
|
|
||||||
}
|
|
||||||
lua_State * LuaState;
|
|
||||||
int FuncRef;
|
|
||||||
} Callback(tolua_S, FuncRef);
|
|
||||||
|
|
||||||
bool bRetVal = self->ForEachCommand(Callback);
|
|
||||||
|
|
||||||
/* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */
|
|
||||||
luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef);
|
|
||||||
|
|
||||||
/* Push return value on stack */
|
|
||||||
tolua_pushboolean(tolua_S, bRetVal);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -825,39 +805,38 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S)
|
|||||||
|
|
||||||
static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S)
|
static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S)
|
||||||
{
|
{
|
||||||
int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */
|
/*
|
||||||
if (NumArgs != 1)
|
Function signature:
|
||||||
|
cPluginManager:Get():ForEachConsoleCommand(a_CallbackFn) -> bool
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Check params:
|
||||||
|
cLuaState L(tolua_S);
|
||||||
|
if (
|
||||||
|
!L.CheckParamUserType(1, "cPluginManager") ||
|
||||||
|
!L.CheckParamFunction(2) ||
|
||||||
|
!L.CheckParamEnd(3)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
LOGWARN("Error in function call 'ForEachConsoleCommand': Requires 1 argument, got %i", NumArgs);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cPluginManager * self = (cPluginManager *)tolua_tousertype(tolua_S, 1, nullptr);
|
// Get the params:
|
||||||
if (self == nullptr)
|
cLuaState::cRef FnRef;
|
||||||
{
|
L.GetStackValues(2, FnRef);
|
||||||
LOGWARN("Error in function call 'ForEachConsoleCommand': Not called on an object instance");
|
if (!FnRef.IsValid())
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!lua_isfunction(tolua_S, 2))
|
|
||||||
{
|
|
||||||
LOGWARN("Error in function call 'ForEachConsoleCommand': Expected a function for parameter #1");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
|
|
||||||
if (FuncRef == LUA_REFNIL)
|
|
||||||
{
|
{
|
||||||
LOGWARN("Error in function call 'ForEachConsoleCommand': Could not get function reference of parameter #1");
|
LOGWARN("Error in function call 'ForEachConsoleCommand': Could not get function reference of parameter #1");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callback for enumerating all commands:
|
||||||
class cLuaCallback : public cPluginManager::cCommandEnumCallback
|
class cLuaCallback : public cPluginManager::cCommandEnumCallback
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
cLuaCallback(lua_State * a_LuaState, int a_FuncRef):
|
cLuaCallback(cLuaState & a_LuaState, cLuaState::cRef & a_FnRef):
|
||||||
LuaState(a_LuaState),
|
m_LuaState(a_LuaState),
|
||||||
FuncRef(a_FuncRef)
|
m_FnRef(a_FnRef)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -866,34 +845,16 @@ static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S)
|
|||||||
{
|
{
|
||||||
UNUSED(a_Plugin);
|
UNUSED(a_Plugin);
|
||||||
UNUSED(a_Permission);
|
UNUSED(a_Permission);
|
||||||
|
bool ret = false;
|
||||||
lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */
|
m_LuaState.Call(m_FnRef, a_Command, a_HelpString, cLuaState::Return, ret);
|
||||||
tolua_pushcppstring(LuaState, a_Command);
|
return ret;
|
||||||
tolua_pushcppstring(LuaState, a_HelpString);
|
|
||||||
|
|
||||||
int s = lua_pcall(LuaState, 2, 1, 0);
|
|
||||||
if (cLuaState::ReportErrors(LuaState, s))
|
|
||||||
{
|
|
||||||
return true; /* Abort enumeration */
|
|
||||||
}
|
}
|
||||||
|
cLuaState & m_LuaState;
|
||||||
|
cLuaState::cRef & m_FnRef;
|
||||||
|
} Callback(L, FnRef);
|
||||||
|
|
||||||
if (lua_isboolean(LuaState, -1))
|
// Execute and push the returned value:
|
||||||
{
|
L.Push(cPluginManager::Get()->ForEachConsoleCommand(Callback));
|
||||||
return (tolua_toboolean(LuaState, -1, 0) > 0);
|
|
||||||
}
|
|
||||||
return false; /* Continue enumeration */
|
|
||||||
}
|
|
||||||
lua_State * LuaState;
|
|
||||||
int FuncRef;
|
|
||||||
} Callback(tolua_S, FuncRef);
|
|
||||||
|
|
||||||
bool bRetVal = self->ForEachConsoleCommand(Callback);
|
|
||||||
|
|
||||||
/* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */
|
|
||||||
luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef);
|
|
||||||
|
|
||||||
/* Push return value on stack */
|
|
||||||
tolua_pushboolean(tolua_S, bRetVal);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ void cBlockBedHandler::OnDestroyed(cChunkInterface & a_ChunkInterface, cWorldInt
|
|||||||
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
NIBBLETYPE OldMeta = a_ChunkInterface.GetBlockMeta(a_BlockX, a_BlockY, a_BlockZ);
|
||||||
|
|
||||||
Vector3i ThisPos( a_BlockX, a_BlockY, a_BlockZ);
|
Vector3i ThisPos( a_BlockX, a_BlockY, a_BlockZ);
|
||||||
Vector3i Direction = MetaDataToDirection( OldMeta & 0x7);
|
Vector3i Direction = MetaDataToDirection( OldMeta & 0x3);
|
||||||
if (OldMeta & 0x8)
|
if (OldMeta & 0x8)
|
||||||
{
|
{
|
||||||
// Was pillow
|
// Was pillow
|
||||||
@ -111,7 +111,7 @@ void cBlockBedHandler::OnUse(cChunkInterface & a_ChunkInterface, cWorldInterface
|
|||||||
// Is foot end
|
// Is foot end
|
||||||
VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken
|
VERIFY((Meta & 0x4) != 0x4); // Occupied flag should never be set, else our compilator (intended) is broken
|
||||||
|
|
||||||
PillowDirection = MetaDataToDirection(Meta & 0x7);
|
PillowDirection = MetaDataToDirection(Meta & 0x3);
|
||||||
if (a_ChunkInterface.GetBlock(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
|
if (a_ChunkInterface.GetBlock(a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z) == E_BLOCK_BED) // Must always use pillow location for sleeping
|
||||||
{
|
{
|
||||||
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z);
|
a_WorldInterface.GetBroadcastManager().BroadcastUseBed(*a_Player, a_BlockX + PillowDirection.x, a_BlockY, a_BlockZ + PillowDirection.z);
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
cFastRandom rand;
|
cFastRandom rand;
|
||||||
|
|
||||||
// Old leaves - 3 bits contain display; new leaves - 1st bit, shifted left two for saplings to understand
|
// Old leaves - 3 bits contain display; new leaves - 1st bit, shifted left two for saplings to understand
|
||||||
if (rand.NextInt(6) == 0)
|
if (rand.NextInt(20) == 0)
|
||||||
{
|
{
|
||||||
a_Pickups.push_back(
|
a_Pickups.push_back(
|
||||||
cItem(
|
cItem(
|
||||||
|
@ -6,12 +6,28 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "FastRandom.h"
|
#include "FastRandom.h"
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#define thread_local __declspec(thread)
|
#define thread_local static __declspec(thread)
|
||||||
|
#elif defined __APPLE__
|
||||||
|
#define thread_local static __thread
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
thread_local unsigned int m_Counter = 0;
|
static unsigned int GetRandomSeed()
|
||||||
|
{
|
||||||
|
thread_local bool SeedCounterInitialized = 0;
|
||||||
|
thread_local unsigned int SeedCounter = 0;
|
||||||
|
|
||||||
|
if (!SeedCounterInitialized)
|
||||||
|
{
|
||||||
|
std::random_device rd;
|
||||||
|
std::uniform_int_distribution<unsigned int> dist;
|
||||||
|
SeedCounter = dist(rd);
|
||||||
|
SeedCounterInitialized = true;
|
||||||
|
}
|
||||||
|
return ++SeedCounter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +108,7 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
cFastRandom::cFastRandom(void) :
|
cFastRandom::cFastRandom(void) :
|
||||||
m_LinearRand(m_Counter++)
|
m_LinearRand(GetRandomSeed())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +152,7 @@ int cFastRandom::GenerateRandomInteger(int a_Begin, int a_End)
|
|||||||
// MTRand:
|
// MTRand:
|
||||||
|
|
||||||
MTRand::MTRand() :
|
MTRand::MTRand() :
|
||||||
m_MersenneRand(m_Counter++)
|
m_MersenneRand(GetRandomSeed())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +36,6 @@ void cAggressiveMonster::InStateChasing(std::chrono::milliseconds a_Dt)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MoveToPosition(m_Target->GetPosition());
|
MoveToPosition(m_Target->GetPosition());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ cMonster::cMonster(const AString & a_ConfigName, eMonsterType a_MobType, const A
|
|||||||
, m_SoundDeath(a_SoundDeath)
|
, m_SoundDeath(a_SoundDeath)
|
||||||
, m_AttackRate(3)
|
, m_AttackRate(3)
|
||||||
, m_AttackDamage(1)
|
, m_AttackDamage(1)
|
||||||
, m_AttackRange(2)
|
, m_AttackRange(1)
|
||||||
, m_AttackInterval(0)
|
, m_AttackInterval(0)
|
||||||
, m_SightDistance(25)
|
, m_SightDistance(25)
|
||||||
, m_DropChanceWeapon(0.085f)
|
, m_DropChanceWeapon(0.085f)
|
||||||
@ -147,12 +147,17 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
|
|||||||
(Recalculate lots when close, calculate rarely when far) */
|
(Recalculate lots when close, calculate rarely when far) */
|
||||||
if (
|
if (
|
||||||
((GetPosition() - m_PathFinderDestination).Length() < 0.25) ||
|
((GetPosition() - m_PathFinderDestination).Length() < 0.25) ||
|
||||||
((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.15 * (m_FinalDestination - GetPosition()).SqrLength())))
|
((m_TicksSinceLastPathReset > 10) && (m_TicksSinceLastPathReset > (0.4 * (m_FinalDestination - GetPosition()).SqrLength())))
|
||||||
)
|
)
|
||||||
|
{
|
||||||
|
/* Re-calculating is expensive when there's no path to target, and it results in mobs freezing very often as a result of always recalculating.
|
||||||
|
This is a workaround till we get better path recalculation. */
|
||||||
|
if (!m_NoPathToTarget)
|
||||||
{
|
{
|
||||||
ResetPathFinding();
|
ResetPathFinding();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (m_Path == nullptr)
|
if (m_Path == nullptr)
|
||||||
{
|
{
|
||||||
@ -161,12 +166,21 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
|
|||||||
StopMovingToPosition(); // Invalid chunks, probably world is loading or something, cancel movement.
|
StopMovingToPosition(); // Invalid chunks, probably world is loading or something, cancel movement.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
m_NoPathToTarget = false;
|
||||||
|
m_NoMoreWayPoints = false;
|
||||||
m_PathFinderDestination = m_FinalDestination;
|
m_PathFinderDestination = m_FinalDestination;
|
||||||
m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20);
|
m_Path = new cPath(a_Chunk, GetPosition().Floor(), m_PathFinderDestination.Floor(), 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (m_Path->Step(a_Chunk))
|
switch (m_Path->Step(a_Chunk))
|
||||||
{
|
{
|
||||||
|
case ePathFinderStatus::NEARBY_FOUND:
|
||||||
|
{
|
||||||
|
m_NoPathToTarget = true;
|
||||||
|
m_Path->AcceptNearbyPath();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case ePathFinderStatus::PATH_NOT_FOUND:
|
case ePathFinderStatus::PATH_NOT_FOUND:
|
||||||
{
|
{
|
||||||
StopMovingToPosition(); // Give up pathfinding to that destination.
|
StopMovingToPosition(); // Give up pathfinding to that destination.
|
||||||
@ -179,16 +193,23 @@ bool cMonster::TickPathFinding(cChunk & a_Chunk)
|
|||||||
}
|
}
|
||||||
case ePathFinderStatus::PATH_FOUND:
|
case ePathFinderStatus::PATH_FOUND:
|
||||||
{
|
{
|
||||||
if (--m_GiveUpCounter == 0)
|
if (m_NoMoreWayPoints || (--m_GiveUpCounter == 0))
|
||||||
{
|
{
|
||||||
ResetPathFinding(); // Try to calculate a path again.
|
ResetPathFinding(); // Try to calculate a path again.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
else if (!m_Path->IsLastPoint() && (m_Path->IsFirstPoint() || ReachedNextWaypoint())) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition?
|
else if (!m_Path->IsLastPoint()) // Have we arrived at the next cell, as denoted by m_NextWayPointPosition?
|
||||||
|
{
|
||||||
|
if ((m_Path->IsFirstPoint() || ReachedNextWaypoint()))
|
||||||
{
|
{
|
||||||
m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint();
|
m_NextWayPointPosition = Vector3d(0.5, 0, 0.5) + m_Path->GetNextPoint();
|
||||||
m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition.
|
m_GiveUpCounter = 40; // Give up after 40 ticks (2 seconds) if failed to reach m_NextWayPointPosition.
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_NoMoreWayPoints = true;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -273,7 +294,44 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk)
|
|||||||
int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width;
|
int RelX = FloorC(m_FinalDestination.x) - Chunk->GetPosX() * cChunkDef::Width;
|
||||||
int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width;
|
int RelZ = FloorC(m_FinalDestination.z) - Chunk->GetPosZ() * cChunkDef::Width;
|
||||||
|
|
||||||
// If destination in the air, go down to the lowest air block.
|
// If destination in the air, first try to go 1 block north, or east, or west.
|
||||||
|
// This fixes the player leaning issue.
|
||||||
|
// If that failed, we instead go down to the lowest air block.
|
||||||
|
Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
|
||||||
|
if (!cBlockInfo::IsSolid(BlockType))
|
||||||
|
{
|
||||||
|
bool InTheAir = true;
|
||||||
|
int x, z;
|
||||||
|
for (z = -1; z <= 1; ++z)
|
||||||
|
{
|
||||||
|
for (x = -1; x <= 1; ++x)
|
||||||
|
{
|
||||||
|
if ((x==0) && (z==0))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Chunk = a_Chunk.GetNeighborChunk(FloorC(m_FinalDestination.x+x), FloorC(m_FinalDestination.z+z));
|
||||||
|
if ((Chunk == nullptr) || !Chunk->IsValid())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RelX = FloorC(m_FinalDestination.x+x) - Chunk->GetPosX() * cChunkDef::Width;
|
||||||
|
RelZ = FloorC(m_FinalDestination.z+z) - Chunk->GetPosZ() * cChunkDef::Width;
|
||||||
|
Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
|
||||||
|
if (cBlockInfo::IsSolid(BlockType))
|
||||||
|
{
|
||||||
|
m_FinalDestination.x += x;
|
||||||
|
m_FinalDestination.z += z;
|
||||||
|
InTheAir = false;
|
||||||
|
goto breakBothLoops;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
breakBothLoops:
|
||||||
|
|
||||||
|
// Go down to the lowest air block.
|
||||||
|
if (InTheAir)
|
||||||
|
{
|
||||||
while (m_FinalDestination.y > 0)
|
while (m_FinalDestination.y > 0)
|
||||||
{
|
{
|
||||||
Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
|
Chunk->GetBlockTypeMeta(RelX, FloorC(m_FinalDestination.y) - 1, RelZ, BlockType, BlockMeta);
|
||||||
@ -283,7 +341,8 @@ bool cMonster::EnsureProperDestination(cChunk & a_Chunk)
|
|||||||
}
|
}
|
||||||
m_FinalDestination.y -= 1;
|
m_FinalDestination.y -= 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If destination in water, go up to the highest water block.
|
// If destination in water, go up to the highest water block.
|
||||||
// If destination in solid, go up to first air block.
|
// If destination in solid, go up to first air block.
|
||||||
@ -447,21 +506,29 @@ void cMonster::SetPitchAndYawFromDestination()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Vector3d BodyDistance = m_NextWayPointPosition - GetPosition();
|
||||||
|
double BodyRotation, BodyPitch;
|
||||||
|
BodyDistance.Normalize();
|
||||||
|
VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, BodyRotation, BodyPitch);
|
||||||
|
SetYaw(BodyRotation);
|
||||||
|
|
||||||
Vector3d Distance = FinalDestination - GetPosition();
|
Vector3d Distance = FinalDestination - GetPosition();
|
||||||
{
|
{
|
||||||
double Rotation, Pitch;
|
double HeadRotation, HeadPitch;
|
||||||
Distance.Normalize();
|
Distance.Normalize();
|
||||||
VectorToEuler(Distance.x, Distance.y, Distance.z, Rotation, Pitch);
|
VectorToEuler(Distance.x, Distance.y, Distance.z, HeadRotation, HeadPitch);
|
||||||
SetHeadYaw(Rotation);
|
if (abs(BodyRotation - HeadRotation) < 120)
|
||||||
SetPitch(-Pitch);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Vector3d BodyDistance = m_NextWayPointPosition - GetPosition();
|
SetHeadYaw(HeadRotation);
|
||||||
double Rotation, Pitch;
|
SetPitch(-HeadPitch);
|
||||||
BodyDistance.Normalize();
|
}
|
||||||
VectorToEuler(BodyDistance.x, BodyDistance.y, BodyDistance.z, Rotation, Pitch);
|
else // We're not an owl. If it's more than 120, don't look behind and instead look at where you're walking.
|
||||||
SetYaw(Rotation);
|
{
|
||||||
|
SetHeadYaw(BodyRotation);
|
||||||
|
SetPitch(-BodyPitch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,6 +180,13 @@ protected:
|
|||||||
/** Coordinates for the ultimate, final destination last given to the pathfinder. */
|
/** Coordinates for the ultimate, final destination last given to the pathfinder. */
|
||||||
Vector3d m_PathFinderDestination;
|
Vector3d m_PathFinderDestination;
|
||||||
|
|
||||||
|
/** True if there's no path to target and we're walking to an approximated location. */
|
||||||
|
bool m_NoPathToTarget;
|
||||||
|
|
||||||
|
/** Whether The mob has finished their path, note that this does not imply reaching the destination,
|
||||||
|
the destination may sometimes differ from the current path. */
|
||||||
|
bool m_NoMoreWayPoints;
|
||||||
|
|
||||||
/** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does)
|
/** Finds the lowest non-air block position (not the highest, as cWorld::GetHeight does)
|
||||||
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
If current Y is nonsolid, goes down to try to find a solid block, then returns that + 1
|
||||||
If current Y is solid, goes up to find first nonsolid block, and returns that.
|
If current Y is solid, goes up to find first nonsolid block, and returns that.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
|
#define DISTANCE_MANHATTAN 0 // 1: More speed, a bit less accuracy 0: Max accuracy, less speed.
|
||||||
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
|
#define HEURISTICS_ONLY 0 // 1: Much more speed, much less accurate.
|
||||||
#define CALCULATIONS_PER_STEP 5 // Higher means more CPU load but faster path calculations.
|
#define CALCULATIONS_PER_STEP 10 // Higher means more CPU load but faster path calculations.
|
||||||
// The only version which guarantees the shortest path is 0, 0.
|
// The only version which guarantees the shortest path is 0, 0.
|
||||||
|
|
||||||
enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST};
|
enum class eCellStatus {OPENLIST, CLOSEDLIST, NOLIST};
|
||||||
@ -44,7 +44,8 @@ cPath::cPath(
|
|||||||
m_Destination(a_EndingPoint.Floor()),
|
m_Destination(a_EndingPoint.Floor()),
|
||||||
m_Source(a_StartingPoint.Floor()),
|
m_Source(a_StartingPoint.Floor()),
|
||||||
m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
|
m_CurrentPoint(0), // GetNextPoint increments this to 1, but that's fine, since the first cell is always a_StartingPoint
|
||||||
m_Chunk(&a_Chunk)
|
m_Chunk(&a_Chunk),
|
||||||
|
m_BadChunkFound(false)
|
||||||
{
|
{
|
||||||
// TODO: if src not walkable OR dest not walkable, then abort.
|
// TODO: if src not walkable OR dest not walkable, then abort.
|
||||||
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
|
// Borrow a new "isWalkable" from ProcessIfWalkable, make ProcessIfWalkable also call isWalkable
|
||||||
@ -55,6 +56,7 @@ cPath::cPath(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_NearestPointToTarget = GetCell(m_Source);
|
||||||
m_Status = ePathFinderStatus::CALCULATING;
|
m_Status = ePathFinderStatus::CALCULATING;
|
||||||
m_StepsLeft = a_MaxSteps;
|
m_StepsLeft = a_MaxSteps;
|
||||||
|
|
||||||
@ -81,15 +83,20 @@ cPath::~cPath()
|
|||||||
ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
||||||
{
|
{
|
||||||
m_Chunk = &a_Chunk;
|
m_Chunk = &a_Chunk;
|
||||||
|
|
||||||
if (m_Status != ePathFinderStatus::CALCULATING)
|
if (m_Status != ePathFinderStatus::CALCULATING)
|
||||||
{
|
{
|
||||||
return m_Status;
|
return m_Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_StepsLeft == 0)
|
if (m_BadChunkFound)
|
||||||
{
|
{
|
||||||
FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
|
FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
|
||||||
|
return m_Status;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_StepsLeft == 0)
|
||||||
|
{
|
||||||
|
AttemptToFindAlternative();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -102,9 +109,9 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
|||||||
break; // if we're here, m_Status must have changed either to PATH_FOUND or PATH_NOT_FOUND.
|
break; // if we're here, m_Status must have changed either to PATH_FOUND or PATH_NOT_FOUND.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
m_Chunk = nullptr;
|
m_Chunk = nullptr;
|
||||||
|
}
|
||||||
return m_Status;
|
return m_Status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,6 +119,17 @@ ePathFinderStatus cPath::Step(cChunk & a_Chunk)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Vector3i cPath::AcceptNearbyPath()
|
||||||
|
{
|
||||||
|
ASSERT(m_Status == ePathFinderStatus::NEARBY_FOUND);
|
||||||
|
m_Status = ePathFinderStatus::PATH_FOUND;
|
||||||
|
return m_Destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool cPath::IsSolid(const Vector3i & a_Location)
|
bool cPath::IsSolid(const Vector3i & a_Location)
|
||||||
{
|
{
|
||||||
ASSERT(m_Chunk != nullptr);
|
ASSERT(m_Chunk != nullptr);
|
||||||
@ -119,6 +137,7 @@ bool cPath::IsSolid(const Vector3i & a_Location)
|
|||||||
auto Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
|
auto Chunk = m_Chunk->GetNeighborChunk(a_Location.x, a_Location.z);
|
||||||
if ((Chunk == nullptr) || !Chunk->IsValid())
|
if ((Chunk == nullptr) || !Chunk->IsValid())
|
||||||
{
|
{
|
||||||
|
m_BadChunkFound = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
m_Chunk = Chunk;
|
m_Chunk = Chunk;
|
||||||
@ -149,34 +168,29 @@ bool cPath::Step_Internal()
|
|||||||
{
|
{
|
||||||
cPathCell * CurrentCell = OpenListPop();
|
cPathCell * CurrentCell = OpenListPop();
|
||||||
|
|
||||||
// Path not reachable, open list exauhsted.
|
// Path not reachable.
|
||||||
if (CurrentCell == nullptr)
|
if (CurrentCell == nullptr)
|
||||||
{
|
{
|
||||||
FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
|
AttemptToFindAlternative();
|
||||||
ASSERT(m_Status == ePathFinderStatus::PATH_NOT_FOUND);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Path found.
|
// Path found.
|
||||||
if (
|
if (CurrentCell->m_Location == m_Destination)
|
||||||
(CurrentCell->m_Location == m_Destination + Vector3i(0, 0, 1)) ||
|
|
||||||
(CurrentCell->m_Location == m_Destination + Vector3i(1, 0, 0)) ||
|
|
||||||
(CurrentCell->m_Location == m_Destination + Vector3i(-1, 0, 0)) ||
|
|
||||||
(CurrentCell->m_Location == m_Destination + Vector3i(0, 0, -1)) ||
|
|
||||||
(CurrentCell->m_Location == m_Destination + Vector3i(0, -1, 0))
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
do
|
BuildPath();
|
||||||
{
|
|
||||||
m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points.
|
|
||||||
CurrentCell = CurrentCell->m_Parent;
|
|
||||||
} while (CurrentCell != nullptr);
|
|
||||||
|
|
||||||
FinishCalculation(ePathFinderStatus::PATH_FOUND);
|
FinishCalculation(ePathFinderStatus::PATH_FOUND);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculation not finished yet, process a currentCell by inspecting all neighbors.
|
// Calculation not finished yet.
|
||||||
|
// Check if we have a new NearestPoint.
|
||||||
|
if (CurrentCell->m_H < m_NearestPointToTarget->m_H)
|
||||||
|
{
|
||||||
|
m_NearestPointToTarget = CurrentCell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// process a currentCell by inspecting all neighbors.
|
||||||
|
|
||||||
// Check North, South, East, West on all 3 different heights.
|
// Check North, South, East, West on all 3 different heights.
|
||||||
int i;
|
int i;
|
||||||
@ -213,13 +227,40 @@ bool cPath::Step_Internal()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void cPath::FinishCalculation()
|
void cPath::AttemptToFindAlternative()
|
||||||
{
|
{
|
||||||
for (auto && pair : m_Map)
|
if (m_NearestPointToTarget == GetCell(m_Source))
|
||||||
{
|
{
|
||||||
delete pair.second;
|
FinishCalculation(ePathFinderStatus::PATH_NOT_FOUND);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_Destination = m_NearestPointToTarget->m_Location;
|
||||||
|
BuildPath();
|
||||||
|
FinishCalculation(ePathFinderStatus::NEARBY_FOUND);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPath::BuildPath()
|
||||||
|
{
|
||||||
|
cPathCell * CurrentCell = GetCell(m_Destination);
|
||||||
|
do
|
||||||
|
{
|
||||||
|
m_PathPoints.push_back(CurrentCell->m_Location); // Populate the cPath with points.
|
||||||
|
CurrentCell = CurrentCell->m_Parent;
|
||||||
|
} while (CurrentCell != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void cPath::FinishCalculation()
|
||||||
|
{
|
||||||
m_Map.clear();
|
m_Map.clear();
|
||||||
m_OpenList = std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics>{};
|
m_OpenList = std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics>{};
|
||||||
}
|
}
|
||||||
@ -230,6 +271,10 @@ void cPath::FinishCalculation()
|
|||||||
|
|
||||||
void cPath::FinishCalculation(ePathFinderStatus a_NewStatus)
|
void cPath::FinishCalculation(ePathFinderStatus a_NewStatus)
|
||||||
{
|
{
|
||||||
|
if (m_BadChunkFound)
|
||||||
|
{
|
||||||
|
a_NewStatus = ePathFinderStatus::PATH_NOT_FOUND;
|
||||||
|
}
|
||||||
m_Status = a_NewStatus;
|
m_Status = a_NewStatus;
|
||||||
FinishCalculation();
|
FinishCalculation();
|
||||||
}
|
}
|
||||||
@ -255,7 +300,7 @@ cPathCell * cPath::OpenListPop() // Popping from the open list also means addin
|
|||||||
{
|
{
|
||||||
if (m_OpenList.size() == 0)
|
if (m_OpenList.size() == 0)
|
||||||
{
|
{
|
||||||
return nullptr; // We've exhausted the search space and nothing was found, this will trigger a PATH_NOT_FOUND status.
|
return nullptr; // We've exhausted the search space and nothing was found, this will trigger a PATH_NOT_FOUND or NEARBY_FOUND status.
|
||||||
}
|
}
|
||||||
|
|
||||||
cPathCell * Ret = m_OpenList.top();
|
cPathCell * Ret = m_OpenList.top();
|
||||||
@ -348,7 +393,7 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location)
|
|||||||
{
|
{
|
||||||
Cell = new cPathCell();
|
Cell = new cPathCell();
|
||||||
Cell->m_Location = a_Location;
|
Cell->m_Location = a_Location;
|
||||||
m_Map[a_Location] = Cell;
|
m_Map[a_Location] = UniquePtr<cPathCell>(Cell);
|
||||||
Cell->m_IsSolid = IsSolid(a_Location);
|
Cell->m_IsSolid = IsSolid(a_Location);
|
||||||
Cell->m_Status = eCellStatus::NOLIST;
|
Cell->m_Status = eCellStatus::NOLIST;
|
||||||
#ifdef COMPILING_PATHFIND_DEBUGGER
|
#ifdef COMPILING_PATHFIND_DEBUGGER
|
||||||
@ -360,6 +405,6 @@ cPathCell * cPath::GetCell(const Vector3i & a_Location)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return m_Map[a_Location];
|
return m_Map[a_Location].get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ Put this in your .cpp:
|
|||||||
class cChunk;
|
class cChunk;
|
||||||
|
|
||||||
/* Various little structs and classes */
|
/* Various little structs and classes */
|
||||||
enum class ePathFinderStatus {CALCULATING, PATH_FOUND, PATH_NOT_FOUND};
|
enum class ePathFinderStatus {CALCULATING, PATH_FOUND, PATH_NOT_FOUND, NEARBY_FOUND};
|
||||||
struct cPathCell; // Defined inside Path.cpp
|
struct cPathCell; // Defined inside Path.cpp
|
||||||
class compareHeuristics
|
class compareHeuristics
|
||||||
{
|
{
|
||||||
@ -62,9 +62,17 @@ public:
|
|||||||
/** Destroys the path and frees its memory. */
|
/** Destroys the path and frees its memory. */
|
||||||
~cPath();
|
~cPath();
|
||||||
|
|
||||||
/** Performs part of the path calculation and returns true if the path computation has finished. */
|
/** Performs part of the path calculation and returns the appropriate status.
|
||||||
|
If NEARBY_FOUND is returned, it means that the destination is not reachable, but a nearby destination
|
||||||
|
is reachable. If the user likes the alternative destination, they can call AcceptNearbyPath to treat the path as found,
|
||||||
|
and to make consequent calls to step return PATH_FOUND*/
|
||||||
ePathFinderStatus Step(cChunk & a_Chunk);
|
ePathFinderStatus Step(cChunk & a_Chunk);
|
||||||
|
|
||||||
|
/** Called after the PathFinder's step returns NEARBY_FOUND.
|
||||||
|
Changes the PathFinder status from NEARBY_FOUND to PATH_FOUND, returns the nearby destination that
|
||||||
|
the PathFinder found a path to. */
|
||||||
|
Vector3i AcceptNearbyPath();
|
||||||
|
|
||||||
/* Point retrieval functions, inlined for performance. */
|
/* Point retrieval functions, inlined for performance. */
|
||||||
/** Returns the next point in the path. */
|
/** Returns the next point in the path. */
|
||||||
inline Vector3i GetNextPoint()
|
inline Vector3i GetNextPoint()
|
||||||
@ -93,7 +101,10 @@ public:
|
|||||||
/** Returns the total number of points this path has. */
|
/** Returns the total number of points this path has. */
|
||||||
inline int GetPointCount()
|
inline int GetPointCount()
|
||||||
{
|
{
|
||||||
ASSERT(m_Status == ePathFinderStatus::PATH_FOUND);
|
if (m_Status != ePathFinderStatus::PATH_FOUND)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
return m_PathPoints.size();
|
return m_PathPoints.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,6 +130,8 @@ private:
|
|||||||
bool Step_Internal(); // The public version just calls this version * CALCULATIONS_PER_CALL times.
|
bool Step_Internal(); // The public version just calls this version * CALCULATIONS_PER_CALL times.
|
||||||
void FinishCalculation(); // Clears the memory used for calculating the path.
|
void FinishCalculation(); // Clears the memory used for calculating the path.
|
||||||
void FinishCalculation(ePathFinderStatus a_NewStatus); // Clears the memory used for calculating the path and changes the status.
|
void FinishCalculation(ePathFinderStatus a_NewStatus); // Clears the memory used for calculating the path and changes the status.
|
||||||
|
void AttemptToFindAlternative();
|
||||||
|
void BuildPath();
|
||||||
|
|
||||||
/* Openlist and closedlist management */
|
/* Openlist and closedlist management */
|
||||||
void OpenListAdd(cPathCell * a_Cell);
|
void OpenListAdd(cPathCell * a_Cell);
|
||||||
@ -131,10 +144,11 @@ private:
|
|||||||
|
|
||||||
/* Pathfinding fields */
|
/* Pathfinding fields */
|
||||||
std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics> m_OpenList;
|
std::priority_queue<cPathCell *, std::vector<cPathCell *>, compareHeuristics> m_OpenList;
|
||||||
std::unordered_map<Vector3i, cPathCell *, VectorHasher> m_Map;
|
std::unordered_map<Vector3i, UniquePtr<cPathCell>, VectorHasher> m_Map;
|
||||||
Vector3i m_Destination;
|
Vector3i m_Destination;
|
||||||
Vector3i m_Source;
|
Vector3i m_Source;
|
||||||
int m_StepsLeft;
|
int m_StepsLeft;
|
||||||
|
cPathCell * m_NearestPointToTarget;
|
||||||
|
|
||||||
/* Control fields */
|
/* Control fields */
|
||||||
ePathFinderStatus m_Status;
|
ePathFinderStatus m_Status;
|
||||||
@ -145,6 +159,7 @@ private:
|
|||||||
|
|
||||||
/* Interfacing with the world */
|
/* Interfacing with the world */
|
||||||
cChunk * m_Chunk; // Only valid inside Step()!
|
cChunk * m_Chunk; // Only valid inside Step()!
|
||||||
|
bool m_BadChunkFound;
|
||||||
#ifdef COMPILING_PATHFIND_DEBUGGER
|
#ifdef COMPILING_PATHFIND_DEBUGGER
|
||||||
#include "../path_irrlicht.cpp"
|
#include "../path_irrlicht.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
@ -51,7 +51,7 @@ Implements the 1.8.x protocol classes:
|
|||||||
|
|
||||||
|
|
||||||
/** The slot number that the client uses to indicate "outside the window". */
|
/** The slot number that the client uses to indicate "outside the window". */
|
||||||
static const Int16 SLOT_NUM_OUTSIDE = -1;
|
static const Int16 SLOT_NUM_OUTSIDE = -999;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -2265,7 +2265,7 @@ void cProtocol180::HandlePacketCreativeInventoryAction(cByteBuffer & a_ByteBuffe
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum == SLOT_NUM_OUTSIDE) ? caLeftClickOutside : caLeftClick);
|
m_Client->HandleCreativeInventory(SlotNum, Item, (SlotNum == -1) ? caLeftClickOutside : caLeftClick);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user