Rewritten most of the code for multithreading; still not 100%, but getting there. If this commit proves to be too problematic, we can always undo it.
git-svn-id: http://mc-server.googlecode.com/svn/trunk@251 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
0a46c065bf
commit
4f17362aeb
@ -18,8 +18,8 @@
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\JsonCpp"
|
||||
IntermediateDirectory="$(ConfigurationName)\JsonCpp"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
@ -80,8 +80,8 @@
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\JsonCpp"
|
||||
IntermediateDirectory="$(ConfigurationName)\JsonCpp"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
|
@ -18,8 +18,8 @@
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\Lua"
|
||||
IntermediateDirectory="$(ConfigurationName)\Lua"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
@ -79,8 +79,8 @@
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\Lua"
|
||||
IntermediateDirectory="$(ConfigurationName)\Lua"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
|
@ -205,14 +205,6 @@
|
||||
RelativePath="..\source\cChatColor.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cChestEntity.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cChestEntity.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cChunk.cpp"
|
||||
>
|
||||
@ -379,6 +371,14 @@
|
||||
RelativePath="..\source\cNoise.inc"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPiston.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPiston.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPlugin.cpp"
|
||||
>
|
||||
@ -511,10 +511,6 @@
|
||||
RelativePath="..\source\Endianness.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\FileDefine.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\Globals.cpp"
|
||||
>
|
||||
@ -539,6 +535,31 @@
|
||||
RelativePath="..\source\Globals.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\LeakFinder.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\LeakFinder.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\LuaFunctions.h"
|
||||
>
|
||||
@ -555,10 +576,6 @@
|
||||
RelativePath="..\source\Matrix4f.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\MCSocket.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\MemoryLeak.h"
|
||||
>
|
||||
@ -568,11 +585,28 @@
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\PacketID.h"
|
||||
RelativePath="..\source\StackWalker.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
ExcludedFromBuild="true"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\ptr_cChunk.h"
|
||||
RelativePath="..\source\StackWalker.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
@ -1022,6 +1056,10 @@
|
||||
RelativePath="..\source\packets\cPacket_WindowOpen.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\PacketID.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Mobs"
|
||||
@ -1202,6 +1240,14 @@
|
||||
RelativePath="..\source\cBlockToPickup.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cChestEntity.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cChestEntity.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cDoors.h"
|
||||
>
|
||||
@ -1250,14 +1296,6 @@
|
||||
RelativePath="..\source\cPickup.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPiston.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPiston.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\cPlayer.cpp"
|
||||
>
|
||||
@ -1489,6 +1527,22 @@
|
||||
<File
|
||||
RelativePath="..\source\Bindings.cpp"
|
||||
>
|
||||
<FileConfiguration
|
||||
Name="Debug|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
<FileConfiguration
|
||||
Name="Release|Win32"
|
||||
>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
UsePrecompiledHeader="0"
|
||||
/>
|
||||
</FileConfiguration>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\Bindings.h"
|
||||
@ -1579,6 +1633,26 @@
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="World storage"
|
||||
>
|
||||
<File
|
||||
RelativePath="..\source\WorldStorage.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\WorldStorage.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\WSSCompact.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath="..\source\WSSCompact.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<File
|
||||
RelativePath="..\makefile"
|
||||
|
@ -18,8 +18,8 @@
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\ToLua"
|
||||
IntermediateDirectory="$(ConfigurationName)\ToLua"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
@ -80,8 +80,8 @@
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\ToLua"
|
||||
IntermediateDirectory="$(ConfigurationName)\ToLua"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
|
@ -18,7 +18,7 @@
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\WebServer"
|
||||
IntermediateDirectory="$(ConfigurationName)\webserver"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
@ -80,7 +80,7 @@
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\WebServer"
|
||||
IntermediateDirectory="$(ConfigurationName)\webserver"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
|
@ -18,8 +18,8 @@
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\zlib"
|
||||
IntermediateDirectory="$(ConfigurationName)\zlib"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
>
|
||||
@ -79,8 +79,8 @@
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
|
||||
IntermediateDirectory="$(ConfigurationName)"
|
||||
OutputDirectory="$(SolutionDir)$(ConfigurationName)\zlib"
|
||||
IntermediateDirectory="$(ConfigurationName)\zlib"
|
||||
ConfigurationType="4"
|
||||
CharacterSet="1"
|
||||
WholeProgramOptimization="1"
|
||||
|
@ -394,6 +394,12 @@
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\LeakFinder.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Source\ManualBindings.cpp" />
|
||||
<ClCompile Include="..\source\Matrix4f.cpp" />
|
||||
<ClCompile Include="..\source\md5\md5.cpp" />
|
||||
@ -465,10 +471,18 @@
|
||||
<ClCompile Include="..\source\packets\cPacket_WindowClose.cpp" />
|
||||
<ClCompile Include="..\source\packets\cPacket_WindowOpen.cpp" />
|
||||
<ClCompile Include="..\source\SquirrelBindings.cpp" />
|
||||
<ClCompile Include="..\source\StackWalker.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug with optimized Noise|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\source\StringUtils.cpp" />
|
||||
<ClCompile Include="..\source\Vector3d.cpp" />
|
||||
<ClCompile Include="..\source\Vector3f.cpp" />
|
||||
<ClCompile Include="..\source\Vector3i.cpp" />
|
||||
<ClCompile Include="..\source\WorldStorage.cpp" />
|
||||
<ClCompile Include="..\source\WSSCompact.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Source\BlockID.h" />
|
||||
@ -558,6 +572,7 @@
|
||||
<ClInclude Include="..\source\Endianness.h" />
|
||||
<ClInclude Include="..\Source\FileDefine.h" />
|
||||
<ClInclude Include="..\source\Globals.h" />
|
||||
<ClInclude Include="..\source\LeakFinder.h" />
|
||||
<ClInclude Include="..\Source\LuaFunctions.h" />
|
||||
<ClInclude Include="..\Source\ManualBindings.h" />
|
||||
<ClInclude Include="..\source\Matrix4f.h" />
|
||||
@ -637,10 +652,13 @@
|
||||
<ClInclude Include="..\source\packets\cPacket_WindowOpen.h" />
|
||||
<ClInclude Include="..\source\ptr_cChunk.h" />
|
||||
<ClInclude Include="..\source\SquirrelBindings.h" />
|
||||
<ClInclude Include="..\source\StackWalker.h" />
|
||||
<ClInclude Include="..\source\StringUtils.h" />
|
||||
<ClInclude Include="..\source\Vector3d.h" />
|
||||
<ClInclude Include="..\source\Vector3f.h" />
|
||||
<ClInclude Include="..\source\Vector3i.h" />
|
||||
<ClInclude Include="..\source\WorldStorage.h" />
|
||||
<ClInclude Include="..\source\WSSCompact.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -912,6 +912,10 @@
|
||||
<ClCompile Include="..\source\StringUtils.cpp" />
|
||||
<ClCompile Include="..\source\cIsThread.cpp" />
|
||||
<ClCompile Include="..\source\cSocketThreads.cpp" />
|
||||
<ClCompile Include="..\source\LeakFinder.cpp" />
|
||||
<ClCompile Include="..\source\StackWalker.cpp" />
|
||||
<ClCompile Include="..\source\WorldStorage.cpp" />
|
||||
<ClCompile Include="..\source\WSSCompact.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\source\cServer.h">
|
||||
@ -1405,6 +1409,10 @@
|
||||
<ClInclude Include="..\source\StringUtils.h" />
|
||||
<ClInclude Include="..\source\cIsThread.h" />
|
||||
<ClInclude Include="..\source\cSocketThreads.h" />
|
||||
<ClInclude Include="..\source\WSSCompact.h" />
|
||||
<ClInclude Include="..\source\LeakFinder.h" />
|
||||
<ClInclude Include="..\source\StackWalker.h" />
|
||||
<ClInclude Include="..\source\WorldStorage.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\source\AllToLua.pkg">
|
||||
|
@ -17,6 +17,10 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h> // for mkdir
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
@ -28,6 +32,7 @@
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <tr1/memory>
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -32,14 +32,19 @@
|
||||
#ifndef SOCKET_H
|
||||
#define SOCKET_H
|
||||
|
||||
#include "../source/MCSocket.h"
|
||||
// #ifdef _WIN32
|
||||
// #include <winsock2.h>
|
||||
|
||||
// #endif
|
||||
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
#ifndef _WIN32
|
||||
typedef int SOCKET;
|
||||
#define SOCKET_ERROR (-1)
|
||||
#define closesocket close
|
||||
#endif // !_WIN32
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
enum TypeSocket {BlockingSocket, NonBlockingSocket};
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
** Lua binding: AllToLua
|
||||
** Generated automatically by tolua++-1.0.92 on 02/08/12 12:55:58.
|
||||
** Generated automatically by tolua++-1.0.92 on 02/13/12 11:40:58.
|
||||
*/
|
||||
|
||||
#ifndef __cplusplus
|
||||
@ -3160,14 +3160,14 @@ static int tolua_AllToLua_cEntity_GetWorld00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetWorld'", NULL);
|
||||
#endif
|
||||
@ -3192,14 +3192,14 @@ static int tolua_AllToLua_cEntity_GetPosition00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPosition'", NULL);
|
||||
#endif
|
||||
@ -3224,14 +3224,14 @@ static int tolua_AllToLua_cEntity_GetPosX00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPosX'", NULL);
|
||||
#endif
|
||||
@ -3256,14 +3256,14 @@ static int tolua_AllToLua_cEntity_GetPosY00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPosY'", NULL);
|
||||
#endif
|
||||
@ -3288,14 +3288,14 @@ static int tolua_AllToLua_cEntity_GetPosZ00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPosZ'", NULL);
|
||||
#endif
|
||||
@ -3320,14 +3320,14 @@ static int tolua_AllToLua_cEntity_GetRot00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetRot'", NULL);
|
||||
#endif
|
||||
@ -3352,14 +3352,14 @@ static int tolua_AllToLua_cEntity_GetRotation00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetRotation'", NULL);
|
||||
#endif
|
||||
@ -3384,14 +3384,14 @@ static int tolua_AllToLua_cEntity_GetPitch00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetPitch'", NULL);
|
||||
#endif
|
||||
@ -3416,14 +3416,14 @@ static int tolua_AllToLua_cEntity_GetRoll00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetRoll'", NULL);
|
||||
#endif
|
||||
@ -3792,14 +3792,14 @@ static int tolua_AllToLua_cEntity_GetUniqueID00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetUniqueID'", NULL);
|
||||
#endif
|
||||
@ -3824,14 +3824,14 @@ static int tolua_AllToLua_cEntity_IsDestroyed00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cEntity",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cEntity",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
const cEntity* self = (const cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsDestroyed'", NULL);
|
||||
#endif
|
||||
@ -3929,12 +3929,12 @@ static int tolua_AllToLua_cEntity_SpawnOn00(lua_State* tolua_S)
|
||||
#endif
|
||||
{
|
||||
cEntity* self = (cEntity*) tolua_tousertype(tolua_S,1,0);
|
||||
cClientHandle* a_Target = ((cClientHandle*) tolua_tousertype(tolua_S,2,0));
|
||||
cClientHandle* a_Client = ((cClientHandle*) tolua_tousertype(tolua_S,2,0));
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SpawnOn'", NULL);
|
||||
#endif
|
||||
{
|
||||
self->SpawnOn(a_Target);
|
||||
self->SpawnOn(a_Client);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -4001,20 +4001,6 @@ public:
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
void SpawnOn( cClientHandle* a_Target) {
|
||||
if (push_method("SpawnOn", tolua_AllToLua_cEntity_SpawnOn00)) {
|
||||
tolua_pushusertype(lua_state, (void*)a_Target, "cClientHandle");
|
||||
ToluaBase::dbcall(lua_state, 2, 0);
|
||||
} else {
|
||||
if (lua_state)
|
||||
LOG("pure-virtual method cEntity::SpawnOn not implemented.");
|
||||
else {
|
||||
LOG("pure-virtual method cEntity::SpawnOn called with no lua_state. Aborting");
|
||||
::abort();
|
||||
};
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
|
||||
void cEntity__Initialize( cWorld* a_World) {
|
||||
return ( void )cEntity::Initialize(a_World);
|
||||
@ -4662,20 +4648,6 @@ public:
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
void SpawnOn( cClientHandle* a_Target) {
|
||||
if (push_method("SpawnOn", tolua_AllToLua_cEntity_SpawnOn00)) {
|
||||
tolua_pushusertype(lua_state, (void*)a_Target, "cClientHandle");
|
||||
ToluaBase::dbcall(lua_state, 2, 0);
|
||||
} else {
|
||||
if (lua_state)
|
||||
LOG("pure-virtual method cPawn::SpawnOn not implemented.");
|
||||
else {
|
||||
LOG("pure-virtual method cPawn::SpawnOn called with no lua_state. Aborting");
|
||||
::abort();
|
||||
};
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
|
||||
void cPawn__TeleportTo( cEntity* a_Entity) {
|
||||
return ( void )cPawn::TeleportTo(a_Entity);
|
||||
@ -5646,19 +5618,19 @@ static int tolua_AllToLua_cPlayer_GetColor00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cPlayer",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cPlayer",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0);
|
||||
const cPlayer* self = (const cPlayer*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetColor'", NULL);
|
||||
#endif
|
||||
{
|
||||
std::string tolua_ret = (std::string) self->GetColor();
|
||||
AString tolua_ret = (AString) self->GetColor();
|
||||
tolua_pushcppstring(tolua_S,(const char*)tolua_ret);
|
||||
}
|
||||
}
|
||||
@ -6058,20 +6030,6 @@ public:
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
void SpawnOn( cClientHandle* a_Target) {
|
||||
if (push_method("SpawnOn", tolua_AllToLua_cEntity_SpawnOn00)) {
|
||||
tolua_pushusertype(lua_state, (void*)a_Target, "cClientHandle");
|
||||
ToluaBase::dbcall(lua_state, 2, 0);
|
||||
} else {
|
||||
if (lua_state)
|
||||
LOG("pure-virtual method cPlayer::SpawnOn not implemented.");
|
||||
else {
|
||||
LOG("pure-virtual method cPlayer::SpawnOn called with no lua_state. Aborting");
|
||||
::abort();
|
||||
};
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
|
||||
void cPlayer__Initialize( cWorld* a_World) {
|
||||
return ( void )cPlayer::Initialize(a_World);
|
||||
@ -10117,14 +10075,14 @@ static int tolua_AllToLua_cWorld_GetWorldSeed00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cWorld",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
const cWorld* self = (const cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetWorldSeed'", NULL);
|
||||
#endif
|
||||
@ -10149,20 +10107,20 @@ static int tolua_AllToLua_cWorld_GetName00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cWorld",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
const cWorld* self = (const cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetName'", NULL);
|
||||
#endif
|
||||
{
|
||||
const char* tolua_ret = (const char*) self->GetName();
|
||||
tolua_pushstring(tolua_S,(const char*)tolua_ret);
|
||||
const AString tolua_ret = (const AString) self->GetName();
|
||||
tolua_pushcppstring(tolua_S,(const char*)tolua_ret);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@ -10212,14 +10170,14 @@ static int tolua_AllToLua_cWorld_GetNumChunks00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cWorld",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cWorld",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
const cWorld* self = (const cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumChunks'", NULL);
|
||||
#endif
|
||||
@ -10743,14 +10701,14 @@ static int tolua_AllToLua_cItem_IsEmpty00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cItem",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cItem",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cItem* self = (cItem*) tolua_tousertype(tolua_S,1,0);
|
||||
const cItem* self = (const cItem*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsEmpty'", NULL);
|
||||
#endif
|
||||
@ -10775,7 +10733,7 @@ static int tolua_AllToLua_cItem_Equals00(lua_State* tolua_S)
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cItem",0,&tolua_err) ||
|
||||
!tolua_isusertype(tolua_S,1,"const cItem",0,&tolua_err) ||
|
||||
(tolua_isvaluenil(tolua_S,2,&tolua_err) || !tolua_isusertype(tolua_S,2,"cItem",0,&tolua_err)) ||
|
||||
!tolua_isnoobj(tolua_S,3,&tolua_err)
|
||||
)
|
||||
@ -10783,7 +10741,7 @@ static int tolua_AllToLua_cItem_Equals00(lua_State* tolua_S)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cItem* self = (cItem*) tolua_tousertype(tolua_S,1,0);
|
||||
const cItem* self = (const cItem*) tolua_tousertype(tolua_S,1,0);
|
||||
cItem* a_Item = ((cItem*) tolua_tousertype(tolua_S,2,0));
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Equals'", NULL);
|
||||
@ -11763,20 +11721,6 @@ public:
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
void SpawnOn( cClientHandle* a_Target) {
|
||||
if (push_method("SpawnOn", tolua_AllToLua_cEntity_SpawnOn00)) {
|
||||
tolua_pushusertype(lua_state, (void*)a_Target, "cClientHandle");
|
||||
ToluaBase::dbcall(lua_state, 2, 0);
|
||||
} else {
|
||||
if (lua_state)
|
||||
LOG("pure-virtual method cPickup::SpawnOn not implemented.");
|
||||
else {
|
||||
LOG("pure-virtual method cPickup::SpawnOn called with no lua_state. Aborting");
|
||||
::abort();
|
||||
};
|
||||
return ( void )0;
|
||||
};
|
||||
};
|
||||
|
||||
bool cPickup__CollectedBy( cPlayer* a_Dest) {
|
||||
return ( bool )cPickup::CollectedBy(a_Dest);
|
||||
@ -12120,7 +12064,7 @@ static int tolua_AllToLua_cRoot_GetWorld00(lua_State* tolua_S)
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetWorld'", NULL);
|
||||
#endif
|
||||
{
|
||||
cWorld* tolua_ret = (cWorld*) self->GetWorld();
|
||||
OBSOLETE cWorld* tolua_ret = (OBSOLETE cWorld*) self->GetWorld();
|
||||
tolua_pushusertype(tolua_S,(void*)tolua_ret,"cWorld");
|
||||
}
|
||||
}
|
||||
@ -12387,6 +12331,38 @@ static int tolua_AllToLua_cRoot_ServerCommand00(lua_State* tolua_S)
|
||||
}
|
||||
#endif //#ifndef TOLUA_DISABLE
|
||||
|
||||
/* method: GetTotalChunkCount of class cRoot */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_GetTotalChunkCount00
|
||||
static int tolua_AllToLua_cRoot_GetTotalChunkCount00(lua_State* tolua_S)
|
||||
{
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cRoot",0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,2,&tolua_err)
|
||||
)
|
||||
goto tolua_lerror;
|
||||
else
|
||||
#endif
|
||||
{
|
||||
cRoot* self = (cRoot*) tolua_tousertype(tolua_S,1,0);
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetTotalChunkCount'", NULL);
|
||||
#endif
|
||||
{
|
||||
int tolua_ret = (int) self->GetTotalChunkCount();
|
||||
tolua_pushnumber(tolua_S,(lua_Number)tolua_ret);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'GetTotalChunkCount'.",&tolua_err);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif //#ifndef TOLUA_DISABLE
|
||||
|
||||
/* method: delete of class cTCPLink */
|
||||
#ifndef TOLUA_DISABLE_tolua_AllToLua_cTCPLink_delete00
|
||||
static int tolua_AllToLua_cTCPLink_delete00(lua_State* tolua_S)
|
||||
@ -12424,7 +12400,7 @@ static int tolua_AllToLua_cTCPLink_Connect00(lua_State* tolua_S)
|
||||
tolua_Error tolua_err;
|
||||
if (
|
||||
!tolua_isusertype(tolua_S,1,"cTCPLink",0,&tolua_err) ||
|
||||
!tolua_isstring(tolua_S,2,0,&tolua_err) ||
|
||||
!tolua_iscppstring(tolua_S,2,0,&tolua_err) ||
|
||||
!tolua_isnumber(tolua_S,3,0,&tolua_err) ||
|
||||
!tolua_isnoobj(tolua_S,4,&tolua_err)
|
||||
)
|
||||
@ -12433,7 +12409,7 @@ static int tolua_AllToLua_cTCPLink_Connect00(lua_State* tolua_S)
|
||||
#endif
|
||||
{
|
||||
cTCPLink* self = (cTCPLink*) tolua_tousertype(tolua_S,1,0);
|
||||
const char* a_Address = ((const char*) tolua_tostring(tolua_S,2,0));
|
||||
const AString a_Address = ((const AString) tolua_tocppstring(tolua_S,2,0));
|
||||
unsigned int a_Port = ((unsigned int) tolua_tonumber(tolua_S,3,0));
|
||||
#ifndef TOLUA_RELEASE
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Connect'", NULL);
|
||||
@ -12441,9 +12417,10 @@ static int tolua_AllToLua_cTCPLink_Connect00(lua_State* tolua_S)
|
||||
{
|
||||
bool tolua_ret = (bool) self->Connect(a_Address,a_Port);
|
||||
tolua_pushboolean(tolua_S,(bool)tolua_ret);
|
||||
tolua_pushcppstring(tolua_S,(const char*)a_Address);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return 2;
|
||||
#ifndef TOLUA_RELEASE
|
||||
tolua_lerror:
|
||||
tolua_error(tolua_S,"#ferror in function 'Connect'.",&tolua_err);
|
||||
@ -12470,7 +12447,7 @@ static int tolua_AllToLua_cTCPLink_Send00(lua_State* tolua_S)
|
||||
#endif
|
||||
{
|
||||
cTCPLink* self = (cTCPLink*) tolua_tousertype(tolua_S,1,0);
|
||||
char* a_Data = ((char*) tolua_tostring(tolua_S,2,0));
|
||||
const char* a_Data = ((const char*) tolua_tostring(tolua_S,2,0));
|
||||
unsigned int a_Size = ((unsigned int) tolua_tonumber(tolua_S,3,0));
|
||||
int a_Flags = ((int) tolua_tonumber(tolua_S,4,0));
|
||||
#ifndef TOLUA_RELEASE
|
||||
@ -15919,7 +15896,7 @@ static int tolua_AllToLua_cGroup_GetColor00(lua_State* tolua_S)
|
||||
if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetColor'", NULL);
|
||||
#endif
|
||||
{
|
||||
std::string tolua_ret = (std::string) self->GetColor();
|
||||
const AString tolua_ret = (const AString) self->GetColor();
|
||||
tolua_pushcppstring(tolua_S,(const char*)tolua_ret);
|
||||
}
|
||||
}
|
||||
@ -17752,6 +17729,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S)
|
||||
tolua_function(tolua_S,"GetWebAdmin",tolua_AllToLua_cRoot_GetWebAdmin00);
|
||||
tolua_function(tolua_S,"GetPluginManager",tolua_AllToLua_cRoot_GetPluginManager00);
|
||||
tolua_function(tolua_S,"ServerCommand",tolua_AllToLua_cRoot_ServerCommand00);
|
||||
tolua_function(tolua_S,"GetTotalChunkCount",tolua_AllToLua_cRoot_GetTotalChunkCount00);
|
||||
tolua_endmodule(tolua_S);
|
||||
#ifdef __cplusplus
|
||||
tolua_cclass(tolua_S,"cTCPLink","cTCPLink","",tolua_collect_cTCPLink);
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
** Lua binding: AllToLua
|
||||
** Generated automatically by tolua++-1.0.92 on 02/08/12 12:55:58.
|
||||
** Generated automatically by tolua++-1.0.92 on 02/13/12 11:40:58.
|
||||
*/
|
||||
|
||||
/* Exported function */
|
||||
|
@ -29,6 +29,8 @@
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <time.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
@ -40,6 +42,7 @@
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <tr1/memory>
|
||||
#endif
|
||||
|
||||
|
||||
@ -49,6 +52,7 @@
|
||||
// CRT stuff:
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
||||
@ -95,11 +99,28 @@
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define OBSOLETE __declspec(deprecated)
|
||||
#define ABSTRACT abstract
|
||||
#else
|
||||
// TODO: how do other compilers mark functions as obsolete, so that their usage results in a compile-time warning?
|
||||
#define OBSOLETE
|
||||
// TODO: Can other compilers explicitly mark classes as abstract (no instances can be created)?
|
||||
#define ABSTRACT
|
||||
#endif
|
||||
|
||||
/// Faster than (int)floorf((float)x / (float)div)
|
||||
#define FAST_FLOOR_DIV( x, div ) ( (x) < 0 ? (((int)x / div) - 1) : ((int)x / div) )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// A generic interface used in ForEach() functions
|
||||
template <typename Type> class cListCallback
|
||||
{
|
||||
public:
|
||||
/// 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;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
1040
source/LeakFinder.cpp
Normal file
1040
source/LeakFinder.cpp
Normal file
File diff suppressed because it is too large
Load Diff
145
source/LeakFinder.h
Normal file
145
source/LeakFinder.h
Normal file
@ -0,0 +1,145 @@
|
||||
/**********************************************************************
|
||||
*
|
||||
* LEAKFINDER.H
|
||||
*
|
||||
*
|
||||
*
|
||||
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Copyright (c) 2005-2010, Jochen Kalmbach
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
// #pragma once is supported starting with _MCS_VER 1000,
|
||||
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
HRESULT InitLeakFinder();
|
||||
void DeinitLeakFinder();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// The following is only available if the file is CPP
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include "StackWalker.h"
|
||||
|
||||
// Interface for output...
|
||||
class LeakFinderOutput : public StackWalker
|
||||
{
|
||||
public:
|
||||
typedef enum LeakFinderOptions
|
||||
{
|
||||
// No addition info will be retrived
|
||||
// (only the address is available)
|
||||
LeakFinderNone = 0,
|
||||
LeakFinderShowCompleteCallstack = 0x1000
|
||||
} LeakFinderOptions;
|
||||
|
||||
LeakFinderOutput(int options = OptionsAll, LPCSTR szSymPath = NULL);
|
||||
virtual void OnLeakSearchStart(LPCSTR sszLeakFinderName);
|
||||
virtual void OnLeakStartEntry(LPCSTR szKeyName, SIZE_T nDataSize);
|
||||
protected:
|
||||
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
|
||||
virtual void OnOutput(LPCSTR szText)
|
||||
{
|
||||
printf(szText);
|
||||
StackWalker::OnOutput(szText);
|
||||
}
|
||||
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
|
||||
{
|
||||
if (strcmp(szFuncName, "SymGetLineFromAddr64") == 0) return;
|
||||
StackWalker::OnDbgHelpErr(szFuncName, gle, addr);
|
||||
}
|
||||
};
|
||||
|
||||
class LeakFinderXmlOutput : public LeakFinderOutput
|
||||
{
|
||||
public:
|
||||
LeakFinderXmlOutput();
|
||||
virtual ~LeakFinderXmlOutput();
|
||||
LeakFinderXmlOutput(LPCTSTR szFileName);
|
||||
virtual void OnLeakSearchStart(LPCSTR sszLeakFinderName);
|
||||
virtual void OnLeakStartEntry(LPCSTR szKeyName, SIZE_T nDataSize);
|
||||
protected:
|
||||
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
|
||||
virtual void OnOutput(LPCSTR szText) { }
|
||||
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr) { }
|
||||
|
||||
FILE *m_fXmlFile;
|
||||
};
|
||||
|
||||
// C++ interface:
|
||||
void DeinitLeakFinder(LeakFinderOutput *output);
|
||||
|
||||
class ZZZ_LeakFinder
|
||||
{
|
||||
public:
|
||||
ZZZ_LeakFinder()
|
||||
{
|
||||
m_pXml = NULL;
|
||||
#ifdef XML_LEAK_FINDER
|
||||
m_pXml = new LeakFinderXmlOutput();
|
||||
#endif
|
||||
InitLeakFinder();
|
||||
}
|
||||
~ZZZ_LeakFinder()
|
||||
{
|
||||
DeinitLeakFinder(m_pXml);
|
||||
if (m_pXml != NULL) delete m_pXml;
|
||||
}
|
||||
protected:
|
||||
LeakFinderXmlOutput *m_pXml;
|
||||
};
|
||||
|
||||
#if defined(INIT_LEAK_FINDER)
|
||||
#if _MSC_VER >= 1200
|
||||
#pragma warning(push)
|
||||
#endif
|
||||
#pragma warning (disable:4074)
|
||||
|
||||
// WARNING: If you enable this option, the code might run without the CRT being initialized or after the CRT was deinitialized!!!
|
||||
// Currently the code is not designed to bypass the CRT...
|
||||
//#pragma init_seg (compiler)
|
||||
ZZZ_LeakFinder zzz_LeakFinder;
|
||||
|
||||
#if _MSC_VER >= 1200
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma warning(default:4074)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // __cplusplus
|
@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
// Linux threads http://www.yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
|
||||
// TODO: We shouldn't need these! Use the OS support objects instead
|
||||
#define SOCKET int
|
||||
typedef void *HANDLE;
|
||||
#define CRITICAL_SECTION pthread_mutex_t
|
||||
#define SD_BOTH (2)
|
||||
#define closesocket(x) (shutdown(x, SD_BOTH), close(x))
|
||||
#define SOCKET_ERROR SO_ERROR
|
||||
#define EnterCriticalSection(x) pthread_mutex_lock(x)
|
||||
#define LeaveCriticalSection(x) pthread_mutex_unlock(x)
|
||||
#define InitializeCriticalSection(x) pthread_mutex_init(x, NULL)
|
||||
#define DeleteCriticalSection(x) (x)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline bool IsSocketError( int a_ReturnedValue )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (a_ReturnedValue == SOCKET_ERROR || a_ReturnedValue == 0);
|
||||
#else
|
||||
return (a_ReturnedValue <= 0);
|
||||
#endif
|
||||
}
|
@ -3,57 +3,57 @@
|
||||
//tolua_begin
|
||||
enum ENUM_PACKET_ID
|
||||
{
|
||||
E_KEEP_ALIVE = 0x00,
|
||||
E_LOGIN = 0x01,
|
||||
E_HANDSHAKE = 0x02,
|
||||
E_CHAT = 0x03,
|
||||
E_UPDATE_TIME = 0x04,
|
||||
E_ENTITY_EQUIPMENT = 0x05,
|
||||
E_USE_ENTITY = 0x07,
|
||||
E_UPDATE_HEALTH = 0x08,
|
||||
E_RESPAWN = 0x09,
|
||||
E_FLYING = 0x0a,
|
||||
E_PLAYERPOS = 0x0b,
|
||||
E_PLAYERLOOK = 0x0c,
|
||||
E_PLAYERMOVELOOK = 0x0d,
|
||||
E_BLOCK_DIG = 0x0e,
|
||||
E_BLOCK_PLACE = 0x0f,
|
||||
E_ITEM_SWITCH = 0x10,
|
||||
E_ADD_TO_INV = 0x11, //TODO: Sure this is not Use Bed??
|
||||
E_ANIMATION = 0x12,
|
||||
E_PACKET_13 = 0x13,
|
||||
E_NAMED_ENTITY_SPAWN= 0x14,
|
||||
E_PICKUP_SPAWN = 0x15,
|
||||
E_COLLECT_ITEM = 0x16,
|
||||
E_ADD_VEHICLE = 0x17,
|
||||
E_SPAWN_MOB = 0x18,
|
||||
E_DESTROY_ENT = 0x1d,
|
||||
E_ENTITY = 0x1e,
|
||||
E_REL_ENT_MOVE = 0x1f,
|
||||
E_ENT_LOOK = 0x20,
|
||||
E_REL_ENT_MOVE_LOOK = 0x21,
|
||||
E_ENT_TELEPORT = 0x22,
|
||||
E_ENT_STATUS = 0x26,
|
||||
E_METADATA = 0x28,
|
||||
E_PRE_CHUNK = 0x32,
|
||||
E_MAP_CHUNK = 0x33,
|
||||
E_MULTI_BLOCK = 0x34,
|
||||
E_BLOCK_CHANGE = 0x35,
|
||||
E_BLOCK_ACTION = 0x36,
|
||||
E_EXPLOSION = 0x3C,
|
||||
E_SOUND_EFFECT = 0x3D,
|
||||
E_NEW_INVALID_STATE = 0x46,
|
||||
E_THUNDERBOLT = 0x47,
|
||||
E_WINDOW_OPEN = 0x64,
|
||||
E_WINDOW_CLOSE = 0x65,
|
||||
E_WINDOW_CLICK = 0x66,
|
||||
E_INVENTORY_SLOT = 0x67,
|
||||
E_INVENTORY_WHOLE = 0x68,
|
||||
E_INVENTORY_PROGRESS= 0x69,
|
||||
E_CREATIVE_INVENTORY_ACTION = 0x6B,
|
||||
E_UPDATE_SIGN = 0x82,
|
||||
E_PLAYER_LIST_ITEM = 0xC9,
|
||||
E_PING = 0xfe,
|
||||
E_DISCONNECT = 0xff,
|
||||
E_KEEP_ALIVE = 0x00,
|
||||
E_LOGIN = 0x01,
|
||||
E_HANDSHAKE = 0x02,
|
||||
E_CHAT = 0x03,
|
||||
E_UPDATE_TIME = 0x04,
|
||||
E_ENTITY_EQUIPMENT = 0x05,
|
||||
E_USE_ENTITY = 0x07,
|
||||
E_UPDATE_HEALTH = 0x08,
|
||||
E_RESPAWN = 0x09,
|
||||
E_FLYING = 0x0a,
|
||||
E_PLAYERPOS = 0x0b,
|
||||
E_PLAYERLOOK = 0x0c,
|
||||
E_PLAYERMOVELOOK = 0x0d,
|
||||
E_BLOCK_DIG = 0x0e,
|
||||
E_BLOCK_PLACE = 0x0f,
|
||||
E_ITEM_SWITCH = 0x10,
|
||||
E_ADD_TO_INV = 0x11, // TODO: Sure this is not Use Bed??
|
||||
E_ANIMATION = 0x12,
|
||||
E_PACKET_13 = 0x13,
|
||||
E_NAMED_ENTITY_SPAWN = 0x14,
|
||||
E_PICKUP_SPAWN = 0x15,
|
||||
E_COLLECT_ITEM = 0x16,
|
||||
E_ADD_VEHICLE = 0x17,
|
||||
E_SPAWN_MOB = 0x18,
|
||||
E_DESTROY_ENT = 0x1d,
|
||||
E_ENTITY = 0x1e,
|
||||
E_REL_ENT_MOVE = 0x1f,
|
||||
E_ENT_LOOK = 0x20,
|
||||
E_REL_ENT_MOVE_LOOK = 0x21,
|
||||
E_ENT_TELEPORT = 0x22,
|
||||
E_ENT_STATUS = 0x26,
|
||||
E_METADATA = 0x28,
|
||||
E_PRE_CHUNK = 0x32,
|
||||
E_MAP_CHUNK = 0x33,
|
||||
E_MULTI_BLOCK = 0x34,
|
||||
E_BLOCK_CHANGE = 0x35,
|
||||
E_BLOCK_ACTION = 0x36,
|
||||
E_EXPLOSION = 0x3C,
|
||||
E_SOUND_EFFECT = 0x3D,
|
||||
E_NEW_INVALID_STATE = 0x46,
|
||||
E_THUNDERBOLT = 0x47,
|
||||
E_WINDOW_OPEN = 0x64,
|
||||
E_WINDOW_CLOSE = 0x65,
|
||||
E_WINDOW_CLICK = 0x66,
|
||||
E_INVENTORY_SLOT = 0x67,
|
||||
E_INVENTORY_WHOLE = 0x68,
|
||||
E_INVENTORY_PROGRESS = 0x69,
|
||||
E_CREATIVE_INVENTORY_ACTION = 0x6B,
|
||||
E_UPDATE_SIGN = 0x82,
|
||||
E_PLAYER_LIST_ITEM = 0xC9,
|
||||
E_PING = 0xfe,
|
||||
E_DISCONNECT = 0xff,
|
||||
};
|
||||
//tolua_end
|
||||
|
1345
source/StackWalker.cpp
Normal file
1345
source/StackWalker.cpp
Normal file
File diff suppressed because it is too large
Load Diff
214
source/StackWalker.h
Normal file
214
source/StackWalker.h
Normal file
@ -0,0 +1,214 @@
|
||||
/**********************************************************************
|
||||
*
|
||||
* StackWalker.h
|
||||
*
|
||||
*
|
||||
*
|
||||
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
|
||||
*
|
||||
* Copyright (c) 2005-2010, Jochen Kalmbach
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
|
||||
* used to endorse or promote products derived from this software without
|
||||
* specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* **********************************************************************/
|
||||
// #pragma once is supported starting with _MCS_VER 1000,
|
||||
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
|
||||
#pragma once
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
// special defines for VC5/6 (if no actual PSDK is installed):
|
||||
#if _MSC_VER < 1300
|
||||
typedef unsigned __int64 DWORD64, *PDWORD64;
|
||||
#if defined(_WIN64)
|
||||
typedef unsigned __int64 SIZE_T, *PSIZE_T;
|
||||
#else
|
||||
typedef unsigned long SIZE_T, *PSIZE_T;
|
||||
#endif
|
||||
#endif // _MSC_VER < 1300
|
||||
|
||||
class StackWalkerInternal; // forward
|
||||
class StackWalker
|
||||
{
|
||||
public:
|
||||
typedef enum StackWalkOptions
|
||||
{
|
||||
// No addition info will be retrived
|
||||
// (only the address is available)
|
||||
RetrieveNone = 0,
|
||||
|
||||
// Try to get the symbol-name
|
||||
RetrieveSymbol = 1,
|
||||
|
||||
// Try to get the line for this symbol
|
||||
RetrieveLine = 2,
|
||||
|
||||
// Try to retrieve the module-infos
|
||||
RetrieveModuleInfo = 4,
|
||||
|
||||
// Also retrieve the version for the DLL/EXE
|
||||
RetrieveFileVersion = 8,
|
||||
|
||||
// Contains all the abouve
|
||||
RetrieveVerbose = 0xF,
|
||||
|
||||
// Generate a "good" symbol-search-path
|
||||
SymBuildPath = 0x10,
|
||||
|
||||
// Also use the public Microsoft-Symbol-Server
|
||||
SymUseSymSrv = 0x20,
|
||||
|
||||
// Contains all the abouve "Sym"-options
|
||||
SymAll = 0x30,
|
||||
|
||||
// Contains all options (default)
|
||||
OptionsAll = 0x3F
|
||||
} StackWalkOptions;
|
||||
|
||||
StackWalker(
|
||||
int options = OptionsAll, // 'int' is by design, to combine the enum-flags
|
||||
LPCSTR szSymPath = NULL,
|
||||
DWORD dwProcessId = GetCurrentProcessId(),
|
||||
HANDLE hProcess = GetCurrentProcess()
|
||||
);
|
||||
StackWalker(DWORD dwProcessId, HANDLE hProcess);
|
||||
virtual ~StackWalker();
|
||||
|
||||
typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
|
||||
HANDLE hProcess,
|
||||
DWORD64 qwBaseAddress,
|
||||
PVOID lpBuffer,
|
||||
DWORD nSize,
|
||||
LPDWORD lpNumberOfBytesRead,
|
||||
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
|
||||
);
|
||||
|
||||
BOOL LoadModules();
|
||||
|
||||
BOOL ShowCallstack(
|
||||
HANDLE hThread = GetCurrentThread(),
|
||||
const CONTEXT *context = NULL,
|
||||
PReadProcessMemoryRoutine readMemoryFunction = NULL,
|
||||
LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
|
||||
);
|
||||
|
||||
#if _MSC_VER >= 1300
|
||||
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
|
||||
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
|
||||
protected:
|
||||
#endif
|
||||
enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
|
||||
|
||||
protected:
|
||||
// Entry for each Callstack-Entry
|
||||
typedef struct CallstackEntry
|
||||
{
|
||||
DWORD64 offset; // if 0, we have no valid entry
|
||||
CHAR name[STACKWALK_MAX_NAMELEN];
|
||||
CHAR undName[STACKWALK_MAX_NAMELEN];
|
||||
CHAR undFullName[STACKWALK_MAX_NAMELEN];
|
||||
DWORD64 offsetFromSmybol;
|
||||
DWORD offsetFromLine;
|
||||
DWORD lineNumber;
|
||||
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
|
||||
DWORD symType;
|
||||
LPCSTR symTypeString;
|
||||
CHAR moduleName[STACKWALK_MAX_NAMELEN];
|
||||
DWORD64 baseOfImage;
|
||||
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
|
||||
} CallstackEntry;
|
||||
|
||||
typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
|
||||
|
||||
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
|
||||
virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
|
||||
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
|
||||
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
|
||||
virtual void OnOutput(LPCSTR szText);
|
||||
|
||||
StackWalkerInternal *m_sw;
|
||||
HANDLE m_hProcess;
|
||||
DWORD m_dwProcessId;
|
||||
BOOL m_modulesLoaded;
|
||||
LPSTR m_szSymPath;
|
||||
|
||||
int m_options;
|
||||
int m_MaxRecursionCount;
|
||||
|
||||
static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
|
||||
|
||||
friend StackWalkerInternal;
|
||||
};
|
||||
|
||||
|
||||
// The "ugly" assembler-implementation is needed for systems before XP
|
||||
// If you have a new PSDK and you only compile for XP and later, then you can use
|
||||
// the "RtlCaptureContext"
|
||||
// Currently there is no define which determines the PSDK-Version...
|
||||
// So we just use the compiler-version (and assumes that the PSDK is
|
||||
// the one which was installed by the VS-IDE)
|
||||
|
||||
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
|
||||
// But I currently use it in x64/IA64 environments...
|
||||
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
|
||||
|
||||
#if defined(_M_IX86)
|
||||
#ifdef CURRENT_THREAD_VIA_EXCEPTION
|
||||
// TODO: The following is not a "good" implementation,
|
||||
// because the callstack is only valid in the "__except" block...
|
||||
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
||||
do { \
|
||||
memset(&c, 0, sizeof(CONTEXT)); \
|
||||
EXCEPTION_POINTERS *pExp = NULL; \
|
||||
__try { \
|
||||
throw 0; \
|
||||
} __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
|
||||
if (pExp != NULL) \
|
||||
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
|
||||
c.ContextFlags = contextFlags; \
|
||||
} while(0);
|
||||
#else
|
||||
// The following should be enough for walking the callstack...
|
||||
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
||||
do { \
|
||||
memset(&c, 0, sizeof(CONTEXT)); \
|
||||
c.ContextFlags = contextFlags; \
|
||||
__asm call x \
|
||||
__asm x: pop eax \
|
||||
__asm mov c.Eip, eax \
|
||||
__asm mov c.Ebp, ebp \
|
||||
__asm mov c.Esp, esp \
|
||||
} while(0);
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
// The following is defined for x86 (XP and higher), x64 and IA64:
|
||||
#define GET_CURRENT_CONTEXT(c, contextFlags) \
|
||||
do { \
|
||||
memset(&c, 0, sizeof(CONTEXT)); \
|
||||
c.ContextFlags = contextFlags; \
|
||||
RtlCaptureContext(&c); \
|
||||
} while(0);
|
||||
#endif
|
415
source/WSSCompact.cpp
Normal file
415
source/WSSCompact.cpp
Normal file
@ -0,0 +1,415 @@
|
||||
|
||||
// WSSCompact.cpp
|
||||
|
||||
// Interfaces to the cWSSCompact class representing the "compact" storage schema (PAK-files)
|
||||
|
||||
#include "Globals.h"
|
||||
#include "WSSCompact.h"
|
||||
#include "cWorld.h"
|
||||
#include "zlib.h"
|
||||
#include <json/json.h>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
/// The chunk header, as stored in the file:
|
||||
struct cWSSCompact::sChunkHeader
|
||||
{
|
||||
int m_ChunkX;
|
||||
int m_ChunkZ;
|
||||
int m_CompressedSize;
|
||||
int m_UncompressedSize;
|
||||
} ;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// The maximum number of PAK files that are cached
|
||||
const int MAX_PAK_FILES = 16;
|
||||
|
||||
/// The maximum number of unsaved chunks before the cPAKFile saves them to disk
|
||||
const int MAX_DIRTY_CHUNKS = 16;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cWSSCompact:
|
||||
|
||||
cWSSCompact::~cWSSCompact()
|
||||
{
|
||||
for (cPAKFiles::iterator itr = m_PAKFiles.begin(); itr != m_PAKFiles.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::LoadChunk(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||
if (f == NULL)
|
||||
{
|
||||
// For some reason we couldn't locate the file
|
||||
return false;
|
||||
}
|
||||
|
||||
return f->LoadChunk(a_Chunk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::SaveChunk(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
cPAKFile * f = LoadPAKFile(a_Chunk);
|
||||
if (f == NULL)
|
||||
{
|
||||
// For some reason we couldn't locate the file
|
||||
return false;
|
||||
}
|
||||
return f->SaveChunk(a_Chunk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cWSSCompact::cPAKFile * cWSSCompact::LoadPAKFile(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
// We need to retain this weird conversion code, because some edge chunks are in the wrong PAK file
|
||||
const int LayerX = (int)(floorf((float)a_Chunk->GetPosX() / 32.0f));
|
||||
const int LayerZ = (int)(floorf((float)a_Chunk->GetPosZ() / 32.0f));
|
||||
|
||||
// Is it already cached?
|
||||
for (cPAKFiles::iterator itr = m_PAKFiles.begin(); itr != m_PAKFiles.end(); ++itr)
|
||||
{
|
||||
if (((*itr) != NULL) && ((*itr)->GetLayerX() == LayerX) && ((*itr)->GetLayerZ() == LayerZ))
|
||||
{
|
||||
// Move the file to front and return it:
|
||||
cPAKFile * f = *itr;
|
||||
if (itr != m_PAKFiles.begin())
|
||||
{
|
||||
m_PAKFiles.erase(itr);
|
||||
m_PAKFiles.push_front(f);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
// Load it anew:
|
||||
AString FileName;
|
||||
Printf(FileName, "%s/X%i_Z%i.pak", m_World->GetName().c_str(), LayerX, LayerZ );
|
||||
cPAKFile * f = new cPAKFile(FileName, LayerX, LayerZ);
|
||||
if (f == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
m_PAKFiles.push_front(f);
|
||||
|
||||
// If there are too many PAK files cached, delete the last one used:
|
||||
if (m_PAKFiles.size() > MAX_PAK_FILES)
|
||||
{
|
||||
delete m_PAKFiles.back();
|
||||
m_PAKFiles.pop_back();
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cWSSCompact::cPAKFile
|
||||
|
||||
#define READ(Var) \
|
||||
if (f.Read(&Var, sizeof(Var)) != sizeof(Var)) \
|
||||
{ \
|
||||
LOGERROR("ERROR READING %s FROM FILE %s (line %d); file offset %d", #Var, m_FileName.c_str(), __LINE__, f.Tell()); \
|
||||
return; \
|
||||
}
|
||||
|
||||
cWSSCompact::cPAKFile::cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ) :
|
||||
m_FileName(a_FileName),
|
||||
m_LayerX(a_LayerX),
|
||||
m_LayerZ(a_LayerZ),
|
||||
m_NumDirty(0)
|
||||
{
|
||||
cFile f;
|
||||
if (!f.Open(m_FileName, cFile::fmRead))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Read headers:
|
||||
char PakVersion = 0;
|
||||
READ(PakVersion);
|
||||
if (PakVersion != 1)
|
||||
{
|
||||
LOGERROR("File \"%s\" is in an unknown pak format (%d)", m_FileName.c_str(), PakVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
char ChunkVersion = 0;
|
||||
READ(ChunkVersion);
|
||||
if (ChunkVersion != 1)
|
||||
{
|
||||
LOGERROR("File \"%s\" is in an unknown chunk format (%d)", m_FileName.c_str(), ChunkVersion);
|
||||
return;
|
||||
}
|
||||
|
||||
short NumChunks = 0;
|
||||
READ(NumChunks);
|
||||
|
||||
// Read chunk headers:
|
||||
for (int i = 0; i < NumChunks; i++)
|
||||
{
|
||||
sChunkHeader * Header = new sChunkHeader;
|
||||
READ(*Header);
|
||||
m_ChunkHeaders.push_back(Header);
|
||||
} // for i - chunk headers
|
||||
|
||||
// Read chunk data:
|
||||
if (f.ReadRestOfFile(m_DataContents) == -1)
|
||||
{
|
||||
LOGERROR("Cannot read file \"%s\" contents", m_FileName.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cWSSCompact::cPAKFile::~cPAKFile()
|
||||
{
|
||||
if (m_NumDirty > 0)
|
||||
{
|
||||
SynchronizeFile();
|
||||
}
|
||||
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
int ChunkX = a_Chunk->GetPosX();
|
||||
int ChunkZ = a_Chunk->GetPosZ();
|
||||
sChunkHeader * Header = NULL;
|
||||
int Offset = 0;
|
||||
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
||||
{
|
||||
if (((*itr)->m_ChunkX == ChunkX) && ((*itr)->m_ChunkZ == ChunkZ))
|
||||
{
|
||||
Header = *itr;
|
||||
break;
|
||||
}
|
||||
Offset += (*itr)->m_CompressedSize;
|
||||
}
|
||||
if ((Header == NULL) || (Offset + Header->m_CompressedSize > (int)m_DataContents.size()))
|
||||
{
|
||||
// Chunk not found / data invalid
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadChunk(a_Chunk, Offset, Header);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::cPAKFile::SaveChunk(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
if (!SaveChunkToData(a_Chunk))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (m_NumDirty > MAX_DIRTY_CHUNKS)
|
||||
{
|
||||
SynchronizeFile();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::cPAKFile::LoadChunk(const cChunkPtr & a_Chunk, int a_Offset, sChunkHeader * a_Header)
|
||||
{
|
||||
// Decompress the data:
|
||||
uLongf DestSize = a_Header->m_UncompressedSize;
|
||||
std::auto_ptr<char> BlockData(new char[ DestSize ]);
|
||||
int errorcode = uncompress( (Bytef*)BlockData.get(), &DestSize, (Bytef*)m_DataContents.data() + a_Offset, a_Header->m_CompressedSize );
|
||||
if (errorcode != Z_OK)
|
||||
{
|
||||
LOGERROR("Error %d decompressing data for chunk [%d, %d] from file \"%s\"",
|
||||
errorcode,
|
||||
a_Chunk->GetPosX(), a_Chunk->GetPosZ(),
|
||||
m_FileName.c_str()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (a_Header->m_UncompressedSize != DestSize)
|
||||
{
|
||||
LOGWARNING("Uncompressed data size differs (exp %d, got %d) for chunk [%d, %d] from file \"%s\"",
|
||||
a_Header->m_UncompressedSize, DestSize,
|
||||
a_Chunk->GetPosX(), a_Chunk->GetPosZ(),
|
||||
m_FileName.c_str()
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
a_Chunk->CopyBlockDataFrom(BlockData.get());
|
||||
a_Chunk->SetValid();
|
||||
|
||||
if (DestSize > cChunk::c_BlockDataSize ) // We gots some extra data :D
|
||||
{
|
||||
LOGINFO("Parsing trailing JSON");
|
||||
Json::Value root; // will contain the root value after parsing.
|
||||
Json::Reader reader;
|
||||
if ( !reader.parse( BlockData.get() + cChunk::c_BlockDataSize, root, false ) )
|
||||
{
|
||||
LOGERROR("Failed to parse trailing JSON!");
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Chunk->LoadFromJson( root );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWSSCompact::cPAKFile::EraseChunk(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
int ChunkX = a_Chunk->GetPosX();
|
||||
int ChunkZ = a_Chunk->GetPosZ();
|
||||
sChunkHeader * Header = NULL;
|
||||
int Offset = 0;
|
||||
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
||||
{
|
||||
if (((*itr)->m_ChunkX == ChunkX) && ((*itr)->m_ChunkZ == ChunkZ))
|
||||
{
|
||||
m_DataContents.erase(Offset, (*itr)->m_CompressedSize);
|
||||
delete *itr;
|
||||
itr = m_ChunkHeaders.erase(itr);
|
||||
return;
|
||||
}
|
||||
Offset += (*itr)->m_CompressedSize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWSSCompact::cPAKFile::SaveChunkToData(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
// Erase any existing data for the chunk:
|
||||
EraseChunk(a_Chunk);
|
||||
|
||||
// Serialize the chunk:
|
||||
AString Data;
|
||||
Data.assign(a_Chunk->pGetBlockData(), cChunk::c_BlockDataSize);
|
||||
Json::Value root;
|
||||
a_Chunk->SaveToJson( root );
|
||||
if (!root.empty())
|
||||
{
|
||||
AString JsonData;
|
||||
Json::StyledWriter writer;
|
||||
JsonData = writer.write( root );
|
||||
Data.append(JsonData);
|
||||
}
|
||||
|
||||
// Compress the data:
|
||||
uLongf CompressedSize = compressBound(Data.size());
|
||||
std::auto_ptr<char> Compressed(new char[CompressedSize]);
|
||||
int errorcode = compress2( (Bytef*)Compressed.get(), &CompressedSize, (const Bytef*)Data.data(), Data.size(), Z_DEFAULT_COMPRESSION);
|
||||
if ( errorcode != Z_OK )
|
||||
{
|
||||
LOGERROR("Error %i compressing data for chunk [%d, %d]", errorcode, a_Chunk->GetPosX(), a_Chunk->GetPosZ() );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save the header:
|
||||
sChunkHeader * Header = new sChunkHeader;
|
||||
if (Header == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
Header->m_CompressedSize = CompressedSize;
|
||||
Header->m_ChunkX = a_Chunk->GetPosX();
|
||||
Header->m_ChunkZ = a_Chunk->GetPosZ();
|
||||
Header->m_UncompressedSize = Data.size();
|
||||
m_ChunkHeaders.push_back(Header);
|
||||
|
||||
m_DataContents.append(Compressed.get(), CompressedSize);
|
||||
|
||||
m_NumDirty++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define WRITE(Var) \
|
||||
if (f.Write(&Var, sizeof(Var)) != sizeof(Var)) \
|
||||
{ \
|
||||
LOGERROR("cWSSCompact: ERROR writing %s to file \"%s\" (line %d); file offset %d", #Var, m_FileName.c_str(), __LINE__, f.Tell()); \
|
||||
return; \
|
||||
}
|
||||
|
||||
void cWSSCompact::cPAKFile::SynchronizeFile(void)
|
||||
{
|
||||
cFile f;
|
||||
if (!f.Open(m_FileName, cFile::fmWrite))
|
||||
{
|
||||
LOGERROR("Cannot open PAK file \"%s\" for writing", m_FileName.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
char PakVersion = 1;
|
||||
WRITE(PakVersion);
|
||||
char ChunkVersion = 1;
|
||||
WRITE(ChunkVersion);
|
||||
short NumChunks = (short)m_ChunkHeaders.size();
|
||||
WRITE(NumChunks);
|
||||
for (sChunkHeaders::iterator itr = m_ChunkHeaders.begin(); itr != m_ChunkHeaders.end(); ++itr)
|
||||
{
|
||||
WRITE(**itr);
|
||||
}
|
||||
if (f.Write(m_DataContents.data(), m_DataContents.size()) != m_DataContents.size())
|
||||
{
|
||||
LOGERROR("cWSSCompact: ERROR writing chunk contents to file \"%s\" (line %d); file offset %d", m_FileName.c_str(), __LINE__, f.Tell());
|
||||
return;
|
||||
}
|
||||
m_NumDirty = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
84
source/WSSCompact.h
Normal file
84
source/WSSCompact.h
Normal file
@ -0,0 +1,84 @@
|
||||
|
||||
// WSSCompact.h
|
||||
|
||||
// Interfaces to the cWSSCompact class representing the "Compact" storage schema (PAK-files)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#ifndef WSSCOMPACT_H_INCLUDED
|
||||
#define WSSCOMPACT_H_INCLUDED
|
||||
|
||||
#include "WorldStorage.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cWSSCompact :
|
||||
public cWSSchema
|
||||
{
|
||||
public:
|
||||
cWSSCompact(cWorld * a_World) : cWSSchema(a_World) {}
|
||||
virtual ~cWSSCompact();
|
||||
|
||||
protected:
|
||||
|
||||
struct sChunkHeader;
|
||||
typedef std::vector<sChunkHeader *> sChunkHeaders;
|
||||
|
||||
/// Implements a cache for a single PAK file; implements lazy-write in order to be able to write multiple chunks fast
|
||||
class cPAKFile
|
||||
{
|
||||
public:
|
||||
|
||||
cPAKFile(const AString & a_FileName, int a_LayerX, int a_LayerZ);
|
||||
~cPAKFile();
|
||||
|
||||
bool SaveChunk(const cChunkPtr & a_Chunk);
|
||||
bool LoadChunk(const cChunkPtr & a_Chunk);
|
||||
|
||||
int GetLayerX(void) const {return m_LayerX; }
|
||||
int GetLayerZ(void) const {return m_LayerZ; }
|
||||
|
||||
protected:
|
||||
|
||||
AString m_FileName;
|
||||
int m_LayerX;
|
||||
int m_LayerZ;
|
||||
|
||||
sChunkHeaders m_ChunkHeaders;
|
||||
AString m_DataContents; // Data contents of the file, cached
|
||||
|
||||
int m_NumDirty; // Number of chunks that were written into m_DataContents but not into the file
|
||||
|
||||
bool LoadChunk(const cChunkPtr & a_Chunk, int a_Offset, sChunkHeader * a_Header);
|
||||
void EraseChunk(const cChunkPtr & a_Chunk); // Erases the chunk data from m_DataContents and updates m_ChunkHeaders
|
||||
bool SaveChunkToData(const cChunkPtr & a_Chunk); // Saves the chunk to m_DataContents, updates headers and m_NumDirty
|
||||
void SynchronizeFile(void); // Writes m_DataContents along with the headers to file, resets m_NumDirty
|
||||
} ;
|
||||
|
||||
typedef std::list<cPAKFile *> cPAKFiles;
|
||||
|
||||
cPAKFiles m_PAKFiles; // A MRU cache of PAK files
|
||||
|
||||
/// Loads the correct PAK file either from cache or from disk, manages the m_PAKFiles cache
|
||||
cPAKFile * LoadPAKFile(const cChunkPtr & a_Chunk);
|
||||
|
||||
// cWSSchema overrides:
|
||||
virtual bool LoadChunk(const cChunkPtr & a_Chunk) override;
|
||||
virtual bool SaveChunk(const cChunkPtr & a_Chunk) override;
|
||||
virtual const AString GetName(void) const override {return "compact"; }
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // WSSCOMPACT_H_INCLUDED
|
||||
|
||||
|
||||
|
||||
|
256
source/WorldStorage.cpp
Normal file
256
source/WorldStorage.cpp
Normal file
@ -0,0 +1,256 @@
|
||||
|
||||
// WorldStorage.cpp
|
||||
|
||||
// Implements the cWorldStorage class representing the chunk loading / saving thread
|
||||
|
||||
// To add a new storage schema, implement a cWSSchema descendant and add it to cWorldStorage::InitSchemas()
|
||||
|
||||
#include "Globals.h"
|
||||
#include "WorldStorage.h"
|
||||
#include "WSSCompact.h"
|
||||
#include "cWorld.h"
|
||||
#include "cChunkGenerator.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Example storage schema - forgets all chunks ;)
|
||||
class cWSSForgetful :
|
||||
public cWSSchema
|
||||
{
|
||||
public:
|
||||
cWSSForgetful(cWorld * a_World) : cWSSchema(a_World) {}
|
||||
|
||||
protected:
|
||||
// cWSSchema overrides:
|
||||
virtual bool LoadChunk(const cChunkPtr & a_Chunk) override {return false; }
|
||||
virtual bool SaveChunk(const cChunkPtr & a_Chunk) override {return true; }
|
||||
virtual const AString GetName(void) const override {return "forgetful"; }
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cWorldStorage:
|
||||
|
||||
cWorldStorage::cWorldStorage(void) :
|
||||
super("cWorldStorage"),
|
||||
m_World(NULL),
|
||||
m_SaveSchema(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cWorldStorage::~cWorldStorage()
|
||||
{
|
||||
for (cWSSchemaList::iterator itr = m_Schemas.begin(); itr != m_Schemas.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
} // for itr - m_Schemas[]
|
||||
m_LoadQueue.clear();
|
||||
m_SaveQueue.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWorldStorage::Start(cWorld * a_World, const AString & a_StorageSchemaName)
|
||||
{
|
||||
m_World = a_World;
|
||||
m_StorageSchemaName = a_StorageSchemaName;
|
||||
InitSchemas();
|
||||
|
||||
return super::Start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldStorage::WaitForFinish(void)
|
||||
{
|
||||
LOG("Waiting for the world storage to finish saving");
|
||||
|
||||
// Cancel all loading requests:
|
||||
cCSLock Lock(m_CSLoadQueue);
|
||||
m_LoadQueue.clear();
|
||||
|
||||
// Wait for the thread to finish:
|
||||
mShouldTerminate = true;
|
||||
m_Event.Set();
|
||||
super::Wait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldStorage::QueueLoadChunk(cChunkPtr & a_Chunk)
|
||||
{
|
||||
// Queues the chunk for loading; if not loaded, the chunk will be generated
|
||||
cCSLock Lock(m_CSLoadQueue);
|
||||
m_LoadQueue.remove(a_Chunk); // Don't add twice
|
||||
m_LoadQueue.push_back(a_Chunk);
|
||||
m_Event.Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldStorage::QueueSaveChunk(cChunkPtr & a_Chunk)
|
||||
{
|
||||
cCSLock Lock(m_CSSaveQueue);
|
||||
m_SaveQueue.remove(a_Chunk); // Don't add twice
|
||||
m_SaveQueue.push_back(a_Chunk);
|
||||
m_Event.Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldStorage::UnqueueLoad(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
cCSLock Lock(m_CSLoadQueue);
|
||||
m_LoadQueue.remove(a_Chunk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldStorage::UnqueueSave(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
cCSLock Lock(m_CSSaveQueue);
|
||||
m_SaveQueue.remove(a_Chunk);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldStorage::InitSchemas(void)
|
||||
{
|
||||
// The first schema added is considered the default
|
||||
m_Schemas.push_back(new cWSSCompact(m_World));
|
||||
m_Schemas.push_back(new cWSSForgetful(m_World));
|
||||
// Add new schemas here
|
||||
|
||||
if (m_StorageSchemaName == "Default")
|
||||
{
|
||||
m_SaveSchema = m_Schemas.front();
|
||||
return;
|
||||
}
|
||||
for (cWSSchemaList::iterator itr = m_Schemas.begin(); itr != m_Schemas.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->GetName() == m_StorageSchemaName)
|
||||
{
|
||||
m_SaveSchema = *itr;
|
||||
return;
|
||||
}
|
||||
} // for itr - m_Schemas[]
|
||||
|
||||
// Unknown schema selected, let the admin know:
|
||||
LOGWARNING("Unknown storage schema name \"%s\". Using default. Available schemas:", m_StorageSchemaName.c_str());
|
||||
for (cWSSchemaList::iterator itr = m_Schemas.begin(); itr != m_Schemas.end(); ++itr)
|
||||
{
|
||||
LOGWARNING("\t\"%s\"", (*itr)->GetName().c_str());
|
||||
}
|
||||
m_SaveSchema = m_Schemas.front();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldStorage::Execute(void)
|
||||
{
|
||||
while (!mShouldTerminate)
|
||||
{
|
||||
m_Event.Wait();
|
||||
|
||||
// Process both queues until they are empty again:
|
||||
bool HasMore;
|
||||
do
|
||||
{
|
||||
HasMore = false;
|
||||
if (mShouldTerminate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Load 1 chunk:
|
||||
cChunkPtr ToLoad;
|
||||
{
|
||||
cCSLock Lock(m_CSLoadQueue);
|
||||
if (m_LoadQueue.size() > 0)
|
||||
{
|
||||
ToLoad = m_LoadQueue.front();
|
||||
m_LoadQueue.pop_front();
|
||||
}
|
||||
HasMore = (m_LoadQueue.size() > 0);
|
||||
}
|
||||
if ((ToLoad != NULL) && !LoadChunk(ToLoad))
|
||||
{
|
||||
// The chunk couldn't be loaded, generate it:
|
||||
m_World->GetGenerator().GenerateChunk(ToLoad->GetPosX(), ToLoad->GetPosZ());
|
||||
}
|
||||
|
||||
// Save 1 chunk:
|
||||
cChunkPtr Save;
|
||||
{
|
||||
cCSLock Lock(m_CSSaveQueue);
|
||||
if (m_SaveQueue.size() > 0)
|
||||
{
|
||||
Save = m_SaveQueue.front();
|
||||
m_SaveQueue.pop_front();
|
||||
}
|
||||
HasMore = HasMore || (m_SaveQueue.size() > 0);
|
||||
}
|
||||
if ((Save != NULL) && (!m_SaveSchema->SaveChunk(Save)))
|
||||
{
|
||||
LOGWARNING("Cannot save chunk [%d, %d]", Save->GetPosX(), Save->GetPosZ());
|
||||
}
|
||||
} while (HasMore);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cWorldStorage::LoadChunk(const cChunkPtr & a_Chunk)
|
||||
{
|
||||
if (a_Chunk->IsValid())
|
||||
{
|
||||
// Already loaded (can happen, since the queue is async)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_SaveSchema->LoadChunk(a_Chunk))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
for (cWSSchemaList::iterator itr = m_Schemas.begin(); itr != m_Schemas.end(); ++itr)
|
||||
{
|
||||
if ((*itr)->LoadChunk(a_Chunk))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
94
source/WorldStorage.h
Normal file
94
source/WorldStorage.h
Normal file
@ -0,0 +1,94 @@
|
||||
|
||||
// WorldStorage.h
|
||||
|
||||
// Interfaces to the cWorldStorage class representing the chunk loading / saving thread
|
||||
// This class decides which storage schema to use for saving; it queries all available schemas for loading
|
||||
// Also declares the base class for all storage schemas, cWSSchema
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
#ifndef WORLDSTORAGE_H_INCLUDED
|
||||
#define WORLDSTORAGE_H_INCLUDED
|
||||
|
||||
#include "cChunk.h"
|
||||
#include "cIsThread.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Interface that all the world storage schemas need to implement
|
||||
class cWSSchema ABSTRACT
|
||||
{
|
||||
public:
|
||||
cWSSchema(cWorld * a_World) : m_World(a_World) {}
|
||||
virtual ~cWSSchema() {} // Force the descendants' destructors to be virtual
|
||||
|
||||
virtual bool LoadChunk(const cChunkPtr & a_Chunk) = 0;
|
||||
virtual bool SaveChunk(const cChunkPtr & a_Chunk) = 0;
|
||||
virtual const AString GetName(void) const = 0;
|
||||
|
||||
protected:
|
||||
|
||||
cWorld * m_World;
|
||||
} ;
|
||||
|
||||
typedef std::list<cWSSchema *> cWSSchemaList;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cWorldStorage :
|
||||
public cIsThread
|
||||
{
|
||||
typedef cIsThread super;
|
||||
|
||||
public:
|
||||
|
||||
cWorldStorage(void);
|
||||
~cWorldStorage();
|
||||
|
||||
void QueueLoadChunk(cChunkPtr & a_Chunk); // Queues the chunk for loading; if not loaded, the chunk will be generated
|
||||
void QueueSaveChunk(cChunkPtr & a_Chunk);
|
||||
|
||||
void UnqueueLoad(const cChunkPtr & a_Chunk);
|
||||
void UnqueueSave(const cChunkPtr & a_Chunk);
|
||||
|
||||
bool Start(cWorld * a_World, const AString & a_StorageSchemaName); // Hide the cIsThread's Start() method, we need to provide args
|
||||
void WaitForFinish(void);
|
||||
|
||||
protected:
|
||||
|
||||
cWorld * m_World;
|
||||
AString m_StorageSchemaName;
|
||||
|
||||
cCriticalSection m_CSLoadQueue;
|
||||
cChunkPtrList m_LoadQueue;
|
||||
|
||||
cCriticalSection m_CSSaveQueue;
|
||||
cChunkPtrList m_SaveQueue;
|
||||
|
||||
cEvent m_Event; // Set when there's any addition to the queues
|
||||
|
||||
cWSSchemaList m_Schemas;
|
||||
cWSSchema * m_SaveSchema;
|
||||
|
||||
void InitSchemas(void);
|
||||
|
||||
virtual void Execute(void) override;
|
||||
bool LoadChunk(const cChunkPtr & a_Chunk);
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif // WORLDSTORAGE_H_INCLUDED
|
||||
|
||||
|
||||
|
||||
|
@ -35,6 +35,17 @@ cAuthenticator::cAuthenticator(void) :
|
||||
|
||||
|
||||
|
||||
cAuthenticator::~cAuthenticator()
|
||||
{
|
||||
mShouldTerminate = true;
|
||||
mQueueNonempty.Set();
|
||||
Wait();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Read custom values from INI
|
||||
void cAuthenticator::ReadINI(void)
|
||||
{
|
||||
|
@ -34,6 +34,7 @@ class cAuthenticator :
|
||||
|
||||
public:
|
||||
cAuthenticator(void);
|
||||
~cAuthenticator();
|
||||
|
||||
/// (Re-)read server and address from INI:
|
||||
void ReadINI(void);
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -6,18 +7,26 @@
|
||||
enum ENUM_BLOCK_ID;
|
||||
#endif
|
||||
|
||||
class cChunk;
|
||||
|
||||
|
||||
|
||||
|
||||
class cClientHandle;
|
||||
class cPlayer;
|
||||
class cWorld;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cBlockEntity
|
||||
{
|
||||
protected:
|
||||
cBlockEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cChunk* a_Chunk)
|
||||
cBlockEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World)
|
||||
: m_PosX( a_X )
|
||||
, m_PosY( a_Y )
|
||||
, m_PosZ( a_Z )
|
||||
, m_BlockType( a_BlockType )
|
||||
, m_Chunk( a_Chunk )
|
||||
{}
|
||||
public:
|
||||
virtual ~cBlockEntity() {};
|
||||
@ -26,9 +35,10 @@ public:
|
||||
int GetPosX() { return m_PosX; }
|
||||
int GetPosY() { return m_PosY; }
|
||||
int GetPosZ() { return m_PosZ; }
|
||||
cChunk* GetChunk() { return m_Chunk; }
|
||||
|
||||
ENUM_BLOCK_ID GetBlockType() { return m_BlockType; }
|
||||
|
||||
cWorld * GetWorld(void) const {return m_World; }
|
||||
|
||||
virtual void UsedBy( cPlayer & a_Player ) = 0;
|
||||
virtual void SendTo( cClientHandle* a_Client ) { (void)a_Client; }
|
||||
@ -38,7 +48,11 @@ protected:
|
||||
int m_PosY;
|
||||
int m_PosZ;
|
||||
|
||||
cChunk* m_Chunk;
|
||||
|
||||
ENUM_BLOCK_ID m_BlockType;
|
||||
|
||||
cWorld * m_World;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -3,13 +3,16 @@
|
||||
|
||||
#include "cBlockingTCPLink.h"
|
||||
#include "packets/cPacket.h"
|
||||
#include "MCSocket.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MSG_NOSIGNAL (0)
|
||||
#endif
|
||||
#ifdef __MACH__
|
||||
#define MSG_NOSIGNAL (0)
|
||||
#define MSG_NOSIGNAL (0)
|
||||
#endif
|
||||
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cSocket.h"
|
||||
@ -21,3 +22,7 @@ protected:
|
||||
|
||||
cSocket m_Socket;
|
||||
}; //tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -23,14 +23,18 @@ class cRoot;
|
||||
|
||||
|
||||
|
||||
cChestEntity::cChestEntity(int a_X, int a_Y, int a_Z, cChunk* a_Chunk)
|
||||
: cBlockEntity( E_BLOCK_CHEST, a_X, a_Y, a_Z, a_Chunk )
|
||||
cChestEntity::cChestEntity(int a_X, int a_Y, int a_Z, cWorld * a_World)
|
||||
: cBlockEntity( E_BLOCK_CHEST, a_X, a_Y, a_Z, a_World)
|
||||
, m_TopChest( false )
|
||||
, m_JoinedChest( 0 )
|
||||
, m_JoinedChest( NULL )
|
||||
{
|
||||
m_Content = new cItem[ c_ChestHeight*c_ChestWidth ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChestEntity::~cChestEntity()
|
||||
{
|
||||
if( GetWindow() )
|
||||
@ -44,6 +48,10 @@ cChestEntity::~cChestEntity()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChestEntity::Destroy()
|
||||
{
|
||||
// Drop items
|
||||
@ -51,15 +59,21 @@ void cChestEntity::Destroy()
|
||||
{
|
||||
if( !m_Content[i].IsEmpty() )
|
||||
{
|
||||
cPickup* Pickup = new cPickup( m_PosX*32 + 16, m_PosY*32 + 16, m_PosZ*32 + 16, m_Content[i], 0, 1.f, 0 );
|
||||
Pickup->Initialize( GetChunk()->GetWorld() );
|
||||
cPickup * Pickup = new cPickup( m_PosX * 32 + 16, m_PosY * 32 + 16, m_PosZ * 32 + 16, m_Content[i], 0, 1.f, 0 );
|
||||
Pickup->Initialize(m_World);
|
||||
m_Content[i].Empty();
|
||||
}
|
||||
}
|
||||
if (m_JoinedChest)
|
||||
{
|
||||
m_JoinedChest->RemoveJoinedChest(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cItem * cChestEntity::GetSlot( int a_Slot )
|
||||
{
|
||||
if( a_Slot > -1 && a_Slot < c_ChestHeight*c_ChestWidth )
|
||||
@ -69,6 +83,10 @@ cItem * cChestEntity::GetSlot( int a_Slot )
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChestEntity::SetSlot( int a_Slot, cItem & a_Item )
|
||||
{
|
||||
if( a_Slot > -1 && a_Slot < c_ChestHeight*c_ChestWidth )
|
||||
@ -129,6 +147,10 @@ bool cChestEntity::LoadFromJson( const Json::Value& a_Value )
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChestEntity::SaveToJson( Json::Value& a_Value )
|
||||
{
|
||||
a_Value["x"] = m_PosX;
|
||||
@ -147,6 +169,10 @@ void cChestEntity::SaveToJson( Json::Value& a_Value )
|
||||
a_Value["Slots"] = AllSlots;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChestEntity::SendTo( cClientHandle* a_Client, cServer* a_Server )
|
||||
{
|
||||
(void)a_Client;
|
||||
@ -154,6 +180,10 @@ void cChestEntity::SendTo( cClientHandle* a_Client, cServer* a_Server )
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChestEntity::UsedBy( cPlayer & a_Player )
|
||||
{
|
||||
LOG("Used a chest");
|
||||
@ -185,15 +215,13 @@ void cChestEntity::UsedBy( cPlayer & a_Player )
|
||||
ChestOpen.m_PosZ = GetPosZ();
|
||||
ChestOpen.m_Byte1 = (char)1;
|
||||
ChestOpen.m_Byte2 = (char)1;
|
||||
cWorld::PlayerList PlayerList = cRoot::Get()->GetWorld()->GetAllPlayers();
|
||||
for( cWorld::PlayerList::iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr )
|
||||
{
|
||||
if ((*itr) && (*itr)->GetClientHandle() && !((*itr)->GetClientHandle()->IsDestroyed())) {
|
||||
(*itr)->GetClientHandle()->Send( ChestOpen );
|
||||
}
|
||||
}
|
||||
m_World->GetChunkOfBlock(m_PosX, m_PosY, m_PosZ)->Broadcast(&ChestOpen);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cItem *cChestEntity::GetContents(bool a_OnlyThis)
|
||||
{
|
||||
if (m_JoinedChest && !a_OnlyThis)
|
||||
@ -215,3 +243,7 @@ cItem *cChestEntity::GetContents(bool a_OnlyThis)
|
||||
else
|
||||
return m_Content;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,10 +1,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cBlockEntity.h"
|
||||
#include "cWindowOwner.h"
|
||||
#include "FileDefine.h"
|
||||
#include "packets/cPacket_BlockAction.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
@ -14,10 +18,17 @@ class cClientHandle;
|
||||
class cServer;
|
||||
class cItem;
|
||||
class cNBTData;
|
||||
class cChestEntity : public cBlockEntity, public cWindowOwner
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cChestEntity :
|
||||
public cBlockEntity,
|
||||
public cWindowOwner
|
||||
{
|
||||
public:
|
||||
cChestEntity(int a_X, int a_Y, int a_Z, cChunk * a_Chunk);
|
||||
cChestEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
|
||||
virtual ~cChestEntity();
|
||||
virtual void Destroy();
|
||||
|
||||
@ -44,8 +55,14 @@ public:
|
||||
|
||||
static const int c_ChestWidth = 9;
|
||||
static const int c_ChestHeight = 3;
|
||||
|
||||
private:
|
||||
cItem* m_Content;
|
||||
bool m_TopChest;
|
||||
cChestEntity *m_JoinedChest;
|
||||
};
|
||||
|
||||
cItem * m_Content;
|
||||
bool m_TopChest;
|
||||
cChestEntity * m_JoinedChest;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
129
source/cChunk.h
129
source/cChunk.h
@ -1,15 +1,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define C_CHUNK_USE_INLINE 1
|
||||
|
||||
// Do not touch
|
||||
#if C_CHUNK_USE_INLINE
|
||||
# define __C_CHUNK_INLINE__ inline
|
||||
#define __C_CHUNK_INLINE__ inline
|
||||
#else
|
||||
# define __C_CHUNK_INLINE__
|
||||
#define __C_CHUNK_INLINE__
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
@ -23,10 +33,14 @@ class cWorld;
|
||||
class cFurnaceEntity;
|
||||
class cPacket;
|
||||
class cBlockEntity;
|
||||
class cEntity;
|
||||
class cClientHandle;
|
||||
class cServer;
|
||||
class MTRand;
|
||||
class cPlayer;
|
||||
|
||||
typedef std::list<cFurnaceEntity *> cFurnaceEntityList;
|
||||
typedef std::list<cClientHandle *> cClientHandleList;
|
||||
typedef std::list<cBlockEntity *> cBlockEntityList;
|
||||
|
||||
|
||||
|
||||
@ -39,6 +53,9 @@ public:
|
||||
~cChunk();
|
||||
|
||||
void Initialize();
|
||||
bool IsValid(void) const {return m_IsValid; } // Returns true if the chunk is valid (loaded / generated)
|
||||
void SetValid(bool a_SendToClients = true); // Also wakes up all clients attached to this chunk to let them finish logging in
|
||||
bool CanUnload(void);
|
||||
|
||||
void Tick(float a_Dt, MTRand & a_TickRandom);
|
||||
|
||||
@ -51,42 +68,49 @@ public:
|
||||
void AsyncUnload( cClientHandle* a_Client );
|
||||
|
||||
void SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta );
|
||||
void FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta );
|
||||
void FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); // Doesn't force block updates on neighbors, use for simple changes such as grass growing etc.
|
||||
char GetBlock( int a_X, int a_Y, int a_Z );
|
||||
char GetBlock( int a_BlockIdx );
|
||||
cBlockEntity* GetBlockEntity( int a_X, int a_Y, int a_Z );
|
||||
void RemoveBlockEntity( cBlockEntity* a_BlockEntity );
|
||||
void AddBlockEntity( cBlockEntity* a_BlockEntity );
|
||||
|
||||
void CollectPickupsByPlayer(cPlayer * a_Player);
|
||||
void UpdateSign(int a_PosX, int a_PosY, int a_PosZ, const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4); // Also sends update packets to all clients in the chunk
|
||||
|
||||
char GetHeight( int a_X, int a_Z );
|
||||
|
||||
void SendBlockTo( int a_X, int a_Y, int a_Z, cClientHandle* a_Client );
|
||||
|
||||
void AddClient( cClientHandle* a_Client );
|
||||
void AddClient ( cClientHandle* a_Client );
|
||||
void RemoveClient( cClientHandle* a_Client );
|
||||
bool HasClient ( cClientHandle* a_Client );
|
||||
bool HasAnyClient(void); // Returns true if theres any client in the chunk; false otherwise
|
||||
|
||||
std::list< cEntity* > & GetEntities();// { return m_Entities; }
|
||||
void AddEntity( cEntity & a_Entity );
|
||||
bool RemoveEntity( cEntity & a_Entity, cChunk* a_CalledFrom = 0 );
|
||||
void LockEntities();
|
||||
void UnlockEntities();
|
||||
void AddEntity( cEntity * a_Entity );
|
||||
void RemoveEntity( cEntity * a_Entity);
|
||||
|
||||
const std::list< cClientHandle* > & GetClients();// { return m_LoadedByClient; }
|
||||
// TODO: This interface is dangerous
|
||||
OBSOLETE const std::list< cClientHandle* > & GetClients();// { return m_LoadedByClient; }
|
||||
|
||||
inline void RecalculateLighting() { m_bCalculateLighting = true; } // Recalculate lighting next tick
|
||||
inline void RecalculateHeightmap() { m_bCalculateHeightmap = true; } // Recalculate heightmap next tick
|
||||
void SpreadLight(char* a_LightBuffer);
|
||||
void CalculateLighting(); // Recalculate right now
|
||||
void CalculateHeightmap();
|
||||
|
||||
bool LoadFromDisk();
|
||||
|
||||
// Broadcasts to all clients that have loaded this chunk
|
||||
void Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude = 0 ) const;
|
||||
void Broadcast( const cPacket & a_Packet, cClientHandle * a_Exclude = NULL) {Broadcast(&a_Packet, a_Exclude); }
|
||||
void Broadcast( const cPacket * a_Packet, cClientHandle * a_Exclude = NULL);
|
||||
|
||||
char* pGetBlockData() { return m_BlockData; }
|
||||
char* pGetType() { return m_BlockType; }
|
||||
char* pGetMeta() { return m_BlockMeta; }
|
||||
char* pGetLight() { return m_BlockLight; }
|
||||
char* pGetSkyLight() { return m_BlockSkyLight; }
|
||||
|
||||
void CopyBlockDataFrom(const char * a_NewBlockData); // Copies all blockdata, recalculates heightmap (used by chunk loaders)
|
||||
void LoadFromJson( const Json::Value & a_Value );
|
||||
void SaveToJson( Json::Value & a_Value );
|
||||
|
||||
char GetLight(char* a_Buffer, int a_BlockIdx);
|
||||
char GetLight(char* a_Buffer, int x, int y, int z);
|
||||
@ -95,9 +119,6 @@ public:
|
||||
|
||||
void PositionToWorldPosition(int a_ChunkX, int a_ChunkY, int a_ChunkZ, int & a_X, int & a_Y, int & a_Z);
|
||||
|
||||
void AddTickBlockEntity( cFurnaceEntity* a_Entity );
|
||||
void RemoveTickBlockEntity( cFurnaceEntity* a_Entity );
|
||||
|
||||
inline static unsigned int MakeIndex(int x, int y, int z )
|
||||
{
|
||||
if( x < 16 && x > -1 && y < 128 && y > -1 && z < 16 && z > -1 )
|
||||
@ -112,28 +133,28 @@ public:
|
||||
void AddReference();
|
||||
void RemoveReference();
|
||||
int GetReferenceCount();
|
||||
|
||||
private:
|
||||
struct sChunkState;
|
||||
sChunkState* m_pState;
|
||||
|
||||
friend class cChunkMap; // So it has access to buffers and shit
|
||||
void LoadFromJson( const Json::Value & a_Value );
|
||||
void SaveToJson( Json::Value & a_Value );
|
||||
bool m_IsValid; // True if the chunk is loaded / generated
|
||||
|
||||
cCriticalSection m_CSBlockLists;
|
||||
std::map< unsigned int, int > m_ToTickBlocks;
|
||||
std::vector< unsigned int > m_PendingSendBlocks;
|
||||
|
||||
cCriticalSection m_CSClients;
|
||||
cClientHandleList m_LoadedByClient;
|
||||
cClientHandleList m_UnloadQuery;
|
||||
|
||||
void CalculateLighting(); // Recalculate right now
|
||||
void CalculateHeightmap();
|
||||
void SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff);
|
||||
void SpreadLightOfBlockX(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||
void SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||
void SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||
|
||||
void CreateBlockEntities();
|
||||
cCriticalSection m_CSEntities;
|
||||
cEntityList m_Entities;
|
||||
cBlockEntityList m_BlockEntities;
|
||||
|
||||
bool m_bCalculateLighting;
|
||||
bool m_bCalculateHeightmap;
|
||||
|
||||
int m_PosX, m_PosY, m_PosZ;
|
||||
cWorld* m_World;
|
||||
cWorld * m_World;
|
||||
|
||||
char m_BlockData[c_BlockDataSize]; // Chunk data ready to be compressed and sent
|
||||
char *m_BlockType; // Pointers to an element in m_BlockData
|
||||
@ -141,19 +162,55 @@ private:
|
||||
char *m_BlockLight; // += NumBlocks/2
|
||||
char *m_BlockSkyLight; // += NumBlocks/2
|
||||
|
||||
unsigned char m_HeightMap[16*16];
|
||||
unsigned char m_HeightMap[16 * 16];
|
||||
|
||||
unsigned int m_BlockTickNum;
|
||||
unsigned int m_BlockTickX, m_BlockTickY, m_BlockTickZ;
|
||||
|
||||
cCriticalSection* m_EntitiesCriticalSection;
|
||||
void RemoveBlockEntity( cBlockEntity* a_BlockEntity );
|
||||
void AddBlockEntity( cBlockEntity* a_BlockEntity );
|
||||
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z );
|
||||
|
||||
void SpreadLightOfBlock(char* a_LightBuffer, int a_X, int a_Y, int a_Z, char a_Falloff);
|
||||
void SpreadLightOfBlockX(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||
void SpreadLightOfBlockY(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||
void SpreadLightOfBlockZ(char* a_LightBuffer, int a_X, int a_Y, int a_Z);
|
||||
|
||||
void CreateBlockEntities();
|
||||
};
|
||||
|
||||
typedef std::tr1::shared_ptr<cChunk> cChunkPtr;
|
||||
|
||||
typedef std::list<cChunkPtr> cChunkPtrList;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cChunkCoords
|
||||
{
|
||||
public:
|
||||
int m_ChunkX;
|
||||
int m_ChunkZ;
|
||||
|
||||
cChunkCoords(int a_ChunkX, int a_ChunkZ) : m_ChunkX(a_ChunkX), m_ChunkZ(a_ChunkZ) {}
|
||||
|
||||
bool operator == (const cChunkCoords & a_Other)
|
||||
{
|
||||
return ((m_ChunkX == a_Other.m_ChunkX) && (m_ChunkZ == a_Other.m_ChunkZ));
|
||||
}
|
||||
} ;
|
||||
|
||||
typedef std::list<cChunkCoords> cChunkCoordsList;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if C_CHUNK_USE_INLINE
|
||||
# include "cChunk.inl.h"
|
||||
#endif
|
||||
#include "cChunk.inl.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -2,11 +2,13 @@
|
||||
#include "Globals.h"
|
||||
|
||||
#include "cChunkGenerator.h"
|
||||
#include "cChunkMap.h"
|
||||
#include "cChunk.h"
|
||||
#include "cWorld.h"
|
||||
#include "cWorldGenerator.h"
|
||||
#include "cWorldGenerator_Test.h"
|
||||
|
||||
|
||||
|
||||
|
||||
#include "cMCLogger.h"
|
||||
|
||||
typedef std::pair<int, int> ChunkCoord;
|
||||
typedef std::list< ChunkCoord > ChunkCoordList;
|
||||
@ -16,45 +18,20 @@ typedef std::list< ChunkCoord > ChunkCoordList;
|
||||
|
||||
|
||||
/// If the generation queue size exceeds this number, a warning will be output
|
||||
#define QUEUE_WARNING_LIMIT 1000
|
||||
const int QUEUE_WARNING_LIMIT = 1000;
|
||||
|
||||
/// If the generation queue size exceeds this number, chunks with no clients will be skipped
|
||||
const int QUEUE_SKIP_LIMIT = 50;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct cChunkGenerator::sChunkGeneratorState
|
||||
cChunkGenerator::cChunkGenerator(void)
|
||||
: super("cChunkGenerator")
|
||||
, m_World(NULL)
|
||||
, m_pWorldGenerator(NULL)
|
||||
{
|
||||
cCriticalSection m_CriticalSection; // For protecting the variables in this struct
|
||||
|
||||
ChunkCoordList GenerateQueue;
|
||||
ChunkCoord CurrentlyGeneratingCoords;
|
||||
cChunk* pCurrentlyGenerating;
|
||||
bool bCurrentlyGenerating;
|
||||
|
||||
cSemaphore m_Semaphore;
|
||||
cThread * pThread;
|
||||
|
||||
bool bStop;
|
||||
|
||||
sChunkGeneratorState(void)
|
||||
: m_Semaphore(1, 0)
|
||||
, pThread( 0 )
|
||||
, bStop( false )
|
||||
, bCurrentlyGenerating( false )
|
||||
, pCurrentlyGenerating( false )
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChunkGenerator::cChunkGenerator( cChunkMap* a_pChunkMap )
|
||||
: m_pState( new sChunkGeneratorState )
|
||||
, m_pChunkMap( a_pChunkMap )
|
||||
{
|
||||
m_pState->pThread = new cThread( GenerateThread, this, "cChunkGenerator::GenerateThread" );
|
||||
m_pState->pThread->Start( true );
|
||||
}
|
||||
|
||||
|
||||
@ -63,97 +40,106 @@ cChunkGenerator::cChunkGenerator( cChunkMap* a_pChunkMap )
|
||||
|
||||
cChunkGenerator::~cChunkGenerator()
|
||||
{
|
||||
m_pState->bStop = true;
|
||||
|
||||
m_pState->m_Semaphore.Signal(); // Signal so thread can continue and exit
|
||||
delete m_pState->pThread;
|
||||
|
||||
delete m_pState;
|
||||
Stop();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkGenerator::GenerateChunk( int a_X, int a_Z )
|
||||
bool cChunkGenerator::Start(cWorld * a_World, const AString & a_WorldGeneratorName)
|
||||
{
|
||||
cCSLock Lock(&m_pState->m_CriticalSection);
|
||||
|
||||
if (m_pState->bCurrentlyGenerating)
|
||||
{
|
||||
if ((m_pState->CurrentlyGeneratingCoords.first == a_X) && (m_pState->CurrentlyGeneratingCoords.second == a_Z))
|
||||
{
|
||||
return; // Already generating this chunk, so ignore
|
||||
}
|
||||
}
|
||||
|
||||
m_pState->GenerateQueue.remove( ChunkCoord(a_X, a_Z) );
|
||||
if (m_pState->GenerateQueue.size() >= QUEUE_WARNING_LIMIT)
|
||||
{
|
||||
LOGWARN("WARNING: Adding chunk (%i, %i) to generation queue; Queue is too big! (%i)", a_X, a_Z, m_pState->GenerateQueue.size() );
|
||||
}
|
||||
m_pState->GenerateQueue.push_back( ChunkCoord(a_X, a_Z) );
|
||||
|
||||
Lock.Unlock();
|
||||
m_World = a_World;
|
||||
|
||||
m_pState->m_Semaphore.Signal();
|
||||
if (a_WorldGeneratorName.compare("Test") == 0 )
|
||||
{
|
||||
m_pWorldGenerator = new cWorldGenerator_Test();
|
||||
}
|
||||
else // Default
|
||||
{
|
||||
m_pWorldGenerator = new cWorldGenerator();
|
||||
}
|
||||
|
||||
return super::Start();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkGenerator::GenerateThread( void* a_Params )
|
||||
void cChunkGenerator::Stop(void)
|
||||
{
|
||||
// Cache some values for easy access (they are all references/pointers)
|
||||
cChunkGenerator * self = (cChunkGenerator*)a_Params;
|
||||
sChunkGeneratorState * m_pState = self->m_pState;
|
||||
ChunkCoordList & GenerateQueue = m_pState->GenerateQueue;
|
||||
cChunkMap & ChunkMap = *self->m_pChunkMap;
|
||||
cCriticalSection * CriticalSection = &m_pState->m_CriticalSection;
|
||||
cSemaphore & Semaphore = m_pState->m_Semaphore;
|
||||
mShouldTerminate = true;
|
||||
m_Event.Set();
|
||||
Wait();
|
||||
|
||||
delete m_pWorldGenerator;
|
||||
m_pWorldGenerator = NULL;
|
||||
}
|
||||
|
||||
while (!m_pState->bStop)
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkGenerator::GenerateChunk(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
|
||||
// Check if it is already in the queue:
|
||||
for (cChunkCoordsList::iterator itr = m_Queue.begin(); itr != m_Queue.end(); ++itr)
|
||||
{
|
||||
cCSLock Lock(CriticalSection);
|
||||
if (GenerateQueue.size() == 0)
|
||||
if ((itr->m_ChunkX == a_ChunkX) && (itr->m_ChunkZ == a_ChunkZ))
|
||||
{
|
||||
// Already in the queue, bail out
|
||||
return;
|
||||
}
|
||||
} // for itr - m_Queue[]
|
||||
|
||||
// Add to queue, issue a warning if too many:
|
||||
if (m_Queue.size() >= QUEUE_WARNING_LIMIT)
|
||||
{
|
||||
LOGWARN("WARNING: Adding chunk [%i, %i] to generation queue; Queue is too big! (%i)", a_ChunkX, a_ChunkZ, m_Queue.size());
|
||||
}
|
||||
m_Queue.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||
|
||||
m_Event.Set();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkGenerator::Execute(void)
|
||||
{
|
||||
while (!mShouldTerminate)
|
||||
{
|
||||
cCSLock Lock(m_CS);
|
||||
while (m_Queue.size() == 0)
|
||||
{
|
||||
cCSUnlock Unlock(Lock);
|
||||
Semaphore.Wait();
|
||||
m_Event.Wait();
|
||||
if (mShouldTerminate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_pState->bStop) break;
|
||||
|
||||
ChunkCoord coord = *GenerateQueue.begin(); // Get next coord from queue
|
||||
GenerateQueue.erase( GenerateQueue.begin() ); // Remove coordinate from queue
|
||||
m_pState->bCurrentlyGenerating = true;
|
||||
m_pState->CurrentlyGeneratingCoords = coord;
|
||||
cChunkCoords coords = m_Queue.front(); // Get next coord from queue
|
||||
m_Queue.erase( m_Queue.begin() ); // Remove coordinate from queue
|
||||
bool SkipEnabled = (m_Queue.size() > QUEUE_SKIP_LIMIT);
|
||||
Lock.Unlock(); // Unlock ASAP
|
||||
|
||||
ChunkMap.GetWorld()->LockChunks();
|
||||
if( ChunkMap.GetChunk( coord.first, 0, coord.second ) ) // Make sure it has not been loaded in the meantime. Don't want to generate the same chunk twice
|
||||
{ // This is possible when forcing the server to generate a chunk in the main thread
|
||||
ChunkMap.GetWorld()->UnlockChunks();
|
||||
cChunkPtr Chunk = m_World->GetChunk(coords.m_ChunkX, 0, coords.m_ChunkZ);
|
||||
if ((Chunk != NULL) && (Chunk->IsValid() || (SkipEnabled && !Chunk->HasAnyClient())))
|
||||
{
|
||||
// Already generated / overload-skip, ignore request
|
||||
continue;
|
||||
}
|
||||
ChunkMap.GetWorld()->UnlockChunks();
|
||||
|
||||
LOGINFO("cChunkGenerator generating chunk %i %i", coord.first, coord.second );
|
||||
cChunk* Chunk = new cChunk( coord.first, 0, coord.second, ChunkMap.GetWorld() );
|
||||
|
||||
Lock.Lock();
|
||||
m_pState->pCurrentlyGenerating = Chunk;
|
||||
Lock.Unlock();
|
||||
|
||||
Chunk->Initialize(); // Generate the chunk
|
||||
|
||||
ChunkMap.GetWorld()->LockChunks();
|
||||
ChunkMap.AddChunk( Chunk );
|
||||
ChunkMap.GetWorld()->UnlockChunks();
|
||||
|
||||
Lock.Lock();
|
||||
m_pState->bCurrentlyGenerating = false;
|
||||
m_pState->pCurrentlyGenerating = 0;
|
||||
Lock.Unlock();
|
||||
LOG("Generating chunk [%d, %d]", coords.m_ChunkX, coords.m_ChunkZ);
|
||||
m_pWorldGenerator->GenerateChunk(Chunk);
|
||||
|
||||
Chunk->SetValid();
|
||||
} // while (!bStop)
|
||||
}
|
||||
|
||||
|
@ -1,20 +1,62 @@
|
||||
|
||||
// cChunkGenerator.h
|
||||
|
||||
// Interfaces to the cChunkGenerator class representing the thread that generates chunks
|
||||
|
||||
// The object takes requests for generating chunks and processes them in a separate thread one by one.
|
||||
// The requests are not added to the queue if there is already a request with the same coords
|
||||
// Before generating, the thread checks if the chunk hasn't been already generated.
|
||||
// It is theoretically possible to have multiple generator threads by having multiple instances of this object (if the cChunkPtr is thread-safe)
|
||||
// If the generator queue is overloaded, the generator skips chunks with no clients in them
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
class cChunk;
|
||||
class cChunkMap;
|
||||
class cChunkGenerator
|
||||
#include "cIsThread.h"
|
||||
#include "cChunk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cWorld;
|
||||
class cWorldGenerator;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cChunkGenerator :
|
||||
cIsThread
|
||||
{
|
||||
typedef cIsThread super;
|
||||
|
||||
public:
|
||||
cChunkGenerator( cChunkMap* a_pChunkMap );
|
||||
|
||||
cChunkGenerator (void);
|
||||
~cChunkGenerator();
|
||||
|
||||
void GenerateChunk( int a_X, int a_Z );
|
||||
bool Start(cWorld * a_World, const AString & a_WorldGeneratorName);
|
||||
void Stop(void);
|
||||
|
||||
void GenerateChunk(int a_ChunkX, int a_ChunkZ); // Queues the chunk for generation; removes duplicate requests
|
||||
|
||||
private:
|
||||
static void GenerateThread( void* a_Params );
|
||||
|
||||
cChunkMap* m_pChunkMap;
|
||||
// cIsThread override:
|
||||
virtual void Execute(void) override;
|
||||
|
||||
cWorld * m_World;
|
||||
cWorldGenerator * m_pWorldGenerator;
|
||||
|
||||
cCriticalSection m_CS;
|
||||
cChunkCoordsList m_Queue;
|
||||
cEvent m_Event; // Set when an item is added to the queue or the thread should terminate
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
struct sChunkGeneratorState;
|
||||
sChunkGeneratorState* m_pState;
|
||||
};
|
@ -6,7 +6,6 @@
|
||||
#include "cWorld.h"
|
||||
#include "cRoot.h"
|
||||
#include "cMakeDir.h"
|
||||
#include <math.h> // floorf
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstdlib> // abs
|
||||
@ -18,27 +17,6 @@
|
||||
|
||||
#define USE_MEMCPY
|
||||
|
||||
#define LAYER_SIZE (32)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cChunkMap::cChunkLayer:
|
||||
|
||||
cChunkMap::cChunkData* cChunkMap::cChunkLayer::GetChunk( int a_X, int a_Z )
|
||||
{
|
||||
const int LocalX = a_X - m_X * LAYER_SIZE;
|
||||
const int LocalZ = a_Z - m_Z * LAYER_SIZE;
|
||||
//LOG("LocalX:%i LocalZ:%i", LocalX, LocalZ );
|
||||
if ((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1))
|
||||
{
|
||||
return &m_Chunks[ LocalX + LocalZ * LAYER_SIZE ];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -46,10 +24,8 @@ cChunkMap::cChunkData* cChunkMap::cChunkLayer::GetChunk( int a_X, int a_Z )
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cChunkMap:
|
||||
|
||||
cChunkMap::cChunkMap(cWorld* a_World )
|
||||
: m_Layers( 0 )
|
||||
, m_NumLayers( 0 )
|
||||
, m_World( a_World )
|
||||
cChunkMap::cChunkMap(cWorld * a_World )
|
||||
: m_World( a_World )
|
||||
{
|
||||
}
|
||||
|
||||
@ -59,173 +35,54 @@ cChunkMap::cChunkMap(cWorld* a_World )
|
||||
|
||||
cChunkMap::~cChunkMap()
|
||||
{
|
||||
// TODO: delete layers
|
||||
cCSLock Lock(m_CSLayers);
|
||||
for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
} // for itr - m_Layers[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunkMap::RemoveLayer( cChunkLayer* a_Layer )
|
||||
void cChunkMap::RemoveLayer( cChunkLayer* a_Layer )
|
||||
{
|
||||
cChunkLayer* NewLayers = 0;
|
||||
if( m_NumLayers > 1 )
|
||||
NewLayers = new cChunkLayer[m_NumLayers-1];
|
||||
cCSLock Lock(m_CSLayers);
|
||||
m_Layers.remove(a_Layer);
|
||||
}
|
||||
|
||||
int idx = 0;
|
||||
bool bExcludedLayer = false;
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
|
||||
|
||||
|
||||
|
||||
cChunkMap::cChunkLayer * cChunkMap::GetLayer(int a_LayerX, int a_LayerZ)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
for (cChunkLayerList::const_iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||
{
|
||||
if( &m_Layers[i] != a_Layer )
|
||||
if (((*itr)->GetX() == a_LayerX) && ((*itr)->GetZ() == a_LayerZ))
|
||||
{
|
||||
if( idx < m_NumLayers-1 )
|
||||
{
|
||||
NewLayers[ idx ] = m_Layers[i];
|
||||
idx++;
|
||||
}
|
||||
return *itr;
|
||||
}
|
||||
else
|
||||
bExcludedLayer = true;
|
||||
}
|
||||
|
||||
if( !bExcludedLayer )
|
||||
{
|
||||
LOGWARN("Could not remove layer, because layer was not found %i %i", a_Layer->m_X, a_Layer->m_Z);
|
||||
delete [] NewLayers;
|
||||
return false;
|
||||
}
|
||||
|
||||
if( m_Layers ) delete [] m_Layers;
|
||||
m_Layers = NewLayers;
|
||||
m_NumLayers--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChunkMap::cChunkLayer* cChunkMap::AddLayer( const cChunkLayer & a_Layer )
|
||||
{
|
||||
cChunkLayer* TempLayers = new cChunkLayer[m_NumLayers+1];
|
||||
if( m_NumLayers > 0 )
|
||||
{
|
||||
memcpy( TempLayers, m_Layers, sizeof( cChunkLayer ) * m_NumLayers );
|
||||
delete [] m_Layers;
|
||||
}
|
||||
m_Layers = TempLayers;
|
||||
|
||||
m_Layers[m_NumLayers] = a_Layer;
|
||||
cChunkLayer* NewLayer = &m_Layers[m_NumLayers];
|
||||
m_NumLayers++;
|
||||
|
||||
return NewLayer;
|
||||
// Not found, create new:
|
||||
cChunkLayer * Layer = new cChunkLayer(a_LayerX, a_LayerZ, this);
|
||||
if (Layer == NULL)
|
||||
{
|
||||
LOGERROR("cChunkMap: Cannot create new layer, server out of memory?");
|
||||
return NULL;
|
||||
}
|
||||
m_Layers.push_back(Layer);
|
||||
return Layer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::AddChunk( cChunk* a_Chunk )
|
||||
{
|
||||
const int LayerX = (int)(floorf((float)a_Chunk->GetPosX() / (float)(LAYER_SIZE)));
|
||||
const int LayerZ = (int)(floorf((float)a_Chunk->GetPosZ() / (float)(LAYER_SIZE)));
|
||||
cChunkLayer* FoundLayer = GetLayer( LayerX, LayerZ );
|
||||
if( !FoundLayer )
|
||||
{
|
||||
cChunkLayer NewLayer( LAYER_SIZE*LAYER_SIZE );
|
||||
NewLayer.m_X = LayerX;
|
||||
NewLayer.m_Z = LayerZ;
|
||||
FoundLayer = AddLayer( NewLayer );
|
||||
LOG("Created new layer [%i %i] (total layers %i)", LayerX, LayerZ, m_NumLayers );
|
||||
}
|
||||
|
||||
//Get local coordinates in layer
|
||||
const int LocalX = a_Chunk->GetPosX() - LayerX * LAYER_SIZE;
|
||||
const int LocalZ = a_Chunk->GetPosZ() - LayerZ * LAYER_SIZE;
|
||||
if( FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_LiveChunk )
|
||||
{
|
||||
LOGWARN("WARNING: Added chunk to layer while it was already loaded!");
|
||||
}
|
||||
if( FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_Compressed )
|
||||
{
|
||||
LOGWARN("WARNING: Added chunk to layer while a compressed version exists!");
|
||||
}
|
||||
FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_LiveChunk = a_Chunk;
|
||||
FoundLayer->m_NumChunksLoaded++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::RemoveChunk( cChunk* a_Chunk )
|
||||
{
|
||||
cChunkLayer* Layer = GetLayerForChunk( a_Chunk->GetPosX(), a_Chunk->GetPosZ() );
|
||||
if( Layer )
|
||||
{
|
||||
cChunkData* Data = Layer->GetChunk( a_Chunk->GetPosX(), a_Chunk->GetPosZ() );
|
||||
if( Data->m_LiveChunk )
|
||||
{
|
||||
CompressChunk( Data );
|
||||
Data->m_LiveChunk = 0; // Set live chunk to 0
|
||||
}
|
||||
Layer->m_NumChunksLoaded--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::CompressChunk( cChunkData* a_ChunkData )
|
||||
{
|
||||
if( a_ChunkData->m_LiveChunk )
|
||||
{
|
||||
// Delete already present compressed data
|
||||
if( a_ChunkData->m_Compressed ) delete [] a_ChunkData->m_Compressed;
|
||||
|
||||
// Get Json data
|
||||
Json::Value root;
|
||||
std::string JsonData = "";
|
||||
a_ChunkData->m_LiveChunk->SaveToJson( root );
|
||||
if( !root.empty() )
|
||||
{
|
||||
Json::StyledWriter writer; // TODO FIXME: change to FastWriter ? :D
|
||||
JsonData = writer.write( root );
|
||||
}
|
||||
|
||||
unsigned int TotalSize = cChunk::c_BlockDataSize + JsonData.size();
|
||||
uLongf CompressedSize = compressBound( TotalSize );
|
||||
a_ChunkData->m_Compressed = new char[CompressedSize];
|
||||
char* DataSource = a_ChunkData->m_LiveChunk->pGetBlockData();
|
||||
if( JsonData.size() > 0 )
|
||||
{
|
||||
// Move stuff around, so data is aligned in memory
|
||||
DataSource = new char[TotalSize];
|
||||
memcpy( DataSource, a_ChunkData->m_LiveChunk->pGetBlockData(), cChunk::c_BlockDataSize );
|
||||
memcpy( DataSource + cChunk::c_BlockDataSize, JsonData.c_str(), JsonData.size() );
|
||||
}
|
||||
|
||||
int errorcode = compress2( (Bytef*)a_ChunkData->m_Compressed, &CompressedSize, (const Bytef*)DataSource, TotalSize, Z_DEFAULT_COMPRESSION);
|
||||
if( errorcode != Z_OK )
|
||||
{
|
||||
LOGERROR("Error compressing data (%i)", errorcode );
|
||||
}
|
||||
|
||||
a_ChunkData->m_CompressedSize = CompressedSize;
|
||||
a_ChunkData->m_UncompressedSize = TotalSize;
|
||||
|
||||
if( DataSource != a_ChunkData->m_LiveChunk->pGetBlockData() )
|
||||
delete [] DataSource;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChunkMap::cChunkLayer* cChunkMap::GetLayerForChunk( int a_ChunkX, int a_ChunkZ )
|
||||
cChunkMap::cChunkLayer * cChunkMap::GetLayerForChunk( int a_ChunkX, int a_ChunkZ )
|
||||
{
|
||||
const int LayerX = (int)(floorf((float)a_ChunkX / (float)(LAYER_SIZE)));
|
||||
const int LayerZ = (int)(floorf((float)a_ChunkZ / (float)(LAYER_SIZE)));
|
||||
@ -236,108 +93,43 @@ cChunkMap::cChunkLayer* cChunkMap::GetLayerForChunk( int a_ChunkX, int a_ChunkZ
|
||||
|
||||
|
||||
|
||||
cChunkMap::cChunkLayer* cChunkMap::GetLayer( int a_LayerX, int a_LayerZ )
|
||||
cChunkPtr cChunkMap::GetChunk( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
{
|
||||
// Find layer in memory
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ );
|
||||
if (Layer == NULL)
|
||||
{
|
||||
if( m_Layers[i].m_X == a_LayerX && m_Layers[i].m_Z == a_LayerZ )
|
||||
{
|
||||
return &m_Layers[i];
|
||||
}
|
||||
// An error must have occurred, since layers are automatically created if they don't exist
|
||||
return cChunkPtr();
|
||||
}
|
||||
|
||||
// Find layer on disk
|
||||
cChunkLayer* Layer = LoadLayer( a_LayerX, a_LayerZ );
|
||||
if( !Layer ) return 0;
|
||||
|
||||
cChunkLayer* NewLayer = AddLayer( *Layer );
|
||||
delete Layer;
|
||||
return NewLayer;
|
||||
cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ);
|
||||
if (!(Chunk->IsValid()))
|
||||
{
|
||||
m_World->GetStorage().QueueLoadChunk(Chunk);
|
||||
}
|
||||
return Chunk;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cChunk* cChunkMap::GetChunk( int a_X, int a_Y, int a_Z )
|
||||
cChunkPtr cChunkMap::GetChunkNoGen( int a_ChunkX, int a_ChunkY, int a_ChunkZ )
|
||||
{
|
||||
cChunkLayer* Layer = GetLayerForChunk( a_X, a_Z );
|
||||
cCSLock Lock(m_CSLayers);
|
||||
cChunkLayer * Layer = GetLayerForChunk( a_ChunkX, a_ChunkZ );
|
||||
if (Layer == NULL)
|
||||
{
|
||||
return NULL;
|
||||
// An error must have occurred, since layers are automatically created if they don't exist
|
||||
return cChunkPtr();
|
||||
}
|
||||
|
||||
cChunkData* Data = Layer->GetChunk( a_X, a_Z );
|
||||
if (Data->m_LiveChunk != NULL)
|
||||
{
|
||||
// Already loaded and alive
|
||||
return Data->m_LiveChunk;
|
||||
}
|
||||
|
||||
// Do we at least have the compressed chunk?
|
||||
if (Data->m_Compressed == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The chunk has been cached (loaded from file, but not decompressed):
|
||||
uLongf DestSize = Data->m_UncompressedSize;
|
||||
char* BlockData = new char[ DestSize ];
|
||||
int errorcode = uncompress( (Bytef*)BlockData, &DestSize, (Bytef*)Data->m_Compressed, Data->m_CompressedSize );
|
||||
if( Data->m_UncompressedSize != DestSize )
|
||||
{
|
||||
LOGWARN("Lulwtf, expected uncompressed size differs!");
|
||||
delete [] BlockData;
|
||||
}
|
||||
else if( errorcode != Z_OK )
|
||||
{
|
||||
LOGERROR("ERROR: Decompressing chunk data! %i", errorcode );
|
||||
switch( errorcode )
|
||||
{
|
||||
case Z_MEM_ERROR:
|
||||
LOGERROR("Not enough memory");
|
||||
break;
|
||||
case Z_BUF_ERROR:
|
||||
LOGERROR("Not enough room in output buffer");
|
||||
break;
|
||||
case Z_DATA_ERROR:
|
||||
LOGERROR("Input data corrupted or incomplete");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
delete [] BlockData;
|
||||
}
|
||||
else
|
||||
{
|
||||
cChunk* Chunk = new cChunk(a_X, a_Y, a_Z, m_World);
|
||||
memcpy( Chunk->m_BlockData, BlockData, cChunk::c_BlockDataSize );
|
||||
Chunk->CalculateHeightmap();
|
||||
Data->m_LiveChunk = Chunk;
|
||||
Layer->m_NumChunksLoaded++;
|
||||
|
||||
if( DestSize > cChunk::c_BlockDataSize ) // We gots some extra data :D
|
||||
{
|
||||
LOGINFO("Parsing trailing JSON");
|
||||
Json::Value root; // will contains the root value after parsing.
|
||||
Json::Reader reader;
|
||||
if( !reader.parse( BlockData + cChunk::c_BlockDataSize, root, false ) )
|
||||
{
|
||||
LOGERROR("Failed to parse trailing JSON!");
|
||||
}
|
||||
else
|
||||
{
|
||||
Chunk->LoadFromJson( root );
|
||||
}
|
||||
}
|
||||
|
||||
delete [] BlockData;
|
||||
delete [] Data->m_Compressed; Data->m_Compressed = 0; Data->m_CompressedSize = 0;
|
||||
return Chunk;
|
||||
}
|
||||
return NULL;
|
||||
cChunkPtr Chunk = Layer->GetChunk(a_ChunkX, a_ChunkZ);
|
||||
|
||||
// TODO: Load, but do not generate, if not valid
|
||||
|
||||
return Chunk;
|
||||
}
|
||||
|
||||
|
||||
@ -346,17 +138,11 @@ cChunk* cChunkMap::GetChunk( int a_X, int a_Y, int a_Z )
|
||||
|
||||
void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
||||
{
|
||||
for( int lay = 0; lay < m_NumLayers; ++lay )
|
||||
cCSLock Lock(m_CSLayers);
|
||||
for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||
{
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
|
||||
{
|
||||
cChunk* Chunk = m_Layers[lay].m_Chunks[i].m_LiveChunk;
|
||||
if ( Chunk != NULL)
|
||||
{
|
||||
Chunk->Tick( a_Dt, a_TickRandom );
|
||||
}
|
||||
}
|
||||
} // for lay - m_Layers[]
|
||||
(*itr)->Tick(a_Dt, a_TickRandom);
|
||||
} // for itr - m_Layers
|
||||
}
|
||||
|
||||
|
||||
@ -365,255 +151,125 @@ void cChunkMap::Tick( float a_Dt, MTRand & a_TickRandom )
|
||||
|
||||
void cChunkMap::UnloadUnusedChunks()
|
||||
{
|
||||
cWorld* World = m_World;
|
||||
for( int l = 0; l < m_NumLayers; ++l )
|
||||
cCSLock Lock(m_CSLayers);
|
||||
for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||
{
|
||||
cChunkLayer & Layer = m_Layers[l];
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
|
||||
{
|
||||
cChunk* Chunk = Layer.m_Chunks[i].m_LiveChunk;
|
||||
if( Chunk && Chunk->GetClients().size() == 0 && Chunk->GetReferenceCount() <= 0 )
|
||||
{
|
||||
//Chunk->SaveToDisk();
|
||||
World->RemoveSpread( ptr_cChunk( Chunk ) );
|
||||
RemoveChunk( Chunk );
|
||||
delete Chunk;
|
||||
}
|
||||
}
|
||||
|
||||
// Unload layers
|
||||
if( Layer.m_NumChunksLoaded == 0 )
|
||||
{
|
||||
SaveLayer( &Layer );
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i ) // Free all chunk data for layer
|
||||
{
|
||||
delete [] Layer.m_Chunks[i].m_Compressed;
|
||||
delete Layer.m_Chunks[i].m_LiveChunk;
|
||||
}
|
||||
if( RemoveLayer( &Layer ) ) l--;
|
||||
}
|
||||
else if( Layer.m_NumChunksLoaded < 0 )
|
||||
{
|
||||
LOGERROR("WTF! Chunks loaded in layer is %i !!", Layer.m_NumChunksLoaded );
|
||||
}
|
||||
}
|
||||
(*itr)->UnloadUnusedChunks();
|
||||
} // for itr - m_Layers
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cChunkMap::RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom /* = 0 */ )
|
||||
void cChunkMap::SaveAllChunks(void)
|
||||
{
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
cCSLock Lock(m_CSLayers);
|
||||
for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||
{
|
||||
cChunkLayer & Layer = m_Layers[i];
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
|
||||
{
|
||||
cChunk* Chunk = Layer.m_Chunks[i].m_LiveChunk;
|
||||
if( Chunk != a_CalledFrom )
|
||||
{
|
||||
if( Chunk && Chunk->RemoveEntity( a_Entity, a_CalledFrom ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG("WARNING: Entity was not found in any chunk!");
|
||||
return false;
|
||||
(*itr)->Save();
|
||||
} // for itr - m_Layers[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::SaveAllChunks()
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cChunkMap::cChunkLayer:
|
||||
|
||||
cChunkMap::cChunkLayer::cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent)
|
||||
: m_LayerX( a_LayerX )
|
||||
, m_LayerZ( a_LayerZ )
|
||||
, m_Parent( a_Parent )
|
||||
, m_NumChunksLoaded( 0 )
|
||||
{
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
{
|
||||
SaveLayer( &m_Layers[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************
|
||||
* Saving and loading
|
||||
**/
|
||||
|
||||
void cChunkMap::SaveLayer( cChunkLayer* a_Layer )
|
||||
cChunkPtr cChunkMap::cChunkLayer::GetChunk( int a_ChunkX, int a_ChunkZ )
|
||||
{
|
||||
std::string WorldName = m_World->GetName();
|
||||
cMakeDir::MakeDir( WorldName.c_str() );
|
||||
|
||||
AString SourceFile;
|
||||
Printf(SourceFile, "%s/X%i_Z%i.pak", WorldName.c_str(), a_Layer->m_X, a_Layer->m_Z );
|
||||
|
||||
cFile f;
|
||||
if (!f.Open(SourceFile, cFile::fmWrite))
|
||||
// Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check
|
||||
|
||||
const int LocalX = a_ChunkX - m_LayerX * LAYER_SIZE;
|
||||
const int LocalZ = a_ChunkZ - m_LayerZ * LAYER_SIZE;
|
||||
|
||||
|
||||
if (!((LocalX < LAYER_SIZE) && (LocalZ < LAYER_SIZE) && (LocalX > -1) && (LocalZ > -1)))
|
||||
{
|
||||
LOGERROR("ERROR: Could not write to file %s", SourceFile.c_str());
|
||||
return;
|
||||
assert(!"Asking a cChunkLayer for a chunk that doesn't belong to it!");
|
||||
return cChunkPtr();
|
||||
}
|
||||
|
||||
//---------------
|
||||
// Header
|
||||
char PakVersion = 1;
|
||||
char ChunkVersion = 1;
|
||||
f.Write(&PakVersion, sizeof(PakVersion)); // pak version
|
||||
f.Write(&ChunkVersion, sizeof(ChunkVersion)); // chunk version
|
||||
|
||||
// Count number of chunks in layer
|
||||
short NumChunks = 0;
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
|
||||
|
||||
int Index = LocalX + LocalZ * LAYER_SIZE;
|
||||
if (m_Chunks[Index].get() == NULL)
|
||||
{
|
||||
if( a_Layer->m_Chunks[i].m_Compressed || a_Layer->m_Chunks[i].m_LiveChunk )
|
||||
{
|
||||
NumChunks++;
|
||||
}
|
||||
m_Chunks[Index].reset(new cChunk(a_ChunkX, 0, a_ChunkZ, m_Parent->GetWorld()));
|
||||
}
|
||||
|
||||
f.Write(&NumChunks, sizeof(NumChunks));
|
||||
LOG("Num Chunks in layer [%d, %d]: %i", a_Layer->m_X, a_Layer->m_Z, NumChunks);
|
||||
|
||||
// Chunk headers
|
||||
for (int z = 0; z < LAYER_SIZE; ++z)
|
||||
{
|
||||
for (int x = 0; x < LAYER_SIZE; ++x)
|
||||
{
|
||||
cChunkData & Data = a_Layer->m_Chunks[x + z * LAYER_SIZE];
|
||||
CompressChunk(&Data);
|
||||
if (Data.m_Compressed != NULL)
|
||||
{
|
||||
int ChunkX = a_Layer->m_X * LAYER_SIZE + x;
|
||||
int ChunkZ = a_Layer->m_Z * LAYER_SIZE + z;
|
||||
unsigned int Size = Data.m_CompressedSize; // Needs to be size of compressed data
|
||||
unsigned int USize = Data.m_UncompressedSize; // Uncompressed size
|
||||
f.Write(&ChunkX, sizeof(ChunkX));
|
||||
f.Write(&ChunkZ, sizeof(ChunkZ));
|
||||
f.Write(&Size, sizeof(Size));
|
||||
f.Write(&USize, sizeof(USize));
|
||||
}
|
||||
} // for x - a_Layer->mChunks[x]
|
||||
} // for z - a_Layer->m_Chunks[z]
|
||||
|
||||
// Chunk data
|
||||
for (int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i)
|
||||
{
|
||||
char * Compressed = a_Layer->m_Chunks[i].m_Compressed;
|
||||
if (Compressed != NULL)
|
||||
{
|
||||
f.Write(Compressed, a_Layer->m_Chunks[i].m_CompressedSize);
|
||||
if (a_Layer->m_Chunks[i].m_LiveChunk != NULL) // If there's a live chunk we have no need for compressed data
|
||||
{
|
||||
delete [] a_Layer->m_Chunks[i].m_Compressed;
|
||||
a_Layer->m_Chunks[i].m_Compressed = 0;
|
||||
a_Layer->m_Chunks[i].m_CompressedSize = 0;
|
||||
}
|
||||
}
|
||||
} // for i - a_Layer->m_Chunks[]
|
||||
return m_Chunks[Index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define READ(File, Var) \
|
||||
if (File.Read(&Var, sizeof(Var)) != sizeof(Var)) \
|
||||
{ \
|
||||
LOGERROR("ERROR READING %s FROM FILE %s (line %d)", #Var, SourceFile.c_str(), __LINE__); \
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
cChunkMap::cChunkLayer* cChunkMap::LoadLayer(int a_LayerX, int a_LayerZ )
|
||||
void cChunkMap::cChunkLayer::Tick(float a_Dt, MTRand & a_TickRand)
|
||||
{
|
||||
std::string WorldName = m_World->GetName();
|
||||
|
||||
AString SourceFile;
|
||||
Printf(SourceFile, "%s/X%i_Z%i.pak", WorldName.c_str(), a_LayerX, a_LayerZ);
|
||||
|
||||
cFile f(SourceFile, cFile::fmRead);
|
||||
if (!f.IsOpen())
|
||||
for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char PakVersion = 0;
|
||||
char ChunkVersion = 0;
|
||||
|
||||
READ(f, PakVersion);
|
||||
if (PakVersion != 1)
|
||||
{
|
||||
LOGERROR("WRONG PAK VERSION in file \"%s\"!", SourceFile.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
READ(f, ChunkVersion);
|
||||
if (ChunkVersion != 1 )
|
||||
{
|
||||
LOGERROR("WRONG CHUNK VERSION in file \"%s\"!", SourceFile.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
short NumChunks = 0;
|
||||
READ(f, NumChunks);
|
||||
|
||||
LOG("Num chunks in file \"%s\": %i", SourceFile.c_str(), NumChunks);
|
||||
|
||||
std::auto_ptr<cChunkLayer> Layer(new cChunkLayer(LAYER_SIZE * LAYER_SIZE)); // The auto_ptr deletes the Layer if we exit with an error
|
||||
Layer->m_X = a_LayerX;
|
||||
Layer->m_Z = a_LayerZ;
|
||||
|
||||
cChunkData * OrderedData[LAYER_SIZE * LAYER_SIZE]; // So we can loop over the chunks in the order they were loaded
|
||||
|
||||
// Loop over all chunk headers
|
||||
for( short i = 0; i < NumChunks; ++i )
|
||||
{
|
||||
int ChunkX = 0;
|
||||
int ChunkZ = 0;
|
||||
READ(f, ChunkX);
|
||||
READ(f, ChunkZ);
|
||||
cChunkData* Data = Layer->GetChunk( ChunkX, ChunkZ );
|
||||
|
||||
if (Data == NULL)
|
||||
if ((m_Chunks[i] != NULL) && (m_Chunks[i]->IsValid()))
|
||||
{
|
||||
LOGERROR("Chunk with wrong coordinates [%i, %i] in pak file \"%s\"!", ChunkX, ChunkZ, SourceFile.c_str());
|
||||
return NULL;
|
||||
m_Chunks[i]->Tick(a_Dt, a_TickRand);
|
||||
}
|
||||
else
|
||||
{
|
||||
READ(f, Data->m_CompressedSize);
|
||||
READ(f, Data->m_UncompressedSize);
|
||||
}
|
||||
OrderedData[i] = Data;
|
||||
}
|
||||
|
||||
// Loop over chunks again, in the order they were loaded, and load their compressed data
|
||||
for( short i = 0; i < NumChunks; ++i )
|
||||
{
|
||||
cChunkData* Data = OrderedData[i];
|
||||
Data->m_Compressed = new char[ Data->m_CompressedSize ];
|
||||
if (f.Read(Data->m_Compressed, Data->m_CompressedSize) != Data->m_CompressedSize)
|
||||
{
|
||||
LOGERROR("ERROR reading compressed data for chunk #%i from file \"%s\"", i, SourceFile.c_str());
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return Layer.release();
|
||||
} // for i - m_Chunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cChunkMap::GetNumChunks()
|
||||
void cChunkMap::cChunkLayer::Save(void)
|
||||
{
|
||||
cWorld * World = m_Parent->GetWorld();
|
||||
for (int i = 0; i < ARRAYCOUNT(m_Chunks); ++i)
|
||||
{
|
||||
if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid())
|
||||
{
|
||||
World->GetStorage().QueueSaveChunk(m_Chunks[i]);
|
||||
}
|
||||
} // for i - m_Chunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cChunkMap::cChunkLayer::UnloadUnusedChunks(void)
|
||||
{
|
||||
for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++)
|
||||
{
|
||||
if ((m_Chunks[i] != NULL) && (m_Chunks[i]->CanUnload()))
|
||||
{
|
||||
// TODO: Save the chunk if it was changed
|
||||
m_Chunks[i].reset();
|
||||
}
|
||||
} // for i - m_Chunks[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cChunkMap::GetNumChunks(void)
|
||||
{
|
||||
cCSLock Lock(m_CSLayers);
|
||||
int NumChunks = 0;
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr)
|
||||
{
|
||||
NumChunks += m_Layers[i].m_NumChunksLoaded;
|
||||
NumChunks += (*itr)->GetNumChunksLoaded();
|
||||
}
|
||||
return NumChunks;
|
||||
}
|
||||
|
@ -1,91 +1,84 @@
|
||||
|
||||
// cChunkMap.h
|
||||
|
||||
// Interfaces to the cChunkMap class representing the chunk storage for a single world
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cChunk.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cWorld;
|
||||
class cEntity;
|
||||
class cChunk;
|
||||
class MTRand;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cChunkMap
|
||||
{
|
||||
public:
|
||||
|
||||
static const int LAYER_SIZE = 32;
|
||||
|
||||
cChunkMap(cWorld* a_World );
|
||||
~cChunkMap();
|
||||
|
||||
void AddChunk( cChunk* a_Chunk );
|
||||
|
||||
cChunk* GetChunk( int a_X, int a_Y, int a_Z );
|
||||
void RemoveChunk( cChunk* a_Chunk );
|
||||
cChunkPtr GetChunk ( int a_X, int a_Y, int a_Z ); // Also queues the chunk for loading / generating if not valid
|
||||
cChunkPtr GetChunkNoGen( int a_X, int a_Y, int a_Z ); // Also queues the chunk for loading if not valid; doesn't generate
|
||||
|
||||
void Tick( float a_Dt, MTRand & a_TickRand );
|
||||
|
||||
void UnloadUnusedChunks();
|
||||
bool RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom = 0 );
|
||||
void SaveAllChunks();
|
||||
|
||||
cWorld* GetWorld() { return m_World; }
|
||||
|
||||
int GetNumChunks();
|
||||
int GetNumChunks(void);
|
||||
|
||||
private:
|
||||
|
||||
class cChunkData
|
||||
{
|
||||
public:
|
||||
cChunkData()
|
||||
: m_Compressed( 0 )
|
||||
, m_LiveChunk( 0 )
|
||||
, m_CompressedSize( 0 )
|
||||
, m_UncompressedSize( 0 )
|
||||
{}
|
||||
char* m_Compressed;
|
||||
unsigned int m_CompressedSize;
|
||||
unsigned int m_UncompressedSize;
|
||||
cChunk* m_LiveChunk;
|
||||
};
|
||||
|
||||
class cChunkLayer
|
||||
{
|
||||
public:
|
||||
cChunkLayer()
|
||||
: m_Chunks( 0 )
|
||||
, m_X( 0 )
|
||||
, m_Z( 0 )
|
||||
, m_NumChunksLoaded( 0 )
|
||||
{}
|
||||
cChunkLayer( int a_NumChunks )
|
||||
: m_Chunks( new cChunkData[a_NumChunks] )
|
||||
, m_X( 0 )
|
||||
, m_Z( 0 )
|
||||
, m_NumChunksLoaded( 0 )
|
||||
{}
|
||||
cChunkData * GetChunk( int a_X, int a_Z );
|
||||
cChunkLayer(int a_LayerX, int a_LayerZ, cChunkMap * a_Parent);
|
||||
|
||||
/// Always returns an assigned chunkptr, but the chunk needn't be valid (loaded / generated) - callers must check
|
||||
cChunkPtr GetChunk( int a_ChunkX, int a_ChunkZ );
|
||||
|
||||
cChunkData * m_Chunks;
|
||||
int m_X, m_Z;
|
||||
int GetX(void) const {return m_LayerX; }
|
||||
int GetZ(void) const {return m_LayerZ; }
|
||||
int GetNumChunksLoaded(void) const {return m_NumChunksLoaded; }
|
||||
|
||||
void Save(void);
|
||||
void UnloadUnusedChunks(void);
|
||||
|
||||
void Tick( float a_Dt, MTRand & a_TickRand );
|
||||
|
||||
protected:
|
||||
|
||||
cChunkPtr m_Chunks[LAYER_SIZE * LAYER_SIZE];
|
||||
int m_LayerX;
|
||||
int m_LayerZ;
|
||||
cChunkMap * m_Parent;
|
||||
int m_NumChunksLoaded;
|
||||
};
|
||||
|
||||
typedef std::list<cChunkLayer *> cChunkLayerList;
|
||||
// TODO: Use smart pointers for cChunkLayerList as well, so that ticking and saving needn't lock the entire layerlist
|
||||
// This however means that cChunkLayer needs to interlock its m_Chunks[]
|
||||
|
||||
void SaveLayer( cChunkLayer* a_Layer );
|
||||
cChunkLayer* LoadLayer( int a_LayerX, int a_LayerZ );
|
||||
cChunkLayer* GetLayerForChunk( int a_ChunkX, int a_ChunkZ );
|
||||
cChunkLayer* GetLayer( int a_LayerX, int a_LayerZ );
|
||||
cChunkLayer* AddLayer( const cChunkLayer & a_Layer );
|
||||
bool RemoveLayer( cChunkLayer* a_Layer );
|
||||
void CompressChunk( cChunkData* a_ChunkData );
|
||||
cChunkLayer * GetLayerForChunk( int a_ChunkX, int a_ChunkZ ); // Creates the layer if it doesn't already exist
|
||||
cChunkLayer * GetLayer( int a_LayerX, int a_LayerZ ); // Creates the layer if it doesn't already exist
|
||||
void RemoveLayer( cChunkLayer* a_Layer );
|
||||
|
||||
int m_NumLayers;
|
||||
cChunkLayer* m_Layers;
|
||||
cCriticalSection m_CSLayers;
|
||||
cChunkLayerList m_Layers;
|
||||
|
||||
cWorld* m_World;
|
||||
cWorld * m_World;
|
||||
};
|
||||
|
||||
|
||||
|
@ -4,7 +4,6 @@
|
||||
#include "cClientHandle.h"
|
||||
#include "cServer.h"
|
||||
#include "cWorld.h"
|
||||
#include "cChunk.h"
|
||||
#include "cPickup.h"
|
||||
#include "cPluginManager.h"
|
||||
#include "cPlayer.h"
|
||||
@ -24,7 +23,6 @@
|
||||
#include "cBlockToPickup.h"
|
||||
#include "cMonster.h"
|
||||
#include "cChatColor.h"
|
||||
#include "cThread.h"
|
||||
#include "cSocket.h"
|
||||
#include "cTimer.h"
|
||||
|
||||
@ -67,6 +65,10 @@
|
||||
#include "packets/cPacket_UpdateSign.h"
|
||||
#include "packets/cPacket_Ping.h"
|
||||
#include "packets/cPacket_PlayerListItem.h"
|
||||
#include "packets/cPacket_NamedEntitySpawn.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define AddPistonDir(x, y, z, dir, amount) switch (dir) { case 0: (y)-=(amount); break; case 1: (y)+=(amount); break;\
|
||||
@ -79,13 +81,6 @@
|
||||
|
||||
|
||||
|
||||
// fwd: cServer.cpp:
|
||||
extern std::string GetWSAError();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cClientHandle:
|
||||
|
||||
@ -98,11 +93,11 @@ cClientHandle::cClientHandle(const cSocket & a_Socket)
|
||||
, m_Player(NULL)
|
||||
, m_bKicking(false)
|
||||
, m_TimeLastPacket(cWorld::GetTime())
|
||||
, m_bLoggedIn(false)
|
||||
, m_bKeepThreadGoing(true)
|
||||
, m_bSendLoginResponse(false)
|
||||
, m_Ping(1000)
|
||||
, m_bPositionConfirmed(false)
|
||||
, m_State(csConnected)
|
||||
, m_LastStreamedChunkX(0x7fffffff) // bogus chunk coords to force streaming upon login
|
||||
, m_LastStreamedChunkZ(0x7fffffff)
|
||||
{
|
||||
cTimer t1;
|
||||
m_LastPingTime = t1.GetNowTime();
|
||||
@ -137,8 +132,6 @@ cClientHandle::cClientHandle(const cSocket & a_Socket)
|
||||
m_PacketMap[E_RESPAWN] = new cPacket_Respawn;
|
||||
m_PacketMap[E_PING] = new cPacket_Ping;
|
||||
|
||||
memset(m_LoadedChunks, 0x00, sizeof(m_LoadedChunks));
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
m_pSendThread = new cThread(SendThread, this, "cClientHandle::SendThread");
|
||||
m_pSendThread->Start (true);
|
||||
@ -155,26 +148,26 @@ cClientHandle::~cClientHandle()
|
||||
{
|
||||
LOG("Deleting client \"%s\"", GetUsername().c_str());
|
||||
|
||||
for(unsigned int i = 0; i < VIEWDISTANCE*VIEWDISTANCE; i++)
|
||||
{
|
||||
if (m_LoadedChunks[i]) m_LoadedChunks[i]->RemoveClient(this);
|
||||
}
|
||||
|
||||
cWorld::PlayerList PlayerList = cRoot::Get()->GetWorld()->GetAllPlayers();
|
||||
for(cWorld::PlayerList::iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr)
|
||||
{
|
||||
if ((*itr) && (*itr)->GetClientHandle() && !GetUsername().empty())
|
||||
{
|
||||
std::string NameColor = (m_Player ? m_Player->GetColor() : "");
|
||||
cPacket_PlayerListItem PlayerList(NameColor + GetUsername(), false, (short)9999);
|
||||
(*itr)->GetClientHandle()->Send(PlayerList);
|
||||
}
|
||||
}
|
||||
// Remove from cSocketThreads, just in case
|
||||
cRoot::Get()->GetServer()->ClientDestroying(this);
|
||||
|
||||
if (m_Username.size() > 0)
|
||||
m_LoadedChunks.clear();
|
||||
m_ChunksToSend.clear();
|
||||
|
||||
if (m_Player != NULL)
|
||||
{
|
||||
cPacket_Chat Left(m_Username + " left the game!");
|
||||
cRoot::Get()->GetServer()->Broadcast(Left, this);
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
if (!m_Username.empty() && (World != NULL))
|
||||
{
|
||||
// Send the Offline PlayerList packet:
|
||||
AString NameColor = (m_Player ? m_Player->GetColor() : "");
|
||||
cPacket_PlayerListItem PlayerList(NameColor + GetUsername(), false, (short)9999);
|
||||
World->Broadcast(PlayerList, this);
|
||||
|
||||
// Send the Chat packet:
|
||||
cPacket_Chat Left(m_Username + " left the game!");
|
||||
World->Broadcast(Left, this);
|
||||
}
|
||||
}
|
||||
|
||||
// First stop sending thread
|
||||
@ -191,16 +184,6 @@ cClientHandle::~cClientHandle()
|
||||
m_Semaphore.Signal();
|
||||
delete m_pSendThread;
|
||||
|
||||
while (!m_PendingNrmSendPackets.empty())
|
||||
{
|
||||
delete *m_PendingNrmSendPackets.begin();
|
||||
m_PendingNrmSendPackets.erase(m_PendingNrmSendPackets.begin());
|
||||
}
|
||||
while (!m_PendingLowSendPackets.empty())
|
||||
{
|
||||
delete *m_PendingLowSendPackets.begin();
|
||||
m_PendingLowSendPackets.erase(m_PendingLowSendPackets.begin());
|
||||
}
|
||||
if (m_Player != NULL)
|
||||
{
|
||||
m_Player->SetClientHandle(NULL);
|
||||
@ -211,6 +194,18 @@ cClientHandle::~cClientHandle()
|
||||
{
|
||||
delete m_PacketMap[i];
|
||||
}
|
||||
|
||||
{
|
||||
cCSLock Lock(m_SendCriticalSection);
|
||||
for (PacketList::iterator itr = m_PendingNrmSendPackets.begin(); itr != m_PendingNrmSendPackets.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
}
|
||||
for (PacketList::iterator itr = m_PendingLowSendPackets.begin(); itr != m_PendingLowSendPackets.end(); ++itr)
|
||||
{
|
||||
delete *itr;
|
||||
}
|
||||
}
|
||||
|
||||
LOG("ClientHandle at %p destroyed", this);
|
||||
}
|
||||
@ -222,6 +217,12 @@ cClientHandle::~cClientHandle()
|
||||
void cClientHandle::Destroy()
|
||||
{
|
||||
m_bDestroyed = true;
|
||||
|
||||
if ((m_Player != NULL) && (m_Player->GetWorld() != NULL))
|
||||
{
|
||||
RemoveFromAllChunks();
|
||||
}
|
||||
|
||||
if (m_Socket.IsValid())
|
||||
{
|
||||
m_Socket.CloseSocket();
|
||||
@ -237,7 +238,10 @@ void cClientHandle::Destroy()
|
||||
|
||||
void cClientHandle::Kick(const AString & a_Reason)
|
||||
{
|
||||
LOG("Kicking user \"%s\" for \"%s\"", m_Username.c_str(), a_Reason.c_str());
|
||||
if (m_State >= csAuthenticating) // Don't log pings
|
||||
{
|
||||
LOG("Kicking user \"%s\" for \"%s\"", m_Username.c_str(), a_Reason.c_str());
|
||||
}
|
||||
Send(cPacket_Disconnect(a_Reason));
|
||||
m_bKicking = true;
|
||||
}
|
||||
@ -248,7 +252,56 @@ void cClientHandle::Kick(const AString & a_Reason)
|
||||
|
||||
void cClientHandle::Authenticate(void)
|
||||
{
|
||||
m_bSendLoginResponse = true;
|
||||
// Spawn player (only serversided, so data is loaded)
|
||||
m_Player = new cPlayer(this, GetUsername());
|
||||
|
||||
cWorld * World = cRoot::Get()->GetWorld(m_Player->GetLoadedWorldName());
|
||||
if (World == NULL)
|
||||
{
|
||||
World = cRoot::Get()->GetDefaultWorld();
|
||||
}
|
||||
|
||||
m_Player->LoginSetGameMode (World->GetGameMode()); //set player's gamemode to server's gamemode at login. TODO: set to last player's gamemode at logout
|
||||
|
||||
m_Player->SetIP (m_Socket.GetIPString());
|
||||
|
||||
cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::E_PLUGIN_PLAYER_SPAWN, 1, m_Player);
|
||||
|
||||
// Return a server login packet
|
||||
cPacket_Login LoginResponse;
|
||||
LoginResponse.m_ProtocolVersion = m_Player->GetUniqueID();
|
||||
//LoginResponse.m_Username = "";
|
||||
LoginResponse.m_ServerMode = m_Player->GetGameMode(); // set gamemode from player.
|
||||
LoginResponse.m_MapSeed = cRoot::Get()->GetWorld()->GetWorldSeed();
|
||||
LoginResponse.m_Dimension = 0;
|
||||
LoginResponse.m_MaxPlayers = (unsigned char)cRoot::Get()->GetWorld()->GetMaxPlayers();
|
||||
LoginResponse.m_Difficulty = 2;
|
||||
Send(LoginResponse);
|
||||
|
||||
// Send Weather if raining:
|
||||
if ((World->GetWeather() == 1) || (World->GetWeather() == 2))
|
||||
{
|
||||
cPacket_NewInvalidState RainPacket;
|
||||
RainPacket.m_Reason = 1; //begin rain
|
||||
Send(RainPacket);
|
||||
}
|
||||
|
||||
// Send time
|
||||
Send(cPacket_TimeUpdate(World->GetWorldTime()));
|
||||
|
||||
// Send inventory
|
||||
m_Player->GetInventory().SendWholeInventory(this);
|
||||
|
||||
// Send health
|
||||
cPacket_UpdateHealth Health;
|
||||
Health.m_Health = (short)m_Player->GetHealth();
|
||||
Health.m_Food = m_Player->GetFood();
|
||||
Health.m_Saturation = m_Player->GetFoodSaturation();
|
||||
Send(Health);
|
||||
|
||||
m_Player->Initialize(World);
|
||||
m_State = csDownloadingWorld;
|
||||
StreamChunks();
|
||||
}
|
||||
|
||||
|
||||
@ -257,135 +310,110 @@ void cClientHandle::Authenticate(void)
|
||||
|
||||
void cClientHandle::StreamChunks(void)
|
||||
{
|
||||
if (!m_bLoggedIn)
|
||||
if (m_State < csDownloadingWorld)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
assert(m_Player != NULL);
|
||||
|
||||
int ChunkPosX = (int)floor(m_Player->GetPosX() / 16);
|
||||
int ChunkPosZ = (int)floor(m_Player->GetPosZ() / 16);
|
||||
|
||||
int ChunkPosX = FAST_FLOOR_DIV(m_Player->GetPosX(), 16);
|
||||
int ChunkPosZ = FAST_FLOOR_DIV(m_Player->GetPosZ(), 16);
|
||||
if ((ChunkPosX == m_LastStreamedChunkX) && (ChunkPosZ == m_LastStreamedChunkZ))
|
||||
{
|
||||
// Already streamed for this position
|
||||
return;
|
||||
}
|
||||
m_LastStreamedChunkX = ChunkPosX;
|
||||
m_LastStreamedChunkZ = ChunkPosZ;
|
||||
|
||||
// DEBUG:
|
||||
LOGINFO("Streaming chunks centered on [%d, %d]", ChunkPosX, ChunkPosZ);
|
||||
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
assert(World != NULL);
|
||||
|
||||
cChunk * NeededChunks[VIEWDISTANCE * VIEWDISTANCE] = { 0 };
|
||||
const int MaxDist = VIEWDISTANCE + GENERATEDISTANCE * 2;
|
||||
for (int x = 0; x < MaxDist; x++)
|
||||
// Remove all loaded chunks that are no longer in range:
|
||||
{
|
||||
for (int z = 0; z < MaxDist; z++)
|
||||
cCSLock Lock(m_CSChunkLists);
|
||||
for (cChunkCoordsList::iterator itr = m_LoadedChunks.begin(); itr != m_LoadedChunks.end();)
|
||||
{
|
||||
int RelX = x - (MaxDist - 1) / 2;
|
||||
int RelZ = z - (MaxDist - 1) / 2;
|
||||
cChunk * Chunk = World->GetChunk(ChunkPosX + RelX, 0, ChunkPosZ + RelZ); // Touch all chunks in wide range, so they get generated
|
||||
if (
|
||||
(x >= GENERATEDISTANCE) &&
|
||||
(x < VIEWDISTANCE + GENERATEDISTANCE) &&
|
||||
(z >= GENERATEDISTANCE) &&
|
||||
(z < VIEWDISTANCE + GENERATEDISTANCE)
|
||||
) // but player only needs chunks in view distance
|
||||
int RelX = (*itr).m_ChunkX - ChunkPosX;
|
||||
int RelZ = (*itr).m_ChunkZ - ChunkPosZ;
|
||||
if ((RelX > VIEWDISTANCE) || (RelX < -VIEWDISTANCE) || (RelZ > VIEWDISTANCE) || (RelZ < -VIEWDISTANCE))
|
||||
{
|
||||
NeededChunks[(x - GENERATEDISTANCE) + (z - GENERATEDISTANCE) * VIEWDISTANCE] = Chunk;
|
||||
World->GetChunk((*itr).m_ChunkX, 0, (*itr).m_ChunkZ)->RemoveClient(this);
|
||||
itr = m_LoadedChunks.erase(itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
} // for itr - m_LoadedChunks[]
|
||||
for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end();)
|
||||
{
|
||||
int RelX = (*itr).m_ChunkX - ChunkPosX;
|
||||
int RelZ = (*itr).m_ChunkZ - ChunkPosZ;
|
||||
if ((RelX > VIEWDISTANCE) || (RelX < -VIEWDISTANCE) || (RelZ > VIEWDISTANCE) || (RelZ < -VIEWDISTANCE))
|
||||
{
|
||||
itr = m_ChunksToSend.erase(itr);
|
||||
}
|
||||
else
|
||||
{
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cChunk * MissingChunks[VIEWDISTANCE * VIEWDISTANCE];
|
||||
memset(MissingChunks, 0, sizeof(MissingChunks));
|
||||
unsigned int MissIndex = 0;
|
||||
for(int i = 0; i < VIEWDISTANCE * VIEWDISTANCE; i++) // Handshake loop - touch each chunk once
|
||||
|
||||
// Add all chunks that are in range and not yet in m_LoadedChunks:
|
||||
// Queue these smartly - from the center out to the edge
|
||||
for (int d = 0; d <= VIEWDISTANCE; ++d) // cycle through (square) distance, from nearest to furthest
|
||||
{
|
||||
if (NeededChunks[i] == 0) continue; // Chunk is not yet loaded, so ignore
|
||||
// This can cause MissIndex to be 0 and thus chunks will not be unloaded while they are actually out of range,
|
||||
// which might actually be a good thing, otherwise it would keep trying to unload chunks until the new chunks are fully loaded
|
||||
bool bChunkMissing = true;
|
||||
for(int j = 0; j < VIEWDISTANCE*VIEWDISTANCE; j++)
|
||||
// For each distance add chunks in a hollow square centered around current position:
|
||||
for (int i = -d; i <= d; ++i)
|
||||
{
|
||||
if (m_LoadedChunks[j] == NeededChunks[i])
|
||||
{
|
||||
bChunkMissing = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bChunkMissing)
|
||||
StreamChunk(ChunkPosX + d, ChunkPosZ + i);
|
||||
StreamChunk(ChunkPosX - d, ChunkPosZ + i);
|
||||
} // for i
|
||||
for (int i = -d + 1; i < d; ++i)
|
||||
{
|
||||
MissingChunks[MissIndex] = NeededChunks[i];
|
||||
MissIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
if (MissIndex > 0)
|
||||
StreamChunk(ChunkPosX + i, ChunkPosZ + d);
|
||||
StreamChunk(ChunkPosX + i, ChunkPosZ - d);
|
||||
} // for i
|
||||
} // for d
|
||||
|
||||
// Touch chunks GENERATEDISTANCE ahead to let them generate:
|
||||
for (int d = VIEWDISTANCE + 1; d <= VIEWDISTANCE + GENERATEDISTANCE; ++d) // cycle through (square) distance, from nearest to furthest
|
||||
{
|
||||
// Chunks are gonna be streamed in, so chunks probably also need to be streamed out <- optimization
|
||||
for(int x = 0; x < VIEWDISTANCE; x++)
|
||||
// For each distance touch chunks in a hollow square centered around current position:
|
||||
for (int i = -d; i <= d; ++i)
|
||||
{
|
||||
for(int z = 0; z < VIEWDISTANCE; z++)
|
||||
{
|
||||
cChunk* Chunk = m_LoadedChunks[x + z*VIEWDISTANCE];
|
||||
if (Chunk != NULL)
|
||||
{
|
||||
if ((Chunk->GetPosX() < ChunkPosX - (VIEWDISTANCE - 1) / 2)
|
||||
|| (Chunk->GetPosX() > ChunkPosX + (VIEWDISTANCE - 1) / 2)
|
||||
|| (Chunk->GetPosZ() < ChunkPosZ - (VIEWDISTANCE - 1) / 2)
|
||||
|| (Chunk->GetPosZ() > ChunkPosZ + (VIEWDISTANCE - 1) / 2)
|
||||
)
|
||||
{
|
||||
Chunk->RemoveClient(this);
|
||||
Chunk->AsyncUnload(this); // TODO - I think it's possible to unload the chunk immediately instead of next tick
|
||||
// I forgot why I made it happen next tick
|
||||
|
||||
m_LoadedChunks[x + z * VIEWDISTANCE] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StreamChunksSmart(MissingChunks, MissIndex);
|
||||
|
||||
memcpy(m_LoadedChunks, NeededChunks, sizeof(NeededChunks));
|
||||
}
|
||||
World->GetChunk(ChunkPosX + d, 0, ChunkPosZ + i);
|
||||
World->GetChunk(ChunkPosX - d, 0, ChunkPosZ + i);
|
||||
} // for i
|
||||
for (int i = -d + 1; i < d; ++i)
|
||||
{
|
||||
World->GetChunk(ChunkPosX + i, 0, ChunkPosZ + d);
|
||||
World->GetChunk(ChunkPosX + i, 0, ChunkPosZ - d);
|
||||
} // for i
|
||||
} // for d
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Sends chunks to the player from the player position outward
|
||||
void cClientHandle::StreamChunksSmart(cChunk** a_Chunks, unsigned int a_NumChunks)
|
||||
void cClientHandle::StreamChunk(int a_ChunkX, int a_ChunkZ)
|
||||
{
|
||||
int X = (int)floor(m_Player->GetPosX() / 16);
|
||||
int Y = (int)floor(m_Player->GetPosY() / 128);
|
||||
int Z = (int)floor(m_Player->GetPosZ() / 16);
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
assert(World != NULL);
|
||||
|
||||
bool bAllDone = false;
|
||||
while(!bAllDone)
|
||||
cChunkPtr Chunk = World->GetChunk(a_ChunkX, 0, a_ChunkZ);
|
||||
if (!Chunk->HasClient(this))
|
||||
{
|
||||
bAllDone = true;
|
||||
int ClosestIdx = -1;
|
||||
unsigned int ClosestSqrDist = (unsigned int)-1; // wraps around, becomes biggest number possible
|
||||
for(unsigned int i = 0; i < a_NumChunks; ++i)
|
||||
{
|
||||
if (a_Chunks[i])
|
||||
{
|
||||
bAllDone = false;
|
||||
int DistX = a_Chunks[i]->GetPosX()-X;
|
||||
int DistY = a_Chunks[i]->GetPosY()-Y;
|
||||
int DistZ = a_Chunks[i]->GetPosZ()-Z;
|
||||
unsigned int SqrDist = (DistX*DistX)+(DistY*DistY)+(DistZ*DistZ);
|
||||
if (SqrDist < ClosestSqrDist)
|
||||
{
|
||||
ClosestSqrDist = SqrDist;
|
||||
ClosestIdx = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ClosestIdx > -1)
|
||||
{
|
||||
a_Chunks[ClosestIdx]->Send(this);
|
||||
a_Chunks[ClosestIdx]->AddClient(this);
|
||||
//LOGINFO("CCC: Sending chunk %i %i", a_Chunks[ClosestIdx]->GetPosX(), a_Chunks[ClosestIdx]->GetPosZ());
|
||||
a_Chunks[ClosestIdx] = 0;
|
||||
}
|
||||
Chunk->AddClient(this);
|
||||
cCSLock Lock(m_CSChunkLists);
|
||||
m_LoadedChunks.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||
m_ChunksToSend.push_back(cChunkCoords(a_ChunkX, a_ChunkZ));
|
||||
}
|
||||
}
|
||||
|
||||
@ -393,18 +421,41 @@ void cClientHandle::StreamChunksSmart(cChunk** a_Chunks, unsigned int a_NumChunk
|
||||
|
||||
|
||||
|
||||
// This removes the client from all chunks. Used when switching worlds
|
||||
// Removes the client from all chunks. Used when switching worlds or destroying the player
|
||||
void cClientHandle::RemoveFromAllChunks()
|
||||
{
|
||||
for(int i = 0; i < VIEWDISTANCE*VIEWDISTANCE; i++)
|
||||
cCSLock Lock(m_CSChunkLists);
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
if (World != NULL)
|
||||
{
|
||||
if (m_LoadedChunks[i])
|
||||
for (cChunkCoordsList::iterator itr = m_LoadedChunks.begin(); itr != m_LoadedChunks.end(); ++itr)
|
||||
{
|
||||
m_LoadedChunks[i]->RemoveClient(this);
|
||||
m_LoadedChunks[i]->AsyncUnload(this);
|
||||
m_LoadedChunks[i] = 0;
|
||||
World->GetChunk(itr->m_ChunkX, 0, itr->m_ChunkZ)->RemoveClient(this);
|
||||
}
|
||||
}
|
||||
m_LoadedChunks.clear();
|
||||
m_ChunksToSend.clear();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::ChunkJustSent(cChunk * a_ChunkCompleted)
|
||||
{
|
||||
cCSLock Lock(m_CSChunkLists);
|
||||
for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end(); ++itr)
|
||||
{
|
||||
if (((*itr).m_ChunkX == a_ChunkCompleted->GetPosX()) && ((*itr).m_ChunkZ == a_ChunkCompleted->GetPosZ()))
|
||||
{
|
||||
m_ChunksToSend.erase(itr);
|
||||
if ((m_State == csDownloadingWorld) && (m_ChunksToSend.empty()))
|
||||
{
|
||||
CheckIfWorldDownloaded();
|
||||
}
|
||||
return;
|
||||
}
|
||||
} // for itr - m_ChunksToSend[]
|
||||
}
|
||||
|
||||
|
||||
@ -418,63 +469,115 @@ void cClientHandle::HandlePacket(cPacket * a_Packet)
|
||||
// cPacket* CopiedPacket = a_Packet->Clone();
|
||||
// a_Packet = CopiedPacket;
|
||||
|
||||
//LOG("Packet: 0x%02x", a_Packet->m_PacketID);
|
||||
// LOG("Recv packet 0x%02x from client \"%s\" (\"%s\")", a_Packet->m_PacketID, m_Socket.GetIPString().c_str(), m_Username.c_str());
|
||||
|
||||
if (m_bKicking)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_bLoggedIn)
|
||||
switch (m_State)
|
||||
{
|
||||
switch (a_Packet->m_PacketID)
|
||||
case csConnected:
|
||||
{
|
||||
case E_NEW_INVALID_STATE: // New/Invalid State packet received. I'm guessing the client only sends it when there's a problem with the bed?
|
||||
switch (a_Packet->m_PacketID)
|
||||
{
|
||||
LOGINFO("Got New Invalid State packet");
|
||||
break;
|
||||
}
|
||||
case E_NEW_INVALID_STATE: // New/Invalid State packet received. I'm guessing the client only sends it when there's a problem with the bed?
|
||||
{
|
||||
LOGINFO("Got New Invalid State packet");
|
||||
break;
|
||||
}
|
||||
case E_PING: HandlePing (); break;
|
||||
case E_HANDSHAKE: HandleHandshake(reinterpret_cast<cPacket_Handshake *>(a_Packet)); break;
|
||||
case E_LOGIN: HandleLogin (reinterpret_cast<cPacket_Login *> (a_Packet)); break;
|
||||
|
||||
// Ignored packets:
|
||||
case E_PLAYERLOOK:
|
||||
case E_PLAYERMOVELOOK:
|
||||
case E_PLAYERPOS:
|
||||
case E_KEEP_ALIVE: break;
|
||||
default: HandleUnexpectedPacket(a_Packet); break;
|
||||
} // switch (PacketType)
|
||||
break;
|
||||
} // case csConnected
|
||||
|
||||
case E_PING: HandlePing(); break;
|
||||
case E_HANDSHAKE: HandleHandshake (reinterpret_cast<cPacket_Handshake *> (a_Packet)); break;
|
||||
case E_LOGIN: HandleLogin (reinterpret_cast<cPacket_Login *> (a_Packet)); break;
|
||||
case E_PLAYERMOVELOOK: HandleMoveLookLogin(reinterpret_cast<cPacket_PlayerMoveLook *>(a_Packet)); break;
|
||||
case E_KEEP_ALIVE: break;
|
||||
default: HandleDefaultLogin (a_Packet); break;
|
||||
} // switch (Packet type)
|
||||
}
|
||||
else if (!m_bPositionConfirmed) // m_bLoggedIn is true
|
||||
{
|
||||
switch (a_Packet->m_PacketID)
|
||||
case csAuthenticating:
|
||||
{
|
||||
case E_PLAYERMOVELOOK: HandleMoveLookConfirm(reinterpret_cast<cPacket_PlayerMoveLook *>(a_Packet)); break;
|
||||
// No default handling, ignore everything else
|
||||
} // switch (Packet type)
|
||||
} // if (! position confirmed)
|
||||
// Waiting for external authentication, no packets are handled
|
||||
switch (a_Packet->m_PacketID)
|
||||
{
|
||||
// Ignored packets:
|
||||
case E_KEEP_ALIVE:
|
||||
case E_PLAYERLOOK:
|
||||
case E_PLAYERMOVELOOK:
|
||||
case E_PLAYERPOS: break;
|
||||
|
||||
default: HandleUnexpectedPacket(a_Packet); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case csDownloadingWorld:
|
||||
{
|
||||
// Waiting for chunks to stream to client, no packets are handled
|
||||
switch (a_Packet->m_PacketID)
|
||||
{
|
||||
// Ignored packets:
|
||||
case E_KEEP_ALIVE:
|
||||
case E_PLAYERLOOK:
|
||||
case E_PLAYERMOVELOOK:
|
||||
case E_PLAYERPOS: break;
|
||||
|
||||
default: HandleUnexpectedPacket(a_Packet); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case csConfirmingPos:
|
||||
{
|
||||
switch (a_Packet->m_PacketID)
|
||||
{
|
||||
// Ignored packets:
|
||||
case E_KEEP_ALIVE:
|
||||
case E_PLAYERLOOK:
|
||||
case E_PLAYERPOS: break;
|
||||
|
||||
if (m_bPositionConfirmed)
|
||||
{
|
||||
switch (a_Packet->m_PacketID)
|
||||
case E_PLAYERMOVELOOK: HandleMoveLookConfirm(reinterpret_cast<cPacket_PlayerMoveLook *>(a_Packet)); break;
|
||||
|
||||
default:
|
||||
{
|
||||
HandleUnexpectedPacket(a_Packet);
|
||||
break;
|
||||
}
|
||||
} // switch (PacketType)
|
||||
break;
|
||||
} // case csConfirmingPos
|
||||
|
||||
case csPlaying:
|
||||
{
|
||||
case E_CREATIVE_INVENTORY_ACTION: HandleCreativeInventory(reinterpret_cast<cPacket_CreativeInventoryAction *>(a_Packet)); break;
|
||||
case E_PLAYERPOS: HandlePlayerPos (reinterpret_cast<cPacket_PlayerPosition *> (a_Packet)); break;
|
||||
case E_BLOCK_DIG: HandleBlockDig (reinterpret_cast<cPacket_BlockDig *> (a_Packet)); break;
|
||||
case E_BLOCK_PLACE: HandleBlockPlace (reinterpret_cast<cPacket_BlockPlace *> (a_Packet)); break;
|
||||
case E_PICKUP_SPAWN: HandlePickupSpawn (reinterpret_cast<cPacket_PickupSpawn *> (a_Packet)); break;
|
||||
case E_CHAT: HandleChat (reinterpret_cast<cPacket_Chat *> (a_Packet)); break;
|
||||
case E_PLAYERLOOK: HandlePlayerLook (reinterpret_cast<cPacket_PlayerLook *> (a_Packet)); break;
|
||||
case E_PLAYERMOVELOOK: HandlePlayerMoveLook (reinterpret_cast<cPacket_PlayerMoveLook *> (a_Packet)); break;
|
||||
case E_ANIMATION: HandleAnimation (reinterpret_cast<cPacket_ArmAnim *> (a_Packet)); break;
|
||||
case E_ITEM_SWITCH: HandleItemSwitch (reinterpret_cast<cPacket_ItemSwitch *> (a_Packet)); break;
|
||||
case E_WINDOW_CLOSE: HandleWindowClose (reinterpret_cast<cPacket_WindowClose *> (a_Packet)); break;
|
||||
case E_WINDOW_CLICK: HandleWindowClick (reinterpret_cast<cPacket_WindowClick *> (a_Packet)); break;
|
||||
case E_UPDATE_SIGN: HandleUpdateSign (reinterpret_cast<cPacket_UpdateSign *> (a_Packet)); break;
|
||||
case E_USE_ENTITY: HandleUseEntity (reinterpret_cast<cPacket_UseEntity *> (a_Packet)); break;
|
||||
case E_RESPAWN: HandleRespawn();
|
||||
case E_DISCONNECT: HandleDisconnect (reinterpret_cast<cPacket_Disconnect *> (a_Packet)); break;
|
||||
case E_KEEP_ALIVE: HandleKeepAlive (reinterpret_cast<cPacket_KeepAlive *> (a_Packet)); break;
|
||||
} // switch (Packet type)
|
||||
} // if (normal game)
|
||||
switch (a_Packet->m_PacketID)
|
||||
{
|
||||
case E_CREATIVE_INVENTORY_ACTION: HandleCreativeInventory(reinterpret_cast<cPacket_CreativeInventoryAction *>(a_Packet)); break;
|
||||
case E_PLAYERPOS: HandlePlayerPos (reinterpret_cast<cPacket_PlayerPosition *> (a_Packet)); break;
|
||||
case E_BLOCK_DIG: HandleBlockDig (reinterpret_cast<cPacket_BlockDig *> (a_Packet)); break;
|
||||
case E_BLOCK_PLACE: HandleBlockPlace (reinterpret_cast<cPacket_BlockPlace *> (a_Packet)); break;
|
||||
case E_PICKUP_SPAWN: HandlePickupSpawn (reinterpret_cast<cPacket_PickupSpawn *> (a_Packet)); break;
|
||||
case E_CHAT: HandleChat (reinterpret_cast<cPacket_Chat *> (a_Packet)); break;
|
||||
case E_PLAYERLOOK: HandlePlayerLook (reinterpret_cast<cPacket_PlayerLook *> (a_Packet)); break;
|
||||
case E_PLAYERMOVELOOK: HandlePlayerMoveLook (reinterpret_cast<cPacket_PlayerMoveLook *> (a_Packet)); break;
|
||||
case E_ANIMATION: HandleAnimation (reinterpret_cast<cPacket_ArmAnim *> (a_Packet)); break;
|
||||
case E_ITEM_SWITCH: HandleItemSwitch (reinterpret_cast<cPacket_ItemSwitch *> (a_Packet)); break;
|
||||
case E_WINDOW_CLOSE: HandleWindowClose (reinterpret_cast<cPacket_WindowClose *> (a_Packet)); break;
|
||||
case E_WINDOW_CLICK: HandleWindowClick (reinterpret_cast<cPacket_WindowClick *> (a_Packet)); break;
|
||||
case E_UPDATE_SIGN: HandleUpdateSign (reinterpret_cast<cPacket_UpdateSign *> (a_Packet)); break;
|
||||
case E_USE_ENTITY: HandleUseEntity (reinterpret_cast<cPacket_UseEntity *> (a_Packet)); break;
|
||||
case E_RESPAWN: HandleRespawn(); break;
|
||||
case E_DISCONNECT: HandleDisconnect (reinterpret_cast<cPacket_Disconnect *> (a_Packet)); break;
|
||||
case E_KEEP_ALIVE: HandleKeepAlive (reinterpret_cast<cPacket_KeepAlive *> (a_Packet)); break;
|
||||
} // switch (Packet type)
|
||||
break;
|
||||
} // case csPlaying
|
||||
} // switch (m_State)
|
||||
}
|
||||
|
||||
|
||||
@ -484,7 +587,6 @@ void cClientHandle::HandlePacket(cPacket * a_Packet)
|
||||
void cClientHandle::HandlePing(void)
|
||||
{
|
||||
// Somebody tries to retrieve information about the server
|
||||
LOGINFO("Got ping from \"%s\"", m_Socket.GetIPString().c_str());
|
||||
AString Reply;
|
||||
Printf(Reply, "%s%s%i%s%i",
|
||||
cRoot::Get()->GetWorld()->GetDescription().c_str(),
|
||||
@ -554,6 +656,7 @@ void cClientHandle::HandleLogin(cPacket_Login * a_Packet)
|
||||
}
|
||||
|
||||
// Schedule for authentication; until then, let them wait (but do not block)
|
||||
m_State = csAuthenticating;
|
||||
cRoot::Get()->GetAuthenticator().Authenticate(m_Username, cRoot::Get()->GetServer()->GetServerID());
|
||||
}
|
||||
|
||||
@ -561,48 +664,11 @@ void cClientHandle::HandleLogin(cPacket_Login * a_Packet)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleMoveLookLogin(cPacket_PlayerMoveLook * a_Packet)
|
||||
{
|
||||
// After this is received we're safe to send anything
|
||||
if (m_Player == NULL)
|
||||
{
|
||||
LOGWARNING("Received PlayerMoveLook packet for NULL player from client \"%s\", kicking.", m_Socket.GetIPString().c_str());
|
||||
Kick("Hacked client"); // Don't tell them why we don't want them
|
||||
return;
|
||||
}
|
||||
if (!cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::E_PLUGIN_PLAYER_JOIN, 1, m_Player))
|
||||
{
|
||||
// Broadcast that this player has joined the game! Yay~
|
||||
cPacket_Chat Joined(m_Username + " joined the game!");
|
||||
cRoot::Get()->GetServer()->Broadcast(Joined, this);
|
||||
}
|
||||
|
||||
// Now initialize player (adds to entity list etc.)
|
||||
cWorld* PlayerWorld = cRoot::Get()->GetWorld(m_Player->GetLoadedWorldName());
|
||||
if (!PlayerWorld)
|
||||
{
|
||||
PlayerWorld = cRoot::Get()->GetDefaultWorld();
|
||||
}
|
||||
m_Player->Initialize(PlayerWorld);
|
||||
|
||||
// Then we can start doing more stuffs! :D
|
||||
m_bLoggedIn = true;
|
||||
LOG("Player \"%s\" completely logged in", m_Username.c_str());
|
||||
StreamChunks();
|
||||
|
||||
// Send position
|
||||
m_ConfirmPosition = m_Player->GetPosition();
|
||||
Send(cPacket_PlayerMoveLook(m_Player));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::HandleDefaultLogin(cPacket * a_Packet)
|
||||
void cClientHandle::HandleUnexpectedPacket(cPacket * a_Packet)
|
||||
{
|
||||
LOGWARNING(
|
||||
"Invalid packet in login state: 0x%02x from client \"%s\", username \"%s\"",
|
||||
"Invalid packet in state %d: 0x%02x from client \"%s\", username \"%s\"",
|
||||
m_State,
|
||||
a_Packet->m_PacketID,
|
||||
m_Socket.GetIPString().c_str(),
|
||||
m_Username.c_str()
|
||||
@ -627,11 +693,13 @@ void cClientHandle::HandleMoveLookConfirm(cPacket_PlayerMoveLook * a_Packet)
|
||||
{
|
||||
LOGINFO("Exact position confirmed by client!");
|
||||
}
|
||||
m_bPositionConfirmed = true;
|
||||
m_State = csPlaying;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGWARNING("Player \"%s\" sent a weird position confirmation %.2 blocks away, waiting for another confirmation", m_Username.c_str(), Dist);
|
||||
LOGWARNING("Player \"%s\" sent a weird position confirmation %.2f blocks away, retrying", m_Username.c_str(), Dist);
|
||||
m_ConfirmPosition = m_Player->GetPosition();
|
||||
Send(cPacket_PlayerMoveLook(m_Player));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1448,14 +1516,12 @@ void cClientHandle::HandleWindowClick(cPacket_WindowClick * a_Packet)
|
||||
void cClientHandle::HandleUpdateSign(cPacket_UpdateSign * a_Packet)
|
||||
{
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
cChunk * Chunk = World->GetChunkOfBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
|
||||
cBlockEntity * BlockEntity = Chunk->GetBlockEntity(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
|
||||
if ((BlockEntity != NULL) && ((BlockEntity->GetBlockType() == E_BLOCK_SIGN_POST) || (BlockEntity->GetBlockType() == E_BLOCK_WALLSIGN)))
|
||||
cChunkPtr Chunk = World->GetChunkOfBlock(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ);
|
||||
if ((Chunk == NULL) || !Chunk->IsValid())
|
||||
{
|
||||
cSignEntity * Sign = reinterpret_cast<cSignEntity *>(BlockEntity);
|
||||
Sign->SetLines(a_Packet->m_Line1, a_Packet->m_Line2, a_Packet->m_Line3, a_Packet->m_Line4);
|
||||
Sign->SendTo(NULL); // Broadcast to all players in chunk
|
||||
return;
|
||||
}
|
||||
Chunk->UpdateSign(a_Packet->m_PosX, a_Packet->m_PosY, a_Packet->m_PosZ, a_Packet->m_Line1, a_Packet->m_Line2, a_Packet->m_Line3, a_Packet->m_Line4);
|
||||
}
|
||||
|
||||
|
||||
@ -1554,6 +1620,7 @@ void cClientHandle::Tick(float a_Dt)
|
||||
cPacket_Disconnect DC("Nooooo!! You timed out! D: Come back!");
|
||||
m_Socket.Send(&DC);
|
||||
|
||||
// TODO: Cannot sleep in the tick thread!
|
||||
cSleep::MilliSleep(1000); // Give packet some time to be received
|
||||
|
||||
Destroy();
|
||||
@ -1563,63 +1630,37 @@ void cClientHandle::Tick(float a_Dt)
|
||||
// Send ping packet
|
||||
if (m_LastPingTime + cClientHandle::PING_TIME_MS <= t1.GetNowTime())
|
||||
{
|
||||
// TODO: why a random ping ID, can't we just use normal ascending numbers?
|
||||
MTRand r1;
|
||||
m_PingID = r1.randInt();
|
||||
m_PingID++;
|
||||
cPacket_KeepAlive Ping(m_PingID);
|
||||
m_PingStartTime = t1.GetNowTime();
|
||||
Send(Ping);
|
||||
m_LastPingTime = m_PingStartTime;
|
||||
}
|
||||
|
||||
if (m_bSendLoginResponse)
|
||||
|
||||
if (m_State >= csDownloadingWorld)
|
||||
{
|
||||
m_bSendLoginResponse = false;
|
||||
|
||||
// Spawn player (only serversided, so data is loaded)
|
||||
m_Player = new cPlayer(this, GetUsername()); // !!DO NOT INITIALIZE!! <- is done after receiving MoveLook Packet
|
||||
|
||||
cWorld* World = cRoot::Get()->GetWorld(m_Player->GetLoadedWorldName());
|
||||
if (!World) World = cRoot::Get()->GetDefaultWorld();
|
||||
World->LockEntities();
|
||||
m_Player->LoginSetGameMode (World->GetGameMode()); //set player's gamemode to server's gamemode at login. TODO: set to last player's gamemode at logout
|
||||
|
||||
m_Player->SetIP (m_Socket.GetIPString());
|
||||
|
||||
cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::E_PLUGIN_PLAYER_SPAWN, 1, m_Player);
|
||||
|
||||
// Return a server login packet
|
||||
cPacket_Login LoginResponse;
|
||||
LoginResponse.m_ProtocolVersion = m_Player->GetUniqueID();
|
||||
//LoginResponse.m_Username = "";
|
||||
LoginResponse.m_ServerMode = m_Player->GetGameMode(); //set gamemode from player.
|
||||
LoginResponse.m_MapSeed = cRoot::Get()->GetWorld()->GetWorldSeed();
|
||||
LoginResponse.m_Dimension = 0;
|
||||
LoginResponse.m_MaxPlayers = (unsigned char)cRoot::Get()->GetWorld()->GetMaxPlayers();
|
||||
LoginResponse.m_Difficulty = 2;
|
||||
Send(LoginResponse);
|
||||
|
||||
// Send Weather if raining:
|
||||
if ((World->GetWeather() == 1) || (World->GetWeather() == 2)) {
|
||||
cPacket_NewInvalidState RainPacket;
|
||||
RainPacket.m_Reason = 1; //begin rain
|
||||
Send(RainPacket);
|
||||
}
|
||||
|
||||
// Send time
|
||||
Send(cPacket_TimeUpdate(World->GetWorldTime()));
|
||||
|
||||
// Send inventory
|
||||
m_Player->GetInventory().SendWholeInventory(this);
|
||||
|
||||
// Send health
|
||||
cPacket_UpdateHealth Health;
|
||||
Health.m_Health = (short)m_Player->GetHealth();
|
||||
Health.m_Food = m_Player->GetFood();
|
||||
Health.m_Saturation = m_Player->GetFoodSaturation();
|
||||
Send(Health);
|
||||
|
||||
World->UnlockEntities();
|
||||
cWorld * World = m_Player->GetWorld();
|
||||
cCSLock Lock(m_CSChunkLists);
|
||||
int NumSent = 0;
|
||||
for (cChunkCoordsList::iterator itr = m_ChunksToSend.begin(); itr != m_ChunksToSend.end();)
|
||||
{
|
||||
cChunkPtr Chunk = World->GetChunk(itr->m_ChunkX, 0, itr->m_ChunkZ);
|
||||
if (!Chunk->IsValid())
|
||||
{
|
||||
++itr;
|
||||
continue;
|
||||
}
|
||||
// The chunk has become valid, send it and remove it from the list:
|
||||
Chunk->Send(this);
|
||||
itr = m_ChunksToSend.erase(itr);
|
||||
NumSent++;
|
||||
if (NumSent > 10)
|
||||
{
|
||||
// Only send up to 10 chunks per tick, otherwise we'd choke the tick thread
|
||||
break;
|
||||
}
|
||||
CheckIfWorldDownloaded();
|
||||
} // for itr - m_ChunksToSend[]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1627,15 +1668,46 @@ void cClientHandle::Tick(float a_Dt)
|
||||
|
||||
|
||||
|
||||
void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* = E_PRIORITY_NORMAL */)
|
||||
void cClientHandle::Send(const cPacket * a_Packet, ENUM_PRIORITY a_Priority /* = E_PRIORITY_NORMAL */)
|
||||
{
|
||||
if (m_bKicking) return; // Don't add more packets if player is getting kicked anyway
|
||||
|
||||
// If it is the packet spawning myself for myself, drop it silently:
|
||||
if (a_Packet->m_PacketID == E_NAMED_ENTITY_SPAWN)
|
||||
{
|
||||
if (((cPacket_NamedEntitySpawn *)a_Packet)->m_UniqueID == m_Player->GetUniqueID())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter out packets that don't belong to a csDownloadingWorld state:
|
||||
if (m_State == csDownloadingWorld)
|
||||
{
|
||||
switch (a_Packet->m_PacketID)
|
||||
{
|
||||
case E_PLAYERMOVELOOK:
|
||||
case E_KEEP_ALIVE:
|
||||
case E_PRE_CHUNK:
|
||||
{
|
||||
// Allow
|
||||
break;
|
||||
}
|
||||
case E_MAP_CHUNK:
|
||||
{
|
||||
CheckIfWorldDownloaded();
|
||||
break;
|
||||
}
|
||||
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
bool bSignalSemaphore = true;
|
||||
cCSLock Lock(m_SendCriticalSection);
|
||||
if (a_Priority == E_PRIORITY_NORMAL)
|
||||
{
|
||||
if (a_Packet.m_PacketID == E_REL_ENT_MOVE_LOOK)
|
||||
if (a_Packet->m_PacketID == E_REL_ENT_MOVE_LOOK)
|
||||
{
|
||||
PacketList & Packets = m_PendingNrmSendPackets;
|
||||
for (PacketList::iterator itr = Packets.begin(); itr != Packets.end(); ++itr)
|
||||
@ -1645,11 +1717,10 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* =
|
||||
{
|
||||
case E_REL_ENT_MOVE_LOOK:
|
||||
{
|
||||
const cPacket_RelativeEntityMoveLook* ThisPacketData = reinterpret_cast< const cPacket_RelativeEntityMoveLook* >(&a_Packet);
|
||||
const cPacket_RelativeEntityMoveLook* ThisPacketData = reinterpret_cast< const cPacket_RelativeEntityMoveLook* >(a_Packet);
|
||||
cPacket_RelativeEntityMoveLook* PacketData = reinterpret_cast< cPacket_RelativeEntityMoveLook* >(*itr);
|
||||
if (ThisPacketData->m_UniqueID == PacketData->m_UniqueID)
|
||||
{
|
||||
//LOGINFO("Optimized by removing double packet");
|
||||
Packets.erase(itr);
|
||||
bBreak = true;
|
||||
bSignalSemaphore = false; // Because 1 packet is removed, semaphore count is the same
|
||||
@ -1665,11 +1736,11 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* =
|
||||
}
|
||||
} // for itr - Packets[]
|
||||
} // if (E_REL_ENT_MOVE_LOOK
|
||||
m_PendingNrmSendPackets.push_back(a_Packet.Clone());
|
||||
m_PendingNrmSendPackets.push_back(a_Packet->Clone());
|
||||
}
|
||||
else if (a_Priority == E_PRIORITY_LOW)
|
||||
{
|
||||
m_PendingLowSendPackets.push_back(a_Packet.Clone());
|
||||
m_PendingLowSendPackets.push_back(a_Packet->Clone());
|
||||
}
|
||||
Lock.Unlock();
|
||||
if (bSignalSemaphore)
|
||||
@ -1682,6 +1753,44 @@ void cClientHandle::Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority /* =
|
||||
|
||||
|
||||
|
||||
void cClientHandle::CheckIfWorldDownloaded(void)
|
||||
{
|
||||
if (m_State != csDownloadingWorld)
|
||||
{
|
||||
return;
|
||||
}
|
||||
cCSLock Lock(m_CSChunkLists);
|
||||
if (m_ChunksToSend.empty())
|
||||
{
|
||||
SendConfirmPosition();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::SendConfirmPosition(void)
|
||||
{
|
||||
LOG("Spawning player \"%s\"", m_Username.c_str());
|
||||
|
||||
m_State = csConfirmingPos;
|
||||
|
||||
if (!cRoot::Get()->GetPluginManager()->CallHook(cPluginManager::E_PLUGIN_PLAYER_JOIN, 1, m_Player))
|
||||
{
|
||||
// Broadcast that this player has joined the game! Yay~
|
||||
cPacket_Chat Joined(m_Username + " joined the game!");
|
||||
cRoot::Get()->GetServer()->Broadcast(Joined, this);
|
||||
}
|
||||
|
||||
m_ConfirmPosition = m_Player->GetPosition();
|
||||
Send(cPacket_PlayerMoveLook(m_Player));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cClientHandle::SendThread(void *lpParam)
|
||||
{
|
||||
cClientHandle* self = (cClientHandle*)lpParam;
|
||||
@ -1737,6 +1846,9 @@ void cClientHandle::SendThread(void *lpParam)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// LOG("Sending packet 0x%02x to \"%s\" (\"%s\")", Packet->m_PacketID, self->m_Socket.GetIPString().c_str(), self->m_Username.c_str());
|
||||
|
||||
bool bSuccess = self->m_Socket.Send(Packet);
|
||||
|
||||
if (!bSuccess)
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "packets/cPacket.h"
|
||||
#include "Vector3d.h"
|
||||
#include "cSocketThreads.h"
|
||||
#include "cChunk.h"
|
||||
|
||||
#include "packets/cPacket_KeepAlive.h"
|
||||
#include "packets/cPacket_PlayerPosition.h"
|
||||
@ -46,8 +47,6 @@
|
||||
|
||||
|
||||
|
||||
// class Game;
|
||||
class cChunk;
|
||||
class cPlayer;
|
||||
class cRedstone;
|
||||
|
||||
@ -70,9 +69,6 @@ public:
|
||||
cClientHandle(const cSocket & a_Socket);
|
||||
~cClientHandle();
|
||||
|
||||
static const int VIEWDISTANCE = 17; // MUST be odd number or CRASH!
|
||||
static const int GENERATEDISTANCE = 2; // Server generates this many chunks AHEAD of player sight.
|
||||
|
||||
const cSocket & GetSocket(void) const {return m_Socket; }
|
||||
cSocket & GetSocket(void) {return m_Socket; }
|
||||
|
||||
@ -81,21 +77,22 @@ public:
|
||||
void Kick(const AString & a_Reason); //tolua_export
|
||||
void Authenticate(void); // Called by cAuthenticator when the user passes authentication
|
||||
|
||||
void StreamChunks();
|
||||
void StreamChunksSmart( cChunk** a_Chunks, unsigned int a_NumChunks );
|
||||
void RemoveFromAllChunks();
|
||||
void StreamChunks(void);
|
||||
|
||||
// Removes the client from all chunks. Used when switching worlds or destroying the player
|
||||
void RemoveFromAllChunks(void);
|
||||
|
||||
void ChunkJustSent(cChunk * a_ChunkSent); // Called by cChunk when it is loaded / generated and sent to all clients registered in it
|
||||
|
||||
inline void SetLoggedIn( bool a_bLoggedIn ) { m_bLoggedIn = a_bLoggedIn; }
|
||||
inline bool IsLoggedIn() { return m_bLoggedIn; }
|
||||
inline bool IsLoggedIn(void) const { return m_State >= csAuthenticating; }
|
||||
|
||||
void Tick(float a_Dt);
|
||||
|
||||
bool IsDestroyed() { return m_bDestroyed; }
|
||||
void Destroy();
|
||||
|
||||
cChunk* m_LoadedChunks[VIEWDISTANCE*VIEWDISTANCE];
|
||||
|
||||
void Send( const cPacket & a_Packet, ENUM_PRIORITY a_Priority = E_PRIORITY_NORMAL );
|
||||
void Send(const cPacket & a_Packet, ENUM_PRIORITY a_Priority = E_PRIORITY_NORMAL) { Send(&a_Packet, a_Priority); }
|
||||
void Send(const cPacket * a_Packet, ENUM_PRIORITY a_Priority = E_PRIORITY_NORMAL);
|
||||
|
||||
static void SendThread( void *lpParam );
|
||||
|
||||
@ -105,6 +102,9 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
static const int VIEWDISTANCE = 4; // Number of chunks the player can see in each direction; 4 is the minimum ( http://wiki.vg/Protocol_FAQ#.E2.80.A6all_connecting_clients_spasm_and_jerk_uncontrollably.21 )
|
||||
static const int GENERATEDISTANCE = 1; // Server generates this many chunks AHEAD of player sight.
|
||||
|
||||
int m_ProtocolVersion;
|
||||
AString m_Username;
|
||||
AString m_Password;
|
||||
@ -114,13 +114,16 @@ private:
|
||||
PacketList m_PendingNrmSendPackets;
|
||||
PacketList m_PendingLowSendPackets;
|
||||
|
||||
cCriticalSection m_CSChunkLists;
|
||||
cChunkCoordsList m_LoadedChunks; // Chunks that the player belongs to
|
||||
cChunkCoordsList m_ChunksToSend; // Chunks that need to be sent to the player (queued because they weren't generated yet or there's not enough time to send them)
|
||||
|
||||
cThread * m_pSendThread;
|
||||
|
||||
cSocket m_Socket;
|
||||
|
||||
cCriticalSection m_CriticalSection;
|
||||
cCriticalSection m_SendCriticalSection;
|
||||
// cCriticalSection m_SocketCriticalSection;
|
||||
cSemaphore m_Semaphore;
|
||||
|
||||
Vector3d m_ConfirmPosition;
|
||||
@ -130,34 +133,46 @@ private:
|
||||
bool m_bDestroyed;
|
||||
cPlayer * m_Player;
|
||||
bool m_bKicking;
|
||||
|
||||
// Chunk position when the last StreamChunks() was called; used to avoid re-streaming while in the same chunk
|
||||
int m_LastStreamedChunkX;
|
||||
int m_LastStreamedChunkZ;
|
||||
|
||||
float m_TimeLastPacket;
|
||||
|
||||
|
||||
short m_Ping;
|
||||
int m_PingID;
|
||||
long long m_PingStartTime;
|
||||
long long m_LastPingTime;
|
||||
static const unsigned short PING_TIME_MS = 1000; //minecraft sends 1 per 20 ticks (1 second or every 1000 ms)
|
||||
|
||||
bool m_bLoggedIn;
|
||||
bool m_bPositionConfirmed;
|
||||
bool m_bSendLoginResponse;
|
||||
enum eState
|
||||
{
|
||||
csConnected, // The client has just connected, waiting for their handshake / login
|
||||
csAuthenticating, // The client has logged in, waiting for external authentication
|
||||
csDownloadingWorld, // The client is waiting for chunks, we're waiting for the loader to provide and send them
|
||||
csConfirmingPos, // The client has been sent the position packet, waiting for them to repeat the position back
|
||||
csPlaying, // Normal gameplay
|
||||
|
||||
// TODO: Add Kicking and Destroyed here as well
|
||||
} ;
|
||||
|
||||
eState m_State;
|
||||
|
||||
bool m_bKeepThreadGoing;
|
||||
|
||||
void HandlePacket(cPacket * a_Packet);
|
||||
|
||||
// Packets handled while !m_bLoggedIn:
|
||||
void HandlePing (void);
|
||||
void HandleHandshake (cPacket_Handshake * a_Packet);
|
||||
void HandleLogin (cPacket_Login * a_Packet);
|
||||
void HandleMoveLookLogin(cPacket_PlayerMoveLook * a_Packet); // While !m_bLoggedIn
|
||||
void HandleDefaultLogin (cPacket * a_Packet); // the default case
|
||||
// Packets handled in csConnected:
|
||||
void HandlePing (void);
|
||||
void HandleHandshake (cPacket_Handshake * a_Packet);
|
||||
void HandleLogin (cPacket_Login * a_Packet);
|
||||
void HandleUnexpectedPacket(cPacket * a_Packet); // the default case -> kick
|
||||
|
||||
// Packets handled while !m_bPositionConfirmed:
|
||||
// Packets handled while in csConfirmingPos:
|
||||
void HandleMoveLookConfirm(cPacket_PlayerMoveLook * a_Packet); // While !m_bPositionConfirmed
|
||||
|
||||
// Packets handled while m_bPositionConfirmed (normal gameplay):
|
||||
// Packets handled while in csPlaying:
|
||||
void HandleCreativeInventory(cPacket_CreativeInventoryAction * a_Packet);
|
||||
void HandlePlayerPos (cPacket_PlayerPosition * a_Packet);
|
||||
void HandleBlockDig (cPacket_BlockDig * a_Packet);
|
||||
@ -179,7 +194,14 @@ private:
|
||||
/// Returns true if the rate block interactions is within a reasonable limit (bot protection)
|
||||
bool CheckBlockInteractionsRate(void);
|
||||
|
||||
void SendLoginResponse();
|
||||
/// Checks whether all loaded chunks have been sent to the client; if so, sends the position to confirm
|
||||
void CheckIfWorldDownloaded(void);
|
||||
|
||||
/// Sends the PlayerMoveLook packet that the client needs to reply to for the game to start
|
||||
void SendConfirmPosition(void);
|
||||
|
||||
/// Adds a single chunk to be streamed to the client; used by StreamChunks()
|
||||
void StreamChunk(int a_ChunkX, int a_ChunkZ);
|
||||
|
||||
// cSocketThreads::cCallback overrides:
|
||||
virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client
|
||||
|
@ -11,8 +11,7 @@
|
||||
cCriticalSection::cCriticalSection()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
m_CriticalSectionPtr = new CRITICAL_SECTION;
|
||||
InitializeCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
InitializeCriticalSection( &m_CriticalSection );
|
||||
#else
|
||||
m_Attributes = new pthread_mutexattr_t;
|
||||
pthread_mutexattr_init((pthread_mutexattr_t*)m_Attributes);
|
||||
@ -33,8 +32,7 @@ cCriticalSection::cCriticalSection()
|
||||
cCriticalSection::~cCriticalSection()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DeleteCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
delete (CRITICAL_SECTION*)m_CriticalSectionPtr;
|
||||
DeleteCriticalSection( &m_CriticalSection );
|
||||
#else
|
||||
if( pthread_mutex_destroy( (pthread_mutex_t*)m_CriticalSectionPtr ) != 0 )
|
||||
{
|
||||
@ -53,7 +51,7 @@ cCriticalSection::~cCriticalSection()
|
||||
void cCriticalSection::Lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
EnterCriticalSection( &m_CriticalSection );
|
||||
#else
|
||||
pthread_mutex_lock( (pthread_mutex_t*)m_CriticalSectionPtr );
|
||||
#endif
|
||||
@ -66,7 +64,7 @@ void cCriticalSection::Lock()
|
||||
void cCriticalSection::Unlock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
LeaveCriticalSection( &m_CriticalSection );
|
||||
#else
|
||||
pthread_mutex_unlock( (pthread_mutex_t*)m_CriticalSectionPtr );
|
||||
#endif
|
||||
@ -81,9 +79,7 @@ void cCriticalSection::Unlock()
|
||||
|
||||
cCSLock::cCSLock(cCriticalSection * a_CS)
|
||||
: m_CS(a_CS)
|
||||
#ifdef _DEBUG
|
||||
, m_IsLocked(false)
|
||||
#endif
|
||||
{
|
||||
Lock();
|
||||
}
|
||||
@ -94,9 +90,7 @@ cCSLock::cCSLock(cCriticalSection * a_CS)
|
||||
|
||||
cCSLock::cCSLock(cCriticalSection & a_CS)
|
||||
: m_CS(&a_CS)
|
||||
#ifdef _DEBUG
|
||||
, m_IsLocked(false)
|
||||
#endif
|
||||
{
|
||||
Lock();
|
||||
}
|
||||
@ -107,12 +101,10 @@ cCSLock::cCSLock(cCriticalSection & a_CS)
|
||||
|
||||
cCSLock::~cCSLock()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (!m_IsLocked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif // _DEBUG
|
||||
Unlock();
|
||||
}
|
||||
|
||||
@ -122,11 +114,8 @@ cCSLock::~cCSLock()
|
||||
|
||||
void cCSLock::Lock(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
assert(!m_IsLocked);
|
||||
m_IsLocked = true;
|
||||
#endif // _DEBUG
|
||||
|
||||
m_CS->Lock();
|
||||
}
|
||||
|
||||
@ -136,11 +125,8 @@ void cCSLock::Lock(void)
|
||||
|
||||
void cCSLock::Unlock(void)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
assert(m_IsLocked);
|
||||
m_IsLocked = false;
|
||||
#endif // _DEBUG
|
||||
|
||||
m_CS->Unlock();
|
||||
}
|
||||
|
||||
|
@ -1,18 +1,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cCriticalSection
|
||||
{
|
||||
public:
|
||||
cCriticalSection();
|
||||
cCriticalSection(void);
|
||||
~cCriticalSection();
|
||||
|
||||
void Lock();
|
||||
void Unlock();
|
||||
void Lock(void);
|
||||
void Unlock(void);
|
||||
|
||||
private:
|
||||
void* m_CriticalSectionPtr; // Pointer to a CRITICAL_SECTION object
|
||||
#ifndef _WIN32
|
||||
void* m_Attributes;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
CRITICAL_SECTION m_CriticalSection;
|
||||
#else // _WIN32
|
||||
void* m_CriticalSectionPtr; // Pointer to a CRITICAL_SECTION object
|
||||
void* m_Attributes;
|
||||
#endif // else _WIN32
|
||||
};
|
||||
|
||||
|
||||
@ -23,10 +32,10 @@ class cCSLock
|
||||
{
|
||||
cCriticalSection * m_CS;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// Unlike a cCriticalSection, this object should be used from a single thread, therefore access to m_IsLocked is not threadsafe
|
||||
// In Windows, it is an error to call cCriticalSection::Unlock() multiple times if the lock is not held,
|
||||
// therefore we need to check this value whether we are locked or not.
|
||||
bool m_IsLocked;
|
||||
#endif // _DEBUG
|
||||
|
||||
public:
|
||||
cCSLock(cCriticalSection * a_CS);
|
||||
|
@ -14,15 +14,24 @@
|
||||
|
||||
#include "packets/cPacket_DestroyEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cEntity::m_EntityCount = 0;
|
||||
cCriticalSection cEntity::m_CSCount;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntity::cEntity(const double & a_X, const double & a_Y, const double & a_Z)
|
||||
: m_UniqueID( 0 )
|
||||
: m_UniqueID( 0 )
|
||||
, m_Referencers( new cReferenceManager( cReferenceManager::RFMNGR_REFERENCERS ) )
|
||||
, m_References( new cReferenceManager( cReferenceManager::RFMNGR_REFERENCES ) )
|
||||
, m_ChunkX( 0 )
|
||||
, m_ChunkY( 0 )
|
||||
, m_ChunkZ( 0 )
|
||||
, m_ChunkX( 0 )
|
||||
, m_ChunkY( 0 )
|
||||
, m_ChunkZ( 0 )
|
||||
, m_Pos( new Vector3d( a_X, a_Y, a_Z ) )
|
||||
, m_bDirtyPosition( true )
|
||||
, m_Rot( new Vector3f() )
|
||||
@ -32,12 +41,24 @@ cEntity::cEntity(const double & a_X, const double & a_Y, const double & a_Z)
|
||||
, m_World( 0 )
|
||||
, m_bRemovedFromChunk( false )
|
||||
{
|
||||
cCSLock Lock(m_CSCount);
|
||||
m_EntityCount++;
|
||||
m_UniqueID = m_EntityCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cEntity::~cEntity()
|
||||
{
|
||||
LOG("Deleting entity %d at pos {%.2f, %.2f} ~ [%d, %d]; ptr %p",
|
||||
m_UniqueID,
|
||||
m_Pos->x, m_Pos->z,
|
||||
(int)(m_Pos->x / 16), (int)(m_Pos->z / 16),
|
||||
this
|
||||
);
|
||||
|
||||
if( !m_bDestroyed || !m_bRemovedFromChunk )
|
||||
{
|
||||
LOGERROR("ERROR: Entity deallocated without being destroyed %i or unlinked %i", m_bDestroyed, m_bRemovedFromChunk );
|
||||
@ -48,6 +69,10 @@ cEntity::~cEntity()
|
||||
delete m_Rot;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::Initialize( cWorld* a_World )
|
||||
{
|
||||
m_World = a_World;
|
||||
@ -56,111 +81,124 @@ void cEntity::Initialize( cWorld* a_World )
|
||||
MoveToCorrectChunk(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::WrapRotation()
|
||||
{
|
||||
while(m_Rot->x > 180.f) m_Rot->x-=360.f; // Wrap it
|
||||
while(m_Rot->x < -180.f) m_Rot->x+=360.f;
|
||||
while(m_Rot->y > 180.f) m_Rot->y-=360.f;
|
||||
while(m_Rot->y < -180.f) m_Rot->y+=360.f;
|
||||
while (m_Rot->x > 180.f) m_Rot->x-=360.f; // Wrap it
|
||||
while (m_Rot->x < -180.f) m_Rot->x+=360.f;
|
||||
while (m_Rot->y > 180.f) m_Rot->y-=360.f;
|
||||
while (m_Rot->y < -180.f) m_Rot->y+=360.f;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::MoveToCorrectChunk(bool a_bIgnoreOldChunk)
|
||||
{
|
||||
if( !m_World ) return; // Entity needs a world to move to a chunk
|
||||
assert(m_World != NULL); // Entity needs a world to move to a chunk
|
||||
if( !m_World ) return;
|
||||
|
||||
int ChunkX = 0, ChunkY = 0, ChunkZ = 0;
|
||||
cWorld::BlockToChunk( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z, ChunkX, ChunkY, ChunkZ );
|
||||
if(a_bIgnoreOldChunk || m_ChunkX != ChunkX || m_ChunkY != ChunkY || m_ChunkZ != ChunkZ)
|
||||
if (!a_bIgnoreOldChunk && (m_ChunkX == ChunkX) && (m_ChunkY == ChunkY) && (m_ChunkZ == ChunkZ))
|
||||
{
|
||||
LOG("From %i %i To %i %i", m_ChunkX, m_ChunkZ, ChunkX, ChunkZ );
|
||||
cChunk* Chunk = 0;
|
||||
if(!a_bIgnoreOldChunk)
|
||||
Chunk = m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
return;
|
||||
}
|
||||
|
||||
if (!a_bIgnoreOldChunk)
|
||||
{
|
||||
cChunkPtr OldChunk = m_World->GetChunk(m_ChunkX, m_ChunkY, m_ChunkZ);
|
||||
OldChunk->RemoveEntity(this);
|
||||
cPacket_DestroyEntity DestroyEntity( this );
|
||||
OldChunk->Broadcast(DestroyEntity);
|
||||
}
|
||||
|
||||
typedef std::list< cClientHandle* > ClientList;
|
||||
ClientList BeforeClients;
|
||||
if( Chunk )
|
||||
m_ChunkX = ChunkX;
|
||||
m_ChunkY = ChunkY;
|
||||
m_ChunkZ = ChunkZ;
|
||||
cChunkPtr NewChunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if ( NewChunk != NULL )
|
||||
{
|
||||
NewChunk->AddEntity( this );
|
||||
std::auto_ptr<cPacket> SpawnPacket(GetSpawnPacket());
|
||||
if (SpawnPacket.get() != NULL)
|
||||
{
|
||||
Chunk->RemoveEntity( *this );
|
||||
BeforeClients = Chunk->GetClients();
|
||||
}
|
||||
m_ChunkX = ChunkX; m_ChunkY = ChunkY; m_ChunkZ = ChunkZ;
|
||||
cChunk* NewChunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
ClientList AfterClients;
|
||||
if( NewChunk )
|
||||
{
|
||||
NewChunk->AddEntity( *this );
|
||||
AfterClients = NewChunk->GetClients();
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
* I reaalllyyyy don't like this piece of code, but it's needed I guess (maybe there's a way to optimize this)
|
||||
**/
|
||||
// Now compare clients before with after
|
||||
for( ClientList::iterator itr = BeforeClients.begin(); itr != BeforeClients.end(); ++itr )
|
||||
{
|
||||
bool bFound = false;
|
||||
for( ClientList::iterator itr2 = AfterClients.begin(); itr2 != AfterClients.end(); ++itr2 )
|
||||
{
|
||||
if( *itr2 == *itr )
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !bFound ) // Client was in old chunk, but not new, so destroy on that client
|
||||
{
|
||||
cPacket_DestroyEntity DestroyEntity( this );
|
||||
(*itr)->Send( DestroyEntity );
|
||||
}
|
||||
}
|
||||
|
||||
// Now compare clients after with before
|
||||
for( ClientList::iterator itr = AfterClients.begin(); itr != AfterClients.end(); ++itr )
|
||||
{
|
||||
bool bFound = false;
|
||||
for( ClientList::iterator itr2 = BeforeClients.begin(); itr2 != BeforeClients.end(); ++itr2 )
|
||||
{
|
||||
if( *itr2 == *itr )
|
||||
{
|
||||
bFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( !bFound ) // Client is in the new chunk, but not in old, so spawn on the client
|
||||
{
|
||||
SpawnOn( *itr );
|
||||
}
|
||||
NewChunk->Broadcast(SpawnPacket.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::Destroy()
|
||||
{
|
||||
if( !m_bDestroyed )
|
||||
{
|
||||
m_bDestroyed = true;
|
||||
if( !m_bRemovedFromChunk )
|
||||
RemoveFromChunk(0);
|
||||
}
|
||||
}
|
||||
|
||||
void cEntity::RemoveFromChunk( cChunk* a_Chunk )
|
||||
{
|
||||
if( m_World )
|
||||
{
|
||||
cChunk* Chunk = ( a_Chunk ? a_Chunk : (cChunk*)m_World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ ) );
|
||||
if( Chunk )
|
||||
{
|
||||
cPacket_DestroyEntity DestroyEntity( this );
|
||||
Chunk->Broadcast( DestroyEntity );
|
||||
Chunk->RemoveEntity( *this );
|
||||
m_bRemovedFromChunk = true;
|
||||
RemoveFromChunk();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::RemoveFromChunk(void)
|
||||
{
|
||||
if ( m_World == NULL )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cChunkPtr Chunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if ( Chunk != NULL )
|
||||
{
|
||||
cPacket_DestroyEntity DestroyEntity( this );
|
||||
Chunk->Broadcast( DestroyEntity );
|
||||
Chunk->RemoveEntity( this );
|
||||
m_bRemovedFromChunk = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SpawnOn(cClientHandle * a_Client)
|
||||
{
|
||||
std::auto_ptr<cPacket> SpawnPacket(GetSpawnPacket());
|
||||
if (SpawnPacket.get() == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (a_Client == NULL)
|
||||
{
|
||||
cChunkPtr Chunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if ( Chunk != NULL )
|
||||
{
|
||||
Chunk->Broadcast(SpawnPacket.get());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Client->Send(SpawnPacket.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CLASS_DEF_GETCLASS( cEntity );
|
||||
bool cEntity::IsA( const char* a_EntityType )
|
||||
{
|
||||
@ -169,6 +207,10 @@ bool cEntity::IsA( const char* a_EntityType )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Set orientations
|
||||
void cEntity::SetRot( const Vector3f & a_Rot )
|
||||
@ -177,45 +219,39 @@ void cEntity::SetRot( const Vector3f & a_Rot )
|
||||
m_bDirtyOrientation = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetRotation( float a_Rotation )
|
||||
{
|
||||
m_Rot->x = a_Rotation;
|
||||
m_bDirtyOrientation = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetPitch( float a_Pitch )
|
||||
{
|
||||
m_Rot->y = a_Pitch;
|
||||
m_bDirtyOrientation = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetRoll( float a_Roll )
|
||||
{
|
||||
m_Rot->z = a_Roll;
|
||||
m_bDirtyOrientation = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Get orientations
|
||||
const Vector3f & cEntity::GetRot()
|
||||
{
|
||||
return *m_Rot;
|
||||
}
|
||||
|
||||
float cEntity::GetRotation()
|
||||
{
|
||||
return m_Rot->x;
|
||||
}
|
||||
|
||||
float cEntity::GetPitch()
|
||||
{
|
||||
return m_Rot->y;
|
||||
}
|
||||
|
||||
float cEntity::GetRoll()
|
||||
{
|
||||
return m_Rot->z;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Get look vector (this is NOT a rotation!)
|
||||
@ -228,6 +264,10 @@ Vector3f cEntity::GetLookVector()
|
||||
return Look;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Set position
|
||||
void cEntity::SetPosition( const Vector3d & a_Pos )
|
||||
@ -237,6 +277,10 @@ void cEntity::SetPosition( const Vector3d & a_Pos )
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetPosition( const double & a_PosX, const double & a_PosY, const double & a_PosZ )
|
||||
{
|
||||
m_Pos->Set( a_PosX, a_PosY, a_PosZ );
|
||||
@ -244,6 +288,10 @@ void cEntity::SetPosition( const double & a_PosX, const double & a_PosY, const d
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetPosX( const double & a_PosX )
|
||||
{
|
||||
m_Pos->x = a_PosX;
|
||||
@ -251,6 +299,10 @@ void cEntity::SetPosX( const double & a_PosX )
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetPosY( const double & a_PosY )
|
||||
{
|
||||
m_Pos->y = a_PosY;
|
||||
@ -258,6 +310,10 @@ void cEntity::SetPosY( const double & a_PosY )
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::SetPosZ( const double & a_PosZ )
|
||||
{
|
||||
m_Pos->z = a_PosZ;
|
||||
@ -265,27 +321,9 @@ void cEntity::SetPosZ( const double & a_PosZ )
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Get position
|
||||
const Vector3d & cEntity::GetPosition()
|
||||
{
|
||||
return *m_Pos;
|
||||
}
|
||||
|
||||
const double & cEntity::GetPosX()
|
||||
{
|
||||
return m_Pos->x;
|
||||
}
|
||||
|
||||
const double & cEntity::GetPosY()
|
||||
{
|
||||
return m_Pos->y;
|
||||
}
|
||||
|
||||
const double & cEntity::GetPosZ()
|
||||
{
|
||||
return m_Pos->z;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Reference stuffs
|
||||
@ -295,12 +333,24 @@ void cEntity::AddReference( cEntity*& a_EntityPtr )
|
||||
a_EntityPtr->ReferencedBy( a_EntityPtr );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::ReferencedBy( cEntity*& a_EntityPtr )
|
||||
{
|
||||
m_Referencers->AddReference( a_EntityPtr );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cEntity::Dereference( cEntity*& a_EntityPtr )
|
||||
{
|
||||
m_Referencers->Dereference( a_EntityPtr );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "MemoryLeak.h"
|
||||
|
||||
|
||||
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3f.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define CLASS_PROT_ISA() virtual bool IsA( const char* a_EntityType );
|
||||
#define CLASS_PROT_GETCLASS() virtual const char* GetClass();
|
||||
@ -27,12 +36,19 @@
|
||||
CLASS_DEF_ISA( classname, superclass ) \
|
||||
CLASS_DEF_GETCLASS( classname )
|
||||
|
||||
class cChunk;
|
||||
|
||||
|
||||
|
||||
|
||||
class cWorld;
|
||||
class cReferenceManager;
|
||||
class Vector3d;
|
||||
class Vector3f;
|
||||
class cClientHandle;
|
||||
class cPacket;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cEntity //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
@ -52,16 +68,16 @@ public: //tolua_export
|
||||
virtual bool IsA( const char* a_EntityType ); //tolua_export
|
||||
virtual const char* GetClass(); //tolua_export
|
||||
|
||||
cWorld* GetWorld() { return m_World; } //tolua_export
|
||||
cWorld * GetWorld(void) const { return m_World; } //tolua_export
|
||||
|
||||
const Vector3d & GetPosition(); //tolua_export
|
||||
const double & GetPosX(); //tolua_export
|
||||
const double & GetPosY(); //tolua_export
|
||||
const double & GetPosZ(); //tolua_export
|
||||
const Vector3f & GetRot(); //tolua_export
|
||||
float GetRotation(); //tolua_export
|
||||
float GetPitch(); //tolua_export
|
||||
float GetRoll(); //tolua_export
|
||||
const Vector3d & GetPosition(void) const {return *m_Pos; } //tolua_export
|
||||
const double & GetPosX (void) const {return m_Pos->x; } //tolua_export
|
||||
const double & GetPosY (void) const {return m_Pos->y; } //tolua_export
|
||||
const double & GetPosZ (void) const {return m_Pos->z; } //tolua_export
|
||||
const Vector3f & GetRot (void) const {return *m_Rot; } //tolua_export
|
||||
float GetRotation(void) const {return m_Rot->x; } //tolua_export
|
||||
float GetPitch (void) const {return m_Rot->y; } //tolua_export
|
||||
float GetRoll (void) const {return m_Rot->z; } //tolua_export
|
||||
Vector3f GetLookVector(); //tolua_export
|
||||
|
||||
void SetPosX( const double & a_PosX ); //tolua_export
|
||||
@ -74,18 +90,21 @@ public: //tolua_export
|
||||
void SetPitch( float a_Pitch ); //tolua_export
|
||||
void SetRoll( float a_Roll ); //tolua_export
|
||||
|
||||
inline int GetUniqueID() { return m_UniqueID; } //tolua_export
|
||||
inline bool IsDestroyed() { return m_bDestroyed; } //tolua_export
|
||||
inline int GetUniqueID(void) const { return m_UniqueID; } //tolua_export
|
||||
inline bool IsDestroyed(void) const { return m_bDestroyed; } //tolua_export
|
||||
|
||||
void Destroy(); //tolua_export
|
||||
void RemoveFromChunk( cChunk* a_Chunk ); // for internal use in cChunk
|
||||
void RemoveFromChunk(void); // for internal use in cChunk
|
||||
|
||||
virtual void Tick(float a_Dt) = 0; //tolua_export
|
||||
|
||||
virtual void SpawnOn( cClientHandle* a_Target ) = 0; //tolua_export
|
||||
virtual cPacket * GetSpawnPacket(void) const {assert(!"GetSpawnedPacket unimplemented!"); return NULL; }; // _X: Needs to be implemented due to Lua bindings
|
||||
void SpawnOn (cClientHandle * a_Client); // tolua_export
|
||||
|
||||
void WrapRotation();
|
||||
|
||||
protected:
|
||||
|
||||
void SetWorld( cWorld* a_World ) { m_World = a_World; }
|
||||
void MoveToCorrectChunk(bool a_bIgnoreOldChunk = false);
|
||||
|
||||
@ -94,7 +113,9 @@ protected:
|
||||
void ReferencedBy( cEntity*& a_EntityPtr );
|
||||
void Dereference( cEntity*& a_EntityPtr );
|
||||
|
||||
static cCriticalSection m_CSCount;
|
||||
static int m_EntityCount;
|
||||
|
||||
int m_UniqueID;
|
||||
|
||||
cReferenceManager* m_Referencers;
|
||||
@ -111,6 +132,12 @@ protected:
|
||||
bool m_bRemovedFromChunk;
|
||||
|
||||
ENUM_ENTITY_TYPE m_EntityType;
|
||||
private:
|
||||
|
||||
cWorld* m_World;
|
||||
}; //tolua_export
|
||||
|
||||
typedef std::list<cEntity *> cEntityList;
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -154,7 +154,8 @@ int cFile::Write(const void * iBuffer, int iNumBytes)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
|
||||
int res = fwrite(iBuffer, 1, iNumBytes, m_File); // fwrite() returns the portion of Count parameter actually written, so we need to send iNumBytes as Count
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@ -230,3 +231,23 @@ int cFile::GetSize(void) const
|
||||
|
||||
|
||||
|
||||
|
||||
int cFile::ReadRestOfFile(AString & a_Contents)
|
||||
{
|
||||
assert(IsOpen());
|
||||
|
||||
if (!IsOpen())
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
int DataSize = GetSize() - Tell();
|
||||
|
||||
// HACK: This depends on the internal knowledge that AString's data() function returns the internal buffer directly
|
||||
a_Contents.assign(DataSize, '\0');
|
||||
return Read((void *)a_Contents.data(), DataSize);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -51,7 +51,7 @@ public:
|
||||
{
|
||||
fmRead, // Read-only. If the file doesn't exist, object will not be valid
|
||||
fmWrite, // Write-only. If the file already exists, it will be overwritten
|
||||
fmReadWrite, // Read/write. If the file already exists, it will be left intact
|
||||
fmReadWrite, // Read/write. If the file already exists, it will be left intact; writing will overwrite the data from the beginning
|
||||
} ;
|
||||
|
||||
/// Simple constructor - creates an unopened file object, use Open() to open / create a real file
|
||||
@ -83,6 +83,9 @@ public:
|
||||
/// Returns the size of file, in bytes, or -1 for failure; asserts if not open
|
||||
int GetSize(void) const;
|
||||
|
||||
/// Reads the file from current position till EOF into an AString; returns the number of bytes read or -1 for error
|
||||
int ReadRestOfFile(AString & a_Contents);
|
||||
|
||||
private:
|
||||
#ifdef USE_STDIO_FILE
|
||||
FILE * m_File;
|
||||
|
@ -18,8 +18,12 @@
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
cFurnaceEntity::cFurnaceEntity(int a_X, int a_Y, int a_Z, cChunk* a_Chunk)
|
||||
: cBlockEntity( E_BLOCK_FURNACE, a_X, a_Y, a_Z, a_Chunk )
|
||||
|
||||
|
||||
|
||||
|
||||
cFurnaceEntity::cFurnaceEntity(int a_X, int a_Y, int a_Z, cWorld * a_World)
|
||||
: cBlockEntity( E_BLOCK_FURNACE, a_X, a_Y, a_Z, a_World )
|
||||
, m_Items( new cItem[3] )
|
||||
, m_CookingItem( 0 )
|
||||
, m_CookTime( 0 )
|
||||
@ -29,6 +33,10 @@ cFurnaceEntity::cFurnaceEntity(int a_X, int a_Y, int a_Z, cChunk* a_Chunk)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cFurnaceEntity::~cFurnaceEntity()
|
||||
{
|
||||
// Tell window its owner is destroyed
|
||||
@ -44,6 +52,10 @@ cFurnaceEntity::~cFurnaceEntity()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFurnaceEntity::Destroy()
|
||||
{
|
||||
// Drop items
|
||||
@ -51,16 +63,17 @@ void cFurnaceEntity::Destroy()
|
||||
{
|
||||
if( !m_Items[i].IsEmpty() )
|
||||
{
|
||||
cPickup* Pickup = new cPickup( m_PosX*32 + 16, m_PosY*32 + 16, m_PosZ*32 + 16, m_Items[i], 0, 1.f, 0 );
|
||||
Pickup->Initialize( m_Chunk->GetWorld() );
|
||||
cPickup* Pickup = new cPickup( m_PosX * 32 + 16, m_PosY * 32 + 16, m_PosZ * 32 + 16, m_Items[i], 0, 1.f, 0 );
|
||||
Pickup->Initialize(m_World);
|
||||
m_Items[i].Empty();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from tick list
|
||||
GetChunk()->RemoveTickBlockEntity( this );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFurnaceEntity::UsedBy( cPlayer & a_Player )
|
||||
{
|
||||
LOG("Used a furnace");
|
||||
@ -84,6 +97,10 @@ void cFurnaceEntity::UsedBy( cPlayer & a_Player )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFurnaceEntity::Tick( float a_Dt )
|
||||
{
|
||||
//LOG("Time left: %0.1f Time burned: %0.1f Burn time: %0.1f", m_CookTime - m_TimeCooked, m_TimeBurned, m_BurnTime );
|
||||
@ -173,6 +190,10 @@ bool cFurnaceEntity::Tick( float a_Dt )
|
||||
return ((m_CookingItem != 0) || (m_TimeBurned < m_BurnTime)) && m_BurnTime > 0.f; // Keep on ticking, if there's more to cook, or if it's cooking
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cFurnaceEntity::StartCooking()
|
||||
{
|
||||
cFurnaceRecipe* FR = cRoot::Get()->GetFurnaceRecipe();
|
||||
@ -200,7 +221,6 @@ bool cFurnaceEntity::StartCooking()
|
||||
m_TimeCooked = 0.f;
|
||||
m_CookTime = R->CookTime;
|
||||
}
|
||||
GetChunk()->AddTickBlockEntity( this );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -208,13 +228,14 @@ bool cFurnaceEntity::StartCooking()
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFurnaceEntity::ResetCookTimer()
|
||||
{
|
||||
if( m_CookingItem )
|
||||
{
|
||||
delete m_CookingItem;
|
||||
m_CookingItem = 0;
|
||||
}
|
||||
delete m_CookingItem;
|
||||
m_CookingItem = NULL;
|
||||
m_TimeCooked = 0.f;
|
||||
m_CookTime = 0.f;
|
||||
}
|
||||
@ -290,18 +311,21 @@ bool cFurnaceEntity::LoadFromJson( const Json::Value& a_Value )
|
||||
if( !Item.IsEmpty() )
|
||||
{
|
||||
m_CookingItem = new cItem( Item );
|
||||
GetChunk()->AddTickBlockEntity( this );
|
||||
}
|
||||
}
|
||||
|
||||
m_CookTime = (float)a_Value.get("CookTime", 0).asDouble();
|
||||
m_CookTime = (float)a_Value.get("CookTime", 0).asDouble();
|
||||
m_TimeCooked = (float)a_Value.get("TimeCooked", 0).asDouble();
|
||||
m_BurnTime = (float)a_Value.get("BurnTime", 0).asDouble();
|
||||
m_BurnTime = (float)a_Value.get("BurnTime", 0).asDouble();
|
||||
m_TimeBurned = (float)a_Value.get("TimeBurned", 0).asDouble();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cFurnaceEntity::SaveToJson( Json::Value& a_Value )
|
||||
{
|
||||
a_Value["x"] = m_PosX;
|
||||
@ -329,4 +353,8 @@ void cFurnaceEntity::SaveToJson( Json::Value& a_Value )
|
||||
a_Value["TimeCooked"] = m_TimeCooked;
|
||||
a_Value["BurnTime"] = m_BurnTime;
|
||||
a_Value["TimeBurned"] = m_TimeBurned;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,23 +1,33 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cBlockEntity.h"
|
||||
#include "cWindowOwner.h"
|
||||
#include "FileDefine.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
class cChunk;
|
||||
class cClientHandle;
|
||||
class cServer;
|
||||
class cItem;
|
||||
class cNBTData;
|
||||
class cFurnaceEntity : public cBlockEntity, public cWindowOwner
|
||||
|
||||
|
||||
|
||||
|
||||
class cFurnaceEntity :
|
||||
public cBlockEntity,
|
||||
public cWindowOwner
|
||||
{
|
||||
public:
|
||||
cFurnaceEntity(int a_X, int a_Y, int a_Z, cChunk* a_Chunk);
|
||||
cFurnaceEntity(int a_X, int a_Y, int a_Z, cWorld * a_World);
|
||||
virtual ~cFurnaceEntity();
|
||||
virtual void Destroy();
|
||||
|
||||
@ -32,12 +42,18 @@ public:
|
||||
bool StartCooking();
|
||||
|
||||
void ResetCookTimer();
|
||||
|
||||
private:
|
||||
cItem* m_Items;
|
||||
cItem* m_CookingItem;
|
||||
float m_CookTime;
|
||||
float m_TimeCooked;
|
||||
|
||||
float m_BurnTime;
|
||||
float m_TimeBurned;
|
||||
};
|
||||
cItem * m_Items;
|
||||
cItem * m_CookingItem;
|
||||
float m_CookTime;
|
||||
float m_TimeCooked;
|
||||
|
||||
float m_BurnTime;
|
||||
float m_TimeBurned;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@ public: //tolua_export
|
||||
typedef std::map< std::string, bool > CommandMap;
|
||||
const CommandMap & GetCommands() const { return m_Commands; }
|
||||
|
||||
std::string GetColor() const { return m_Color; } //tolua_export
|
||||
const AString & GetColor() const { return m_Color; } //tolua_export
|
||||
|
||||
typedef std::list< cGroup* > GroupList;
|
||||
const GroupList & GetInherits() const { return m_Inherits; }
|
||||
|
@ -67,6 +67,7 @@ cIsThread::cIsThread(const AString & iThreadName) :
|
||||
|
||||
cIsThread::~cIsThread()
|
||||
{
|
||||
mShouldTerminate = true;
|
||||
Wait();
|
||||
}
|
||||
|
||||
@ -81,7 +82,7 @@ bool cIsThread::Start(void)
|
||||
|
||||
// Create the thread suspended, so that the mHandle variable is valid in the thread procedure
|
||||
DWORD ThreadID = 0;
|
||||
HANDLE mHandle = CreateThread(NULL, 0, thrExecute, this, CREATE_SUSPENDED, &ThreadID);
|
||||
mHandle = CreateThread(NULL, 0, thrExecute, this, CREATE_SUSPENDED, &ThreadID);
|
||||
if (mHandle == NULL)
|
||||
{
|
||||
LOGERROR("ERROR: Could not create thread \"%s\", GLE = %d!", mThreadName.c_str(), GetLastError());
|
||||
@ -122,10 +123,12 @@ bool cIsThread::Wait(void)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
LOG("Waiting for thread \"%s\" to terminate.", mThreadName.c_str());
|
||||
// Cannot log, logger may already be stopped:
|
||||
// LOG("Waiting for thread \"%s\" to terminate.", mThreadName.c_str());
|
||||
int res = WaitForSingleObject(mHandle, INFINITE);
|
||||
mHandle = NULL;
|
||||
LOG("Thread \"%s\" %s terminated, GLE = %d", mThreadName.c_str(), (res == WAIT_OBJECT_0) ? "" : "not", GetLastError());
|
||||
// Cannot log, logger may already be stopped:
|
||||
// LOG("Thread \"%s\" %s terminated, GLE = %d", mThreadName.c_str(), (res == WAIT_OBJECT_0) ? "" : "not", GetLastError());
|
||||
return (res == WAIT_OBJECT_0);
|
||||
|
||||
#else // _WIN32
|
||||
|
@ -39,7 +39,6 @@ public:
|
||||
|
||||
private:
|
||||
AString mThreadName;
|
||||
cEvent mEvent; // This event is set when the thread begins executing
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
|
@ -24,11 +24,11 @@ public:
|
||||
m_ItemCount = 0;
|
||||
m_ItemHealth = 0;
|
||||
} //tolua_export
|
||||
bool IsEmpty() //tolua_export
|
||||
bool IsEmpty(void) const //tolua_export
|
||||
{ //tolua_export
|
||||
return (m_ItemID <= 0 || m_ItemCount <= 0);
|
||||
} //tolua_export
|
||||
bool Equals( cItem & a_Item ) //tolua_export
|
||||
bool Equals( cItem & a_Item ) const //tolua_export
|
||||
{ //tolua_export
|
||||
return ( (m_ItemID == a_Item.m_ItemID) && (m_ItemHealth == a_Item.m_ItemHealth) );
|
||||
} //tolua_export
|
||||
|
@ -79,29 +79,28 @@ bool cMonster::IsA( const char* a_EntityType )
|
||||
return cPawn::IsA( a_EntityType );
|
||||
}
|
||||
|
||||
void cMonster::SpawnOn( cClientHandle* a_Target )
|
||||
|
||||
|
||||
|
||||
|
||||
cPacket * cMonster::GetSpawnPacket(void) const
|
||||
{
|
||||
LOG("Spawn monster on client");
|
||||
cPacket_SpawnMob Spawn;
|
||||
Spawn.m_UniqueID = GetUniqueID();
|
||||
Spawn.m_Type = m_MobType;
|
||||
*Spawn.m_Pos = Vector3i((*m_Pos)*32);
|
||||
Spawn.m_Yaw = 0;
|
||||
Spawn.m_Pitch = 0;
|
||||
Spawn.m_MetaDataSize = 1;
|
||||
Spawn.m_MetaData = new char[Spawn.m_MetaDataSize];
|
||||
Spawn.m_MetaData[0] = 0x7f; // not on fire/crouching/riding
|
||||
if( a_Target == 0 )
|
||||
{
|
||||
cChunk* Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
Chunk->Broadcast( Spawn );
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Target->Send( Spawn );
|
||||
}
|
||||
cPacket_SpawnMob * Spawn = new cPacket_SpawnMob;
|
||||
Spawn->m_UniqueID = GetUniqueID();
|
||||
Spawn->m_Type = m_MobType;
|
||||
*Spawn->m_Pos = Vector3i((*m_Pos) * 32);
|
||||
Spawn->m_Yaw = 0;
|
||||
Spawn->m_Pitch = 0;
|
||||
Spawn->m_MetaDataSize = 1;
|
||||
Spawn->m_MetaData = new char[Spawn->m_MetaDataSize];
|
||||
Spawn->m_MetaData[0] = 0x7f; // not on fire/crouching/riding
|
||||
return Spawn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::MoveToPosition( const Vector3f & a_Position )
|
||||
{
|
||||
m_bMovingToDestination = true;
|
||||
@ -118,6 +117,10 @@ bool cMonster::ReachedDestination()
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::Tick(float a_Dt)
|
||||
{
|
||||
cPawn::Tick(a_Dt);
|
||||
@ -201,10 +204,17 @@ void cMonster::Tick(float a_Dt)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::ReplicateMovement()
|
||||
{
|
||||
cChunk* InChunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( !InChunk ) return;
|
||||
cChunkPtr InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if ( !InChunk->IsValid() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(m_bDirtyOrientation && !m_bDirtyPosition)
|
||||
{
|
||||
@ -259,6 +269,10 @@ void cMonster::ReplicateMovement()
|
||||
MoveToCorrectChunk();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::HandlePhysics(float a_Dt)
|
||||
{
|
||||
if( m_bOnGround ) // check if it's still on the ground
|
||||
@ -464,9 +478,13 @@ void cMonster::Attack(float a_Dt) {
|
||||
}
|
||||
|
||||
|
||||
//----Debug
|
||||
|
||||
void cMonster::ListMonsters() {
|
||||
|
||||
|
||||
#if 0
|
||||
// TODO: Implement this debug function inside cWorld instead - the world owns the entities
|
||||
void cMonster::ListMonsters()
|
||||
{
|
||||
|
||||
cWorld::EntityList Entities = cRoot::Get()->GetWorld()->GetEntities();
|
||||
cRoot::Get()->GetWorld()->LockEntities();
|
||||
@ -478,67 +496,80 @@ void cMonster::ListMonsters() {
|
||||
}
|
||||
cRoot::Get()->GetWorld()->UnlockEntities();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//Checks for Players close by and if they are visible return the closest
|
||||
cPlayer *cMonster::FindClosestPlayer()
|
||||
cPlayer * cMonster::FindClosestPlayer(void)
|
||||
{
|
||||
cTracer LineOfSight(cRoot::Get()->GetWorld());
|
||||
cWorld::PlayerList Players = cRoot::Get()->GetWorld()->GetAllPlayers();
|
||||
|
||||
float ClosestDistance = m_SightDistance + 1.f; //Something that is higher than the max :D
|
||||
cPlayer* ClosestPlayer = 0;
|
||||
|
||||
for( cWorld::PlayerList::iterator itr = Players.begin(); itr != Players.end(); ++itr)
|
||||
{
|
||||
Vector3f Pos = (*itr)->GetPosition();
|
||||
float Distance = (Pos - *(m_Pos)).Length();
|
||||
|
||||
if(Distance <= m_SightDistance)
|
||||
{
|
||||
if(!LineOfSight.Trace(*(m_Pos),(Pos - *(m_Pos)),(int)(Pos - *(m_Pos)).Length()))
|
||||
{
|
||||
if(Distance < ClosestDistance)
|
||||
{
|
||||
ClosestDistance = Distance;
|
||||
ClosestPlayer = *itr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ClosestPlayer;
|
||||
return m_World->FindClosestPlayer(m_Pos, m_SightDistance);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::GetMonsterConfig(const char* pm_name)
|
||||
{
|
||||
cRoot::Get()->GetMonsterConfig()->Get()->AssignAttributes(this, pm_name);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::SetAttackRate(int ar)
|
||||
{
|
||||
m_AttackRate = (float)ar;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::SetAttackRange(float ar)
|
||||
{
|
||||
m_AttackRange = ar;
|
||||
}
|
||||
void cMonster::SetAttackDamage(float ad) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::SetAttackDamage(float ad)
|
||||
{
|
||||
m_AttackDamage = ad;
|
||||
}
|
||||
void cMonster::SetSightDistance(float sd) {
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::SetSightDistance(float sd)
|
||||
{
|
||||
m_SightDistance = sd;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::DropItem(ENUM_ITEM_ID a_Item, unsigned int a_Count)
|
||||
{
|
||||
if(a_Count > 0)
|
||||
if (a_Count > 0)
|
||||
{
|
||||
cPickup* Pickup = new cPickup( (int)(m_Pos->x*32), (int)(m_Pos->y*32), (int)(m_Pos->z*32), cItem( a_Item, (char) a_Count ) );
|
||||
cPickup * Pickup = new cPickup( (int)(m_Pos->x * 32), (int)(m_Pos->y * 32), (int)(m_Pos->z * 32), cItem( a_Item, (char) a_Count ) );
|
||||
Pickup->Initialize( GetWorld() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cMonster::RandomDropItem(ENUM_ITEM_ID a_Item, unsigned int a_Min, unsigned int a_Max)
|
||||
{
|
||||
MTRand r1;
|
||||
|
@ -16,9 +16,10 @@ public:
|
||||
|
||||
virtual bool IsA( const char* a_EntityType );
|
||||
|
||||
virtual void SpawnOn( cClientHandle* a_Target );
|
||||
virtual cPacket * GetSpawnPacket(void) const override;
|
||||
|
||||
virtual void Tick(float a_Dt);
|
||||
virtual void Tick(float a_Dt) override;
|
||||
|
||||
virtual void HandlePhysics(float a_Dt);
|
||||
virtual void ReplicateMovement();
|
||||
|
||||
|
134
source/cPawn.cpp
134
source/cPawn.cpp
@ -17,8 +17,16 @@
|
||||
#include "packets/cPacket_EntityStatus.h"
|
||||
#include "packets/cPacket_Metadata.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
CLASS_DEFINITION( cPawn, cEntity )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPawn::cPawn()
|
||||
: cEntity( 0, 0, 0 )
|
||||
, m_LastPosX( 0.0 )
|
||||
@ -34,16 +42,28 @@ cPawn::cPawn()
|
||||
SetMaxFoodLevel(125);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPawn::~cPawn()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::Heal( int a_Health )
|
||||
{
|
||||
(void)a_Health;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::TakeDamage( int a_Damage, cEntity* a_Instigator )
|
||||
{
|
||||
TakeDamageInfo TDI;
|
||||
@ -51,8 +71,6 @@ void cPawn::TakeDamage( int a_Damage, cEntity* a_Instigator )
|
||||
TDI.Instigator = a_Instigator;
|
||||
cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_TAKE_DAMAGE, 2, this, &TDI );
|
||||
|
||||
|
||||
|
||||
if( TDI.Damage == 0 ) return;
|
||||
if( m_Health <= 0 ) return; // Can't take damage if already dead
|
||||
|
||||
@ -62,14 +80,19 @@ void cPawn::TakeDamage( int a_Damage, cEntity* a_Instigator )
|
||||
cPacket_EntityStatus Status;
|
||||
Status.m_UniqueID = GetUniqueID();
|
||||
Status.m_Status = cPacket_EntityStatus::STATUS_TAKEDAMAGE;
|
||||
cChunk* Chunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
Chunk->Broadcast( Status );
|
||||
cChunkPtr Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
Chunk->Broadcast( Status );
|
||||
|
||||
if( m_Health <= 0 )
|
||||
if (m_Health <= 0)
|
||||
{
|
||||
KilledBy( TDI.Instigator );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::KilledBy( cEntity* a_Killer )
|
||||
{
|
||||
m_Health = 0;
|
||||
@ -82,16 +105,23 @@ void cPawn::KilledBy( cEntity* a_Killer )
|
||||
cPacket_EntityStatus Status;
|
||||
Status.m_UniqueID = GetUniqueID();
|
||||
Status.m_Status = cPacket_EntityStatus::STATUS_DIE;
|
||||
cChunk* Chunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
Chunk->Broadcast( Status ); // Die
|
||||
cChunkPtr Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
Chunk->Broadcast( Status ); // Die
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::TeleportTo( cEntity* a_Entity )
|
||||
{
|
||||
TeleportTo( a_Entity->GetPosX(), a_Entity->GetPosY(), a_Entity->GetPosZ() );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::TeleportTo( const double & a_PosX, const double & a_PosY, const double & a_PosZ )
|
||||
{
|
||||
SetPosition( a_PosX, a_PosY, a_PosZ );
|
||||
@ -99,31 +129,41 @@ void cPawn::TeleportTo( const double & a_PosX, const double & a_PosY, const doub
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
|
||||
cRoot::Get()->GetServer()->Broadcast( TeleportEntity );
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::Tick(float a_Dt)
|
||||
{
|
||||
CheckMetaDataBurn(); //Check to see if pawn should burn based on block they are on
|
||||
|
||||
if(GetMetaData() == BURNING)
|
||||
if (GetMetaData() == BURNING)
|
||||
{
|
||||
InStateBurning(a_Dt);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::SetMetaData(MetaData a_MetaData)
|
||||
{
|
||||
cChunk* InChunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
cChunkPtr InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
|
||||
if(InChunk)
|
||||
{ //Broadcast new status to clients in the chunk
|
||||
m_MetaData = a_MetaData;
|
||||
cPacket_Metadata md(a_MetaData, GetUniqueID());
|
||||
InChunk->Broadcast(md);
|
||||
}
|
||||
//Broadcast new status to clients in the chunk
|
||||
m_MetaData = a_MetaData;
|
||||
cPacket_Metadata md(a_MetaData, GetUniqueID());
|
||||
InChunk->Broadcast(md);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//----Change Entity MetaData
|
||||
void cPawn::CheckMetaDataBurn()
|
||||
{
|
||||
@ -131,49 +171,67 @@ void cPawn::CheckMetaDataBurn()
|
||||
char BlockAbove = GetWorld()->GetBlock((int) m_Pos->x, (int) m_Pos->y + 1, (int) m_Pos->z);
|
||||
char BlockBelow = GetWorld()->GetBlock((int) m_Pos->x, (int) m_Pos->y - 1, (int) m_Pos->z);
|
||||
|
||||
if(GetMetaData() == BURNING
|
||||
&& (IsBlockWater(Block)
|
||||
|| IsBlockWater(BlockAbove)
|
||||
|| IsBlockWater(BlockBelow)))
|
||||
if (
|
||||
(GetMetaData() == BURNING) &&
|
||||
(IsBlockWater(Block) || IsBlockWater(BlockAbove) || IsBlockWater(BlockBelow))
|
||||
)
|
||||
{
|
||||
SetMetaData(NORMAL);
|
||||
}else if(m_bBurnable && GetMetaData() != BURNING
|
||||
&& (IsBlockLava(Block) || Block == E_BLOCK_FIRE
|
||||
|| IsBlockLava(BlockAbove) || BlockAbove == E_BLOCK_FIRE
|
||||
|| IsBlockLava(BlockBelow) || BlockBelow == E_BLOCK_FIRE)) {
|
||||
}
|
||||
else if (
|
||||
m_bBurnable &&
|
||||
(GetMetaData() != BURNING) &&
|
||||
(
|
||||
IsBlockLava(Block) || (Block == E_BLOCK_FIRE) ||
|
||||
IsBlockLava(BlockAbove) || (BlockAbove == E_BLOCK_FIRE) ||
|
||||
IsBlockLava(BlockBelow) || (BlockBelow == E_BLOCK_FIRE)
|
||||
)
|
||||
)
|
||||
{
|
||||
SetMetaData(BURNING);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//What to do if On fire
|
||||
void cPawn::InStateBurning(float a_Dt)
|
||||
{
|
||||
m_FireDamageInterval += a_Dt;
|
||||
char Block = GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z );
|
||||
char BlockAbove = GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y + 1, (int)m_Pos->z );
|
||||
if(m_FireDamageInterval > 800) {
|
||||
if (m_FireDamageInterval > 800)
|
||||
{
|
||||
|
||||
m_FireDamageInterval = 0;
|
||||
TakeDamage(1, this);
|
||||
|
||||
m_BurnPeriod++;
|
||||
if(IsBlockLava(Block) || Block == E_BLOCK_FIRE
|
||||
|| IsBlockLava(BlockAbove) || BlockAbove == E_BLOCK_FIRE) {
|
||||
if (IsBlockLava(Block) || Block == E_BLOCK_FIRE
|
||||
|| IsBlockLava(BlockAbove) || BlockAbove == E_BLOCK_FIRE)
|
||||
{
|
||||
m_BurnPeriod = 0;
|
||||
TakeDamage(6, this);
|
||||
}else{
|
||||
}
|
||||
else
|
||||
{
|
||||
TakeDamage(1, this);
|
||||
}
|
||||
|
||||
if(m_BurnPeriod > 7) {
|
||||
if (m_BurnPeriod > 7)
|
||||
{
|
||||
SetMetaData(NORMAL);
|
||||
m_BurnPeriod = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::SetMaxHealth(short a_MaxHealth)
|
||||
{
|
||||
this->m_MaxHealth = a_MaxHealth;
|
||||
@ -182,6 +240,10 @@ void cPawn::SetMaxHealth(short a_MaxHealth)
|
||||
m_Health = a_MaxHealth;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPawn::SetMaxFoodLevel(short a_MaxFoodLevel)
|
||||
{
|
||||
m_MaxFoodLevel = a_MaxFoodLevel;
|
||||
@ -189,3 +251,7 @@ void cPawn::SetMaxFoodLevel(short a_MaxFoodLevel)
|
||||
//Reset food level
|
||||
m_FoodLevel = a_MaxFoodLevel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cEntity.h"
|
||||
#include "math.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
struct TakeDamageInfo //tolua_export
|
||||
{ //tolua_export
|
||||
@ -8,6 +13,10 @@ struct TakeDamageInfo //tolua_export
|
||||
cEntity* Instigator; //tolua_export
|
||||
}; //tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPawn : public cEntity //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
@ -19,7 +28,7 @@ public:
|
||||
virtual void TeleportTo( cEntity* a_Entity ); //tolua_export
|
||||
virtual void TeleportTo( const double & a_PosX, const double & a_PosY, const double & a_PosZ ); //tolua_export
|
||||
|
||||
virtual void Tick(float a_Dt);
|
||||
virtual void Tick(float a_Dt) override;
|
||||
|
||||
void Heal( int a_Health ); //tolua_export
|
||||
virtual void TakeDamage( int a_Damage, cEntity* a_Instigator ); //tolua_export
|
||||
@ -39,8 +48,8 @@ public:
|
||||
virtual short GetMaxHealth() { return m_MaxHealth; }
|
||||
|
||||
//virtual void SetMaxFood(short a_MaxFood);
|
||||
virtual short GetMaxFood() { return m_MaxFoodLevel/6; }
|
||||
virtual short GetFood() { return m_FoodLevel/6; }
|
||||
virtual short GetMaxFood() { return m_MaxFoodLevel / 6; }
|
||||
virtual short GetFood() { return m_FoodLevel / 6; }
|
||||
|
||||
//virtual void SetMaxFoodSaturation(float a_MaxFoodSaturation);
|
||||
virtual float GetMaxFoodSaturation() { return fmod(m_MaxFoodLevel, 6.f); }
|
||||
@ -50,6 +59,7 @@ public:
|
||||
virtual short GetMaxFoodLevel() { return m_MaxFoodLevel; }
|
||||
|
||||
protected:
|
||||
|
||||
short m_Health;
|
||||
short m_FoodLevel;
|
||||
short m_MaxHealth;
|
||||
@ -57,7 +67,7 @@ protected:
|
||||
|
||||
bool m_bBurnable;
|
||||
|
||||
MetaData m_MetaData;
|
||||
MetaData m_MetaData;
|
||||
|
||||
double m_LastPosX, m_LastPosY, m_LastPosZ;
|
||||
float m_TimeLastTeleportPacket;
|
||||
@ -66,3 +76,7 @@ protected:
|
||||
float m_BurnPeriod;
|
||||
|
||||
}; //tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -54,23 +54,22 @@ cPickup::cPickup(int a_X, int a_Y, int a_Z, const cItem & a_Item, float a_SpeedX
|
||||
//LOG("New pickup: ID(%i) Amount(%i) Health(%i)", m_Item.m_ItemID, m_Item.m_ItemCount, m_Item.m_ItemHealth );
|
||||
|
||||
// Spawn it on clients
|
||||
cPacket_PickupSpawn PickupSpawn;
|
||||
PickupSpawn.m_UniqueID = m_UniqueID;
|
||||
PickupSpawn.m_Item = (short)m_Item->m_ItemID;
|
||||
PickupSpawn.m_Count = m_Item->m_ItemCount;
|
||||
PickupSpawn.m_Health = m_Item->m_ItemHealth;
|
||||
PickupSpawn.m_PosX = a_X;
|
||||
PickupSpawn.m_PosY = a_Y;
|
||||
PickupSpawn.m_PosZ = a_Z;
|
||||
PickupSpawn.m_Rotation = (char)(m_Speed->x * 8);
|
||||
PickupSpawn.m_Pitch = (char)(m_Speed->y * 8);
|
||||
PickupSpawn.m_Roll = (char)(m_Speed->z * 8);
|
||||
if(PickupSpawn.m_Item != E_ITEM_EMPTY)
|
||||
cRoot::Get()->GetServer()->Broadcast( PickupSpawn );
|
||||
if (!a_Item.IsEmpty())
|
||||
{
|
||||
std::auto_ptr<cPacket> PickupSpawn(GetSpawnPacket());
|
||||
if (PickupSpawn.get() != NULL)
|
||||
{
|
||||
cRoot::Get()->GetServer()->Broadcast( PickupSpawn.get() );
|
||||
}
|
||||
}
|
||||
|
||||
m_EntityType = E_PICKUP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPickup::cPickup(cPacket_PickupSpawn* a_PickupSpawnPacket)
|
||||
: cEntity( ((double)a_PickupSpawnPacket->m_PosX)/32, ((double)a_PickupSpawnPacket->m_PosY)/32, ((double)a_PickupSpawnPacket->m_PosZ)/32 )
|
||||
, m_Speed( new Vector3f() )
|
||||
@ -93,29 +92,43 @@ cPickup::cPickup(cPacket_PickupSpawn* a_PickupSpawnPacket)
|
||||
m_Speed->z = (float)(a_PickupSpawnPacket->m_Roll) / 8;
|
||||
|
||||
// Spawn it on clients
|
||||
if(a_PickupSpawnPacket->m_Item != E_ITEM_EMPTY)
|
||||
if (a_PickupSpawnPacket->m_Item != E_ITEM_EMPTY)
|
||||
{
|
||||
cRoot::Get()->GetServer()->Broadcast( *a_PickupSpawnPacket );
|
||||
}
|
||||
|
||||
m_EntityType = E_PICKUP;
|
||||
}
|
||||
|
||||
void cPickup::SpawnOn( cClientHandle* a_Target )
|
||||
|
||||
|
||||
|
||||
|
||||
cPacket * cPickup::GetSpawnPacket(void) const
|
||||
{
|
||||
cPacket_PickupSpawn PickupSpawn;
|
||||
PickupSpawn.m_UniqueID = m_UniqueID;
|
||||
PickupSpawn.m_Item = (short)m_Item->m_ItemID;
|
||||
PickupSpawn.m_Count = m_Item->m_ItemCount;
|
||||
PickupSpawn.m_Health = m_Item->m_ItemHealth;
|
||||
PickupSpawn.m_PosX = (int)(m_Pos->x * 32);
|
||||
PickupSpawn.m_PosY = (int)(m_Pos->y * 32);
|
||||
PickupSpawn.m_PosZ = (int)(m_Pos->z * 32);
|
||||
PickupSpawn.m_Rotation = (char)(m_Speed->x * 8);
|
||||
PickupSpawn.m_Pitch = (char)(m_Speed->y * 8);
|
||||
PickupSpawn.m_Roll = (char)(m_Speed->z * 8);
|
||||
if(PickupSpawn.m_Item != E_ITEM_EMPTY)
|
||||
a_Target->Send( PickupSpawn );
|
||||
if (m_Item->IsEmpty())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cPacket_PickupSpawn * PickupSpawn = new cPacket_PickupSpawn;
|
||||
PickupSpawn->m_UniqueID = m_UniqueID;
|
||||
PickupSpawn->m_Item = (short)m_Item->m_ItemID;
|
||||
PickupSpawn->m_Count = m_Item->m_ItemCount;
|
||||
PickupSpawn->m_Health = m_Item->m_ItemHealth;
|
||||
PickupSpawn->m_PosX = (int) (m_Pos->x * 32);
|
||||
PickupSpawn->m_PosY = (int) (m_Pos->y * 32);
|
||||
PickupSpawn->m_PosZ = (int) (m_Pos->z * 32);
|
||||
PickupSpawn->m_Rotation = (char)(m_Speed->x * 8);
|
||||
PickupSpawn->m_Pitch = (char)(m_Speed->y * 8);
|
||||
PickupSpawn->m_Roll = (char)(m_Speed->z * 8);
|
||||
return PickupSpawn;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPickup::Tick(float a_Dt)
|
||||
{
|
||||
m_Timer += a_Dt;
|
||||
@ -142,28 +155,28 @@ void cPickup::Tick(float a_Dt)
|
||||
}
|
||||
|
||||
if(!m_bCollected)
|
||||
{
|
||||
HandlePhysics( a_Dt );
|
||||
}
|
||||
|
||||
if( !m_bReplicated || m_bDirtyPosition )
|
||||
{
|
||||
MoveToCorrectChunk();
|
||||
m_bReplicated = true;
|
||||
m_bDirtyPosition = false;
|
||||
cChunk* Chunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
{
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
Chunk->Broadcast( TeleportEntity );
|
||||
}
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ )->Broadcast( &TeleportEntity );
|
||||
}
|
||||
|
||||
//printf("YSpeed: %f, OnGround: %i\n", m_SpeedY, m_bOnGround );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPickup::HandlePhysics(float a_Dt)
|
||||
{
|
||||
m_ResultingSpeed->Set(0.f, 0.f, 0.f);
|
||||
cWorld* World = GetWorld();
|
||||
cWorld * World = GetWorld();
|
||||
|
||||
if( m_bOnGround ) // check if it's still on the ground
|
||||
{
|
||||
@ -273,14 +286,14 @@ void cPickup::HandlePhysics(float a_Dt)
|
||||
*m_Pos += *m_ResultingSpeed * a_Dt;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Usable for debugging
|
||||
//SetPosition(m_Pos->x, m_Pos->y, m_Pos->z);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPickup::CollectedBy( cPlayer* a_Dest )
|
||||
{
|
||||
if(m_bCollected) return false; // It's already collected!
|
||||
@ -303,3 +316,7 @@ bool cPickup::CollectedBy( cPlayer* a_Dest )
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,38 +1,53 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cEntity.h"
|
||||
|
||||
|
||||
|
||||
|
||||
class cPacket_PickupSpawn;
|
||||
class cPlayer;
|
||||
class cItem;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPickup : public cEntity //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
CLASS_PROTOTYPE();
|
||||
|
||||
cPickup(int a_X, int a_Y, int a_Z, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); //tolua_export
|
||||
cPickup(cPacket_PickupSpawn* a_PickupSpawnPacket); //tolua_export
|
||||
cPickup(cPacket_PickupSpawn * a_PickupSpawnPacket); //tolua_export
|
||||
~cPickup(); //tolua_export
|
||||
|
||||
cItem* GetItem() { return m_Item; } //tolua_export
|
||||
cItem * GetItem() { return m_Item; } //tolua_export
|
||||
|
||||
void SpawnOn( cClientHandle* a_Target );
|
||||
virtual cPacket * GetSpawnPacket(void) const override;
|
||||
|
||||
virtual bool CollectedBy( cPlayer* a_Dest ); //tolua_export
|
||||
|
||||
void Tick(float a_Dt);
|
||||
void HandlePhysics(float a_Dt);
|
||||
|
||||
private:
|
||||
Vector3f* m_Speed;
|
||||
Vector3f* m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
|
||||
|
||||
Vector3f* m_WaterSpeed;
|
||||
bool m_bOnGround;
|
||||
bool m_bReplicated;
|
||||
Vector3f * m_Speed;
|
||||
Vector3f * m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;)
|
||||
|
||||
Vector3f * m_WaterSpeed;
|
||||
bool m_bOnGround;
|
||||
bool m_bReplicated;
|
||||
|
||||
float m_Timer;
|
||||
|
||||
cItem* m_Item;
|
||||
|
||||
bool m_bCollected;
|
||||
};//tolua_export
|
||||
}; //tolua_export
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -20,8 +20,6 @@ extern bool g_BlockPistonBreakable[];
|
||||
case 2: (z)-=(amount); break; case 3: (z)+=(amount); break;\
|
||||
case 4: (x)-=(amount); break; case 5: (x)+=(amount); break; }
|
||||
|
||||
#define FAST_FLOOR( x ) ( (x) < 0 ? ((int)x)-1 : ((int)x) )
|
||||
|
||||
|
||||
|
||||
|
||||
@ -49,6 +47,10 @@ unsigned short cPiston::FirstPassthroughBlock( int pistonX, int pistonY, int pis
|
||||
return 9001;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPiston::ExtendPiston( int pistx, int pisty, int pistz ) {
|
||||
char pistonBlock = m_World->GetBlock( pistx, pisty, pistz );
|
||||
char pistonMeta = m_World->GetBlockMeta( pistx, pisty, pistz );
|
||||
@ -87,7 +89,7 @@ void cPiston::ExtendPiston( int pistx, int pisty, int pistz ) {
|
||||
Action.m_Byte2 = pistonMeta;
|
||||
|
||||
|
||||
cChunk* Chunk = m_World->GetChunk( FAST_FLOOR(pistx/16), FAST_FLOOR(pisty/16), FAST_FLOOR(pistz/16) );
|
||||
cChunkPtr Chunk = m_World->GetChunkOfBlock(pistx, pisty, pistz);
|
||||
Chunk->Broadcast( Action );
|
||||
m_World->FastSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta | 8 );
|
||||
|
||||
@ -109,33 +111,53 @@ void cPiston::ExtendPiston( int pistx, int pisty, int pistz ) {
|
||||
|
||||
}
|
||||
|
||||
void cPiston::RetractPiston( int pistx, int pisty, int pistz ) {
|
||||
|
||||
|
||||
|
||||
|
||||
void cPiston::RetractPiston( int pistx, int pisty, int pistz )
|
||||
{
|
||||
char pistonBlock = m_World->GetBlock( pistx, pisty, pistz );
|
||||
char pistonMeta = m_World->GetBlockMeta( pistx, pisty, pistz );
|
||||
if (pistonMeta > 6) {// only retract if piston is not already retracted
|
||||
//send blockaction packet
|
||||
cPacket_BlockAction Action;
|
||||
Action.m_PosX = (int)pistx;
|
||||
Action.m_PosY = (short)pisty;
|
||||
Action.m_PosZ = (int)pistz;
|
||||
Action.m_Byte1 = 1;
|
||||
Action.m_Byte2 = pistonMeta & ~(8);
|
||||
cChunk* Chunk = m_World->GetChunk( FAST_FLOOR(pistx/16), FAST_FLOOR(pisty/16), FAST_FLOOR(pistz/16) );
|
||||
Chunk->Broadcast( Action );
|
||||
m_World->FastSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8) );
|
||||
|
||||
AddDir( pistx, pisty, pistz, pistonMeta & 7, 1 )
|
||||
if( m_World->GetBlock( pistx, pisty, pistz ) == E_BLOCK_PISTON_EXTENSION ) {
|
||||
if( pistonBlock == E_BLOCK_STICKY_PISTON ) {
|
||||
int tempx = pistx, tempy = pisty, tempz = pistz;
|
||||
AddDir( tempx, tempy, tempz, pistonMeta&7, 1 )
|
||||
char tempblock = m_World->GetBlock( tempx, tempy, tempz );
|
||||
if(tempblock == E_BLOCK_OBSIDIAN || tempblock == E_BLOCK_BEDROCK || tempblock == E_BLOCK_PISTON_EXTENSION) {return;}
|
||||
m_World->SetBlock( pistx, pisty, pistz, tempblock, m_World->GetBlockMeta( tempx, tempy, tempz ) );
|
||||
m_World->SetBlock( tempx, tempy, tempz, E_BLOCK_AIR, 0 );
|
||||
}else{
|
||||
m_World->SetBlock( pistx, pisty, pistz, E_BLOCK_AIR, 0 );
|
||||
if (pistonMeta <= 6) // only retract if piston is not already retracted
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//send blockaction packet
|
||||
cPacket_BlockAction Action;
|
||||
Action.m_PosX = (int)pistx;
|
||||
Action.m_PosY = (short)pisty;
|
||||
Action.m_PosZ = (int)pistz;
|
||||
Action.m_Byte1 = 1;
|
||||
Action.m_Byte2 = pistonMeta & ~(8);
|
||||
cChunkPtr Chunk = m_World->GetChunkOfBlock(pistx, pisty, pistz);
|
||||
Chunk->Broadcast( Action );
|
||||
m_World->FastSetBlock( pistx, pisty, pistz, pistonBlock, pistonMeta & ~(8) );
|
||||
|
||||
AddDir( pistx, pisty, pistz, pistonMeta & 7, 1 )
|
||||
if ( m_World->GetBlock( pistx, pisty, pistz ) == E_BLOCK_PISTON_EXTENSION )
|
||||
{
|
||||
if ( pistonBlock == E_BLOCK_STICKY_PISTON )
|
||||
{
|
||||
int tempx = pistx, tempy = pisty, tempz = pistz;
|
||||
AddDir( tempx, tempy, tempz, pistonMeta & 7, 1 )
|
||||
char tempblock = m_World->GetBlock( tempx, tempy, tempz );
|
||||
if (
|
||||
(tempblock == E_BLOCK_OBSIDIAN) ||
|
||||
(tempblock == E_BLOCK_BEDROCK) ||
|
||||
(tempblock == E_BLOCK_PISTON_EXTENSION)
|
||||
)
|
||||
{
|
||||
// These cannot be moved by the sticky piston, bail out
|
||||
return;
|
||||
}
|
||||
m_World->SetBlock( pistx, pisty, pistz, tempblock, m_World->GetBlockMeta( tempx, tempy, tempz ) );
|
||||
m_World->SetBlock( tempx, tempy, tempz, E_BLOCK_AIR, 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_World->SetBlock( pistx, pisty, pistz, E_BLOCK_AIR, 0 );
|
||||
}
|
||||
}
|
||||
}
|
@ -20,8 +20,8 @@ public:
|
||||
|
||||
static char RotationPitchToMetaData( float a_Rotation, float a_Pitch )
|
||||
{
|
||||
std::printf("pre:a_Rotation %f \n",a_Rotation);
|
||||
std::printf("a_Pitch %f \n",a_Pitch);
|
||||
LOG("pre:a_Rotation %f \n",a_Rotation);
|
||||
LOG("a_Pitch %f \n",a_Pitch);
|
||||
|
||||
if (a_Pitch >= 50.f ){
|
||||
return 0x1;
|
||||
@ -34,13 +34,13 @@ public:
|
||||
|
||||
if( a_Rotation > 360.f ) a_Rotation -= 360.f;
|
||||
if( a_Rotation >= 0.f && a_Rotation < 90.f )
|
||||
{ std::printf("1111\n");return 0x4;}
|
||||
{ LOG("1111\n");return 0x4;}
|
||||
else if( a_Rotation >= 180 && a_Rotation < 270 )
|
||||
{ std::printf("2222\n");return 0x5;}
|
||||
{ LOG("2222\n");return 0x5;}
|
||||
else if( a_Rotation >= 90 && a_Rotation < 180 )
|
||||
{ std::printf("3333\n");return 0x2;}
|
||||
{ LOG("3333\n");return 0x2;}
|
||||
else
|
||||
{ std::printf("4444\n");return 0x3;}
|
||||
{ LOG("4444\n");return 0x3;}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -126,39 +126,39 @@ cPlayer::~cPlayer(void)
|
||||
delete m_CreativeInventory;
|
||||
}
|
||||
delete m_pState;
|
||||
GetWorld()->RemovePlayer( this ); // TODO - Remove from correct world? Or get rid of this?
|
||||
m_World->RemovePlayer( this );
|
||||
}
|
||||
|
||||
|
||||
|
||||
void cPlayer::SpawnOn( cClientHandle* a_Target )
|
||||
|
||||
|
||||
cPacket * cPlayer::GetSpawnPacket(void) const
|
||||
{
|
||||
if( a_Target == m_ClientHandle || !m_bVisible ) return;
|
||||
LOG("cPlayer::SpawnOn -> Sending %s to %s", m_pState->PlayerName.c_str(), (a_Target) ? a_Target->GetUsername().c_str() : "Everybody" );
|
||||
cPacket_NamedEntitySpawn SpawnPacket;
|
||||
SpawnPacket.m_UniqueID = m_UniqueID;
|
||||
SpawnPacket.m_PlayerName = m_pState->PlayerName;
|
||||
SpawnPacket.m_PosX = (int)(m_Pos->x * 32);
|
||||
SpawnPacket.m_PosY = (int)(m_Pos->y * 32);
|
||||
SpawnPacket.m_PosZ = (int)(m_Pos->z * 32);
|
||||
SpawnPacket.m_Rotation = (char)((m_Rot->x/360.f)*256);
|
||||
SpawnPacket.m_Pitch = (char)((m_Rot->y/360.f)*256);
|
||||
SpawnPacket.m_CurrentItem = (short)m_Inventory->GetEquippedItem().m_ItemID;
|
||||
if( a_Target == 0 )
|
||||
if (!m_bVisible )
|
||||
{
|
||||
cChunk* Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
Chunk->Broadcast( SpawnPacket, m_ClientHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Target->Send( SpawnPacket );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cPacket_NamedEntitySpawn * SpawnPacket = new cPacket_NamedEntitySpawn;
|
||||
SpawnPacket->m_UniqueID = m_UniqueID;
|
||||
SpawnPacket->m_PlayerName = m_pState->PlayerName;
|
||||
SpawnPacket->m_PosX = (int)(m_Pos->x * 32);
|
||||
SpawnPacket->m_PosY = (int)(m_Pos->y * 32);
|
||||
SpawnPacket->m_PosZ = (int)(m_Pos->z * 32);
|
||||
SpawnPacket->m_Rotation = (char)((m_Rot->x / 360.f) * 256);
|
||||
SpawnPacket->m_Pitch = (char)((m_Rot->y / 360.f) * 256);
|
||||
SpawnPacket->m_CurrentItem = (short)m_Inventory->GetEquippedItem().m_ItemID;
|
||||
return SpawnPacket;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::Tick(float a_Dt)
|
||||
{
|
||||
cChunk* InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if ( !InChunk ) return;
|
||||
cChunkPtr InChunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
|
||||
cPawn::Tick(a_Dt);
|
||||
|
||||
@ -168,16 +168,18 @@ void cPlayer::Tick(float a_Dt)
|
||||
InChunk->Broadcast( EntityLook, m_ClientHandle );
|
||||
m_bDirtyOrientation = false;
|
||||
}
|
||||
else if(m_bDirtyPosition )
|
||||
else if (m_bDirtyPosition )
|
||||
{
|
||||
cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_PLAYER_MOVE, 1, this );
|
||||
|
||||
float DiffX = (float)(GetPosX() - m_LastPosX );
|
||||
float DiffY = (float)(GetPosY() - m_LastPosY );
|
||||
float DiffZ = (float)(GetPosZ() - m_LastPosZ );
|
||||
float SqrDist = DiffX*DiffX + DiffY*DiffY + DiffZ*DiffZ;
|
||||
if( SqrDist > 4*4 // 4 blocks is max Relative Move
|
||||
|| cWorld::GetTime() - m_TimeLastTeleportPacket > 2 ) // Send an absolute position every 2 seconds
|
||||
float SqrDist = DiffX * DiffX + DiffY * DiffY + DiffZ * DiffZ;
|
||||
if (
|
||||
(SqrDist > 4 * 4) || // 4 blocks is max Relative Move
|
||||
(cWorld::GetTime() - m_TimeLastTeleportPacket > 2 ) // Send an absolute position every 2 seconds
|
||||
)
|
||||
{
|
||||
//LOG("Teleported %f", sqrtf(SqrDist) );
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
@ -216,49 +218,23 @@ void cPlayer::Tick(float a_Dt)
|
||||
|
||||
if( m_Health > 0 ) // make sure player is alive
|
||||
{
|
||||
if( cWorld::GetTime() - m_TimeLastPickupCheck > 0.5f ) // Each 0.5 second, check for pickups
|
||||
{
|
||||
m_TimeLastPickupCheck = cWorld::GetTime();
|
||||
// and also check if near a pickup
|
||||
// TODO: Don't only check in current chunks, but also close chunks (chunks within range)
|
||||
cChunk* Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
Chunk->LockEntities();
|
||||
cWorld::EntityList Entities = Chunk->GetEntities();
|
||||
for( cWorld::EntityList::iterator itr = Entities.begin(); itr != Entities.end();++itr)
|
||||
{
|
||||
if( (*itr)->GetEntityType() != cEntity::E_PICKUP ) continue; // Only pickups
|
||||
float DiffX = (float)((*itr)->GetPosX() - GetPosX() );
|
||||
float DiffY = (float)((*itr)->GetPosY() - GetPosY() );
|
||||
float DiffZ = (float)((*itr)->GetPosZ() - GetPosZ() );
|
||||
float SqrDist = DiffX*DiffX + DiffY*DiffY + DiffZ*DiffZ;
|
||||
if(SqrDist < 1.5f*1.5f) // 1.5 block
|
||||
{
|
||||
cPickup* Pickup = reinterpret_cast<cPickup*>(*itr);
|
||||
Pickup->CollectedBy( this );
|
||||
}
|
||||
}
|
||||
Chunk->UnlockEntities();
|
||||
}
|
||||
// TODO: Don't only check in current chunks, but also close chunks (chunks within range)
|
||||
GetWorld()->GetChunk(m_ChunkX, m_ChunkY, m_ChunkZ)->CollectPickupsByPlayer(this);
|
||||
}
|
||||
|
||||
cTimer t1;
|
||||
// Send Player List (Once per m_LastPlayerListTime/1000 ms)
|
||||
if (m_LastPlayerListTime + cPlayer::PLAYER_LIST_TIME_MS <= t1.GetNowTime())
|
||||
{
|
||||
cWorld::PlayerList PlayerList = cRoot::Get()->GetWorld()->GetAllPlayers();
|
||||
for( cWorld::PlayerList::iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr)
|
||||
{
|
||||
if ((*itr) && (*itr)->GetClientHandle() && !((*itr)->GetClientHandle()->IsDestroyed()))
|
||||
{
|
||||
cPacket_PlayerListItem PlayerListItem(GetColor() + m_pState->PlayerName, true, GetClientHandle()->GetPing());
|
||||
(*itr)->GetClientHandle()->Send( PlayerListItem );
|
||||
}
|
||||
}
|
||||
m_World->SendPlayerList(this);
|
||||
m_LastPlayerListTime = t1.GetNowTime();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetTouchGround( bool a_bTouchGround )
|
||||
{
|
||||
m_bTouchGround = a_bTouchGround;
|
||||
@ -439,30 +415,36 @@ void cPlayer::CloseWindow(char a_WindowType)
|
||||
ChestClose.m_PosZ = block->GetPosZ();
|
||||
ChestClose.m_Byte1 = 1;
|
||||
ChestClose.m_Byte2 = 0;
|
||||
cWorld::PlayerList PlayerList = cRoot::Get()->GetWorld()->GetAllPlayers();
|
||||
for( cWorld::PlayerList::iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr )
|
||||
{
|
||||
if ((*itr) && (*itr)->GetClientHandle() && !((*itr)->GetClientHandle()->IsDestroyed())) {
|
||||
(*itr)->GetClientHandle()->Send( ChestClose );
|
||||
}
|
||||
}
|
||||
m_World->Broadcast(ChestClose);
|
||||
}
|
||||
|
||||
m_CurrentWindow->Close( *this );
|
||||
}
|
||||
m_CurrentWindow = 0;
|
||||
m_CurrentWindow = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetLastBlockActionTime()
|
||||
{
|
||||
m_LastBlockActionTime = cRoot::Get()->GetWorld()->GetTime();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetLastBlockActionCnt( int a_LastBlockActionCnt )
|
||||
{
|
||||
m_LastBlockActionCnt = a_LastBlockActionCnt;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetGameMode( int a_GameMode )
|
||||
{
|
||||
if ( (a_GameMode < 2) && (a_GameMode >= 0) )
|
||||
@ -487,21 +469,37 @@ void cPlayer::SetGameMode( int a_GameMode )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::LoginSetGameMode( int a_GameMode )
|
||||
{
|
||||
m_GameMode = a_GameMode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetIP( std::string a_IP )
|
||||
{
|
||||
m_IP = a_IP;
|
||||
m_IP = a_IP;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SendMessage( const char* a_Message )
|
||||
{
|
||||
m_ClientHandle->Send( cPacket_Chat( a_Message ) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::TeleportTo( const double & a_PosX, const double & a_PosY, const double & a_PosZ )
|
||||
{
|
||||
SetPosition( a_PosX, a_PosY, a_PosZ );
|
||||
@ -515,31 +513,43 @@ void cPlayer::TeleportTo( const double & a_PosX, const double & a_PosY, const do
|
||||
m_ClientHandle->Send( PlayerPosition );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::MoveTo( const Vector3d & a_NewPos )
|
||||
{
|
||||
// TODO: should do some checks to see if player is not moving through terrain
|
||||
SetPosition( a_NewPos );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::SetVisible( bool a_bVisible )
|
||||
{
|
||||
if( a_bVisible == true && m_bVisible == false ) // Make visible
|
||||
if (a_bVisible && !m_bVisible) // Make visible
|
||||
{
|
||||
m_bVisible = true;
|
||||
SpawnOn( 0 ); // Spawn on everybody
|
||||
SpawnOn( NULL ); // Spawn on everybody
|
||||
}
|
||||
if( a_bVisible == false && m_bVisible == true )
|
||||
if (!a_bVisible && m_bVisible)
|
||||
{
|
||||
m_bVisible = false;
|
||||
cPacket_DestroyEntity DestroyEntity( this );
|
||||
cChunk* Chunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
cChunkPtr Chunk = GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if ( Chunk != NULL )
|
||||
{
|
||||
Chunk->Broadcast( DestroyEntity ); // Destroy on all clients
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::AddToGroup( const char* a_GroupName )
|
||||
{
|
||||
cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName );
|
||||
@ -628,6 +638,10 @@ void cPlayer::ResolvePermissions()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::ResolveGroups()
|
||||
{
|
||||
// Clear resolved groups first
|
||||
@ -666,17 +680,29 @@ void cPlayer::ResolveGroups()
|
||||
}
|
||||
}
|
||||
|
||||
std::string cPlayer::GetColor()
|
||||
{
|
||||
if( m_Color != '-' )
|
||||
return cChatColor::MakeColor( m_Color );
|
||||
|
||||
if( m_pState->Groups.size() < 1 )
|
||||
|
||||
|
||||
|
||||
AString cPlayer::GetColor(void) const
|
||||
{
|
||||
if ( m_Color != '-' )
|
||||
{
|
||||
return cChatColor::MakeColor( m_Color );
|
||||
}
|
||||
|
||||
if ( m_pState->Groups.size() < 1 )
|
||||
{
|
||||
return cChatColor::White;
|
||||
}
|
||||
|
||||
return (*m_pState->Groups.begin())->GetColor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::TossItem( bool a_bDraggingItem, int a_Amount /* = 1 */ )
|
||||
{
|
||||
if( a_bDraggingItem )
|
||||
@ -714,18 +740,22 @@ void cPlayer::TossItem( bool a_bDraggingItem, int a_Amount /* = 1 */ )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cPlayer::MoveToWorld( const char* a_WorldName )
|
||||
{
|
||||
cWorld* World = cRoot::Get()->GetWorld( a_WorldName );
|
||||
if( World )
|
||||
cWorld * World = cRoot::Get()->GetWorld( a_WorldName );
|
||||
if ( World )
|
||||
{
|
||||
/* Remove all links to the old world */
|
||||
GetWorld()->RemovePlayer( this );
|
||||
GetClientHandle()->RemoveFromAllChunks();
|
||||
cChunk* Chunk = GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
m_World->RemovePlayer( this );
|
||||
m_ClientHandle->RemoveFromAllChunks();
|
||||
cChunkPtr Chunk = m_World->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if ( Chunk != NULL )
|
||||
{
|
||||
Chunk->RemoveEntity( *this );
|
||||
Chunk->RemoveEntity( this );
|
||||
Chunk->Broadcast( cPacket_DestroyEntity( this ) ); // Remove player entity from all clients in old world
|
||||
}
|
||||
|
||||
@ -741,6 +771,10 @@ bool cPlayer::MoveToWorld( const char* a_WorldName )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cPlayer::LoadPermissionsFromDisk()
|
||||
{
|
||||
m_pState->Groups.clear();
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cPawn.h"
|
||||
@ -14,7 +15,10 @@ class cInventory;
|
||||
class cClientHandle;
|
||||
|
||||
|
||||
class cPlayer : public cPawn //tolua_export
|
||||
|
||||
|
||||
|
||||
class cPlayer : public cPawn //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
CLASS_PROTOTYPE();
|
||||
@ -24,8 +28,8 @@ public:
|
||||
|
||||
virtual void Initialize( cWorld* a_World ); //tolua_export
|
||||
|
||||
virtual void SpawnOn( cClientHandle* a_Target );
|
||||
virtual void Tick(float a_Dt);
|
||||
virtual cPacket * GetSpawnPacket(void) const override;
|
||||
virtual void Tick(float a_Dt) override;
|
||||
|
||||
void SetTouchGround( bool a_bTouchGround );
|
||||
inline void SetStance( const double & a_Stance ) { m_Stance = a_Stance; }
|
||||
@ -71,7 +75,7 @@ public:
|
||||
StringList GetResolvedPermissions(); // >> EXPORTED IN MANUALBINDINGS <<
|
||||
bool IsInGroup( const char* a_Group ); //tolua_export
|
||||
|
||||
std::string GetColor(); //tolua_export
|
||||
AString GetColor(void) const; //tolua_export
|
||||
|
||||
void TossItem( bool a_bDraggingItem, int a_Amount = 1 ); //tolua_export
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string> // TODO - use const char*
|
||||
#pragma once
|
||||
|
||||
struct lua_State;
|
||||
class cLuaCommandBinder;
|
||||
|
@ -12,7 +12,6 @@
|
||||
|
||||
class cThread;
|
||||
class cMonsterConfig;
|
||||
class cMCLogger;
|
||||
class cGroupManager;
|
||||
class cRecipeChecker;
|
||||
class cFurnaceRecipe;
|
||||
@ -21,6 +20,10 @@ class cPluginManager;
|
||||
class cServer;
|
||||
class cWorld;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cRoot //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
@ -32,7 +35,7 @@ public:
|
||||
void Start();
|
||||
|
||||
cServer* GetServer() { return m_Server; } //tolua_export
|
||||
cWorld* GetWorld(); //tolua_export
|
||||
OBSOLETE cWorld* GetWorld(); //tolua_export
|
||||
cWorld* GetDefaultWorld(); //tolua_export
|
||||
cWorld* GetWorld( const char* a_WorldName ); //tolua_export
|
||||
cMonsterConfig *GetMonsterConfig() { return m_MonsterConfig;}
|
||||
|
@ -241,7 +241,7 @@ cServer::~cServer()
|
||||
|
||||
|
||||
// TODO - Need to modify this or something, so it broadcasts to all worlds? And move this to cWorld?
|
||||
void cServer::Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude /* = 0 */ )
|
||||
void cServer::Broadcast( const cPacket * a_Packet, cClientHandle* a_Exclude /* = 0 */ )
|
||||
{
|
||||
for( ClientList::iterator itr = m_pState->Clients.begin(); itr != m_pState->Clients.end(); ++itr)
|
||||
{
|
||||
@ -277,6 +277,7 @@ void cServer::StartListenClient()
|
||||
if (!m_SocketThreads.AddClient(&(NewHandle->GetSocket()), NewHandle))
|
||||
{
|
||||
// For some reason SocketThreads have rejected the handle, clean it up
|
||||
LOGERROR("Client \"%s\" cannot be handled, server probably unstable", SClient.GetIPString().c_str());
|
||||
SClient.CloseSocket();
|
||||
delete NewHandle;
|
||||
return;
|
||||
@ -423,7 +424,7 @@ bool cServer::Command( cClientHandle & a_Client, const char* a_Cmd )
|
||||
|
||||
|
||||
|
||||
void cServer::ServerCommand( const char* a_Cmd )
|
||||
void cServer::ServerCommand( const char * a_Cmd )
|
||||
{
|
||||
AString Command( a_Cmd );
|
||||
AStringVector split = StringSplit( Command, " " );
|
||||
@ -454,30 +455,29 @@ void cServer::ServerCommand( const char* a_Cmd )
|
||||
}
|
||||
if( split[0].compare( "list" ) == 0 )
|
||||
{
|
||||
cWorld::EntityList Entities = cRoot::Get()->GetWorld()->GetEntities();
|
||||
std::string PlayerString;
|
||||
int NumPlayers = 0;
|
||||
cRoot::Get()->GetWorld()->LockEntities();
|
||||
for( cWorld::EntityList::iterator itr = Entities.begin(); itr != Entities.end(); ++itr)
|
||||
class cPlayerLogger : public cPlayerListCallback
|
||||
{
|
||||
if( (*itr)->GetEntityType() != cEntity::E_PLAYER ) continue;
|
||||
PlayerString.push_back(' ');
|
||||
PlayerString += ((cPlayer*)*itr)->GetName();
|
||||
NumPlayers++;
|
||||
}
|
||||
cRoot::Get()->GetWorld()->UnlockEntities();
|
||||
printf( "Players (%i):%s\n", NumPlayers, PlayerString.c_str() );
|
||||
virtual bool Item(cPlayer * a_Player) override
|
||||
{
|
||||
LOG("\t%s @ %s", a_Player->GetName().c_str(), a_Player->GetClientHandle()->GetSocket().GetIPString());
|
||||
return false;
|
||||
}
|
||||
} Logger;
|
||||
cRoot::Get()->GetWorld()->ForEachPlayer(&Logger);
|
||||
return;
|
||||
}
|
||||
if( split[0].compare( "numchunks" ) == 0 )
|
||||
{
|
||||
printf("Num loaded chunks: %i\n", cRoot::Get()->GetWorld()->GetNumChunks() );
|
||||
printf("Num loaded chunks: %i\n", cRoot::Get()->GetTotalChunkCount() );
|
||||
return;
|
||||
}
|
||||
if(split[0].compare("monsters") == 0 ){
|
||||
cMonster::ListMonsters();
|
||||
|
||||
if(split[0].compare("monsters") == 0 )
|
||||
{
|
||||
// TODO: cWorld::ListMonsters();
|
||||
return;
|
||||
}
|
||||
|
||||
if(split.size() > 1)
|
||||
{
|
||||
if( split[0].compare( "say" ) == 0 )
|
||||
|
@ -35,9 +35,9 @@ public: //tolua_export
|
||||
int GetPort() { return m_iServerPort; }
|
||||
bool IsConnected(){return m_bIsConnected;} // returns connection status
|
||||
void StartListenClient(); // Listen to client
|
||||
int RecClient(cClientHandle *sRecSocket); // receive message for a particular socket
|
||||
|
||||
void Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude = 0 );
|
||||
void Broadcast(const cPacket & a_Packet, cClientHandle* a_Exclude = NULL) { Broadcast(&a_Packet, a_Exclude); }
|
||||
void Broadcast(const cPacket * a_Packet, cClientHandle* a_Exclude = NULL);
|
||||
|
||||
bool Tick(float a_Dt);
|
||||
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
|
||||
|
||||
cSignEntity::cSignEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cChunk* a_Chunk)
|
||||
: cBlockEntity(a_BlockType, a_X, a_Y, a_Z, a_Chunk)
|
||||
cSignEntity::cSignEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World)
|
||||
: cBlockEntity(a_BlockType, a_X, a_Y, a_Z, a_World)
|
||||
{
|
||||
}
|
||||
|
||||
@ -44,7 +44,7 @@ void cSignEntity::UsedBy( cPlayer & a_Player )
|
||||
|
||||
|
||||
|
||||
void cSignEntity::SetLines( const std::string & a_Line1, const std::string & a_Line2, const std::string & a_Line3, const std::string & a_Line4 )
|
||||
void cSignEntity::SetLines( const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4 )
|
||||
{
|
||||
m_Line[0] = a_Line1;
|
||||
m_Line[1] = a_Line2;
|
||||
@ -56,7 +56,7 @@ void cSignEntity::SetLines( const std::string & a_Line1, const std::string & a_L
|
||||
|
||||
|
||||
|
||||
void cSignEntity::SetLine( int a_Index, std::string a_Line )
|
||||
void cSignEntity::SetLine( int a_Index, const AString & a_Line )
|
||||
{
|
||||
if( a_Index < 4 && a_Index > -1 )
|
||||
{
|
||||
@ -68,7 +68,7 @@ void cSignEntity::SetLine( int a_Index, std::string a_Line )
|
||||
|
||||
|
||||
|
||||
std::string cSignEntity::GetLine( int a_Index )
|
||||
AString cSignEntity::GetLine( int a_Index ) const
|
||||
{
|
||||
if( a_Index < 4 && a_Index > -1 )
|
||||
{
|
||||
@ -92,13 +92,13 @@ void cSignEntity::SendTo( cClientHandle* a_Client )
|
||||
Sign.m_Line3 = m_Line[2];
|
||||
Sign.m_Line4 = m_Line[3];
|
||||
|
||||
if( a_Client )
|
||||
if ( a_Client != NULL )
|
||||
{
|
||||
a_Client->Send( Sign );
|
||||
}
|
||||
else // broadcast of a_Client == 0
|
||||
{
|
||||
GetChunk()->Broadcast( Sign );
|
||||
m_World->GetChunkOfBlock(m_PosX, m_PosY, m_PosZ)->Broadcast( Sign );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cBlockEntity.h"
|
||||
#include "FileDefine.h"
|
||||
|
||||
|
||||
|
||||
@ -16,11 +16,11 @@ namespace Json
|
||||
|
||||
|
||||
|
||||
class cWorld;
|
||||
class cSignEntity : public cBlockEntity
|
||||
class cSignEntity :
|
||||
public cBlockEntity
|
||||
{
|
||||
public:
|
||||
cSignEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cChunk* a_Chunk);
|
||||
cSignEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z, cWorld * a_World);
|
||||
virtual ~cSignEntity();
|
||||
|
||||
bool LoadFromFile(cFile & a_File); // deprecated format
|
||||
@ -28,15 +28,17 @@ public:
|
||||
bool LoadFromJson( const Json::Value& a_Value );
|
||||
void SaveToJson( Json::Value& a_Value );
|
||||
|
||||
void SetLines( const std::string & a_Line1, const std::string & a_Line2, const std::string & a_Line3, const std::string & a_Line4 );
|
||||
void SetLine( int a_Index, std::string a_Line );
|
||||
void SetLines( const AString & a_Line1, const AString & a_Line2, const AString & a_Line3, const AString & a_Line4 );
|
||||
void SetLine( int a_Index, const AString & a_Line );
|
||||
|
||||
std::string GetLine( int a_Index );
|
||||
AString GetLine( int a_Index ) const;
|
||||
|
||||
virtual void UsedBy( cPlayer & a_Player );
|
||||
virtual void SendTo( cClientHandle* a_Client );
|
||||
|
||||
private:
|
||||
std::string m_Line[4];
|
||||
|
||||
AString m_Line[4];
|
||||
};
|
||||
|
||||
|
||||
|
@ -12,33 +12,56 @@ cSimulatorManager::cSimulatorManager()
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cSimulatorManager::~cSimulatorManager()
|
||||
{
|
||||
for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr )
|
||||
{
|
||||
delete *itr;
|
||||
} // for itr - m_Simulators[]
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSimulatorManager::Simulate( float a_Dt )
|
||||
{
|
||||
m_Ticks++;
|
||||
for( std::vector <std::pair<cSimulator *, short> *>::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr )
|
||||
for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr )
|
||||
{
|
||||
|
||||
if(m_Ticks % (*itr)->second == 0)
|
||||
(*itr)->first->Simulate(a_Dt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSimulatorManager::WakeUp(int a_X, int a_Y, int a_Z)
|
||||
{
|
||||
for( std::vector <std::pair<cSimulator *, short> *>::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr )
|
||||
for (cSimulators::iterator itr = m_Simulators.begin(); itr != m_Simulators.end(); ++itr )
|
||||
{
|
||||
(*itr)->first->WakeUp(a_X, a_Y, a_Z);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSimulatorManager::RegisterSimulator(cSimulator *a_Simulator, short a_Rate)
|
||||
{
|
||||
//TODO needs some checking
|
||||
std::pair<cSimulator *, short> *Pair = new std::pair<cSimulator *, short>(a_Simulator, a_Rate);
|
||||
|
||||
m_Simulators.push_back(Pair);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,6 +1,18 @@
|
||||
|
||||
// cSimulatorManager.h
|
||||
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
|
||||
|
||||
#include "cSimulator.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cSimulatorManager
|
||||
@ -12,9 +24,16 @@ public:
|
||||
void Simulate( float a_Dt );
|
||||
void WakeUp(int a_X, int a_Y, int a_Z);
|
||||
|
||||
void RegisterSimulator(cSimulator *a_Simulator, short a_Rate);
|
||||
void RegisterSimulator(cSimulator * a_Simulator, short a_Rate); // Takes ownership of the simulator object!
|
||||
|
||||
protected:
|
||||
std::vector <std::pair<cSimulator *, short> *> m_Simulators;
|
||||
long long m_Ticks;
|
||||
};
|
||||
|
||||
typedef std::vector <std::pair<cSimulator *, short> *> cSimulators;
|
||||
|
||||
cSimulators m_Simulators;
|
||||
long long m_Ticks;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -267,6 +267,34 @@ int cSocket::Connect(SockAddr_In & a_Address)
|
||||
|
||||
|
||||
|
||||
int cSocket::Connect(const AString & a_HostNameOrAddr, unsigned short a_Port)
|
||||
{
|
||||
// First try IP Address string to hostent conversion, because it's faster
|
||||
unsigned long addr = inet_addr(a_HostNameOrAddr.c_str());
|
||||
hostent * hp = gethostbyaddr((char*)&addr, sizeof(addr), AF_INET);
|
||||
if (hp == NULL)
|
||||
{
|
||||
// It is not an IP Address string, but rather a regular hostname, resolve:
|
||||
hp = gethostbyname(a_HostNameOrAddr.c_str());
|
||||
if (hp == NULL)
|
||||
{
|
||||
LOGWARN("cTCPLink: Could not resolve hostname \"%s\"", a_HostNameOrAddr.c_str());
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
sockaddr_in server;
|
||||
server.sin_addr.s_addr = *((unsigned long*)hp->h_addr);
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_port = htons( (unsigned short)a_Port );
|
||||
return connect(m_Socket, (sockaddr *)&server, sizeof(server));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int cSocket::Receive(char* a_Buffer, unsigned int a_Length, unsigned int a_Flags)
|
||||
{
|
||||
return recv(m_Socket, a_Buffer, a_Length, a_Flags);
|
||||
|
@ -1,3 +1,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@ -70,6 +71,7 @@ public:
|
||||
int Listen( int a_Backlog );
|
||||
cSocket Accept();
|
||||
int Connect(SockAddr_In & a_Address); // Returns 0 on success, !0 on failure
|
||||
int Connect(const AString & a_HostNameOrAddr, unsigned short a_Port); // Returns 0 on success, !0 on failure
|
||||
int Receive( char* a_Buffer, unsigned int a_Length, unsigned int a_Flags );
|
||||
int Send (const char * a_Buffer, unsigned int a_Length);
|
||||
int Send (const cPacket * a_Packet); // Sends the packet, doesn't handle partial sends
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "Globals.h"
|
||||
#include "cSocketThreads.h"
|
||||
#include "cClientHandle.h"
|
||||
#include "packets/cPacket_RelativeEntityMoveLook.h"
|
||||
// #include "packets/cPacket_RelativeEntityMoveLook.h"
|
||||
|
||||
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
|
||||
cSocketThreads::cSocketThreads(void)
|
||||
{
|
||||
LOG("cSocketThreads startup");
|
||||
}
|
||||
|
||||
|
||||
@ -60,6 +61,7 @@ bool cSocketThreads::AddClient(cSocket * a_Socket, cCallback * a_Client)
|
||||
if (!Thread->Start())
|
||||
{
|
||||
// There was an error launching the thread (but it was already logged along with the reason)
|
||||
LOGERROR("A new cSocketThread failed to start");
|
||||
delete Thread;
|
||||
return false;
|
||||
}
|
||||
@ -141,6 +143,17 @@ cSocketThreads::cSocketThread::cSocketThread(cSocketThreads * a_Parent) :
|
||||
|
||||
|
||||
|
||||
cSocketThreads::cSocketThread::~cSocketThread()
|
||||
{
|
||||
mShouldTerminate = true;
|
||||
m_ControlSocket1.CloseSocket();
|
||||
m_ControlSocket2.CloseSocket();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cSocketThreads::cSocketThread::AddClient(cSocket * a_Socket, cCallback * a_Client)
|
||||
{
|
||||
assert(m_NumSlots < MAX_SLOTS); // Use HasEmptySlot() to check before adding
|
||||
@ -310,6 +323,7 @@ bool cSocketThreads::cSocketThread::Start(void)
|
||||
// Start the thread
|
||||
if (!super::Start())
|
||||
{
|
||||
LOGERROR("Cannot start new cSocketThread");
|
||||
m_ControlSocket2.CloseSocket();
|
||||
return false;
|
||||
}
|
||||
@ -383,8 +397,6 @@ void cSocketThreads::cSocketThread::Execute(void)
|
||||
|
||||
RemoveClosedSockets();
|
||||
} // while (!mShouldTerminate)
|
||||
|
||||
LOG("cSocketThread %p is terminating", this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -87,6 +87,7 @@ private:
|
||||
public:
|
||||
|
||||
cSocketThread(cSocketThreads * a_Parent);
|
||||
~cSocketThread();
|
||||
|
||||
// All these methods assume parent's m_CS is locked
|
||||
bool HasEmptySlot(void) const {return m_NumSlots < MAX_SLOTS; }
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include "cTCPLink.h"
|
||||
#include "cSocket.h"
|
||||
#include "MCSocket.h"
|
||||
|
||||
|
||||
|
||||
@ -45,58 +44,24 @@ void cTCPLink::CloseSocket()
|
||||
}
|
||||
}
|
||||
|
||||
bool cTCPLink::Connect( const char* a_Address, unsigned int a_Port )
|
||||
bool cTCPLink::Connect( const AString & a_Address, unsigned int a_Port )
|
||||
{
|
||||
if( m_Socket )
|
||||
{
|
||||
LOGWARN("WARNING: cTCPLink Connect() called while still connected. ALWAYS disconnect before re-connecting!");
|
||||
}
|
||||
|
||||
struct hostent *hp;
|
||||
unsigned int addr;
|
||||
struct sockaddr_in server;
|
||||
|
||||
#ifdef _WIN32
|
||||
WSADATA wsaData;
|
||||
int wsaret=WSAStartup(/*0x101*/ MAKEWORD(2, 2),&wsaData);
|
||||
|
||||
if(wsaret!=0)
|
||||
{
|
||||
LOGERROR("cTCPLink: WSAStartup returned error");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
m_Socket=socket(AF_INET,SOCK_STREAM,0);
|
||||
m_Socket = cSocket::CreateSocket();
|
||||
if( !m_Socket.IsValid() )
|
||||
{
|
||||
LOGERROR("cTCPLink: Invalid socket");
|
||||
m_Socket = 0;
|
||||
LOGERROR("cTCPLink: Failed to create socket");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
addr=inet_addr( a_Address );
|
||||
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
|
||||
if(hp==NULL)
|
||||
if (m_Socket.Connect(a_Address, a_Port) != 0)
|
||||
{
|
||||
//LOGWARN("cTCPLink: gethostbyaddr returned NULL");
|
||||
hp = gethostbyname( a_Address );
|
||||
if( hp == NULL )
|
||||
{
|
||||
LOGWARN("cTCPLink: Could not resolve %s", a_Address);
|
||||
CloseSocket();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
server.sin_addr.s_addr=*((unsigned long*)hp->h_addr);
|
||||
server.sin_family=AF_INET;
|
||||
server.sin_port=htons( (unsigned short)a_Port );
|
||||
if( connect( m_Socket, (struct sockaddr*)&server, sizeof(server) ) )
|
||||
{
|
||||
LOGWARN("cTCPLink: No response from server (%i)", errno);
|
||||
CloseSocket();
|
||||
LOGWARN("cTCPLink: Cannot connect to server \"%s\" (%s)", m_Socket.GetLastErrorString().c_str());
|
||||
m_Socket.CloseSocket();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -105,41 +70,60 @@ bool cTCPLink::Connect( const char* a_Address, unsigned int a_Port )
|
||||
return true;
|
||||
}
|
||||
|
||||
int cTCPLink::Send( char* a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
|
||||
|
||||
|
||||
|
||||
|
||||
int cTCPLink::Send(const char * a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
|
||||
{
|
||||
//LOG("TCPLink::Send()");
|
||||
if( !m_Socket )
|
||||
(void)a_Flags;
|
||||
if (!m_Socket.IsValid())
|
||||
{
|
||||
LOGWARN("cTCPLink: Trying to send data without a valid connection!");
|
||||
return -1;
|
||||
}
|
||||
return send( m_Socket, a_Data, a_Size, a_Flags | MSG_NOSIGNAL );
|
||||
return m_Socket.Send(a_Data, a_Size);
|
||||
}
|
||||
|
||||
int cTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ )
|
||||
|
||||
|
||||
|
||||
|
||||
int cTCPLink::SendMessage(const char * a_Message, int a_Flags /* = 0 */ )
|
||||
{
|
||||
//LOG("TCPLink::SendMessage()");
|
||||
if( !m_Socket )
|
||||
(void)a_Flags;
|
||||
if (!m_Socket.IsValid())
|
||||
{
|
||||
LOGWARN("cTCPLink: Trying to send message without a valid connection!");
|
||||
return -1;
|
||||
}
|
||||
return send( m_Socket, a_Message, strlen(a_Message), a_Flags | MSG_NOSIGNAL );
|
||||
return m_Socket.Send(a_Message, strlen(a_Message));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cTCPLink::ReceiveThread( void* a_Param)
|
||||
{
|
||||
cTCPLink* self = (cTCPLink*)a_Param;
|
||||
SOCKET Socket = self->m_Socket;
|
||||
cSocket Socket = self->m_Socket;
|
||||
int Received = 0;
|
||||
do
|
||||
{
|
||||
char Data[256];
|
||||
Received = recv(Socket, Data, 256, 0);
|
||||
self->ReceivedData( Data, (Received>0?Received:-1) );
|
||||
Received = Socket.Receive(Data, sizeof(Data), 0);
|
||||
self->ReceivedData( Data, ((Received > 0) ? Received : -1) );
|
||||
} while ( Received > 0 );
|
||||
|
||||
LOGINFO("cTCPLink Disconnected (%i)", Received );
|
||||
|
||||
if( Socket == self->m_Socket ) self->m_StopEvent->Set();
|
||||
if (Socket == self->m_Socket)
|
||||
{
|
||||
self->m_StopEvent->Set();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -8,9 +8,9 @@ public: //tolua_export
|
||||
cTCPLink(); //tolua_export
|
||||
~cTCPLink(); //tolua_export
|
||||
|
||||
bool Connect( const char* a_Address, unsigned int a_Port ); //tolua_export
|
||||
int Send( char* a_Data, unsigned int a_Size, int a_Flags = 0 ); //tolua_export
|
||||
int SendMessage( const char* a_Message, int a_Flags = 0 ); //tolua_export
|
||||
bool Connect (const AString & a_Address, unsigned int a_Port ); //tolua_export
|
||||
int Send (const char * a_Data, unsigned int a_Size, int a_Flags = 0 ); //tolua_export
|
||||
int SendMessage(const char * a_Message, int a_Flags = 0 ); //tolua_export
|
||||
void CloseSocket(); //tolua_export
|
||||
protected: //tolua_export
|
||||
virtual void ReceivedData( char a_Data[256], int a_Size ) = 0; //tolua_export
|
||||
|
@ -27,7 +27,28 @@
|
||||
|
||||
|
||||
|
||||
cWebAdmin * WebAdmin = 0;
|
||||
/// Helper class - appends all player names together in a 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;
|
||||
} ;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cWebAdmin * WebAdmin = NULL;
|
||||
|
||||
|
||||
|
||||
@ -191,12 +212,10 @@ void cWebAdmin::Request_Handler(webserver::http_request* r)
|
||||
Content += "</ul>";
|
||||
Content += "<h4>Players:</h4><ul>";
|
||||
|
||||
cWorld* World = cRoot::Get()->GetWorld(); // TODO - Create a list of worlds and players
|
||||
cWorld::PlayerList PlayerList = World->GetAllPlayers();
|
||||
for( cWorld::PlayerList::iterator itr = PlayerList.begin(); itr != PlayerList.end(); ++itr )
|
||||
{
|
||||
Content += std::string("<li>") + std::string( (*itr)->GetName() ) + "</li>";
|
||||
}
|
||||
cPlayerAccum PlayerAccum;
|
||||
cWorld * World = cRoot::Get()->GetWorld(); // TODO - Create a list of worlds and players
|
||||
World->ForEachPlayer(&PlayerAccum);
|
||||
Content.append(PlayerAccum.m_Contents);
|
||||
Content += "</ul><br>";
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
163
source/cWorld.h
163
source/cWorld.h
@ -2,16 +2,18 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "BlockID.h"
|
||||
#include "BlockID.h"
|
||||
#else
|
||||
enum ENUM_ITEM_ID;
|
||||
enum ENUM_ITEM_ID;
|
||||
#endif
|
||||
|
||||
#define MAX_PLAYERS 65535
|
||||
|
||||
#include "cSimulatorManager.h"
|
||||
#include "ptr_cChunk.h"
|
||||
#include "MersenneTwister.h"
|
||||
#include "cChunkMap.h"
|
||||
#include "WorldStorage.h"
|
||||
#include "cChunkGenerator.h"
|
||||
|
||||
|
||||
|
||||
@ -23,25 +25,23 @@ class cFireSimulator;
|
||||
class cWaterSimulator;
|
||||
class cLavaSimulator;
|
||||
class cSandSimulator;
|
||||
class cChunkMap;
|
||||
class cItem;
|
||||
class cPlayer;
|
||||
class cClientHandle;
|
||||
class cChunk;
|
||||
class cEntity;
|
||||
class cBlockEntity;
|
||||
class cWorldGenerator;
|
||||
class cWorldGenerator; // The generator that actually generates the chunks for a single world
|
||||
class cChunkGenerator; // The thread responsible for generating chunks
|
||||
typedef std::list< cPlayer * > cPlayerList;
|
||||
typedef cListCallback<cPlayer> cPlayerListCallback;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cWorld //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
typedef std::list< cClientHandle* > ClientList;
|
||||
typedef std::list< cEntity* > EntityList;
|
||||
typedef std::list< ptr_cChunk > ChunkList;
|
||||
typedef std::list< cPlayer* > PlayerList;
|
||||
std::vector<int> m_RSList;
|
||||
|
||||
|
||||
static cWorld* GetWorld(); //tolua_export
|
||||
|
||||
@ -50,16 +50,15 @@ public:
|
||||
{
|
||||
return m_Time;
|
||||
}
|
||||
long long GetWorldTime() { return m_WorldTime; } //tolua_export
|
||||
long long GetWorldTime(void) const { return m_WorldTime; } //tolua_export
|
||||
|
||||
int GetGameMode() { return m_GameMode; } //return gamemode for world
|
||||
int GetGameMode(void) const { return m_GameMode; } //return gamemode for world
|
||||
|
||||
void SetWorldTime(long long a_WorldTime) { m_WorldTime = a_WorldTime; } //tolua_export
|
||||
|
||||
cChunk* GetChunk( int a_X, int a_Y, int a_Z );
|
||||
cChunk* GetChunkReliable( int a_X, int a_Y, int a_Z );
|
||||
ptr_cChunk GetChunkUnreliable( int a_X, int a_Y, int a_Z );
|
||||
cChunk* GetChunkOfBlock( int a_X, int a_Y, int a_Z );
|
||||
cChunkPtr GetChunk ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) {return m_ChunkMap->GetChunk (a_ChunkX, a_ChunkY, a_ChunkZ); }
|
||||
cChunkPtr GetChunkNoGen ( int a_ChunkX, int a_ChunkY, int a_ChunkZ ) {return m_ChunkMap->GetChunkNoGen(a_ChunkX, a_ChunkY, a_ChunkZ); }
|
||||
cChunkPtr GetChunkOfBlock( int a_X, int a_Y, int a_Z );
|
||||
char GetHeight( int a_X, int a_Z ); //tolua_export
|
||||
|
||||
//void AddClient( cClientHandle* a_Client );
|
||||
@ -69,25 +68,38 @@ public:
|
||||
void Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude = 0 );
|
||||
|
||||
// MOTD
|
||||
std::string GetDescription();
|
||||
const AString & GetDescription(void) const {return m_Description; }
|
||||
|
||||
// Max Players
|
||||
unsigned int GetMaxPlayers();
|
||||
unsigned int GetMaxPlayers(void) const {return m_MaxPlayers; }
|
||||
void SetMaxPlayers(int iMax);
|
||||
|
||||
void AddPlayer( cPlayer* a_Player );
|
||||
void RemovePlayer( cPlayer* a_Player );
|
||||
PlayerList & GetAllPlayers();
|
||||
bool ForEachPlayer(cPlayerListCallback * a_Callback); // Calls the callback for each player in the list
|
||||
|
||||
// TODO: This interface is dangerous!
|
||||
cPlayerList & GetAllPlayers() {return m_Players; }
|
||||
|
||||
typedef struct lua_State lua_State;
|
||||
void GetAllPlayers( lua_State* L ); // >> EXPORTED IN MANUALBINDINGS <<
|
||||
unsigned int GetNumPlayers(); //tolua_export
|
||||
cPlayer* GetPlayer( const char* a_PlayerName ); //tolua_export
|
||||
|
||||
// TODO: This interface is dangerous
|
||||
cPlayer * GetPlayer( const char * a_PlayerName ); //tolua_export
|
||||
|
||||
cPlayer * FindClosestPlayer(const Vector3f & a_Pos, float a_SightLimit);
|
||||
|
||||
void SendPlayerList(cPlayer * a_DestPlayer); // Sends playerlist to the player
|
||||
|
||||
void AddEntity( cEntity* a_Entity );
|
||||
bool RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom = 0 );
|
||||
EntityList & GetEntities();
|
||||
void RemoveEntityFromChunk( cEntity * a_Entity);
|
||||
|
||||
// TODO: This interface is dangerous!
|
||||
cEntityList & GetEntities(void) {return m_AllEntities; }
|
||||
|
||||
cEntity* GetEntity( int a_UniqueID ); //tolua_export
|
||||
// TODO: This interface is dangerous!
|
||||
cEntity * GetEntity( int a_UniqueID ); //tolua_export
|
||||
|
||||
void SetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); //tolua_export
|
||||
void FastSetBlock( int a_X, int a_Y, int a_Z, char a_BlockType, char a_BlockMeta ); //tolua_export
|
||||
@ -105,13 +117,13 @@ public:
|
||||
inline cWaterSimulator *GetWaterSimulator() { return m_WaterSimulator; }
|
||||
inline cLavaSimulator *GetLavaSimulator() { return m_LavaSimulator; }
|
||||
|
||||
|
||||
cBlockEntity* GetBlockEntity( int a_X, int a_Y, int a_Z ); //tolua_export
|
||||
// TODO: This interface is dangerous!
|
||||
cBlockEntity * GetBlockEntity( int a_X, int a_Y, int a_Z ); //tolua_export
|
||||
|
||||
void GrowTree( int a_X, int a_Y, int a_Z ); //tolua_export
|
||||
|
||||
unsigned int GetWorldSeed() { return m_WorldSeed; } //tolua_export
|
||||
const char* GetName(); //tolua_export
|
||||
unsigned int GetWorldSeed(void) const { return m_WorldSeed; } //tolua_export
|
||||
const AString & GetName(void) const {return m_WorldName; } //tolua_export
|
||||
|
||||
inline static void AbsoluteToRelative( int & a_X, int & a_Y, int & a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
|
||||
{
|
||||
@ -126,6 +138,7 @@ public:
|
||||
//a_Y = a_Y - a_ChunkY*16;
|
||||
a_Z = a_Z - a_ChunkZ*16;
|
||||
}
|
||||
|
||||
inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkY, int & a_ChunkZ )
|
||||
{
|
||||
(void)a_Y; // not unused anymore
|
||||
@ -137,21 +150,12 @@ public:
|
||||
}
|
||||
|
||||
void SaveAllChunks(); //tolua_export
|
||||
int GetNumChunks(); //tolua_export
|
||||
int GetNumChunks() const; //tolua_export
|
||||
|
||||
void Tick(float a_Dt);
|
||||
|
||||
void LockClientHandle();
|
||||
void UnlockClientHandle();
|
||||
|
||||
void LockEntities();
|
||||
void UnlockEntities();
|
||||
|
||||
void LockChunks();
|
||||
void UnlockChunks();
|
||||
|
||||
void ReSpreadLighting( const ptr_cChunk& a_Chunk );
|
||||
void RemoveSpread( const ptr_cChunk& a_Chunk );
|
||||
void ReSpreadLighting(const cChunkPtr & a_Chunk );
|
||||
void RemoveSpread(const cChunkPtr & a_Chunk );
|
||||
|
||||
void InitializeSpawn();
|
||||
|
||||
@ -159,18 +163,28 @@ public:
|
||||
void SetWeather ( int ); //tolua_export
|
||||
int GetWeather() { return m_Weather; }; //tolua_export
|
||||
|
||||
cWorldGenerator* GetWorldGenerator() { return m_WorldGenerator; }
|
||||
cChunkGenerator & GetGenerator(void) { return m_Generator; }
|
||||
cWorldStorage & GetStorage (void) { return m_Storage; }
|
||||
|
||||
private:
|
||||
|
||||
friend class cRoot;
|
||||
|
||||
cWorld( const char* a_WorldName );
|
||||
~cWorld();
|
||||
struct sSetBlockData
|
||||
{
|
||||
sSetBlockData( int a_X, int a_Y, int a_Z, char a_BlockID, char a_BlockMeta )
|
||||
: x( a_X )
|
||||
, y( a_Y )
|
||||
, z( a_Z )
|
||||
, BlockID( a_BlockID )
|
||||
, BlockMeta( a_BlockMeta )
|
||||
{}
|
||||
int x, y, z;
|
||||
char BlockID, BlockMeta;
|
||||
};
|
||||
|
||||
typedef std::list< sSetBlockData > FastSetBlockList;
|
||||
|
||||
struct sWorldState;
|
||||
sWorldState* m_pState;
|
||||
|
||||
// This random generator is to be used only in the Tick() method, and thus only in the World-Tick-thread (MTRand is not exactly thread-safe)
|
||||
MTRand m_TickRand;
|
||||
|
||||
@ -186,36 +200,59 @@ private:
|
||||
int m_GameMode;
|
||||
float m_WorldTimeFraction; // When this > 1.f m_WorldTime is incremented by 20
|
||||
|
||||
cSimulatorManager *m_SimulatorManager;
|
||||
cSandSimulator *m_SandSimulator;
|
||||
cWaterSimulator* m_WaterSimulator;
|
||||
cLavaSimulator* m_LavaSimulator;
|
||||
cFireSimulator* m_FireSimulator;
|
||||
|
||||
cCriticalSection* m_ClientHandleCriticalSection;
|
||||
cCriticalSection* m_EntitiesCriticalSection;
|
||||
cCriticalSection* m_ChunksCriticalSection;
|
||||
// The cRedstone class simulates redstone and needs access to m_RSList
|
||||
friend class cRedstone;
|
||||
std::vector<int> m_RSList;
|
||||
|
||||
cWorldGenerator* m_WorldGenerator;
|
||||
cSimulatorManager * m_SimulatorManager;
|
||||
cSandSimulator * m_SandSimulator;
|
||||
cWaterSimulator * m_WaterSimulator;
|
||||
cLavaSimulator * m_LavaSimulator;
|
||||
cFireSimulator * m_FireSimulator;
|
||||
|
||||
cCriticalSection m_CSClients;
|
||||
cCriticalSection m_CSEntities;
|
||||
cCriticalSection m_CSPlayers;
|
||||
|
||||
cWorldStorage m_Storage;
|
||||
|
||||
AString m_Description;
|
||||
|
||||
std::string m_Description;
|
||||
unsigned int m_MaxPlayers;
|
||||
|
||||
cChunkMap* m_ChunkMap;
|
||||
cChunkMap * m_ChunkMap;
|
||||
|
||||
bool m_bAnimals;
|
||||
float m_SpawnMonsterTime;
|
||||
float m_SpawnMonsterRate;
|
||||
|
||||
unsigned int m_WorldSeed;
|
||||
|
||||
int m_Weather;
|
||||
|
||||
cEntityList m_RemoveEntityQueue;
|
||||
cEntityList m_AllEntities;
|
||||
cClientHandleList m_Clients;
|
||||
cPlayerList m_Players;
|
||||
|
||||
cCriticalSection m_CSLighting;
|
||||
cChunkPtrList m_SpreadQueue;
|
||||
|
||||
cCriticalSection m_CSFastSetBlock;
|
||||
FastSetBlockList m_FastSetBlockQueue;
|
||||
|
||||
cChunkGenerator m_Generator;
|
||||
|
||||
AString m_WorldName;
|
||||
|
||||
cWorld(const AString & a_WorldName);
|
||||
~cWorld();
|
||||
|
||||
void TickWeather(float a_Dt); // Handles weather each tick
|
||||
|
||||
void AddToRemoveEntityQueue( cEntity & a_Entity );
|
||||
void RemoveEntity( cEntity* a_Entity );
|
||||
void TickSpawnMobs(float a_Dt); // Handles mob spawning each tick
|
||||
|
||||
void RemoveEntity( cEntity * a_Entity );
|
||||
void UnloadUnusedChunks();
|
||||
|
||||
}; //tolua_export
|
||||
|
||||
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include "cWorld.h"
|
||||
#include "cChunk.h"
|
||||
#include "cGenSettings.h"
|
||||
#include "MersenneTwister.h"
|
||||
|
||||
#include "BlockID.h"
|
||||
#include "Vector3i.h"
|
||||
@ -19,17 +18,33 @@ cWorldGenerator::cWorldGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cWorldGenerator::~cWorldGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void cWorldGenerator::GenerateChunk( cChunk* a_Chunk )
|
||||
|
||||
|
||||
|
||||
void cWorldGenerator::GenerateChunk( cChunkPtr a_Chunk )
|
||||
{
|
||||
assert(!a_Chunk->IsValid());
|
||||
|
||||
memset(a_Chunk->pGetBlockData(), 0, cChunk::c_BlockDataSize);
|
||||
GenerateTerrain( a_Chunk );
|
||||
GenerateFoliage( a_Chunk );
|
||||
a_Chunk->CalculateHeightmap();
|
||||
a_Chunk->CalculateLighting();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static float GetNoise( float x, float y, cNoise & a_Noise )
|
||||
{
|
||||
float oct1 = a_Noise.CubicNoise2D( x*cGenSettings::HeightFreq1, y*cGenSettings::HeightFreq1 )*cGenSettings::HeightAmp1;
|
||||
@ -44,6 +59,10 @@ static float GetNoise( float x, float y, cNoise & a_Noise )
|
||||
return (oct1 + oct2 + oct3) * flatness + height;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#define PI_2 (1.57079633f)
|
||||
static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise )
|
||||
{
|
||||
@ -56,6 +75,10 @@ static float GetMarbleNoise( float x, float y, float z, cNoise & a_Noise )
|
||||
return oct1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static float GetOreNoise( float x, float y, float z, cNoise & a_Noise )
|
||||
{
|
||||
float oct1 = a_Noise.CubicNoise3D( x*0.1f, y*0.1f, z*0.1f );
|
||||
@ -69,7 +92,11 @@ static float GetOreNoise( float x, float y, float z, cNoise & a_Noise )
|
||||
return oct1;
|
||||
}
|
||||
|
||||
void cWorldGenerator::GenerateTerrain( cChunk* a_Chunk )
|
||||
|
||||
|
||||
|
||||
|
||||
void cWorldGenerator::GenerateTerrain( cChunkPtr a_Chunk )
|
||||
{
|
||||
Vector3i ChunkPos( a_Chunk->GetPosX(), a_Chunk->GetPosY(), a_Chunk->GetPosZ() );
|
||||
char* BlockType = a_Chunk->pGetType();
|
||||
@ -154,7 +181,9 @@ void cWorldGenerator::GenerateTerrain( cChunk* a_Chunk )
|
||||
|
||||
|
||||
|
||||
void cWorldGenerator::GenerateFoliage( cChunk* a_Chunk )
|
||||
|
||||
|
||||
void cWorldGenerator::GenerateFoliage( cChunkPtr a_Chunk )
|
||||
{
|
||||
const ENUM_BLOCK_ID GrassID = E_BLOCK_GRASS;
|
||||
const ENUM_BLOCK_ID DirtID = E_BLOCK_DIRT;
|
||||
@ -213,7 +242,6 @@ void cWorldGenerator::GenerateFoliage( cChunk* a_Chunk )
|
||||
BlockType[ index ] = (char)GrassID;
|
||||
}
|
||||
|
||||
MTRand r1;
|
||||
// Plant sum trees
|
||||
{
|
||||
int xx = x + PosX*16;
|
||||
@ -253,3 +281,7 @@ void cWorldGenerator::GenerateFoliage( cChunk* a_Chunk )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,17 +1,34 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
class cChunk;
|
||||
|
||||
|
||||
|
||||
|
||||
#include "cChunk.h"
|
||||
#include "MersenneTwister.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cWorldGenerator
|
||||
{
|
||||
public:
|
||||
cWorldGenerator();
|
||||
~cWorldGenerator();
|
||||
|
||||
virtual void GenerateChunk( cChunk* a_Chunk );
|
||||
virtual void GenerateChunk( cChunkPtr a_Chunk );
|
||||
|
||||
protected:
|
||||
|
||||
virtual void GenerateTerrain( cChunk* a_Chunk );
|
||||
virtual void GenerateFoliage( cChunk* a_Chunk );
|
||||
MTRand r1;
|
||||
|
||||
virtual void GenerateTerrain( cChunkPtr a_Chunk );
|
||||
virtual void GenerateFoliage( cChunkPtr a_Chunk );
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
@ -9,7 +9,7 @@
|
||||
|
||||
|
||||
|
||||
void cWorldGenerator_Test::GenerateTerrain( cChunk* a_Chunk )
|
||||
void cWorldGenerator_Test::GenerateTerrain( cChunkPtr a_Chunk )
|
||||
{
|
||||
char* BlockType = a_Chunk->pGetType();
|
||||
|
||||
@ -26,7 +26,7 @@ void cWorldGenerator_Test::GenerateTerrain( cChunk* a_Chunk )
|
||||
}
|
||||
}
|
||||
|
||||
void cWorldGenerator_Test::GenerateFoliage( cChunk* a_Chunk )
|
||||
void cWorldGenerator_Test::GenerateFoliage( cChunkPtr a_Chunk )
|
||||
{
|
||||
(void)a_Chunk;
|
||||
}
|
@ -1,10 +1,20 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cWorldGenerator.h"
|
||||
|
||||
class cWorldGenerator_Test : public cWorldGenerator
|
||||
|
||||
|
||||
|
||||
|
||||
class cWorldGenerator_Test :
|
||||
public cWorldGenerator
|
||||
{
|
||||
protected:
|
||||
virtual void GenerateTerrain( cChunk* a_Chunk );
|
||||
virtual void GenerateFoliage( cChunk* a_Chunk );
|
||||
};
|
||||
virtual void GenerateTerrain( cChunkPtr a_Chunk ) override;
|
||||
virtual void GenerateFoliage( cChunkPtr a_Chunk ) override;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -17,6 +17,22 @@
|
||||
|
||||
|
||||
|
||||
/// If defined, a thorough leak finder will be used (debug MSVC only); leaks will be output to the Output window
|
||||
#define ENABLE_LEAK_FINDER
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||
#define XML_LEAK_FINDER
|
||||
#include "LeakFinder.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ShowCrashReport(int)
|
||||
{
|
||||
@ -27,17 +43,31 @@ void ShowCrashReport(int)
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
#ifdef _DEBUG
|
||||
|
||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||
InitLeakFinder();
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
|
||||
#endif
|
||||
|
||||
// _X: The simple built-in CRT leak finder - simply break when allocating the Nth block ({N} is listed in the leak output)
|
||||
// Only useful when the leak is in the same sequence all the time
|
||||
// _CrtSetBreakAlloc(85950);
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef _DEBUG
|
||||
#ifndef _DEBUG
|
||||
std::signal(SIGSEGV, ShowCrashReport);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
@ -53,12 +83,17 @@ int main( int argc, char **argv )
|
||||
LOGERROR("Unknown exception!");
|
||||
}
|
||||
|
||||
#if USE_SQUIRREL
|
||||
#if USE_SQUIRREL
|
||||
SquirrelVM::Shutdown();
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _DEBUG
|
||||
_CrtDumpMemoryLeaks();
|
||||
#endif
|
||||
#if defined(_MSC_VER) && defined(_DEBUG) && defined(ENABLE_LEAK_FINDER)
|
||||
DeinitLeakFinder();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -19,8 +19,9 @@ cPacket_MapChunk::~cPacket_MapChunk()
|
||||
|
||||
|
||||
|
||||
cPacket_MapChunk::cPacket_MapChunk(cChunk* a_Chunk)
|
||||
cPacket_MapChunk::cPacket_MapChunk(cChunk * a_Chunk)
|
||||
{
|
||||
assert(a_Chunk->IsValid());
|
||||
m_PacketID = E_MAP_CHUNK;
|
||||
|
||||
m_PosX = a_Chunk->GetPosX() * 16; // It has to be block coordinates
|
||||
|
@ -8,7 +8,13 @@
|
||||
|
||||
|
||||
class cChunk;
|
||||
class cPacket_MapChunk : public cPacket
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class cPacket_MapChunk :
|
||||
public cPacket
|
||||
{
|
||||
public:
|
||||
cPacket_MapChunk()
|
||||
@ -21,7 +27,7 @@ public:
|
||||
, m_CompressedSize( 0 )
|
||||
, m_CompressedData( 0 )
|
||||
{ m_PacketID = E_MAP_CHUNK; m_CompressedData = 0; }
|
||||
cPacket_MapChunk(cChunk* a_Chunk);
|
||||
|
||||
cPacket_MapChunk( const cPacket_MapChunk & a_Copy );
|
||||
~cPacket_MapChunk();
|
||||
virtual cPacket* Clone() const { return new cPacket_MapChunk(*this); }
|
||||
@ -38,6 +44,12 @@ public:
|
||||
static const unsigned int c_Size = 1 + 4 + 2 + 4 + 1 + 1 + 1 + 4;
|
||||
|
||||
char * m_CompressedData;
|
||||
|
||||
protected:
|
||||
friend class cChunk;
|
||||
|
||||
cPacket_MapChunk(cChunk * a_Chunk); // Called only from within cChunk, therefore it CAN receive a direct pointer
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -35,6 +35,20 @@ cPacket_Metadata::cPacket_Metadata()
|
||||
|
||||
|
||||
|
||||
cPacket_Metadata::cPacket_Metadata(const cPacket_Metadata & a_Other)
|
||||
: m_EMetaData( a_Other.m_EMetaData )
|
||||
, m_UniqueID( a_Other.m_UniqueID )
|
||||
, m_Type( a_Other.m_Type )
|
||||
, m_MetaData( NULL )
|
||||
{
|
||||
m_PacketID = E_METADATA;
|
||||
FormPacket();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cPacket_Metadata::~cPacket_Metadata()
|
||||
{
|
||||
delete [] m_MetaData;
|
||||
|
@ -13,6 +13,7 @@ class cPacket_Metadata : public cPacket
|
||||
public:
|
||||
cPacket_Metadata(int s, int id);
|
||||
cPacket_Metadata();
|
||||
cPacket_Metadata(const cPacket_Metadata & a_Other);
|
||||
~cPacket_Metadata();
|
||||
|
||||
virtual void Serialize(AString & a_Data) const override;
|
||||
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "cChunk.h"
|
||||
|
||||
class ptr_cChunk
|
||||
{
|
||||
public:
|
||||
ptr_cChunk( cChunk* a_Ptr )
|
||||
: m_Ptr( a_Ptr )
|
||||
{
|
||||
if( m_Ptr ) m_Ptr->AddReference();
|
||||
}
|
||||
|
||||
ptr_cChunk( const ptr_cChunk& a_Clone )
|
||||
: m_Ptr( a_Clone.m_Ptr )
|
||||
{
|
||||
if( m_Ptr ) m_Ptr->AddReference();
|
||||
}
|
||||
|
||||
~ptr_cChunk()
|
||||
{
|
||||
if( m_Ptr ) m_Ptr->RemoveReference();
|
||||
}
|
||||
|
||||
cChunk* operator-> ()
|
||||
{
|
||||
return m_Ptr;
|
||||
}
|
||||
|
||||
cChunk& operator* () { return *m_Ptr; }
|
||||
bool operator!() { return !m_Ptr; }
|
||||
bool operator==( const ptr_cChunk& a_Other ) { return m_Ptr == a_Other.m_Ptr; }
|
||||
operator bool() { return m_Ptr != 0; }
|
||||
operator cChunk*() { return m_Ptr; }
|
||||
private:
|
||||
cChunk* m_Ptr;
|
||||
};
|
Loading…
Reference in New Issue
Block a user