MCServer c++ source files
git-svn-id: http://mc-server.googlecode.com/svn/trunk@3 0a769ca7-a7f5-676a-18bf-c427514a06d6
This commit is contained in:
parent
cc2b15a233
commit
386d58b586
3
source/AllToLua.bat
Normal file
3
source/AllToLua.bat
Normal file
@ -0,0 +1,3 @@
|
||||
"tolua++.exe" -L virtual_method_hooks.lua -o Bindings.cpp -H Bindings.h AllToLua.pkg
|
||||
PAUSE
|
||||
echo "tolua++.exe" -o Bindings.cpp -H Bindings.h AllToLua.pkg
|
41
source/AllToLua.pkg
Normal file
41
source/AllToLua.pkg
Normal file
@ -0,0 +1,41 @@
|
||||
$#include "tolua_base.h"
|
||||
|
||||
$cfile "cTorch.h"
|
||||
$cfile "cStairs.h"
|
||||
$cfile "cLadder.h"
|
||||
|
||||
$cfile "../iniFile/iniFile.h"
|
||||
|
||||
$cfile "BlockID.h"
|
||||
$cfile "PacketID.h"
|
||||
$cfile "Defines.h"
|
||||
$cfile "LuaFunctions.h"
|
||||
$cfile "cStringMap.h"
|
||||
$cfile "cChatColor.h"
|
||||
$cfile "cClientHandle.h"
|
||||
$cfile "cEntity.h"
|
||||
$cfile "cPawn.h"
|
||||
$cfile "cPlayer.h"
|
||||
$cfile "cPluginManager.h"
|
||||
$cfile "cPlugin.h"
|
||||
$cfile "cPlugin_Lua.h"
|
||||
$cfile "cServer.h"
|
||||
$cfile "cWorld.h"
|
||||
$cfile "cInventory.h"
|
||||
$cfile "cItem.h"
|
||||
$cfile "cWebAdmin.h"
|
||||
$cfile "cWebPlugin.h"
|
||||
$cfile "cPickup.h"
|
||||
$cfile "cRoot.h"
|
||||
$cfile "cTCPLink.h"
|
||||
$cfile "Vector3f.h"
|
||||
$cfile "Vector3d.h"
|
||||
$cfile "Vector3i.h"
|
||||
$cfile "Matrix4f.h"
|
||||
$cfile "cCuboid.h"
|
||||
$cfile "cMCLogger.h"
|
||||
$cfile "cTracer.h"
|
||||
$cfile "cGroup.h"
|
||||
$cfile "packets/cPacket_Login.h"
|
||||
$cfile "packets/cPacket_BlockDig.h"
|
||||
$cfile "packets/cPacket_BlockPlace.h"
|
15468
source/Bindings.cpp
Normal file
15468
source/Bindings.cpp
Normal file
File diff suppressed because it is too large
Load Diff
8
source/Bindings.h
Normal file
8
source/Bindings.h
Normal file
@ -0,0 +1,8 @@
|
||||
/*
|
||||
** Lua binding: AllToLua
|
||||
** Generated automatically by tolua++-1.0.92 on 07/15/11 01:36:28.
|
||||
*/
|
||||
|
||||
/* Exported function */
|
||||
TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S);
|
||||
|
151
source/BlockID.h
Normal file
151
source/BlockID.h
Normal file
@ -0,0 +1,151 @@
|
||||
#pragma once
|
||||
|
||||
//tolua_begin
|
||||
enum ENUM_BLOCK_ID
|
||||
{
|
||||
E_BLOCK_AIR = 0,
|
||||
E_BLOCK_STONE = 1,
|
||||
E_BLOCK_GRASS = 2,
|
||||
E_BLOCK_DIRT = 3,
|
||||
E_BLOCK_COBBLESTONE = 4,
|
||||
E_BLOCK_WOOD = 5,
|
||||
E_BLOCK_SAPLING = 6,
|
||||
E_BLOCK_BEDROCK = 7,
|
||||
E_BLOCK_WATER = 8,
|
||||
E_BLOCK_STATIONARY_WATER = 9,
|
||||
E_BLOCK_LAVA = 10,
|
||||
E_BLOCK_STATIONARY_LAVA = 11,
|
||||
E_BLOCK_SAND = 12,
|
||||
E_BLOCK_GRAVEL = 13,
|
||||
E_BLOCK_GOLD_ORE = 14,
|
||||
E_BLOCK_IRON_ORE = 15,
|
||||
E_BLOCK_COAL_ORE = 16,
|
||||
E_BLOCK_LOG = 17,
|
||||
E_BLOCK_LEAVES = 18,
|
||||
E_BLOCK_SPONGE = 19,
|
||||
E_BLOCK_GLASS = 20,
|
||||
E_BLOCK_WHITE_CLOTH = 35,
|
||||
E_BLOCK_YELLOW_FLOWER = 37,
|
||||
E_BLOCK_RED_ROSE = 38,
|
||||
E_BLOCK_BROWN_MUSHROOM = 39,
|
||||
E_BLOCK_RED_MUSHROOM = 40,
|
||||
E_BLOCK_GOLD_BLOCK = 41,
|
||||
E_BLOCK_IRON_BLOCK = 42,
|
||||
E_BLOCK_DOUBLE_STEP = 43,
|
||||
E_BLOCK_STEP = 44,
|
||||
E_BLOCK_BRICK = 45,
|
||||
E_BLOCK_TNT = 46,
|
||||
E_BLOCK_BOOKCASE = 47,
|
||||
E_BLOCK_MOSSY_COBBLESTONE = 48,
|
||||
E_BLOCK_OBSIDIAN = 49,
|
||||
E_BLOCK_TORCH = 50,
|
||||
E_BLOCK_FIRE = 51,
|
||||
E_BLOCK_MOB_SPAWNER = 52,
|
||||
E_BLOCK_WOODEN_STAIRS = 53,
|
||||
E_BLOCK_CHEST = 54,
|
||||
E_BLOCK_REDSTONE_WIRE = 55,
|
||||
E_BLOCK_DIAMOND_ORE = 56,
|
||||
E_BLOCK_DIAMOND_BLOCK = 57,
|
||||
E_BLOCK_WORKBENCH = 58,
|
||||
E_BLOCK_CROPS = 59,
|
||||
E_BLOCK_SOIL = 60,
|
||||
E_BLOCK_FURNACE = 61,
|
||||
E_BLOCK_BURNING_FURNACE = 62,
|
||||
E_BLOCK_SIGN_POST = 63,
|
||||
E_BLOCK_WOODEN_DOOR = 64,
|
||||
E_BLOCK_LADDER = 65,
|
||||
E_BLOCK_MINECART_TRACKS = 66,
|
||||
E_BLOCK_COBBLESTONE_STAIRS = 67,
|
||||
E_BLOCK_WALLSIGN = 68,
|
||||
E_BLOCK_LEVER = 69,
|
||||
E_BLOCK_STONE_PRESSURE_PLATE = 70,
|
||||
E_BLOCK_IRON_DOOR = 71,
|
||||
E_BLOCK_WOODEN_PRESSURE_PLATE = 72,
|
||||
E_BLOCK_REDSTONE_ORE = 73,
|
||||
E_BLOCK_REDSTONE_ORE_GLOWING = 74,
|
||||
E_BLOCK_REDSTONE_TORCH_ON = 75,
|
||||
E_BLOCK_REDSTONE_TORCH_OFF = 76,
|
||||
|
||||
E_BLOCK_SNOW = 78,
|
||||
E_BLOCK_ICE = 79,
|
||||
E_BLOCK_SNOW_BLOCK = 80,
|
||||
E_BLOCK_CACTUS = 81,
|
||||
E_BLOCK_CLAY = 82,
|
||||
E_BLOCK_REEDS = 83,
|
||||
|
||||
E_BLOCK_BLOODSTONE = 87,
|
||||
E_BLOCK_SOULSAND = 88,
|
||||
E_BLOCK_GLOWSTONE = 89,
|
||||
E_BLOCK_PORT = 90,
|
||||
E_BLOCK_JACK_O_LANTERN = 91,
|
||||
E_BLOCK_CAKE = 92,
|
||||
E_BLOCK_REDSTONE_REPEATER_OFF = 93,
|
||||
E_BLOCK_REDSTONE_REPEATER_ON = 94,
|
||||
E_BLOCK_LOCKED_CHEST = 95,
|
||||
E_BLOCK_TRAPDOOR = 96,
|
||||
};
|
||||
//tolua_end
|
||||
|
||||
//tolua_begin
|
||||
enum ENUM_ITEM_ID
|
||||
{
|
||||
E_ITEM_EMPTY = -1,
|
||||
E_ITEM_STONE = 1,
|
||||
E_ITEM_GRASS = 2,
|
||||
E_ITEM_DIRT = 3,
|
||||
E_ITEM_COBBLESTONE = 4,
|
||||
E_ITEM_WOOD = 5,
|
||||
E_ITEM_SAPLING = 6,
|
||||
E_ITEM_BEDROCK = 7,
|
||||
E_ITEM_WATER = 8,
|
||||
E_ITEM_STATIONARY_WATER = 9,
|
||||
E_ITEM_LAVA = 10,
|
||||
E_ITEM_STATIONARY_LAVA = 11,
|
||||
E_ITEM_SAND = 12,
|
||||
E_ITEM_GRAVEL = 13,
|
||||
E_ITEM_GOLD_ORE = 14,
|
||||
E_ITEM_IRON_ORE = 15,
|
||||
E_ITEM_COAL_ORE = 16,
|
||||
E_ITEM_LOG = 17,
|
||||
E_ITEM_LEAVES = 18,
|
||||
E_ITEM_GOLD_BLOCK = 41,
|
||||
E_ITEM_IRON_BLOCK = 42,
|
||||
E_ITEM_DIAMOND_BLOCK = 57,
|
||||
E_ITEM_FLINT_AND_STEEL = 259,
|
||||
E_ITEM_APPLE = 260,
|
||||
E_ITEM_BOW = 261,
|
||||
E_ITEM_ARROW = 262,
|
||||
E_ITEM_COAL = 263,
|
||||
E_ITEM_DIAMOND = 264,
|
||||
E_ITEM_IRON = 265,
|
||||
E_ITEM_GOLD = 266,
|
||||
|
||||
E_ITEM_MUSHROOM_SOUP = 282,
|
||||
E_ITEM_GOLD_SWORD = 283,
|
||||
E_ITEM_GOLD_SHOVEL = 284,
|
||||
E_ITEM_GOLD_PICKAXE = 285,
|
||||
E_ITEM_GOLD_AXE = 286,
|
||||
E_ITEM_STRING = 287,
|
||||
E_ITEM_FEATHER = 288,
|
||||
|
||||
E_ITEM_BREAD = 297,
|
||||
|
||||
E_ITEM_RAW_MEAT = 319,
|
||||
E_ITEM_COOKED_MEAT = 320,
|
||||
|
||||
E_ITEM_GOLDEN_APPLE = 322,
|
||||
E_ITEM_SIGN = 323,
|
||||
|
||||
E_ITEM_MILK = 335,
|
||||
|
||||
E_ITEM_EGG = 344,
|
||||
E_ITEM_COMPASS = 345,
|
||||
E_ITEM_FISHING_ROD = 346,
|
||||
E_ITEM_CLOCK = 347,
|
||||
E_ITEM_GLOWSTONE_DUST = 348,
|
||||
E_ITEM_RAW_FISH = 349,
|
||||
E_ITEM_COOKED_FISH = 350,
|
||||
|
||||
E_ITEM_CAKE = 354,
|
||||
};
|
||||
//tolua_end
|
129
source/Defines.h
Normal file
129
source/Defines.h
Normal file
@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include "MemoryLeak.h"
|
||||
|
||||
//tolua_begin
|
||||
// emissive blocks
|
||||
extern char g_BlockLightValue[];
|
||||
// whether blocks allow spreading
|
||||
extern char g_BlockSpreadLightFalloff[];
|
||||
// whether blocks are transparent (light can shine though)
|
||||
extern bool g_BlockTransparent[];
|
||||
// one hit break blocks
|
||||
extern bool g_BlockOneHitDig[];
|
||||
//tolua_end
|
||||
|
||||
//--DO NOT DELETE THIS COMMENT-- //tolua_export
|
||||
|
||||
inline bool IsValidBlock( int a_BlockID ) //tolua_export
|
||||
{ //tolua_export
|
||||
if( a_BlockID > -1 &&
|
||||
a_BlockID <= 96 &&
|
||||
a_BlockID != 29 &&
|
||||
a_BlockID != 33 &&
|
||||
a_BlockID != 34 &&
|
||||
a_BlockID != 36 )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} //tolua_export
|
||||
|
||||
inline bool isValidItem( int a_ItemID ) //tolua_export
|
||||
{ //tolua_export
|
||||
if( (a_ItemID >= 256 && a_ItemID <= 358)
|
||||
|| (a_ItemID == 2256 || a_ItemID == 2257) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if( a_ItemID == 0 )
|
||||
return false;
|
||||
|
||||
return IsValidBlock( a_ItemID );
|
||||
} //tolua_export
|
||||
|
||||
inline void AddDirection( int & a_X, char & a_Y, int & a_Z, char a_Direction, bool a_bInverse = false ) //tolua_export
|
||||
{//tolua_export
|
||||
if( !a_bInverse )
|
||||
{
|
||||
switch( a_Direction )
|
||||
{
|
||||
case 0:
|
||||
a_Y--;
|
||||
break;
|
||||
case 1:
|
||||
a_Y++;
|
||||
break;
|
||||
case 2:
|
||||
a_Z--;
|
||||
break;
|
||||
case 3:
|
||||
a_Z++;
|
||||
break;
|
||||
case 4:
|
||||
a_X--;
|
||||
break;
|
||||
case 5:
|
||||
a_X++;
|
||||
break;
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
switch( a_Direction ) // other way around
|
||||
{
|
||||
case 0:
|
||||
a_Y++;
|
||||
break;
|
||||
case 1:
|
||||
a_Y--;
|
||||
break;
|
||||
case 2:
|
||||
a_Z++;
|
||||
break;
|
||||
case 3:
|
||||
a_Z--;
|
||||
break;
|
||||
case 4:
|
||||
a_X++;
|
||||
break;
|
||||
case 5:
|
||||
a_X--;
|
||||
break;
|
||||
};
|
||||
}
|
||||
}//tolua_export
|
||||
|
||||
#include <math.h>
|
||||
#define PI 3.14159265358979323846264338327950288419716939937510582097494459072381640628620899862803482534211706798f
|
||||
#define MIN(a,b) (((a)>(b))?(b):(a))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
inline void EulerToVector( float a_Pan, float a_Pitch, float & a_X, float & a_Y, float & a_Z )
|
||||
{
|
||||
// a_X = sinf ( a_Pan / 180 * PI ) * cosf ( a_Pitch / 180 * PI );
|
||||
// a_Y = -sinf ( a_Pitch / 180 * PI );
|
||||
// a_Z = -cosf ( a_Pan / 180 * PI ) * cosf ( a_Pitch / 180 * PI );
|
||||
a_X = cos(a_Pan / 180 * PI)*cos(a_Pitch / 180 * PI);
|
||||
a_Y = sin(a_Pan / 180 * PI)*cos(a_Pitch / 180 * PI);
|
||||
a_Z = sin(a_Pitch / 180 * PI);
|
||||
}
|
||||
|
||||
inline void VectorToEuler( float a_X, float a_Y, float a_Z, float & a_Pan, float & a_Pitch )
|
||||
{
|
||||
if( a_X != 0 )
|
||||
a_Pan = atan2( a_Z, a_X ) * 180 / PI - 90;
|
||||
else
|
||||
a_Pan = 0;
|
||||
a_Pitch = atan2(a_Y, sqrtf((a_X * a_X) + (a_Z * a_Z))) * 180 / PI;
|
||||
}
|
||||
|
||||
inline float GetSignf( float a_Val )
|
||||
{
|
||||
return (a_Val < 0.f)?-1.f:1.f;
|
||||
}
|
||||
|
||||
inline float GetSpecialSignf( float a_Val )
|
||||
{
|
||||
return (a_Val <= 0.f)?-1.f:1.f;
|
||||
}
|
51
source/Endianness.h
Normal file
51
source/Endianness.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include <WinSock.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
// Changes endianness
|
||||
inline unsigned long long HostToNetwork8( void* a_Value )
|
||||
{
|
||||
unsigned long long __HostToNetwork8;
|
||||
memcpy( &__HostToNetwork8, a_Value, sizeof( __HostToNetwork8 ) );
|
||||
__HostToNetwork8 = (( ( (unsigned long long)htonl((u_long)__HostToNetwork8) ) << 32) + htonl(__HostToNetwork8 >> 32));
|
||||
return __HostToNetwork8;
|
||||
}
|
||||
|
||||
inline unsigned int HostToNetwork4( void* a_Value )
|
||||
{
|
||||
unsigned int __HostToNetwork4;
|
||||
memcpy( &__HostToNetwork4, a_Value, sizeof( __HostToNetwork4 ) );
|
||||
__HostToNetwork4 = ntohl( __HostToNetwork4 );
|
||||
return __HostToNetwork4;
|
||||
}
|
||||
|
||||
inline double NetworkToHostDouble8( void* a_Value )
|
||||
{
|
||||
#define ntohll(x) ((((unsigned long long)ntohl((u_long)x)) << 32) + ntohl(x >> 32))
|
||||
unsigned long long buf = 0;//(*(unsigned long long*)a_Value);
|
||||
memcpy( &buf, a_Value, 8 );
|
||||
buf = ntohll(buf);
|
||||
double x;
|
||||
memcpy(&x, &buf, sizeof(double));
|
||||
return x;
|
||||
}
|
||||
|
||||
inline long long NetworkToHostLong8( void* a_Value )
|
||||
{
|
||||
unsigned long long buf = *(unsigned long long*)a_Value;
|
||||
buf = ntohll(buf);
|
||||
return *reinterpret_cast<long long *>(&buf);
|
||||
}
|
||||
|
||||
inline float NetworkToHostFloat4( void* a_Value )
|
||||
{
|
||||
u_long buf = *(u_long*)a_Value;
|
||||
buf = ntohl( buf );
|
||||
return *(float*)reinterpret_cast<float *>(&buf);
|
||||
}
|
21
source/FileDefine.h
Normal file
21
source/FileDefine.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
// So we don't have to include fstream :P
|
||||
#ifdef _WIN32
|
||||
#ifndef _FILE_DEFINED
|
||||
struct _iobuf {
|
||||
char *_ptr;
|
||||
int _cnt;
|
||||
char *_base;
|
||||
int _flag;
|
||||
int _file;
|
||||
int _charbuf;
|
||||
int _bufsiz;
|
||||
char *_tmpfname;
|
||||
};
|
||||
typedef struct _iobuf FILE;
|
||||
#define _FILE_DEFINED
|
||||
#endif
|
||||
#else
|
||||
#include <stdio.h>
|
||||
#endif
|
17
source/LuaFunctions.h
Normal file
17
source/LuaFunctions.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "cMCLogger.h"
|
||||
#include <time.h>
|
||||
// tolua_begin
|
||||
|
||||
unsigned int GetTime()
|
||||
{
|
||||
return (unsigned int)time(0);
|
||||
}
|
||||
|
||||
std::string GetChar( std::string & a_Str, unsigned int a_Idx )
|
||||
{
|
||||
return std::string(1, a_Str[ a_Idx ]);
|
||||
}
|
||||
|
||||
// tolua_end
|
41
source/MCSocket.h
Normal file
41
source/MCSocket.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <winsock2.h>
|
||||
#define socklen_t int
|
||||
#ifdef SendMessage
|
||||
#undef SendMessage
|
||||
#endif
|
||||
#else
|
||||
|
||||
// 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 <pthread.h>
|
||||
#include <unistd.h>
|
||||
#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)
|
||||
#define sprintf_s(x, y, ...) sprintf(x, __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
inline bool IsSocketError( int a_ReturnedValue )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (a_ReturnedValue == SOCKET_ERROR || a_ReturnedValue == 0);
|
||||
#else
|
||||
return (a_ReturnedValue <= 0);
|
||||
#endif
|
||||
}
|
229
source/ManualBindings.cpp
Normal file
229
source/ManualBindings.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#include "ManualBindings.h"
|
||||
#include "tolua++.h"
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#include "cRoot.h"
|
||||
#include "cWorld.h"
|
||||
#include "cPlugin.h"
|
||||
#include "cPluginManager.h"
|
||||
#include "cLuaCommandBinder.h"
|
||||
#include "cPlayer.h"
|
||||
#include "md5/md5.h"
|
||||
|
||||
extern std::vector<std::string> StringSplit(std::string str, std::string delim);
|
||||
|
||||
/****************************
|
||||
* Lua bound functions with special return types
|
||||
**/
|
||||
|
||||
static int tolua_StringSplit(lua_State* tolua_S)
|
||||
{
|
||||
std::string str = ((std::string) tolua_tocppstring(tolua_S,1,0));
|
||||
std::string delim = ((std::string) tolua_tocppstring(tolua_S,2,0));
|
||||
|
||||
std::vector<std::string> Split = StringSplit( str, delim );
|
||||
|
||||
lua_createtable(tolua_S, Split.size(), 0);
|
||||
int newTable = lua_gettop(tolua_S);
|
||||
int index = 1;
|
||||
std::vector<std::string>::const_iterator iter = Split.begin();
|
||||
while(iter != Split.end()) {
|
||||
tolua_pushstring( tolua_S, (*iter).c_str() );
|
||||
lua_rawseti(tolua_S, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tolua_LOG(lua_State* tolua_S)
|
||||
{
|
||||
const char* str = tolua_tocppstring(tolua_S,1,0);
|
||||
cMCLogger::GetInstance()->LogSimple( str, 0 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_LOGINFO(lua_State* tolua_S)
|
||||
{
|
||||
const char* str = tolua_tocppstring(tolua_S,1,0);
|
||||
cMCLogger::GetInstance()->LogSimple( str, 1 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_LOGWARN(lua_State* tolua_S)
|
||||
{
|
||||
const char* str = tolua_tocppstring(tolua_S,1,0);
|
||||
cMCLogger::GetInstance()->LogSimple( str, 2 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_LOGERROR(lua_State* tolua_S)
|
||||
{
|
||||
const char* str = tolua_tocppstring(tolua_S,1,0);
|
||||
cMCLogger::GetInstance()->LogSimple( str, 3 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_cWorld_GetAllPlayers(lua_State* tolua_S)
|
||||
{
|
||||
cWorld* self = (cWorld*) tolua_tousertype(tolua_S,1,0);
|
||||
lua_State* L = tolua_S;
|
||||
|
||||
self->GetAllPlayers(L);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tolua_cPlugin_GetCommands(lua_State* tolua_S)
|
||||
{
|
||||
cPlugin* self = (cPlugin*) tolua_tousertype(tolua_S,1,0);
|
||||
|
||||
const std::vector< cPlugin::CommandStruct > & AllCommands = self->GetCommands();
|
||||
|
||||
lua_createtable(tolua_S, AllCommands.size(), 0);
|
||||
int newTable = lua_gettop(tolua_S);
|
||||
int index = 1;
|
||||
std::vector< cPlugin::CommandStruct >::const_iterator iter = AllCommands.begin();
|
||||
while(iter != AllCommands.end())
|
||||
{
|
||||
const cPlugin::CommandStruct & CS = *iter;
|
||||
tolua_pushusertype( tolua_S, (void*)&CS, "const cPlugin::CommandStruct" );
|
||||
lua_rawseti(tolua_S, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tolua_cPluginManager_GetAllPlugins(lua_State* tolua_S)
|
||||
{
|
||||
cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0);
|
||||
|
||||
const cPluginManager::PluginList & AllPlugins = self->GetAllPlugins();
|
||||
|
||||
lua_createtable(tolua_S, AllPlugins.size(), 0);
|
||||
int newTable = lua_gettop(tolua_S);
|
||||
int index = 1;
|
||||
cPluginManager::PluginList::const_iterator iter = AllPlugins.begin();
|
||||
while(iter != AllPlugins.end())
|
||||
{
|
||||
const cPlugin* Plugin = *iter;
|
||||
tolua_pushusertype( tolua_S, (void*)Plugin, "const cPlugin" );
|
||||
lua_rawseti(tolua_S, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tolua_cPlayer_GetGroups(lua_State* tolua_S)
|
||||
{
|
||||
cPlayer* self = (cPlayer*) tolua_tousertype(tolua_S,1,0);
|
||||
|
||||
const cPlayer::GroupList & AllGroups = self->GetGroups();
|
||||
|
||||
lua_createtable(tolua_S, AllGroups.size(), 0);
|
||||
int newTable = lua_gettop(tolua_S);
|
||||
int index = 1;
|
||||
cPlayer::GroupList::const_iterator iter = AllGroups.begin();
|
||||
while(iter != AllGroups.end())
|
||||
{
|
||||
const cGroup* Group = *iter;
|
||||
tolua_pushusertype( tolua_S, (void*)Group, "const cGroup" );
|
||||
lua_rawseti(tolua_S, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int tolua_cPlugin_BindCommand(lua_State* tolua_S)
|
||||
{
|
||||
cPlugin* self = (cPlugin*) tolua_tousertype(tolua_S,1,0);
|
||||
cPluginManager* PluginManager = cRoot::Get()->GetPluginManager();
|
||||
cLuaCommandBinder* CommandBinder = PluginManager->GetLuaCommandBinder();
|
||||
|
||||
tolua_Error tolua_err;
|
||||
tolua_err.array = 0;
|
||||
tolua_err.index = 0;
|
||||
tolua_err.type = 0;
|
||||
|
||||
std::string Permission = "";
|
||||
std::string Command = "";
|
||||
int Reference = LUA_REFNIL;
|
||||
|
||||
if( tolua_isstring( tolua_S, 2, 0, &tolua_err ) &&
|
||||
lua_isfunction( tolua_S, 3 ) )
|
||||
{
|
||||
Reference = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
|
||||
Command = ((std::string) tolua_tocppstring(tolua_S,2,0));
|
||||
}
|
||||
else if( tolua_isstring( tolua_S, 2, 0, &tolua_err ) &&
|
||||
tolua_isstring( tolua_S, 3, 0, &tolua_err ) &&
|
||||
lua_isfunction( tolua_S, 4 ) )
|
||||
{
|
||||
Reference = luaL_ref(tolua_S, LUA_REGISTRYINDEX);
|
||||
Command = ((std::string) tolua_tocppstring(tolua_S,2,0));
|
||||
Permission = ((std::string) tolua_tocppstring(tolua_S,3,0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if( tolua_err.type == 0 )
|
||||
{
|
||||
tolua_err.type = "function";
|
||||
}
|
||||
tolua_error(tolua_S,"#ferror in function 'BindCommand'.",&tolua_err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if( Reference != LUA_REFNIL )
|
||||
{
|
||||
if( !CommandBinder->BindCommand( Command, Permission, self, tolua_S, Reference ) )
|
||||
{
|
||||
luaL_unref( tolua_S, LUA_REGISTRYINDEX, Reference );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("ERROR: cPlugin:BindCommand invalid function reference in 2nd argument (Command: \"%s\")", Command.c_str() );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tolua_md5(lua_State* tolua_S)
|
||||
{
|
||||
std::string SourceString = tolua_tostring(tolua_S, 1, 0);
|
||||
std::string CryptedString = md5( SourceString );
|
||||
tolua_pushstring( tolua_S, CryptedString.c_str() );
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ManualBindings::Bind( lua_State* tolua_S )
|
||||
{
|
||||
tolua_beginmodule(tolua_S,NULL);
|
||||
tolua_function(tolua_S,"StringSplit",tolua_StringSplit);
|
||||
tolua_function(tolua_S,"LOG",tolua_LOG);
|
||||
tolua_function(tolua_S,"LOGINFO",tolua_LOGINFO);
|
||||
tolua_function(tolua_S,"LOGWARN",tolua_LOGWARN);
|
||||
tolua_function(tolua_S,"LOGERROR",tolua_LOGERROR);
|
||||
tolua_function(tolua_S,"Log",tolua_LOG); // Deprecated
|
||||
|
||||
tolua_beginmodule(tolua_S,"cWorld");
|
||||
tolua_function(tolua_S,"GetAllPlayers",tolua_cWorld_GetAllPlayers);
|
||||
tolua_endmodule(tolua_S);
|
||||
tolua_beginmodule(tolua_S,"cPlugin");
|
||||
tolua_function(tolua_S,"GetCommands",tolua_cPlugin_GetCommands);
|
||||
tolua_function(tolua_S,"BindCommand",tolua_cPlugin_BindCommand);
|
||||
tolua_endmodule(tolua_S);
|
||||
tolua_beginmodule(tolua_S,"cPluginManager");
|
||||
tolua_function(tolua_S,"GetAllPlugins",tolua_cPluginManager_GetAllPlugins);
|
||||
tolua_endmodule(tolua_S);
|
||||
tolua_beginmodule(tolua_S,"cPlayer");
|
||||
tolua_function(tolua_S,"GetGroups",tolua_cPlayer_GetGroups);
|
||||
tolua_endmodule(tolua_S);
|
||||
|
||||
tolua_function(tolua_S,"md5",tolua_md5);
|
||||
|
||||
tolua_endmodule(tolua_S);
|
||||
}
|
8
source/ManualBindings.h
Normal file
8
source/ManualBindings.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
struct lua_State;
|
||||
class ManualBindings
|
||||
{
|
||||
public:
|
||||
static void Bind( lua_State* tolua_S );
|
||||
};
|
0
source/Matrix4f.cpp
Normal file
0
source/Matrix4f.cpp
Normal file
111
source/Matrix4f.h
Normal file
111
source/Matrix4f.h
Normal file
@ -0,0 +1,111 @@
|
||||
#pragma once
|
||||
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include "Vector3f.h"
|
||||
|
||||
class Matrix4f
|
||||
{
|
||||
public:
|
||||
enum
|
||||
{
|
||||
TX=3,
|
||||
TY=7,
|
||||
TZ=11,
|
||||
D0=0, D1=5, D2=10, D3=15,
|
||||
SX=D0, SY=D1, SZ=D2,
|
||||
W=D3
|
||||
};
|
||||
Matrix4f() { Identity(); }
|
||||
float& operator [] ( int a_N ) { return cell[a_N]; }
|
||||
void Identity()
|
||||
{
|
||||
cell[1] = cell[2] = cell[TX] = cell[4] = cell[6] = cell[TY] =
|
||||
cell[8] = cell[9] = cell[TZ] = cell[12] = cell[13] = cell[14] = 0;
|
||||
cell[D0] = cell[D1] = cell[D2] = cell[W] = 1;
|
||||
}
|
||||
void Init( Vector3f a_Pos, float a_RX, float a_RY, float a_RZ )
|
||||
{
|
||||
Matrix4f t;
|
||||
t.RotateX( a_RZ );
|
||||
RotateY( a_RY );
|
||||
Concatenate( t );
|
||||
t.RotateZ( a_RX );
|
||||
Concatenate( t );
|
||||
Translate( a_Pos );
|
||||
}
|
||||
void RotateX( float a_RX )
|
||||
{
|
||||
float sx = (float)sin( a_RX * M_PI / 180 );
|
||||
float cx = (float)cos( a_RX * M_PI / 180 );
|
||||
Identity();
|
||||
cell[5] = cx, cell[6] = sx, cell[9] = -sx, cell[10] = cx;
|
||||
}
|
||||
void RotateY( float a_RY )
|
||||
{
|
||||
float sy = (float)sin( a_RY * M_PI / 180 );
|
||||
float cy = (float)cos( a_RY * M_PI / 180 );
|
||||
Identity ();
|
||||
cell[0] = cy, cell[2] = -sy, cell[8] = sy, cell[10] = cy;
|
||||
}
|
||||
void RotateZ( float a_RZ )
|
||||
{
|
||||
float sz = (float)sin( a_RZ * M_PI / 180 );
|
||||
float cz = (float)cos( a_RZ * M_PI / 180 );
|
||||
Identity ();
|
||||
cell[0] = cz, cell[1] = sz, cell[4] = -sz, cell[5] = cz;
|
||||
}
|
||||
void Translate( Vector3f a_Pos ) { cell[TX] += a_Pos.x; cell[TY] += a_Pos.y; cell[TZ] += a_Pos.z; }
|
||||
void SetTranslation( Vector3f a_Pos ) { cell[TX] = a_Pos.x; cell[TY] = a_Pos.y; cell[TZ] = a_Pos.z; }
|
||||
void Concatenate( const Matrix4f& m2 )
|
||||
{
|
||||
Matrix4f res;
|
||||
int c;
|
||||
for ( c = 0; c < 4; c++ ) for ( int r = 0; r < 4; r++ )
|
||||
res.cell[r * 4 + c] = cell[r * 4] * m2.cell[c] +
|
||||
cell[r * 4 + 1] * m2.cell[c + 4] +
|
||||
cell[r * 4 + 2] * m2.cell[c + 8] +
|
||||
cell[r * 4 + 3] * m2.cell[c + 12];
|
||||
for ( c = 0; c < 16; c++ ) cell[c] = res.cell[c];
|
||||
}
|
||||
Vector3f Transform( const Vector3f& v ) const
|
||||
{
|
||||
float x = cell[0] * v.x + cell[1] * v.y + cell[2] * v.z + cell[3];
|
||||
float y = cell[4] * v.x + cell[5] * v.y + cell[6] * v.z + cell[7];
|
||||
float z = cell[8] * v.x + cell[9] * v.y + cell[10] * v.z + cell[11];
|
||||
return Vector3f( x, y, z );
|
||||
}
|
||||
void Invert()
|
||||
{
|
||||
Matrix4f t;
|
||||
int h, i;
|
||||
float tx = -cell[3], ty = -cell[7], tz = -cell[11];
|
||||
for ( h = 0; h < 3; h++ ) for ( int v = 0; v < 3; v++ ) t.cell[h + v * 4] = cell[v + h * 4];
|
||||
for ( i = 0; i < 11; i++ ) cell[i] = t.cell[i];
|
||||
cell[3] = tx * cell[0] + ty * cell[1] + tz * cell[2];
|
||||
cell[7] = tx * cell[4] + ty * cell[5] + tz * cell[6];
|
||||
cell[11] = tx * cell[8] + ty * cell[9] + tz * cell[10];
|
||||
}
|
||||
Vector3f GetXColumn() { return Vector3f( cell[0], cell[1], cell[2] ); }
|
||||
Vector3f GetYColumn() { return Vector3f( cell[4], cell[5], cell[6] ); }
|
||||
Vector3f GetZColumn() { return Vector3f( cell[8], cell[9], cell[10] ); }
|
||||
void SetXColumn( const Vector3f & a_X )
|
||||
{
|
||||
cell[0] = a_X.x;
|
||||
cell[1] = a_X.y;
|
||||
cell[2] = a_X.z;
|
||||
}
|
||||
void SetYColumn( const Vector3f & a_Y )
|
||||
{
|
||||
cell[4] = a_Y.x;
|
||||
cell[5] = a_Y.y;
|
||||
cell[6] = a_Y.z;
|
||||
}
|
||||
void SetZColumn( const Vector3f & a_Z )
|
||||
{
|
||||
cell[8] = a_Z.x;
|
||||
cell[9] = a_Z.y;
|
||||
cell[10] = a_Z.z;
|
||||
}
|
||||
float cell[16];
|
||||
};
|
18
source/MemoryLeak.h
Normal file
18
source/MemoryLeak.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#ifdef _DEBUG
|
||||
|
||||
#define _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
|
||||
#ifndef DEBUG_NEW
|
||||
#define DEBUG_NEW new(_NORMAL_BLOCK, __FILE__, __LINE__)
|
||||
#define new DEBUG_NEW
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
52
source/PacketID.h
Normal file
52
source/PacketID.h
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
//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,
|
||||
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_WINDOW_OPEN = 0x64,
|
||||
E_WINDOW_CLOSE = 0x65,
|
||||
E_WINDOW_CLICK = 0x66,
|
||||
E_INVENTORY_SLOT = 0x67,
|
||||
E_INVENTORY_WHOLE = 0x68,
|
||||
E_INVENTORY_PROGRESS= 0x69,
|
||||
E_UPDATE_SIGN = 0x82,
|
||||
E_PING = 0xfe,
|
||||
E_DISCONNECT = 0xff,
|
||||
};
|
||||
//tolua_end
|
16
source/Vector3d.cpp
Normal file
16
source/Vector3d.cpp
Normal file
@ -0,0 +1,16 @@
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3f.h"
|
||||
|
||||
Vector3d::Vector3d(const Vector3f & v )
|
||||
: x( v.x )
|
||||
, y( v.y )
|
||||
, z( v.z )
|
||||
{
|
||||
}
|
||||
|
||||
Vector3d::Vector3d(const Vector3f * v )
|
||||
: x( v->x )
|
||||
, y( v->y )
|
||||
, z( v->z )
|
||||
{
|
||||
}
|
40
source/Vector3d.h
Normal file
40
source/Vector3d.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class Vector3f;
|
||||
class Vector3d //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
// convert from float
|
||||
Vector3d(const Vector3f & v ); //tolua_export
|
||||
Vector3d(const Vector3f * v ); //tolua_export
|
||||
|
||||
Vector3d() : x(0), y(0), z(0) {} //tolua_export
|
||||
Vector3d(double a_x, double a_y, double a_z) : x(a_x), y(a_y), z(a_z) {} //tolua_export
|
||||
|
||||
inline void Set(double a_x, double a_y, double a_z) { x = a_x, y = a_y, z = a_z; } //tolua_export
|
||||
inline void Normalize() { double l = 1.0f / Length(); x *= l; y *= l; z *= l; } //tolua_export
|
||||
inline Vector3d NormalizeCopy() { double l = 1.0f / Length(); return Vector3d( x * l, y * l, z * l ); } //tolua_export
|
||||
inline void NormalizeCopy(Vector3d & a_V) { double l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); } //tolua_export
|
||||
inline double Length() const { return (double)sqrt( x * x + y * y + z * z ); } //tolua_export
|
||||
inline double SqrLength() const { return x * x + y * y + z * z; } //tolua_export
|
||||
inline double Dot( const Vector3d & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } //tolua_export
|
||||
inline Vector3d Cross( const Vector3d & v ) const { return Vector3d( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } //tolua_export
|
||||
|
||||
void operator += ( const Vector3d& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
|
||||
void operator += ( Vector3d* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
|
||||
void operator -= ( const Vector3d& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
|
||||
void operator -= ( Vector3d* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
|
||||
void operator *= ( double a_f ) { x *= a_f; y *= a_f; z *= a_f; }
|
||||
|
||||
Vector3d operator + ( const Vector3d& v2 ) const { return Vector3d( x + v2.x, y + v2.y, z + v2.z ); } //tolua_export
|
||||
Vector3d operator + ( const Vector3d* v2 ) const { return Vector3d( x + v2->x, y + v2->y, z + v2->z ); } //tolua_export
|
||||
Vector3d operator - ( const Vector3d& v2 ) const { return Vector3d( x - v2.x, y - v2.y, z - v2.z ); } //tolua_export
|
||||
Vector3d operator - ( const Vector3d* v2 ) const { return Vector3d( x - v2->x, y - v2->y, z - v2->z ); } //tolua_export
|
||||
Vector3d operator * ( const double f ) const { return Vector3d( x * f, y * f, z * f ); } //tolua_export
|
||||
Vector3d operator * ( const Vector3d& v2 ) const { return Vector3d( x * v2.x, y * v2.y, z * v2.z ); } //tolua_export
|
||||
|
||||
double x, y, z; //tolua_export
|
||||
|
||||
};//tolua_export
|
31
source/Vector3f.cpp
Normal file
31
source/Vector3f.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "Vector3f.h"
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3i.h"
|
||||
|
||||
Vector3f::Vector3f( const Vector3d & v )
|
||||
: x( (float)v.x )
|
||||
, y( (float)v.y )
|
||||
, z( (float)v.z )
|
||||
{
|
||||
}
|
||||
|
||||
Vector3f::Vector3f( const Vector3d * v )
|
||||
: x( (float)v->x )
|
||||
, y( (float)v->y )
|
||||
, z( (float)v->z )
|
||||
{
|
||||
}
|
||||
|
||||
Vector3f::Vector3f( const Vector3i & v )
|
||||
: x( (float)v.x )
|
||||
, y( (float)v.y )
|
||||
, z( (float)v.z )
|
||||
{
|
||||
}
|
||||
|
||||
Vector3f::Vector3f( const Vector3i * v )
|
||||
: x( (float)v->x )
|
||||
, y( (float)v->y )
|
||||
, z( (float)v->z )
|
||||
{
|
||||
}
|
47
source/Vector3f.h
Normal file
47
source/Vector3f.h
Normal file
@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class Vector3i;
|
||||
class Vector3d;
|
||||
class Vector3f //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
Vector3f( const Vector3d & v ); //tolua_export
|
||||
Vector3f( const Vector3d * v ); //tolua_export
|
||||
Vector3f( const Vector3i & v ); //tolua_export
|
||||
Vector3f( const Vector3i * v ); //tolua_export
|
||||
|
||||
|
||||
Vector3f() : x(0), y(0), z(0) {} //tolua_export
|
||||
Vector3f(float a_x, float a_y, float a_z) : x(a_x), y(a_y), z(a_z) {} //tolua_export
|
||||
|
||||
inline void Set(float a_x, float a_y, float a_z) { x = a_x, y = a_y, z = a_z; } //tolua_export
|
||||
inline void Normalize() { float l = 1.0f / Length(); x *= l; y *= l; z *= l; } //tolua_export
|
||||
inline Vector3f NormalizeCopy() const { float l = 1.0f / Length(); return Vector3f( x * l, y * l, z * l ); }//tolua_export
|
||||
inline void NormalizeCopy(Vector3f & a_V) const { float l = 1.0f / Length(); a_V.Set(x*l, y*l, z*l ); } //tolua_export
|
||||
inline float Length() const { return (float)sqrtf( x * x + y * y + z * z ); } //tolua_export
|
||||
inline float SqrLength() const { return x * x + y * y + z * z; } //tolua_export
|
||||
inline float Dot( const Vector3f & a_V ) const { return x * a_V.x + y * a_V.y + z * a_V.z; } //tolua_export
|
||||
inline Vector3f Cross( const Vector3f & v ) const { return Vector3f( y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x ); } //tolua_export
|
||||
|
||||
inline bool Equals( const Vector3f & v ) const { return (x == v.x && y == v.y && z == v.z ); } //tolua_export
|
||||
|
||||
void operator += ( const Vector3f& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
|
||||
void operator += ( Vector3f* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
|
||||
void operator -= ( const Vector3f& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
|
||||
void operator -= ( Vector3f* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
|
||||
void operator *= ( float a_f ) { x *= a_f; y *= a_f; z *= a_f; }
|
||||
void operator *= ( Vector3f* a_V ) { x *= a_V->x; y *= a_V->y; z *= a_V->z; }
|
||||
void operator *= ( const Vector3f& a_V ) { x *= a_V.x; y *= a_V.y; z *= a_V.z; }
|
||||
|
||||
Vector3f operator + ( const Vector3f& v2 ) const { return Vector3f( x + v2.x, y + v2.y, z + v2.z ); } //tolua_export
|
||||
Vector3f operator + ( const Vector3f* v2 ) const { return Vector3f( x + v2->x, y + v2->y, z + v2->z ); } //tolua_export
|
||||
Vector3f operator - ( const Vector3f& v2 ) const { return Vector3f( x - v2.x, y - v2.y, z - v2.z ); } //tolua_export
|
||||
Vector3f operator - ( const Vector3f* v2 ) const { return Vector3f( x - v2->x, y - v2->y, z - v2->z ); } //tolua_export
|
||||
Vector3f operator * ( const float f ) const { return Vector3f( x * f, y * f, z * f ); } //tolua_export
|
||||
Vector3f operator * ( const Vector3f& v2 ) const { return Vector3f( x * v2.x, y * v2.y, z * v2.z ); } //tolua_export
|
||||
|
||||
float x, y, z; //tolua_export
|
||||
|
||||
};//tolua_export
|
9
source/Vector3i.cpp
Normal file
9
source/Vector3i.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
#include "Vector3i.h"
|
||||
#include "Vector3d.h"
|
||||
|
||||
Vector3i::Vector3i( const Vector3d & v )
|
||||
: x( (int)v.x )
|
||||
, y( (int)v.y )
|
||||
, z( (int)v.z )
|
||||
{
|
||||
}
|
37
source/Vector3i.h
Normal file
37
source/Vector3i.h
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
class Vector3d;
|
||||
class Vector3i //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
Vector3i( const Vector3d & v ); //tolua_export
|
||||
|
||||
Vector3i() : x(0), y(0), z(0) {} //tolua_export
|
||||
Vector3i(int a_x, int a_y, int a_z) : x(a_x), y(a_y), z(a_z) {} //tolua_export
|
||||
|
||||
inline void Set(int a_x, int a_y, int a_z) { x = a_x, y = a_y, z = a_z; } //tolua_export
|
||||
inline float Length() const { return sqrtf( (float)( x * x + y * y + z * z) ); } //tolua_export
|
||||
inline int SqrLength() const { return x * x + y * y + z * z; } //tolua_export
|
||||
|
||||
inline bool Equals( const Vector3i & v ) const { return (x == v.x && y == v.y && z == v.z ); } //tolua_export
|
||||
inline bool Equals( const Vector3i * v ) const { return (x == v->x && y == v->y && z == v->z ); } //tolua_export
|
||||
|
||||
void operator += ( const Vector3i& a_V ) { x += a_V.x; y += a_V.y; z += a_V.z; }
|
||||
void operator += ( Vector3i* a_V ) { x += a_V->x; y += a_V->y; z += a_V->z; }
|
||||
void operator -= ( const Vector3i& a_V ) { x -= a_V.x; y -= a_V.y; z -= a_V.z; }
|
||||
void operator -= ( Vector3i* a_V ) { x -= a_V->x; y -= a_V->y; z -= a_V->z; }
|
||||
void operator *= ( int a_f ) { x *= a_f; y *= a_f; z *= a_f; }
|
||||
|
||||
friend Vector3i operator + ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x + v2.x, v1.y + v2.y, v1.z + v2.z ); }
|
||||
friend Vector3i operator + ( const Vector3i& v1, Vector3i* v2 ) { return Vector3i( v1.x + v2->x, v1.y + v2->y, v1.z + v2->z ); }
|
||||
friend Vector3i operator - ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x - v2.x, v1.y - v2.y, v1.z - v2.z ); }
|
||||
friend Vector3i operator - ( const Vector3i& v1, Vector3i* v2 ) { return Vector3i( v1.x - v2->x, v1.y - v2->y, v1.z - v2->z ); }
|
||||
friend Vector3i operator - ( const Vector3i* v1, Vector3i& v2 ) { return Vector3i( v1->x - v2.x, v1->y - v2.y, v1->z - v2.z ); }
|
||||
friend Vector3i operator * ( const Vector3i& v, const int f ) { return Vector3i( v.x * f, v.y * f, v.z * f ); }
|
||||
friend Vector3i operator * ( const Vector3i& v1, const Vector3i& v2 ) { return Vector3i( v1.x * v2.x, v1.y * v2.y, v1.z * v2.z ); }
|
||||
friend Vector3i operator * ( const int f, const Vector3i& v ) { return Vector3i( v.x * f, v.y * f, v.z * f ); }
|
||||
|
||||
int x, y, z; //tolua_export
|
||||
}; //tolua_export
|
194
source/cAuthenticator.cpp
Normal file
194
source/cAuthenticator.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
#include "cAuthenticator.h"
|
||||
#include "cBlockingTCPLink.h"
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#include "../iniFile/iniFile.h"
|
||||
#ifndef _WIN32
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
extern void ReplaceString( std::string & a_HayStack, const std::string & a_Needle, const std::string & a_ReplaceWith );
|
||||
|
||||
cAuthenticator::cAuthenticator()
|
||||
{
|
||||
}
|
||||
|
||||
cAuthenticator::~cAuthenticator()
|
||||
{
|
||||
}
|
||||
|
||||
bool cAuthenticator::Authenticate( const char* a_PlayerName, const char* a_ServerID )
|
||||
{
|
||||
// Default values
|
||||
std::string Server = "www.minecraft.net";
|
||||
std::string Address = "/game/checkserver.jsp?user=%USERNAME%&serverId=%SERVERID%";
|
||||
bool bAuthenticate = true;
|
||||
|
||||
// Read custom values from INI
|
||||
cIniFile IniFile("settings.ini");
|
||||
if( IniFile.ReadFile() )
|
||||
{
|
||||
std::string tServer = IniFile.GetValue("Authentication", "Server");
|
||||
std::string tAddress = IniFile.GetValue("Authentication", "Address");
|
||||
bAuthenticate = IniFile.GetValueB("Authentication", "Authenticate", true);
|
||||
bool bSave = false;
|
||||
if( tServer.length() == 0 )
|
||||
{
|
||||
IniFile.SetValue("Authentication", "Server", Server, true );
|
||||
bSave = true;
|
||||
}
|
||||
else
|
||||
Server = tServer;
|
||||
if( tAddress.length() == 0 )
|
||||
{
|
||||
IniFile.SetValue("Authentication", "Address", Address, true );
|
||||
bSave = true;
|
||||
}
|
||||
else
|
||||
Address = tAddress;
|
||||
|
||||
if( bSave )
|
||||
{
|
||||
IniFile.SetValueB("Authentication", "Authenticate", bAuthenticate, true );
|
||||
IniFile.WriteFile();
|
||||
}
|
||||
}
|
||||
|
||||
if( !bAuthenticate ) // If we don't want to authenticate.. just return true
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ReplaceString( Address, "%USERNAME%", a_PlayerName );
|
||||
ReplaceString( Address, "%SERVERID%", a_ServerID );
|
||||
|
||||
|
||||
cBlockingTCPLink TCPLink;
|
||||
if( TCPLink.Connect( Server.c_str(), 80 ) )
|
||||
{
|
||||
//TCPLink.SendMessage( std::string( "GET /game/checkserver.jsp?user=" + std::string(a_PlayerName) + "&serverId=" + std::string(a_ServerID) + " HTTP/1.0\r\n\r\n" ).c_str() );
|
||||
TCPLink.SendMessage( std::string( "GET " + Address + " HTTP/1.0\r\n\r\n" ).c_str() );
|
||||
//LOGINFO("Successfully connected to mc.net");
|
||||
std::string Received = TCPLink.ReceiveData();
|
||||
//LOGINFO("Received data: %s", Received.c_str() );
|
||||
return ParseReceived( Received.c_str(), &TCPLink );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("Could not connect to %s to verify player name! (%s)", Server.c_str(), a_PlayerName );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool cAuthenticator::ParseReceived( const char* a_Data, cBlockingTCPLink* a_TCPLink )
|
||||
{
|
||||
std::stringstream ss(a_Data);
|
||||
|
||||
std::string temp;
|
||||
ss >> temp;
|
||||
//LOGINFO("tmp: %s", temp.c_str() );
|
||||
|
||||
bool bRedirect = false;
|
||||
bool bOK = false;
|
||||
|
||||
if( temp.compare("HTTP/1.1") == 0 || temp.compare("HTTP/1.0") == 0 )
|
||||
{
|
||||
int code;
|
||||
ss >> code;
|
||||
if( code == 302 )
|
||||
{
|
||||
// redirect blabla
|
||||
LOGINFO("Need to redirect!");
|
||||
bRedirect = true;
|
||||
}
|
||||
else if( code == 200 )
|
||||
{
|
||||
LOGINFO("Got 200 OK :D");
|
||||
bOK = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
if( bRedirect )
|
||||
{
|
||||
std::string Location;
|
||||
// Search for "Location:"
|
||||
bool bFoundLocation = false;
|
||||
while( !bFoundLocation && ss.good() )
|
||||
{
|
||||
char c = 0;
|
||||
while( c != '\n' )
|
||||
{
|
||||
ss.get( c );
|
||||
}
|
||||
std::string Name;
|
||||
ss >> Name;
|
||||
if( Name.compare("Location:") == 0 )
|
||||
{
|
||||
bFoundLocation = true;
|
||||
ss >> Location;
|
||||
}
|
||||
}
|
||||
if( !bFoundLocation )
|
||||
{
|
||||
LOGERROR("Could not find location");
|
||||
return false;
|
||||
}
|
||||
|
||||
Location = Location.substr( strlen("http://"), std::string::npos ); // Strip http://
|
||||
std::string Server = Location.substr( 0, Location.find( "/" ) ); // Only leave server address
|
||||
Location = Location.substr( Server.length(), std::string::npos );
|
||||
//LOGINFO("Got location: (%s)", Location.c_str() );
|
||||
//LOGINFO("Got server addr: (%s)", Server.c_str() );
|
||||
a_TCPLink->CloseSocket();
|
||||
if( a_TCPLink->Connect( Server.c_str(), 80 ) )
|
||||
{
|
||||
LOGINFO("Successfully connected to %s", Server.c_str() );
|
||||
a_TCPLink->SendMessage( ( std::string("GET ") + Location + " HTTP/1.0\r\n\r\n").c_str() );
|
||||
std::string Received = a_TCPLink->ReceiveData();
|
||||
//LOGINFO("Received data: %s", Received.c_str() );
|
||||
return ParseReceived( Received.c_str(), a_TCPLink );
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("Could not connect to %s to verify player name!", Server.c_str() );
|
||||
}
|
||||
}
|
||||
else if( bOK )
|
||||
{
|
||||
// Header says OK, so receive the rest.
|
||||
|
||||
// Go past header, double \n means end of headers
|
||||
char c = 0;
|
||||
while( ss.good() )
|
||||
{
|
||||
while( c != '\n' )
|
||||
{
|
||||
ss.get( c );
|
||||
}
|
||||
ss.get( c );
|
||||
if( c == '\n' || c == '\r' || ss.peek() == '\r' || ss.peek() == '\n' )
|
||||
break;
|
||||
}
|
||||
if( !ss.good() ) return false;
|
||||
|
||||
std::string Result;
|
||||
ss >> Result;
|
||||
LOGINFO("Got result: %s", Result.c_str() );
|
||||
if( Result.compare("YES") == 0 )
|
||||
{
|
||||
LOGINFO("Result was \"YES\", so player is authenticated!");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGINFO("Result was \"%s\", so player is NOT authenticated!", Result.c_str() );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
13
source/cAuthenticator.h
Normal file
13
source/cAuthenticator.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
class cBlockingTCPLink;
|
||||
class cAuthenticator
|
||||
{
|
||||
public:
|
||||
cAuthenticator();
|
||||
~cAuthenticator();
|
||||
|
||||
bool Authenticate( const char* a_PlayerName, const char* a_ServerID );
|
||||
private:
|
||||
bool ParseReceived( const char* a_Data, cBlockingTCPLink* a_TCPLink );
|
||||
};
|
34
source/cBlockEntity.h
Normal file
34
source/cBlockEntity.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "BlockID.h"
|
||||
#else
|
||||
enum ENUM_BLOCK_ID;
|
||||
#endif
|
||||
|
||||
class cClientHandle;
|
||||
class cPlayer;
|
||||
class cBlockEntity
|
||||
{
|
||||
protected:
|
||||
cBlockEntity(ENUM_BLOCK_ID a_BlockType, int a_X, int a_Y, int a_Z) : m_PosX( a_X ), m_PosY( a_Y ), m_PosZ( a_Z ), m_BlockType( a_BlockType ) {}
|
||||
public:
|
||||
virtual ~cBlockEntity() {};
|
||||
virtual void Destroy() {};
|
||||
|
||||
int GetPosX() { return m_PosX; }
|
||||
int GetPosY() { return m_PosY; }
|
||||
int GetPosZ() { return m_PosZ; }
|
||||
|
||||
ENUM_BLOCK_ID GetBlockType() { return m_BlockType; }
|
||||
|
||||
virtual void UsedBy( cPlayer & a_Player ) = 0;
|
||||
virtual void SendTo( cClientHandle* a_Client ) { (void)a_Client; }
|
||||
|
||||
protected:
|
||||
int m_PosX; // Position in block coordinates
|
||||
int m_PosY;
|
||||
int m_PosZ;
|
||||
|
||||
ENUM_BLOCK_ID m_BlockType;
|
||||
};
|
37
source/cBlockToPickup.cpp
Normal file
37
source/cBlockToPickup.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "cBlockToPickup.h"
|
||||
#include "BlockID.h"
|
||||
|
||||
ENUM_ITEM_ID cBlockToPickup::ToPickup( unsigned char a_BlockID, ENUM_ITEM_ID a_UsedItemID )
|
||||
{
|
||||
(void)a_UsedItemID;
|
||||
|
||||
switch( a_BlockID )
|
||||
{
|
||||
case E_BLOCK_AIR:
|
||||
return E_ITEM_EMPTY;
|
||||
case E_BLOCK_STONE:
|
||||
return E_ITEM_COBBLESTONE;
|
||||
case E_BLOCK_GRASS:
|
||||
return E_ITEM_DIRT;
|
||||
case E_BLOCK_DIRT:
|
||||
return E_ITEM_DIRT;
|
||||
case E_BLOCK_LOG:
|
||||
return E_ITEM_LOG;
|
||||
case E_BLOCK_COAL_ORE:
|
||||
return E_ITEM_COAL;
|
||||
case E_BLOCK_DIAMOND_ORE:
|
||||
return E_ITEM_DIAMOND;
|
||||
case E_BLOCK_IRON_BLOCK:
|
||||
return E_ITEM_IRON_BLOCK;
|
||||
case E_BLOCK_DIAMOND_BLOCK:
|
||||
return E_ITEM_DIAMOND_BLOCK;
|
||||
case E_BLOCK_GOLD_BLOCK:
|
||||
return E_ITEM_GOLD_BLOCK;
|
||||
case E_BLOCK_SIGN_POST:
|
||||
case E_BLOCK_WALLSIGN:
|
||||
return E_ITEM_SIGN;
|
||||
default:
|
||||
return (ENUM_ITEM_ID)a_BlockID;
|
||||
}
|
||||
return E_ITEM_EMPTY;
|
||||
}
|
13
source/cBlockToPickup.h
Normal file
13
source/cBlockToPickup.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "BlockID.h"
|
||||
#else
|
||||
enum ENUM_ITEM_ID;
|
||||
#endif
|
||||
|
||||
class cBlockToPickup
|
||||
{
|
||||
public:
|
||||
static ENUM_ITEM_ID ToPickup( unsigned char a_BlockID, ENUM_ITEM_ID a_UsedItemID );
|
||||
};
|
137
source/cBlockingTCPLink.cpp
Normal file
137
source/cBlockingTCPLink.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#include "cBlockingTCPLink.h"
|
||||
#include "packets/cPacket.h"
|
||||
#include <string>
|
||||
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define MSG_NOSIGNAL (0)
|
||||
#endif
|
||||
#ifdef __MACH__
|
||||
#define MSG_NOSIGNAL (0)
|
||||
#endif
|
||||
|
||||
cBlockingTCPLink::cBlockingTCPLink()
|
||||
: m_Socket( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
cBlockingTCPLink::~cBlockingTCPLink()
|
||||
{
|
||||
CloseSocket();
|
||||
}
|
||||
|
||||
void cBlockingTCPLink::CloseSocket()
|
||||
{
|
||||
if( m_Socket )
|
||||
{
|
||||
closesocket( m_Socket );
|
||||
m_Socket = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool cBlockingTCPLink::Connect( const char* 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);
|
||||
#ifdef _WIN32
|
||||
if( m_Socket==INVALID_SOCKET )
|
||||
#else
|
||||
if( m_Socket < 0 )
|
||||
#endif
|
||||
{
|
||||
LOGERROR("cTCPLink: Invalid socket");
|
||||
m_Socket = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
addr=inet_addr( a_Address );
|
||||
hp=gethostbyaddr((char*)&addr,sizeof(addr),AF_INET);
|
||||
if(hp==NULL)
|
||||
{
|
||||
//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();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int cBlockingTCPLink::Send( char* a_Data, unsigned int a_Size, int a_Flags /* = 0 */ )
|
||||
{
|
||||
if( !m_Socket )
|
||||
{
|
||||
LOGWARN("cBlockingTCPLink: Trying to send data without a valid connection!");
|
||||
return -1;
|
||||
}
|
||||
return cPacket::SendData( m_Socket, a_Data, a_Size, a_Flags );
|
||||
}
|
||||
|
||||
int cBlockingTCPLink::SendMessage( const char* a_Message, int a_Flags /* = 0 */ )
|
||||
{
|
||||
if( !m_Socket )
|
||||
{
|
||||
LOGWARN("cBlockingTCPLink: Trying to send message without a valid connection!");
|
||||
return -1;
|
||||
}
|
||||
return cPacket::SendData( m_Socket, a_Message, strlen(a_Message), a_Flags );
|
||||
}
|
||||
|
||||
std::string cBlockingTCPLink::ReceiveData()
|
||||
{
|
||||
if( !m_Socket ) return "";
|
||||
|
||||
int Received = 0;
|
||||
char Buffer[256];
|
||||
std::string Data;
|
||||
while( (Received = recv(m_Socket, Buffer, 256, 0) ) > 0 )
|
||||
{
|
||||
//LOGINFO("Recv: %i", Received);
|
||||
//LOG("%s", Buffer );
|
||||
Data.append( Buffer, Received );
|
||||
memset( Buffer, 0, 256 );
|
||||
}
|
||||
|
||||
//LOGINFO("Received returned: %i", Received );
|
||||
return Data;
|
||||
}
|
21
source/cBlockingTCPLink.h
Normal file
21
source/cBlockingTCPLink.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "cSocket.h"
|
||||
#include <string>
|
||||
|
||||
class cEvent;
|
||||
class cBlockingTCPLink //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
cBlockingTCPLink(); //tolua_export
|
||||
~cBlockingTCPLink(); //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
|
||||
void CloseSocket(); //tolua_export
|
||||
std::string ReceiveData(); //tolua_export
|
||||
protected:
|
||||
|
||||
cSocket m_Socket;
|
||||
}; //tolua_export
|
25
source/cChatColor.cpp
Normal file
25
source/cChatColor.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "cChatColor.h"
|
||||
|
||||
const std::string cChatColor::Color = "§";
|
||||
const std::string cChatColor::Delimiter = "\xa7";
|
||||
const std::string cChatColor::Black = cChatColor::Color + "0";
|
||||
const std::string cChatColor::Navy = cChatColor::Color + "1";
|
||||
const std::string cChatColor::Green = cChatColor::Color + "2";
|
||||
const std::string cChatColor::Blue = cChatColor::Color + "3";
|
||||
const std::string cChatColor::Red = cChatColor::Color + "4";
|
||||
const std::string cChatColor::Purple = cChatColor::Color + "5";
|
||||
const std::string cChatColor::Gold = cChatColor::Color + "6";
|
||||
const std::string cChatColor::LightGray = cChatColor::Color + "7";
|
||||
const std::string cChatColor::Gray = cChatColor::Color + "8";
|
||||
const std::string cChatColor::DarkPurple = cChatColor::Color + "9";
|
||||
const std::string cChatColor::LightGreen = cChatColor::Color + "a";
|
||||
const std::string cChatColor::LightBlue = cChatColor::Color + "b";
|
||||
const std::string cChatColor::Rose = cChatColor::Color + "c";
|
||||
const std::string cChatColor::LightPurple = cChatColor::Color + "d";
|
||||
const std::string cChatColor::Yellow = cChatColor::Color + "e";
|
||||
const std::string cChatColor::White = cChatColor::Color + "f";
|
||||
|
||||
const std::string cChatColor::MakeColor( char a_Color )
|
||||
{
|
||||
return cChatColor::Color + a_Color;
|
||||
}
|
32
source/cChatColor.h
Normal file
32
source/cChatColor.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
// tolua_begin
|
||||
class cChatColor
|
||||
{
|
||||
public:
|
||||
static const std::string Color;
|
||||
static const std::string Delimiter;
|
||||
|
||||
static const std::string Black;
|
||||
static const std::string Navy;
|
||||
static const std::string Green;
|
||||
static const std::string Blue;
|
||||
static const std::string Red;
|
||||
static const std::string Purple;
|
||||
static const std::string Gold;
|
||||
static const std::string LightGray;
|
||||
static const std::string Gray;
|
||||
static const std::string DarkPurple;
|
||||
static const std::string LightGreen;
|
||||
static const std::string LightBlue;
|
||||
static const std::string Rose;
|
||||
static const std::string LightPurple;
|
||||
static const std::string Yellow;
|
||||
static const std::string White;
|
||||
|
||||
static const std::string MakeColor( char a_Color );
|
||||
};
|
||||
|
||||
// tolua_end
|
185
source/cChestEntity.cpp
Normal file
185
source/cChestEntity.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
#include "cChestEntity.h"
|
||||
#include "cItem.h"
|
||||
#include <string>
|
||||
#include "cClientHandle.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cPlayer.h"
|
||||
#include "cWindow.h"
|
||||
#include "cPickup.h"
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
cChestEntity::cChestEntity(int a_X, int a_Y, int a_Z)
|
||||
: cBlockEntity( E_BLOCK_CHEST, a_X, a_Y, a_Z )
|
||||
{
|
||||
m_Content = new cItem[ c_ChestHeight*c_ChestWidth ];
|
||||
}
|
||||
|
||||
cChestEntity::~cChestEntity()
|
||||
{
|
||||
if( GetWindow() )
|
||||
{
|
||||
GetWindow()->OwnerDestroyed();
|
||||
}
|
||||
|
||||
if( m_Content )
|
||||
{
|
||||
delete [] m_Content;
|
||||
}
|
||||
}
|
||||
|
||||
void cChestEntity::Destroy()
|
||||
{
|
||||
// Drop items
|
||||
for( int i = 0; i < c_ChestHeight*c_ChestWidth; ++i )
|
||||
{
|
||||
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();
|
||||
m_Content[i].Empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cItem * cChestEntity::GetSlot( int a_Slot )
|
||||
{
|
||||
if( a_Slot > -1 && a_Slot < c_ChestHeight*c_ChestWidth )
|
||||
{
|
||||
return &m_Content[ a_Slot ];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cChestEntity::SetSlot( int a_Slot, cItem & a_Item )
|
||||
{
|
||||
if( a_Slot > -1 && a_Slot < c_ChestHeight*c_ChestWidth )
|
||||
{
|
||||
m_Content[a_Slot] = a_Item;
|
||||
}
|
||||
}
|
||||
|
||||
void cChestEntity::WriteToFile(FILE* a_File)
|
||||
{
|
||||
fwrite( &m_BlockType, sizeof( ENUM_BLOCK_ID ), 1, a_File );
|
||||
fwrite( &m_PosX, sizeof( int ), 1, a_File );
|
||||
fwrite( &m_PosY, sizeof( int ), 1, a_File );
|
||||
fwrite( &m_PosZ, sizeof( int ), 1, a_File );
|
||||
|
||||
unsigned int NumSlots = c_ChestHeight*c_ChestWidth;
|
||||
fwrite( &NumSlots, sizeof(unsigned int), 1, a_File );
|
||||
for(unsigned int i = 0; i < NumSlots; i++)
|
||||
{
|
||||
cItem* Item = GetSlot( i );
|
||||
if( Item )
|
||||
{
|
||||
fwrite( &Item->m_ItemID, sizeof(Item->m_ItemID), 1, a_File );
|
||||
fwrite( &Item->m_ItemCount, sizeof(Item->m_ItemCount), 1, a_File );
|
||||
fwrite( &Item->m_ItemHealth, sizeof(Item->m_ItemHealth), 1, a_File );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cChestEntity::LoadFromFile(FILE* a_File)
|
||||
{
|
||||
if( fread( &m_PosX, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING CHEST FROM FILE"); return false; }
|
||||
if( fread( &m_PosY, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING CHEST FROM FILE"); return false; }
|
||||
if( fread( &m_PosZ, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING CHEST FROM FILE"); return false; }
|
||||
|
||||
unsigned int NumSlots = 0;
|
||||
if( fread( &NumSlots, sizeof(unsigned int), 1, a_File) != 1 ) { LOGERROR("ERROR READING CHEST FROM FILE"); return false; }
|
||||
for(unsigned int i = 0; i < NumSlots; i++)
|
||||
{
|
||||
cItem Item;
|
||||
if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File) != 1 ) { LOGERROR("ERROR READING CHEST FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File) != 1 ) { LOGERROR("ERROR READING CHEST FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File)!= 1 ) { LOGERROR("ERROR READING CHEST FROM FILE"); return false; }
|
||||
SetSlot( i, Item );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cChestEntity::LoadFromJson( const Json::Value& a_Value )
|
||||
{
|
||||
m_PosX = a_Value.get("x", 0).asInt();
|
||||
m_PosY = a_Value.get("y", 0).asInt();
|
||||
m_PosZ = a_Value.get("z", 0).asInt();
|
||||
|
||||
Json::Value AllSlots = a_Value.get("Slots", 0);
|
||||
int SlotIdx = 0;
|
||||
for( Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr )
|
||||
{
|
||||
Json::Value & Slot = *itr;
|
||||
cItem Item;
|
||||
Item.m_ItemID = (ENUM_ITEM_ID)Slot.get("ID", -1 ).asInt();
|
||||
if( Item.m_ItemID > 0 )
|
||||
{
|
||||
Item.m_ItemCount = (char)Slot.get("Count", -1 ).asInt();
|
||||
Item.m_ItemHealth = (short)Slot.get("Health", -1 ).asInt();
|
||||
}
|
||||
SetSlot( SlotIdx, Item );
|
||||
SlotIdx++;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cChestEntity::SaveToJson( Json::Value& a_Value )
|
||||
{
|
||||
a_Value["x"] = m_PosX;
|
||||
a_Value["y"] = m_PosY;
|
||||
a_Value["z"] = m_PosZ;
|
||||
|
||||
unsigned int NumSlots = c_ChestHeight*c_ChestWidth;
|
||||
Json::Value AllSlots;
|
||||
for(unsigned int i = 0; i < NumSlots; i++)
|
||||
{
|
||||
Json::Value Slot;
|
||||
cItem* Item = GetSlot( i );
|
||||
if( Item )
|
||||
{
|
||||
Slot["ID"] = Item->m_ItemID;
|
||||
if( Item->m_ItemID > 0 )
|
||||
{
|
||||
Slot["Count"] = Item->m_ItemCount;
|
||||
Slot["Health"] = Item->m_ItemHealth;
|
||||
}
|
||||
}
|
||||
AllSlots.append( Slot );
|
||||
}
|
||||
a_Value["Slots"] = AllSlots;
|
||||
}
|
||||
|
||||
void cChestEntity::SendTo( cClientHandle* a_Client, cServer* a_Server )
|
||||
{
|
||||
(void)a_Client;
|
||||
(void)a_Server;
|
||||
return;
|
||||
}
|
||||
|
||||
void cChestEntity::UsedBy( cPlayer & a_Player )
|
||||
{
|
||||
LOG("Used a chest");
|
||||
// m_Content[0].m_ItemCount = 1;
|
||||
// m_Content[0].m_ItemID = E_ITEM_STONE;
|
||||
// m_Content[0].m_ItemHealth = 0;
|
||||
|
||||
if( !GetWindow() )
|
||||
{
|
||||
cWindow* Window = new cWindow( this, true );
|
||||
Window->SetSlots( m_Content, c_ChestHeight*c_ChestWidth );
|
||||
Window->SetWindowID( 1 );
|
||||
Window->SetWindowType( 0 );
|
||||
Window->SetWindowTitle("UberChest");
|
||||
OpenWindow( Window );
|
||||
}
|
||||
if( GetWindow() )
|
||||
{
|
||||
if( a_Player.GetWindow() != GetWindow() )
|
||||
{
|
||||
a_Player.OpenWindow( GetWindow() );
|
||||
|
||||
GetWindow()->SendWholeWindow( a_Player.GetClientHandle() );
|
||||
}
|
||||
}
|
||||
}
|
42
source/cChestEntity.h
Normal file
42
source/cChestEntity.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "cBlockEntity.h"
|
||||
#include "cWindowOwner.h"
|
||||
#include "FileDefine.h"
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
};
|
||||
|
||||
class cClientHandle;
|
||||
class cServer;
|
||||
class cItem;
|
||||
class cNBTData;
|
||||
class cChestEntity : public cBlockEntity, public cWindowOwner
|
||||
{
|
||||
public:
|
||||
cChestEntity(int a_X, int a_Y, int a_Z);
|
||||
virtual ~cChestEntity();
|
||||
virtual void Destroy();
|
||||
|
||||
void HandleData( cNBTData* a_NBTData );
|
||||
|
||||
cItem * GetSlot( int a_Slot );
|
||||
void SetSlot( int a_Slot, cItem & a_Item );
|
||||
|
||||
void WriteToFile(FILE* a_File);
|
||||
bool LoadFromFile(FILE* a_File);
|
||||
|
||||
bool LoadFromJson( const Json::Value& a_Value );
|
||||
void SaveToJson( Json::Value& a_Value );
|
||||
|
||||
void SendTo( cClientHandle* a_Client, cServer* a_Server );
|
||||
|
||||
virtual void UsedBy( cPlayer & a_Player );
|
||||
|
||||
static const int c_ChestWidth = 9;
|
||||
static const int c_ChestHeight = 3;
|
||||
private:
|
||||
cItem* m_Content;
|
||||
};
|
90
source/cChicken.cpp
Normal file
90
source/cChicken.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "cChicken.h"
|
||||
|
||||
#include "Vector3f.h"
|
||||
#include "Vector3d.h"
|
||||
|
||||
#include "Defines.h"
|
||||
|
||||
#include "cRoot.h"
|
||||
#include "cWorld.h"
|
||||
#include "cPickup.h"
|
||||
#include "cItem.h"
|
||||
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <stdlib.h> // rand()
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
cChicken::cChicken()
|
||||
: m_ChaseTime( 999999 )
|
||||
|
||||
{
|
||||
//LOG("SPAWNING A CHICKEN!!!!!!!!!!!!!!!!!!!!!");
|
||||
m_EMPersonality = PASSIVE;
|
||||
m_MobType = 93;
|
||||
GetMonsterConfig("Chicken");
|
||||
}
|
||||
|
||||
cChicken::~cChicken()
|
||||
{
|
||||
}
|
||||
|
||||
bool cChicken::IsA( const char* a_EntityType )
|
||||
{
|
||||
//LOG("IsA( cChicken ) : %s", a_EntityType);
|
||||
if( strcmp( a_EntityType, "cChicken" ) == 0 ) return true;
|
||||
return cMonster::IsA( a_EntityType );
|
||||
}
|
||||
|
||||
void cChicken::Tick(float a_Dt)
|
||||
{
|
||||
cMonster::Tick(a_Dt);
|
||||
}
|
||||
|
||||
void cChicken::KilledBy( cEntity* a_Killer )
|
||||
{
|
||||
if( (rand() % 5) == 0 )
|
||||
{
|
||||
cPickup* Pickup = new cPickup( (int)(m_Pos->x*32), (int)(m_Pos->y*32), (int)(m_Pos->z*32), cItem( E_ITEM_EGG, 1 ) );
|
||||
Pickup->Initialize();
|
||||
}
|
||||
if( (rand() % 1) == 0 )
|
||||
{
|
||||
cPickup* Pickup = new cPickup( (int)(m_Pos->x*32), (int)(m_Pos->y*32), (int)(m_Pos->z*32), cItem( E_ITEM_FEATHER, 1 ) );
|
||||
Pickup->Initialize();
|
||||
}
|
||||
cMonster::KilledBy( a_Killer );
|
||||
}
|
||||
|
||||
//What to do if in Idle State
|
||||
void cChicken::InStateIdle(float a_Dt) {
|
||||
cMonster::InStateIdle(a_Dt);
|
||||
}
|
||||
|
||||
//What to do if in Chasing State
|
||||
void cChicken::InStateChasing(float a_Dt) {
|
||||
cMonster::InStateChasing(a_Dt);
|
||||
m_ChaseTime += a_Dt;
|
||||
if( m_Target )
|
||||
{
|
||||
Vector3f Pos = Vector3f( m_Pos );
|
||||
Vector3f Their = Vector3f( m_Target->GetPosition() );
|
||||
if( (Their - Pos).Length() <= m_AttackRange) {
|
||||
cMonster::Attack(a_Dt);
|
||||
}
|
||||
MoveToPosition( Their + Vector3f(0, 0.65f, 0) );
|
||||
} else if( m_ChaseTime > 5.f ) {
|
||||
m_ChaseTime = 0;
|
||||
m_EMState = IDLE;
|
||||
}
|
||||
}
|
||||
|
||||
void cChicken::InStateEscaping(float a_Dt) {
|
||||
cMonster::InStateEscaping(a_Dt);
|
||||
}
|
21
source/cChicken.h
Normal file
21
source/cChicken.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "cMonster.h"
|
||||
|
||||
class cChicken : public cMonster
|
||||
{
|
||||
public:
|
||||
cChicken();
|
||||
~cChicken();
|
||||
|
||||
virtual bool IsA( const char* a_EntityType );
|
||||
|
||||
virtual void Tick(float a_Dt);
|
||||
virtual void KilledBy( cEntity* a_Killer );
|
||||
virtual void InStateIdle(float a_Dt);
|
||||
virtual void InStateChasing(float a_Dt);
|
||||
virtual void InStateEscaping(float a_Dt);
|
||||
//float m_ChaseTime;
|
||||
protected:
|
||||
float m_ChaseTime;
|
||||
};
|
1388
source/cChunk.cpp
Normal file
1388
source/cChunk.cpp
Normal file
File diff suppressed because it is too large
Load Diff
127
source/cChunk.h
Normal file
127
source/cChunk.h
Normal file
@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
};
|
||||
|
||||
class cFurnaceEntity;
|
||||
class cPacket;
|
||||
class cBlockEntity;
|
||||
class cEntity;
|
||||
class cClientHandle;
|
||||
class cServer;
|
||||
class cChunk
|
||||
{
|
||||
public:
|
||||
cChunk(int a_X, int a_Y, int a_Z);
|
||||
~cChunk();
|
||||
|
||||
void Initialize();
|
||||
|
||||
void Tick(float a_Dt);
|
||||
|
||||
inline int GetPosX() { return m_PosX; }
|
||||
inline int GetPosY() { return m_PosY; }
|
||||
inline int GetPosZ() { return m_PosZ; }
|
||||
|
||||
void Send( cClientHandle* a_Client );
|
||||
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 );
|
||||
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 );
|
||||
|
||||
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 RemoveClient( cClientHandle* a_Client );
|
||||
|
||||
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();
|
||||
|
||||
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);
|
||||
|
||||
bool SaveToDisk();
|
||||
bool LoadFromDisk();
|
||||
|
||||
// Broadcasts to all clients that have loaded this chunk
|
||||
void Broadcast( const cPacket & a_Packet, cClientHandle* a_Exclude = 0 ) const;
|
||||
|
||||
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; }
|
||||
|
||||
char GetLight(char* a_Buffer, int a_BlockIdx);
|
||||
char GetLight(char* a_Buffer, int x, int y, int z);
|
||||
void SetLight(char* a_Buffer, int a_BlockIdx, char a_Light);
|
||||
void SetLight(char* a_Buffer, int x, int y, int z, char light);
|
||||
|
||||
void AddTickBlockEntity( cFurnaceEntity* a_Entity );
|
||||
//{
|
||||
// m_TickBlockEntities.remove( a_Entity );
|
||||
// m_TickBlockEntities.push_back( a_Entity );
|
||||
//}
|
||||
|
||||
void RemoveTickBlockEntity( cFurnaceEntity* a_Entity );
|
||||
//{
|
||||
// m_TickBlockEntities.remove( a_Entity );
|
||||
//}
|
||||
|
||||
static const int c_NumBlocks = 16*128*16;
|
||||
static const int c_BlockDataSize = c_NumBlocks * 2 + (c_NumBlocks/2); // 2.5 * numblocks
|
||||
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 );
|
||||
|
||||
void GenerateTerrain();
|
||||
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();
|
||||
|
||||
unsigned int MakeIndex(int x, int y, int z );
|
||||
|
||||
bool m_bCalculateLighting;
|
||||
bool m_bCalculateHeightmap;
|
||||
|
||||
int m_PosX, m_PosY, m_PosZ;
|
||||
|
||||
char m_BlockData[c_BlockDataSize]; // Chunk data ready to be compressed and sent
|
||||
char *m_BlockType; // Pointers to an element in m_BlockData
|
||||
char *m_BlockMeta; // += NumBlocks
|
||||
char *m_BlockLight; // += NumBlocks/2
|
||||
char *m_BlockSkyLight; // += NumBlocks/2
|
||||
|
||||
unsigned char m_HeightMap[16*16];
|
||||
|
||||
unsigned int m_BlockTickNum;
|
||||
unsigned int m_BlockTickX, m_BlockTickY, m_BlockTickZ;
|
||||
|
||||
void* m_EntitiesCriticalSection;
|
||||
};
|
364
source/cChunkLoader.cpp
Normal file
364
source/cChunkLoader.cpp
Normal file
@ -0,0 +1,364 @@
|
||||
#if 0 // ignore all contents of this file
|
||||
#include "cChunkLoader.h"
|
||||
#include "cChunk.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "BlockID.h"
|
||||
#include "cCriticalSection.h"
|
||||
#include "cEvent.h"
|
||||
#include "cThread.h"
|
||||
#include "cSleep.h"
|
||||
|
||||
#include "cChestEntity.h"
|
||||
#include "cFurnaceEntity.h"
|
||||
#include "cSignEntity.h"
|
||||
|
||||
#include <iostream>
|
||||
#ifndef _WIN32
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h> // for mkdir
|
||||
#include <sys/types.h>
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
|
||||
struct ChunkData
|
||||
{
|
||||
ChunkData()
|
||||
: x( 0 )
|
||||
, z( 0 )
|
||||
, Data( 0 )
|
||||
, LiveChunk( 0 )
|
||||
{}
|
||||
int x, z;
|
||||
unsigned int DataSize;
|
||||
unsigned int ChunkStart;
|
||||
char* Data;
|
||||
cChunk* LiveChunk;
|
||||
};
|
||||
|
||||
typedef std::list< ChunkData > ChunkDataList;
|
||||
struct cChunkLoader::ChunkPack
|
||||
{
|
||||
ChunkDataList AllChunks;
|
||||
int x, y, z;
|
||||
};
|
||||
|
||||
typedef std::list< cChunkLoader::ChunkPack > ChunkPackList;
|
||||
struct cChunkLoader::ChunkPacks
|
||||
{
|
||||
ChunkPackList AllPacks;
|
||||
};
|
||||
|
||||
cChunkLoader::cChunkLoader()
|
||||
: m_bStop( false )
|
||||
, m_CriticalSection( new cCriticalSection() )
|
||||
, m_Event( new cEvent() )
|
||||
, m_ChunkPacks( new ChunkPacks )
|
||||
{
|
||||
cThread( SaveThread, this );
|
||||
}
|
||||
|
||||
cChunkLoader::~cChunkLoader()
|
||||
{
|
||||
m_bStop = true;
|
||||
m_Event->Wait();
|
||||
delete m_CriticalSection;
|
||||
}
|
||||
|
||||
void cChunkLoader::SaveThread( void* a_Param )
|
||||
{
|
||||
cChunkLoader* self = (cChunkLoader*)a_Param;
|
||||
while( !self->m_bStop )
|
||||
{
|
||||
cSleep::MilliSleep( 1000 ); // Only check for saving once a second
|
||||
}
|
||||
self->m_Event->Set();
|
||||
}
|
||||
|
||||
cChunk* cChunkLoader::LoadChunk( int a_X, int a_Y, int a_Z )
|
||||
{
|
||||
m_CriticalSection->Lock();
|
||||
cChunk* Chunk = 0;
|
||||
|
||||
Chunk = LoadOldFormat( a_X, a_Y, a_Z );
|
||||
if( Chunk ) { Chunk->CalculateHeightmap(); }
|
||||
else
|
||||
{
|
||||
1; // load new format()
|
||||
}
|
||||
|
||||
m_CriticalSection->Unlock();
|
||||
return Chunk;
|
||||
}
|
||||
|
||||
bool cChunkLoader::SaveChunk( const cChunk & a_Chunk )
|
||||
{
|
||||
m_CriticalSection->Lock();
|
||||
bool Success = SaveOldFormat( a_Chunk );
|
||||
m_CriticalSection->Unlock();
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Old format stuffs
|
||||
**/
|
||||
|
||||
cChunk* cChunkLoader::LoadOldFormat( int a_X, int a_Y, int a_Z )
|
||||
{
|
||||
char SourceFile[128];
|
||||
sprintf_s(SourceFile, 128, "world/X%i_Y%i_Z%i.bin", a_X, a_Y, a_Z );
|
||||
|
||||
FILE* f = 0;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, SourceFile, "rb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(SourceFile, "rb" )) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
cChunk* Chunk = new cChunk( a_X, a_Y, a_Z );
|
||||
if( fread( Chunk->m_BlockData, sizeof(char)*cChunk::c_BlockDataSize, 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
|
||||
// Now load Block Entities
|
||||
ENUM_BLOCK_ID BlockType;
|
||||
while( fread( &BlockType, sizeof(ENUM_BLOCK_ID), 1, f) == 1 )
|
||||
{
|
||||
switch( BlockType )
|
||||
{
|
||||
case E_BLOCK_CHEST:
|
||||
{
|
||||
cChestEntity* ChestEntity = new cChestEntity( 0, 0, 0 );
|
||||
if( !ChestEntity->LoadFromFile( f ) )
|
||||
{
|
||||
LOGERROR("ERROR READING CHEST FROM FILE %s", SourceFile );
|
||||
delete ChestEntity;
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
Chunk->m_BlockEntities.push_back( ChestEntity );
|
||||
}
|
||||
break;
|
||||
case E_BLOCK_FURNACE:
|
||||
{
|
||||
cFurnaceEntity* FurnaceEntity = new cFurnaceEntity( 0, 0, 0 );
|
||||
if( !FurnaceEntity->LoadFromFile( f ) )
|
||||
{
|
||||
LOGERROR("ERROR READING FURNACE FROM FILE %s", SourceFile );
|
||||
delete FurnaceEntity;
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
Chunk->m_BlockEntities.push_back( FurnaceEntity );
|
||||
Chunk->m_TickBlockEntities.push_back( FurnaceEntity ); // They need tickin'
|
||||
}
|
||||
break;
|
||||
case E_BLOCK_SIGN_POST:
|
||||
case E_BLOCK_WALLSIGN:
|
||||
{
|
||||
cSignEntity* SignEntity = new cSignEntity(BlockType, 0, 0, 0 );
|
||||
if( !SignEntity->LoadFromFile( f ) )
|
||||
{
|
||||
LOGERROR("ERROR READING SIGN FROM FILE %s", SourceFile );
|
||||
delete SignEntity;
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
Chunk->m_BlockEntities.push_back( SignEntity );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return Chunk;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool cChunkLoader::SaveOldFormat( const cChunk & a_Chunk )
|
||||
{
|
||||
char SourceFile[128];
|
||||
sprintf_s(SourceFile, 128, "world/X%i_Y%i_Z%i.bin", a_Chunk.m_PosX, a_Chunk.m_PosY, a_Chunk.m_PosZ );
|
||||
|
||||
#ifdef _WIN32
|
||||
{
|
||||
SECURITY_ATTRIBUTES Attrib;
|
||||
Attrib.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
Attrib.lpSecurityDescriptor = NULL;
|
||||
Attrib.bInheritHandle = false;
|
||||
::CreateDirectory("world", &Attrib);
|
||||
}
|
||||
#else
|
||||
{
|
||||
mkdir("world", S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
}
|
||||
#endif
|
||||
|
||||
FILE* f = 0;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, SourceFile, "wb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(SourceFile, "wb" )) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
fwrite( a_Chunk.m_BlockData, sizeof(char)*cChunk::c_BlockDataSize, 1, f );
|
||||
|
||||
// Now write Block Entities
|
||||
for( std::list<cBlockEntity*>::const_iterator itr = a_Chunk.m_BlockEntities.begin(); itr != a_Chunk.m_BlockEntities.end(); ++itr)
|
||||
{
|
||||
cBlockEntity* BlockEntity = *itr;
|
||||
switch( BlockEntity->GetBlockType() )
|
||||
{
|
||||
case E_BLOCK_CHEST:
|
||||
{
|
||||
cChestEntity* ChestEntity = reinterpret_cast< cChestEntity* >( BlockEntity );
|
||||
ChestEntity->WriteToFile( f );
|
||||
}
|
||||
break;
|
||||
case E_BLOCK_FURNACE:
|
||||
{
|
||||
cFurnaceEntity* FurnaceEntity = reinterpret_cast< cFurnaceEntity* >( BlockEntity );
|
||||
FurnaceEntity->WriteToFile( f );
|
||||
}
|
||||
break;
|
||||
case E_BLOCK_SIGN_POST:
|
||||
case E_BLOCK_WALLSIGN:
|
||||
{
|
||||
cSignEntity* SignEntity = reinterpret_cast< cSignEntity* >( BlockEntity );
|
||||
SignEntity->WriteToFile( f );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("ERROR WRITING TO FILE %s", SourceFile);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******************************************
|
||||
* New format
|
||||
**/
|
||||
|
||||
cChunk* cChunkLoader::LoadFormat1( int a_X, int a_Y, int a_Z )
|
||||
{
|
||||
int PakX = (int)(floorf((float)a_X / 16.f));
|
||||
int PakY = (int)(floorf((float)a_Y / 16.f));
|
||||
int PakZ = (int)(floorf((float)a_Z / 16.f));
|
||||
|
||||
ChunkPack * Pack = 0;
|
||||
ChunkPackList & PackList = m_ChunkPacks->AllPacks;
|
||||
for( ChunkPackList::iterator itr = PackList.begin(); itr != PackList.end(); ++itr )
|
||||
{
|
||||
if( itr->x == PakX && itr->y == PakY && itr->z == PakZ )
|
||||
{
|
||||
Pack = &(*itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if( !Pack ) // The pack was not in memory, so try to load it from disk
|
||||
{
|
||||
Pack = LoadPak1( PakX, PakY, PakZ ); // Load .pak file from disk
|
||||
if( Pack )
|
||||
{
|
||||
PackList.push_back( *Pack ); // Add it to the loaded list
|
||||
}
|
||||
}
|
||||
|
||||
if( Pack ) // Allright, the pack is in memory
|
||||
{
|
||||
ChunkData * Data = 0;
|
||||
ChunkDataList & ChunkList = Pack->AllChunks;
|
||||
for( ChunkDataList::iterator itr = ChunkList.begin(); itr != ChunkList.end(); ++itr )
|
||||
{
|
||||
if( itr->x == a_X && itr->z == a_Z )
|
||||
{
|
||||
Data = &(*itr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !Data ) // Sorry, chunk does not exist (yet)
|
||||
return 0;
|
||||
|
||||
if( Data->LiveChunk ) // This chunk is already loaded and decoded (this should actually never happen)
|
||||
return Data->LiveChunk;
|
||||
|
||||
// Decompress chunk, and return brand new chunk
|
||||
|
||||
// doing it...
|
||||
|
||||
return 0; // actually return the chunk
|
||||
}
|
||||
|
||||
return 0; // .pak file didn't exist
|
||||
}
|
||||
|
||||
cChunkLoader::ChunkPack* cChunkLoader::LoadPak1( int PakX, int PakY, int PakZ )
|
||||
{
|
||||
char SourceFile[128];
|
||||
sprintf_s(SourceFile, 128, "world/X%i_Y%i_Z%i.pak", PakX, PakY, PakZ );
|
||||
|
||||
FILE* f = 0;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, SourceFile, "rb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(SourceFile, "rb" )) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
cChunkLoader::ChunkPack * Pack = new cChunkLoader::ChunkPack;
|
||||
Pack->x = PakX;
|
||||
Pack->y = PakY;
|
||||
Pack->z = PakZ;
|
||||
|
||||
short Version = 0;
|
||||
if( fread( &Version, sizeof( short ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; }
|
||||
if( Version != 1 ) { LOGERROR("Wrong pak version! %s", SourceFile ); return 0; }
|
||||
short NumChunks = 0;
|
||||
if( fread( &NumChunks, sizeof( short ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; }
|
||||
|
||||
// Load all the headers
|
||||
for( short i = 0; i < NumChunks; ++i )
|
||||
{
|
||||
ChunkData Data;
|
||||
if( fread( &Data.x, sizeof( int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; }
|
||||
if( fread( &Data.z, sizeof( int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; }
|
||||
if( fread( &Data.DataSize, sizeof( unsigned int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; }
|
||||
if( fread( &Data.ChunkStart, sizeof( unsigned int ), 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; }
|
||||
Pack->AllChunks.push_back( Data );
|
||||
}
|
||||
|
||||
// Load all compressed chunk data in the order the headers were loaded
|
||||
ChunkDataList::iterator itr = Pack->AllChunks.begin();
|
||||
for( short i = 0; i < NumChunks; ++i )
|
||||
{
|
||||
itr->Data = new char[ itr->DataSize ];
|
||||
if( fread( itr->Data, sizeof( char ) * itr->DataSize, 1, f ) != 1 ) { LOGERROR("Error reading file %s", SourceFile ); return 0; }
|
||||
++itr;
|
||||
}
|
||||
|
||||
// And we're done :)
|
||||
return Pack;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
32
source/cChunkLoader.h
Normal file
32
source/cChunkLoader.h
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
class cCriticalSection;
|
||||
class cEvent;
|
||||
class cChunk;
|
||||
class cChunkLoader
|
||||
{
|
||||
public:
|
||||
cChunkLoader();
|
||||
~cChunkLoader();
|
||||
|
||||
cChunk* LoadChunk( int a_X, int a_Y, int a_Z );
|
||||
bool SaveChunk( const cChunk & a_Chunk );
|
||||
|
||||
struct ChunkPack;
|
||||
private:
|
||||
cChunk* LoadFormat1( int a_X, int a_Y, int a_Z );
|
||||
ChunkPack* LoadPak1( int PakX, int PakY, int PakZ ); // This loads a .pak file from disk and returns it, nothing more
|
||||
|
||||
// Old stuffs
|
||||
cChunk* LoadOldFormat( int a_X, int a_Y, int a_Z );
|
||||
bool SaveOldFormat( const cChunk & a_Chunk );
|
||||
|
||||
static void SaveThread( void* a_Param );
|
||||
|
||||
bool m_bStop;
|
||||
cCriticalSection* m_CriticalSection;
|
||||
cEvent* m_Event;
|
||||
|
||||
struct ChunkPacks; // Defined in .cpp
|
||||
ChunkPacks* m_ChunkPacks;
|
||||
};
|
714
source/cChunkMap.cpp
Normal file
714
source/cChunkMap.cpp
Normal file
@ -0,0 +1,714 @@
|
||||
#include "cChunkMap.h"
|
||||
#include "cChunk.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cWorld.h"
|
||||
#include "cRoot.h"
|
||||
#include "cMakeDir.h"
|
||||
#ifndef _WIN32
|
||||
#include <cstring> // memcpy
|
||||
#include <cstdlib> // abs
|
||||
#endif
|
||||
|
||||
#include "zlib.h"
|
||||
#include <json/json.h>
|
||||
|
||||
#define USE_MEMCPY
|
||||
|
||||
#define LAYER_SIZE (32)
|
||||
|
||||
cChunkMap::cChunkMap( int a_Width, int a_Height )
|
||||
: m_Nodes( new cChunkNode[ a_Width * a_Height ] )
|
||||
, m_Width( a_Width )
|
||||
, m_Height( a_Height )
|
||||
, m_Layers( 0 )
|
||||
, m_NumLayers( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
cChunkMap::~cChunkMap()
|
||||
{
|
||||
delete [] m_Nodes;
|
||||
}
|
||||
|
||||
cChunkMap::cChunkNode::cChunkNode()
|
||||
{
|
||||
m_Size = 0;
|
||||
m_Allocated = 0;
|
||||
m_Chunks = 0;
|
||||
}
|
||||
|
||||
cChunkMap::cChunkNode::~cChunkNode()
|
||||
{
|
||||
if( m_Allocated > 0 )
|
||||
{
|
||||
for( unsigned int i = 0; i < m_Size; ++i )
|
||||
{
|
||||
delete m_Chunks[i];
|
||||
}
|
||||
delete [] m_Chunks;
|
||||
}
|
||||
// m_Chunks = 0;
|
||||
// m_Allocated = 0;
|
||||
// m_Size = 0;
|
||||
}
|
||||
|
||||
void cChunkMap::cChunkNode::push_back( cChunk* a_Chunk )
|
||||
{
|
||||
if( m_Allocated == 0 )
|
||||
{
|
||||
resize( 1 );
|
||||
}
|
||||
if( m_Size >= m_Allocated )
|
||||
{
|
||||
resize( m_Allocated*2 );
|
||||
}
|
||||
|
||||
m_Chunks[ m_Size ] = a_Chunk;
|
||||
m_Size++;
|
||||
}
|
||||
|
||||
void cChunkMap::cChunkNode::resize( unsigned int a_NewSize )
|
||||
{
|
||||
cChunk** TempChunks = new cChunk*[a_NewSize];
|
||||
if( m_Allocated > 0 )
|
||||
{
|
||||
#ifdef USE_MEMCPY
|
||||
memcpy( TempChunks, m_Chunks, sizeof( cChunk* ) * m_Size );
|
||||
#else
|
||||
for( unsigned int i = 0; i < a_NewSize; ++i )
|
||||
TempChunks[i] = m_Chunks[i];
|
||||
#endif
|
||||
delete [] m_Chunks;
|
||||
}
|
||||
m_Chunks = TempChunks;
|
||||
m_Allocated = a_NewSize;
|
||||
}
|
||||
|
||||
void cChunkMap::cChunkNode::erase( cChunk* a_Chunk )
|
||||
{
|
||||
if( m_Size == 0 ) return;
|
||||
|
||||
cChunk** TempChunks = new cChunk*[m_Size];
|
||||
unsigned int TempIdx = 0;
|
||||
for( unsigned int i = 0; i < m_Size; ++i )
|
||||
{
|
||||
if( m_Chunks[i] != a_Chunk )
|
||||
{
|
||||
TempChunks[TempIdx] = m_Chunks[i];
|
||||
TempIdx++;
|
||||
}
|
||||
}
|
||||
delete [] m_Chunks;
|
||||
m_Chunks = 0;
|
||||
if( TempIdx > 0 )
|
||||
{
|
||||
m_Chunks = new cChunk*[ TempIdx ];
|
||||
#ifdef USE_MEMCPY
|
||||
memcpy( m_Chunks, TempChunks, sizeof( cChunk* ) * TempIdx );
|
||||
#else
|
||||
for( unsigned int i = 0; i < TempIdx; ++i )
|
||||
m_Chunks[i] = TempChunks[i];
|
||||
#endif
|
||||
}
|
||||
delete [] TempChunks;
|
||||
m_Allocated = TempIdx;
|
||||
m_Size = TempIdx;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool cChunkMap::RemoveLayer( cChunkLayer* a_Layer )
|
||||
{
|
||||
cChunkLayer* NewLayers = 0;
|
||||
if( m_NumLayers > 1 )
|
||||
NewLayers = new cChunkLayer[m_NumLayers-1];
|
||||
|
||||
int idx = 0;
|
||||
bool bExcludedLayer = false;
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
{
|
||||
if( &m_Layers[i] != a_Layer )
|
||||
{
|
||||
if( idx < m_NumLayers-1 )
|
||||
{
|
||||
NewLayers[ idx ] = m_Layers[i];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void cChunkMap::AddChunk( cChunk* a_Chunk )
|
||||
{
|
||||
/* // OLD
|
||||
m_Nodes[ MakeHash( a_Chunk->GetPosX(), a_Chunk->GetPosZ() ) ].push_back( a_Chunk );
|
||||
*/
|
||||
|
||||
// NEW
|
||||
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 );
|
||||
LOGWARN("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!");
|
||||
FoundLayer->m_Chunks[ LocalX + LocalZ * LAYER_SIZE ].m_LiveChunk = a_Chunk;
|
||||
FoundLayer->m_NumChunksLoaded++;
|
||||
}
|
||||
|
||||
void cChunkMap::RemoveChunk( cChunk* a_Chunk )
|
||||
{
|
||||
/* // OLD
|
||||
m_Nodes[ MakeHash( a_Chunk->GetPosX(), a_Chunk->GetPosZ() ) ].erase( a_Chunk );
|
||||
*/
|
||||
|
||||
// NEW
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int cChunkMap::MakeHash( int a_X, int a_Z )
|
||||
{
|
||||
const unsigned int HashX = abs( a_X ) % m_Width;
|
||||
const unsigned int HashZ = abs( a_Z ) % m_Height;
|
||||
return HashX + HashZ * m_Width;
|
||||
}
|
||||
|
||||
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)));
|
||||
return GetLayer( LayerX, LayerZ );
|
||||
}
|
||||
|
||||
cChunkMap::cChunkLayer* cChunkMap::GetLayer( int a_LayerX, int a_LayerZ )
|
||||
{
|
||||
// Find layer in memory
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
{
|
||||
if( m_Layers[i].m_X == a_LayerX && m_Layers[i].m_Z == a_LayerZ )
|
||||
{
|
||||
return &m_Layers[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Find layer on disk
|
||||
cChunkLayer* Layer = LoadLayer( a_LayerX, a_LayerZ );
|
||||
if( !Layer ) return 0;
|
||||
|
||||
cChunkLayer* NewLayer = AddLayer( *Layer );
|
||||
delete Layer;
|
||||
return NewLayer;
|
||||
}
|
||||
|
||||
cChunk* cChunkMap::GetChunk( int a_X, int a_Y, int a_Z )
|
||||
{
|
||||
/* // OLD
|
||||
unsigned int Hash = MakeHash( a_X, a_Z );
|
||||
cChunkNode & Node = m_Nodes[ Hash ];
|
||||
cChunk** Chunks = Node.GetChunks();
|
||||
for( unsigned int i = 0; i < Node.size(); ++i )
|
||||
{
|
||||
if( Chunks[i]->GetPosX() == a_X && // Check if we found the right chunk
|
||||
Chunks[i]->GetPosY() == a_Y &&
|
||||
Chunks[i]->GetPosZ() == a_Z )
|
||||
{
|
||||
return Chunks[i];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// NEW
|
||||
cChunkLayer* Layer = GetLayerForChunk( a_X, a_Z );
|
||||
if( Layer )
|
||||
{
|
||||
cChunkData* Data = Layer->GetChunk( a_X, a_Z );
|
||||
if( Data->m_LiveChunk ) return Data->m_LiveChunk;
|
||||
|
||||
// Decompress cached chunk
|
||||
if( Data->m_Compressed )
|
||||
{
|
||||
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);
|
||||
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
|
||||
{
|
||||
//Json::StyledWriter writer;
|
||||
//LOGINFO("Trailing Json:" );
|
||||
//printf("%s", writer.write( root ).c_str() );
|
||||
Chunk->LoadFromJson( root );
|
||||
}
|
||||
}
|
||||
|
||||
delete [] BlockData;
|
||||
delete [] Data->m_Compressed; Data->m_Compressed = 0; Data->m_CompressedSize = 0;
|
||||
return Chunk;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cChunkMap::Tick( float a_Dt )
|
||||
{
|
||||
/* // OLD
|
||||
for( int i = 0; i < m_Width*m_Height; ++i )
|
||||
{
|
||||
cChunkNode & Node = m_Nodes[ i ];
|
||||
cChunk** Chunks = Node.GetChunks();
|
||||
for( unsigned int i = 0; i < Node.size(); ++i )
|
||||
{
|
||||
Chunks[i]->Tick( a_Dt );
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// NEW
|
||||
for( int l = 0; l < m_NumLayers; ++l )
|
||||
{
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
|
||||
{
|
||||
cChunk* Chunk = m_Layers[l].m_Chunks[i].m_LiveChunk;
|
||||
if( Chunk )
|
||||
Chunk->Tick( a_Dt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cChunkMap::UnloadUnusedChunks()
|
||||
{
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
/* // OLD
|
||||
for( int i = 0; i < m_Width*m_Height; ++i )
|
||||
{
|
||||
cChunkNode & Node = m_Nodes[ i ];
|
||||
cChunk** Chunks = Node.GetChunks();
|
||||
for( unsigned int i = 0; i < Node.size(); ++i )
|
||||
{
|
||||
if( Chunks[i]->GetClients().size() == 0 )
|
||||
{
|
||||
Chunks[i]->SaveToDisk();
|
||||
LOG("Unloading %p", Chunks[i] );
|
||||
World->RemoveSpread( Chunks[i] );
|
||||
cChunk* TheChunk = Chunks[i];
|
||||
RemoveChunk( TheChunk );
|
||||
delete TheChunk;
|
||||
//Node.erase( Chunks[i] );
|
||||
Chunks = Node.GetChunks(); // Chunks pointer is no longer valid, get a new one
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// NEW
|
||||
for( int l = 0; l < m_NumLayers; ++l )
|
||||
{
|
||||
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->SaveToDisk();
|
||||
World->RemoveSpread( 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
|
||||
{
|
||||
if( Layer.m_Chunks[i].m_Compressed )
|
||||
delete [] Layer.m_Chunks[i].m_Compressed;
|
||||
if( Layer.m_Chunks[i].m_LiveChunk )
|
||||
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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cChunkMap::RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom /* = 0 */ )
|
||||
{
|
||||
/* // OLD
|
||||
for( int i = 0; i < m_Width*m_Height; ++i )
|
||||
{
|
||||
cChunkNode & Node = m_Nodes[ i ];
|
||||
cChunk** Chunks = Node.GetChunks();
|
||||
for( unsigned int i = 0; i < Node.size(); ++i )
|
||||
{
|
||||
if( Chunks[i] != a_CalledFrom )
|
||||
{
|
||||
if( Chunks[i]->RemoveEntity( a_Entity, a_CalledFrom ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// NEW
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void cChunkMap::SaveAllChunks()
|
||||
{
|
||||
for( int i = 0; i < m_Width*m_Height; ++i )
|
||||
{
|
||||
cChunkNode & Node = m_Nodes[ i ];
|
||||
cChunk** Chunks = Node.GetChunks();
|
||||
for( unsigned int i = 0; i < Node.size(); ++i )
|
||||
{
|
||||
Chunks[i]->SaveToDisk();
|
||||
}
|
||||
}
|
||||
|
||||
for( int i = 0; i < m_NumLayers; ++i )
|
||||
{
|
||||
SaveLayer( &m_Layers[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/********************************
|
||||
* Saving and loading
|
||||
**/
|
||||
|
||||
void cChunkMap::SaveLayer( cChunkLayer* a_Layer )
|
||||
{
|
||||
cMakeDir::MakeDir("world");
|
||||
|
||||
char SourceFile[128];
|
||||
|
||||
#ifdef _WIN32
|
||||
sprintf_s(SourceFile, 128, "world/X%i_Z%i.pak", a_Layer->m_X, a_Layer->m_Z );
|
||||
#else
|
||||
sprintf(SourceFile, "world/X%i_Z%i.pak", a_Layer->m_X, a_Layer->m_Z );
|
||||
#endif
|
||||
|
||||
|
||||
FILE* f = 0;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, SourceFile, "wb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(SourceFile, "wb" )) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
//---------------
|
||||
// Header
|
||||
char PakVersion = 1;
|
||||
char ChunkVersion = 1;
|
||||
fwrite( &PakVersion, sizeof(PakVersion), 1, f ); // pak version
|
||||
fwrite( &ChunkVersion, sizeof(ChunkVersion), 1, f ); // chunk version
|
||||
|
||||
// Count number of chunks in layer
|
||||
short NumChunks = 0;
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
|
||||
{
|
||||
if( a_Layer->m_Chunks[i].m_Compressed || a_Layer->m_Chunks[i].m_LiveChunk )
|
||||
NumChunks++;
|
||||
}
|
||||
|
||||
fwrite( &NumChunks, sizeof( NumChunks ), 1, f );
|
||||
LOG("Num Chunks in layer: %i", 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 || Data.m_LiveChunk )
|
||||
{
|
||||
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
|
||||
fwrite( &ChunkX, sizeof( ChunkX ), 1, f );
|
||||
fwrite( &ChunkZ, sizeof( ChunkZ ), 1, f );
|
||||
fwrite( &Size, sizeof( Size ), 1, f );
|
||||
fwrite( &USize, sizeof( USize ), 1, f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//----------------
|
||||
// Chunk data
|
||||
for( int i = 0; i < LAYER_SIZE*LAYER_SIZE; ++i )
|
||||
{
|
||||
char* Compressed = a_Layer->m_Chunks[i].m_Compressed;
|
||||
if( Compressed )
|
||||
{
|
||||
fwrite( Compressed, a_Layer->m_Chunks[i].m_CompressedSize, 1, f );
|
||||
if(a_Layer->m_Chunks[i].m_LiveChunk) // 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("ERROR: Could not write to file %s", SourceFile );
|
||||
}
|
||||
}
|
||||
|
||||
cChunkMap::cChunkLayer* cChunkMap::LoadLayer(int a_LayerX, int a_LayerZ )
|
||||
{
|
||||
char SourceFile[128];
|
||||
|
||||
#ifdef _WIN32
|
||||
sprintf_s(SourceFile, 128, "world/X%i_Z%i.pak", a_LayerX, a_LayerZ );
|
||||
#else
|
||||
sprintf(SourceFile, "world/X%i_Z%i.pak", a_LayerX, a_LayerZ );
|
||||
#endif
|
||||
|
||||
FILE* f = 0;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, SourceFile, "rb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(SourceFile, "rb" )) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
char PakVersion = 0;
|
||||
char ChunkVersion = 0;
|
||||
if( fread( &PakVersion, sizeof(PakVersion), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( PakVersion != 1 ) { LOGERROR("WRONG PAK VERSION!"); fclose(f); return 0; }
|
||||
if( fread( &ChunkVersion, sizeof(ChunkVersion), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( PakVersion != 1 ) { LOGERROR("WRONG CHUNK VERSION!"); fclose(f); return 0; }
|
||||
|
||||
short NumChunks = 0;
|
||||
if( fread( &NumChunks, sizeof(NumChunks), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
LOG("Num chunks: %i", NumChunks );
|
||||
|
||||
cChunkLayer* Layer = new cChunkLayer( LAYER_SIZE*LAYER_SIZE );
|
||||
Layer->m_X = a_LayerX;
|
||||
Layer->m_Z = a_LayerZ;
|
||||
cChunkData** OrderedData = new cChunkData*[ NumChunks ]; // 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;
|
||||
if( fread( &ChunkX, sizeof(ChunkX), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &ChunkZ, sizeof(ChunkZ), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
cChunkData* Data = Layer->GetChunk( ChunkX, ChunkZ );
|
||||
if( Data )
|
||||
{
|
||||
if( fread( &Data->m_CompressedSize, sizeof(Data->m_CompressedSize), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &Data->m_UncompressedSize, sizeof(Data->m_UncompressedSize), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGERROR("Chunk with wrong coordinates in pak file! %i %i", ChunkX, ChunkZ );
|
||||
fclose(f);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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( fread( Data->m_Compressed, Data->m_CompressedSize, 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
|
||||
/* // Some testing...
|
||||
uLongf DestSize = Data->m_UncompressedSize;
|
||||
char* BlockData = new char[ DestSize ];
|
||||
int errorcode = uncompress( (Bytef*)BlockData, &DestSize, (Bytef*)Data->m_Compressed, Data->m_CompressedSize );
|
||||
if( errorcode != Z_OK )
|
||||
{
|
||||
LOGERROR("lulwut");
|
||||
}
|
||||
*/
|
||||
}
|
||||
delete [] OrderedData;
|
||||
|
||||
fclose(f);
|
||||
return Layer;
|
||||
}
|
||||
else
|
||||
{
|
||||
//LOGWARN("Could not open file %s", SourceFile );
|
||||
}
|
||||
return 0;
|
||||
}
|
91
source/cChunkMap.h
Normal file
91
source/cChunkMap.h
Normal file
@ -0,0 +1,91 @@
|
||||
#pragma once
|
||||
|
||||
class cEntity;
|
||||
class cChunk;
|
||||
class cChunkMap
|
||||
{
|
||||
public:
|
||||
cChunkMap( int a_Width, int a_Height );
|
||||
~cChunkMap();
|
||||
|
||||
void AddChunk( cChunk* a_Chunk );
|
||||
unsigned int MakeHash( int a_X, int a_Z );
|
||||
|
||||
cChunk* GetChunk( int a_X, int a_Y, int a_Z );
|
||||
void RemoveChunk( cChunk* a_Chunk );
|
||||
|
||||
void Tick( float a_Dt );
|
||||
|
||||
void UnloadUnusedChunks();
|
||||
bool RemoveEntityFromChunk( cEntity & a_Entity, cChunk* a_CalledFrom = 0 );
|
||||
void SaveAllChunks();
|
||||
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 );
|
||||
cChunkData* m_Chunks;
|
||||
int m_X, m_Z;
|
||||
int m_NumChunksLoaded;
|
||||
};
|
||||
|
||||
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 );
|
||||
|
||||
int m_NumLayers;
|
||||
cChunkLayer* m_Layers;
|
||||
|
||||
class cChunkNode
|
||||
{
|
||||
public:
|
||||
cChunkNode();
|
||||
~cChunkNode();
|
||||
void push_back( cChunk* a_Chunk );
|
||||
unsigned int size() { return m_Size; }
|
||||
unsigned int allocated() { return m_Allocated; }
|
||||
void resize( unsigned int a_NewSize );
|
||||
|
||||
void erase( cChunk* a_Chunk );
|
||||
|
||||
cChunk** GetChunks() { return m_Chunks; }
|
||||
private:
|
||||
unsigned int m_Size;
|
||||
unsigned int m_Allocated;
|
||||
cChunk** m_Chunks;
|
||||
};
|
||||
|
||||
cChunkNode* m_Nodes;
|
||||
int m_Width, m_Height;
|
||||
};
|
1082
source/cClientHandle.cpp
Normal file
1082
source/cClientHandle.cpp
Normal file
File diff suppressed because it is too large
Load Diff
70
source/cClientHandle.h
Normal file
70
source/cClientHandle.h
Normal file
@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
class cSocket;
|
||||
class cSemaphore;
|
||||
class cEvent;
|
||||
class Game;
|
||||
class cPacket;
|
||||
class cChunk;
|
||||
class cPlayer;
|
||||
class cClientHandle // tolua_export
|
||||
{ // tolua_export
|
||||
public:
|
||||
enum ENUM_PRIORITY
|
||||
{
|
||||
E_PRIORITY_LOW,
|
||||
E_PRIORITY_NORMAL
|
||||
};
|
||||
|
||||
cClientHandle(const cSocket & a_Socket);
|
||||
~cClientHandle();
|
||||
|
||||
static const int VIEWDISTANCE = 13;
|
||||
|
||||
const cSocket & GetSocket();
|
||||
cPlayer* GetPlayer() { return m_Player; } // tolua_export
|
||||
|
||||
void Kick( const char* a_Reason ); //tolua_export
|
||||
|
||||
void AddPacket( cPacket * a_Packet );
|
||||
void HandlePendingPackets();
|
||||
|
||||
void StreamChunks();
|
||||
void StreamChunksSmart( cChunk** a_Chunks, unsigned int a_NumChunks );
|
||||
|
||||
inline void SetLoggedIn( bool a_bLoggedIn ) { m_bLoggedIn = a_bLoggedIn; }
|
||||
inline bool IsLoggedIn() { return m_bLoggedIn; }
|
||||
|
||||
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 );
|
||||
|
||||
static void SendThread( void *lpParam );
|
||||
static void ReceiveThread( void *lpParam );
|
||||
static void AuthenticateThread( void* a_Param );
|
||||
|
||||
const char* GetUsername();
|
||||
private:
|
||||
void HandlePacket( cPacket* a_Packet );
|
||||
void RemovePacket( cPacket * a_Packet );
|
||||
|
||||
void SendLoginResponse();
|
||||
|
||||
struct sClientHandleState;
|
||||
sClientHandleState* m_pState;
|
||||
|
||||
bool m_bDestroyed;
|
||||
cPlayer* m_Player;
|
||||
bool m_bKicking;
|
||||
|
||||
float m_TimeLastPacket;
|
||||
|
||||
bool m_bLoggedIn;
|
||||
|
||||
bool m_bKeepThreadGoing;
|
||||
}; // tolua_export
|
103
source/cCraftingWindow.cpp
Normal file
103
source/cCraftingWindow.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include "cCraftingWindow.h"
|
||||
#include "cItem.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cRecipeChecker.h"
|
||||
#include "cPlayer.h"
|
||||
#include "cClientHandle.h"
|
||||
#include "cInventory.h"
|
||||
#include "cPickup.h"
|
||||
#include "cRoot.h"
|
||||
|
||||
#include "packets/cPacket_WindowClick.h"
|
||||
#include "packets/cPacket_InventorySlot.h"
|
||||
|
||||
cCraftingWindow::cCraftingWindow( cWindowOwner* a_Owner, bool a_bInventoryVisible )
|
||||
: cWindow( a_Owner, a_bInventoryVisible )
|
||||
{
|
||||
SetWindowID( 1 );
|
||||
SetWindowType( 1 ); // Workbench
|
||||
|
||||
cItem* Slots = new cItem[10];
|
||||
SetSlots( Slots, 10 );
|
||||
}
|
||||
|
||||
void cCraftingWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player )
|
||||
{
|
||||
bool bDontCook = false;
|
||||
// Override for craft result slot
|
||||
if( a_ClickPacket->m_SlotNum == 0 )
|
||||
{
|
||||
LOG("In craft slot: %i x %i !!", GetSlot(0)->m_ItemID, GetSlot(0)->m_ItemCount );
|
||||
cItem* DraggingItem = GetDraggingItem( &a_Player );
|
||||
if( DraggingItem->m_ItemID <= 0 )
|
||||
{
|
||||
*DraggingItem = *GetSlot(0);
|
||||
GetSlot(0)->Empty();
|
||||
}
|
||||
else if( DraggingItem->Equals( *GetSlot(0) ) )
|
||||
{
|
||||
if( DraggingItem->m_ItemCount + GetSlot(0)->m_ItemCount <= 64 )
|
||||
{
|
||||
DraggingItem->m_ItemCount += GetSlot(0)->m_ItemCount;
|
||||
GetSlot(0)->Empty();
|
||||
}
|
||||
else
|
||||
{
|
||||
bDontCook = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bDontCook = true;
|
||||
}
|
||||
LOG("Dragging Dish %i", DraggingItem->m_ItemCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
cWindow::Clicked( a_ClickPacket, a_Player );
|
||||
}
|
||||
|
||||
if( a_ClickPacket->m_SlotNum >= 0 && a_ClickPacket->m_SlotNum < 10 )
|
||||
{
|
||||
cItem CookedItem;
|
||||
if( a_ClickPacket->m_SlotNum == 0 && !bDontCook )
|
||||
{
|
||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( GetSlots()+1, 3, 3, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( GetSlots()+1, 3, 3 );
|
||||
}
|
||||
*GetSlot(0) = CookedItem;
|
||||
LOG("You cooked: %i x %i !!", GetSlot(0)->m_ItemID, GetSlot(0)->m_ItemCount );
|
||||
}
|
||||
SendWholeWindow( a_Player.GetClientHandle() );
|
||||
a_Player.GetInventory().SendWholeInventory( a_Player.GetClientHandle() );
|
||||
// Separate packet for result =/ Don't know why
|
||||
cPacket_InventorySlot Packet;
|
||||
Packet.m_WindowID = (char)GetWindowID();
|
||||
Packet.m_SlotNum = 0;
|
||||
Packet.m_ItemID = (short)GetSlot(0)->m_ItemID;
|
||||
Packet.m_ItemCount = GetSlot(0)->m_ItemCount;
|
||||
Packet.m_ItemUses = (char)GetSlot(0)->m_ItemHealth;
|
||||
a_Player.GetClientHandle()->Send( Packet );
|
||||
}
|
||||
|
||||
void cCraftingWindow::Close( cPlayer & a_Player )
|
||||
{
|
||||
// Start from slot 1, don't drop what's in the result slot
|
||||
for( int i = 1; i < GetNumSlots(); i++ )
|
||||
{
|
||||
cItem* Item = GetSlot( i );
|
||||
if( Item->m_ItemID > 0 && Item->m_ItemCount > 0 )
|
||||
{
|
||||
float vX = 0, vY = 0, vZ = 0;
|
||||
EulerToVector( -a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY );
|
||||
vY = -vY*2 + 1.f;
|
||||
cPickup* Pickup = new cPickup( (int)(a_Player.GetPosX()*32), (int)(a_Player.GetPosY()*32) + (int)(1.6f*32), (int)(a_Player.GetPosZ()*32), *Item, vX*2, vY*2, vZ*2 );
|
||||
Pickup->Initialize();
|
||||
}
|
||||
Item->Empty();
|
||||
}
|
||||
cWindow::Close( a_Player );
|
||||
}
|
13
source/cCraftingWindow.h
Normal file
13
source/cCraftingWindow.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "cWindow.h"
|
||||
|
||||
class cWindowOwner;
|
||||
class cCraftingWindow : public cWindow
|
||||
{
|
||||
public:
|
||||
cCraftingWindow( cWindowOwner* a_Owner, bool a_bInventoryVisible );
|
||||
|
||||
virtual void Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player );
|
||||
virtual void Close( cPlayer & a_Player );
|
||||
};
|
60
source/cCriticalSection.cpp
Normal file
60
source/cCriticalSection.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "cCriticalSection.h"
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
cCriticalSection::cCriticalSection()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
m_CriticalSectionPtr = new CRITICAL_SECTION;
|
||||
InitializeCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
#else
|
||||
m_Attributes = new pthread_mutexattr_t;
|
||||
pthread_mutexattr_init((pthread_mutexattr_t*)m_Attributes);
|
||||
pthread_mutexattr_settype((pthread_mutexattr_t*)m_Attributes, PTHREAD_MUTEX_RECURSIVE);
|
||||
|
||||
m_CriticalSectionPtr = new pthread_mutex_t;
|
||||
if( pthread_mutex_init( (pthread_mutex_t*)m_CriticalSectionPtr, (pthread_mutexattr_t*)m_Attributes ) != 0 )
|
||||
{
|
||||
LOG("ERROR: Could not initialize Critical Section!");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
cCriticalSection::~cCriticalSection()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DeleteCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
delete (CRITICAL_SECTION*)m_CriticalSectionPtr;
|
||||
#else
|
||||
if( pthread_mutex_destroy( (pthread_mutex_t*)m_CriticalSectionPtr ) != 0 )
|
||||
{
|
||||
LOG("ERROR: Could not destroy Critical Section!");
|
||||
}
|
||||
delete (pthread_mutex_t*)m_CriticalSectionPtr;
|
||||
pthread_mutexattr_destroy( (pthread_mutexattr_t*)m_Attributes );
|
||||
delete (pthread_mutexattr_t*)m_Attributes;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cCriticalSection::Lock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
#else
|
||||
pthread_mutex_lock( (pthread_mutex_t*)m_CriticalSectionPtr );
|
||||
#endif
|
||||
}
|
||||
|
||||
void cCriticalSection::Unlock()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection( (CRITICAL_SECTION*)m_CriticalSectionPtr );
|
||||
#else
|
||||
pthread_mutex_unlock( (pthread_mutex_t*)m_CriticalSectionPtr );
|
||||
#endif
|
||||
}
|
16
source/cCriticalSection.h
Normal file
16
source/cCriticalSection.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
class cCriticalSection
|
||||
{
|
||||
public:
|
||||
cCriticalSection();
|
||||
~cCriticalSection();
|
||||
|
||||
void Lock();
|
||||
void Unlock();
|
||||
private:
|
||||
void* m_CriticalSectionPtr; // Pointer to a CRITICAL_SECTION object
|
||||
#ifndef _WIN32
|
||||
void* m_Attributes;
|
||||
#endif
|
||||
};
|
10
source/cCuboid.cpp
Normal file
10
source/cCuboid.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "cCuboid.h"
|
||||
|
||||
#include <algorithm> // swap
|
||||
|
||||
void cCuboid::Sort()
|
||||
{
|
||||
if( p1.x > p2.x ) std::swap( p1.x, p2.x );
|
||||
if( p1.y > p2.y ) std::swap( p1.y, p2.y );
|
||||
if( p1.z > p2.z ) std::swap( p1.z, p2.z );
|
||||
}
|
40
source/cCuboid.h
Normal file
40
source/cCuboid.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "Vector3i.h"
|
||||
#include "Vector3d.h"
|
||||
|
||||
class cCuboid //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
cCuboid() {} //tolua_export
|
||||
cCuboid( const cCuboid & a_Cuboid ) : p1( a_Cuboid.p1 ), p2( a_Cuboid.p2 ) {} //tolua_export
|
||||
cCuboid( const Vector3i & a_p1, const Vector3i & a_p2 ) : p1( a_p1 ), p2( a_p2 ) {} //tolua_export
|
||||
|
||||
|
||||
Vector3i p1, p2; //tolua_export
|
||||
|
||||
void Sort(); //tolua_export
|
||||
|
||||
bool IsInside( const Vector3i & v ) const //tolua_export
|
||||
{ //tolua_export
|
||||
if( v.x >= p1.x && v.x <= p2.x
|
||||
&& v.y >= p1.y && v.y <= p2.y
|
||||
&& v.z >= p1.z && v.z <= p2.z )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} //tolua_export
|
||||
|
||||
bool IsInside( const Vector3d & v ) const //tolua_export
|
||||
{ //tolua_export
|
||||
if( v.x >= p1.x && v.x <= p2.x
|
||||
&& v.y >= p1.y && v.y <= p2.y
|
||||
&& v.z >= p1.z && v.z <= p2.z )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} //tolua_export
|
||||
|
||||
}; //tolua_export
|
283
source/cEntity.cpp
Normal file
283
source/cEntity.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
#include "cEntity.h"
|
||||
#include "cWorld.h"
|
||||
#include "cChunk.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cServer.h"
|
||||
#include "cRoot.h"
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3f.h"
|
||||
#include "Matrix4f.h"
|
||||
#include "cReferenceManager.h"
|
||||
#include "cClientHandle.h"
|
||||
|
||||
#include "packets/cPacket_DestroyEntity.h"
|
||||
|
||||
int cEntity::m_EntityCount = 0;
|
||||
|
||||
cEntity::cEntity(const double & a_X, const double & a_Y, const double & a_Z)
|
||||
: 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_Pos( new Vector3d( a_X, a_Y, a_Z ) )
|
||||
, m_bDirtyPosition( true )
|
||||
, m_Rot( new Vector3f() )
|
||||
, m_bDirtyOrientation( true )
|
||||
, m_bDestroyed( false )
|
||||
, m_EntityType( E_ENTITY )
|
||||
{
|
||||
m_EntityCount++;
|
||||
m_UniqueID = m_EntityCount;
|
||||
}
|
||||
|
||||
cEntity::~cEntity()
|
||||
{
|
||||
delete m_Referencers;
|
||||
delete m_References;
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
{
|
||||
cPacket_DestroyEntity DestroyEntity( this );
|
||||
Chunk->Broadcast( DestroyEntity );
|
||||
Chunk->RemoveEntity( *this );
|
||||
}
|
||||
delete m_Pos;
|
||||
delete m_Rot;
|
||||
}
|
||||
|
||||
void cEntity::Initialize()
|
||||
{
|
||||
cRoot::Get()->GetWorld()->AddEntity( this );
|
||||
|
||||
cWorld::BlockToChunk( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z, m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
{
|
||||
//LOG("Adding entity %i to chunk %i %i %i", m_UniqueID, Chunk->GetPosX(), Chunk->GetPosY(), Chunk->GetPosZ() );
|
||||
Chunk->AddEntity( *this );
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void cEntity::MoveToCorrectChunk()
|
||||
{
|
||||
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( m_ChunkX != ChunkX || m_ChunkY != ChunkY || m_ChunkZ != ChunkZ )
|
||||
{
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
LOG("From %i %i To %i %i", m_ChunkX, m_ChunkZ, ChunkX, ChunkZ );
|
||||
cChunk* Chunk = World->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
|
||||
typedef std::list< cClientHandle* > ClientList;
|
||||
ClientList BeforeClients;
|
||||
if( Chunk )
|
||||
{
|
||||
Chunk->RemoveEntity( *this );
|
||||
BeforeClients = Chunk->GetClients();
|
||||
}
|
||||
m_ChunkX = ChunkX; m_ChunkY = ChunkY; m_ChunkZ = ChunkZ;
|
||||
cChunk* NewChunk = 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CLASS_DEF_GETCLASS( cEntity );
|
||||
bool cEntity::IsA( const char* a_EntityType )
|
||||
{
|
||||
//LOG("IsA( cEntity ) : %s", a_EntityType);
|
||||
if( strcmp( a_EntityType, "cEntity" ) == 0 ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Set orientations
|
||||
void cEntity::SetRot( const Vector3f & a_Rot )
|
||||
{
|
||||
*m_Rot = 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!)
|
||||
Vector3f cEntity::GetLookVector()
|
||||
{
|
||||
Matrix4f m;
|
||||
m.Init( Vector3f(), 0, m_Rot->x, -m_Rot->y );
|
||||
Vector3f Look = m.Transform( Vector3f(0, 0, 1) );
|
||||
LOG("Look: %0.1f %0.1f %0.1f", Look.x, Look.y, Look.z );
|
||||
return Look;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Set position
|
||||
void cEntity::SetPosition( const Vector3d & a_Pos )
|
||||
{
|
||||
*m_Pos = a_Pos;
|
||||
MoveToCorrectChunk();
|
||||
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 );
|
||||
MoveToCorrectChunk();
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
void cEntity::SetPosX( const double & a_PosX )
|
||||
{
|
||||
m_Pos->x = a_PosX;
|
||||
MoveToCorrectChunk();
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
void cEntity::SetPosY( const double & a_PosY )
|
||||
{
|
||||
m_Pos->y = a_PosY;
|
||||
MoveToCorrectChunk();
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
|
||||
void cEntity::SetPosZ( const double & a_PosZ )
|
||||
{
|
||||
m_Pos->z = a_PosZ;
|
||||
MoveToCorrectChunk();
|
||||
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
|
||||
void cEntity::AddReference( cEntity*& a_EntityPtr )
|
||||
{
|
||||
m_References->AddReference( 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 );
|
||||
}
|
108
source/cEntity.h
Normal file
108
source/cEntity.h
Normal file
@ -0,0 +1,108 @@
|
||||
#pragma once
|
||||
|
||||
#include "MemoryLeak.h"
|
||||
|
||||
#define CLASS_PROT_ISA() virtual bool IsA( const char* a_EntityType );
|
||||
#define CLASS_PROT_GETCLASS() virtual const char* GetClass();
|
||||
|
||||
/* Can't use this (yet) because of tolua */
|
||||
#define CLASS_PROTOTYPE() \
|
||||
CLASS_PROT_ISA(); \
|
||||
CLASS_PROT_GETCLASS();
|
||||
|
||||
#define CLASS_DEF_ISA( classname, superclass ) \
|
||||
bool classname::IsA( const char* a_EntityType ) \
|
||||
{ \
|
||||
if( strcmp( a_EntityType, #classname ) == 0 ) return true; \
|
||||
return superclass::IsA( a_EntityType ); \
|
||||
}
|
||||
|
||||
#define CLASS_DEF_GETCLASS( classname ) \
|
||||
const char* classname::GetClass() \
|
||||
{ \
|
||||
return #classname; \
|
||||
}
|
||||
|
||||
#define CLASS_DEFINITION( classname, superclass ) \
|
||||
CLASS_DEF_ISA( classname, superclass ) \
|
||||
CLASS_DEF_GETCLASS( classname )
|
||||
|
||||
class cReferenceManager;
|
||||
class Vector3d;
|
||||
class Vector3f;
|
||||
class cClientHandle;
|
||||
class cEntity //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
cEntity(const double & a_X, const double & a_Y, const double & a_Z); //tolua_export
|
||||
virtual ~cEntity(); //tolua_export
|
||||
|
||||
virtual void Initialize(); //tolua_export
|
||||
|
||||
enum ENUM_ENTITY_TYPE //tolua_export
|
||||
{ //tolua_export
|
||||
E_ENTITY, //tolua_export
|
||||
E_PLAYER, //tolua_export
|
||||
E_PICKUP //tolua_export
|
||||
}; //tolua_export
|
||||
|
||||
virtual unsigned int GetEntityType() { return m_EntityType; } //tolua_export
|
||||
virtual bool IsA( const char* a_EntityType ); //tolua_export
|
||||
virtual const char* GetClass(); //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
|
||||
Vector3f GetLookVector(); //tolua_export
|
||||
|
||||
void SetPosX( const double & a_PosX ); //tolua_export
|
||||
void SetPosY( const double & a_PosY ); //tolua_export
|
||||
void SetPosZ( const double & a_PosZ ); //tolua_export
|
||||
void SetPosition( const double & a_PosX, const double & a_PosY, const double & a_PosZ ); //tolua_export
|
||||
void SetPosition( const Vector3d & a_Pos ); //tolua_export
|
||||
void SetRot( const Vector3f & a_Rot ); //tolua_export
|
||||
void SetRotation( float a_Rotation ); //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
|
||||
|
||||
void Destroy() { m_bDestroyed = true; } //tolua_export
|
||||
|
||||
virtual void Tick(float a_Dt) = 0; //tolua_export
|
||||
|
||||
virtual void SpawnOn( cClientHandle* a_Target ) = 0; //tolua_export
|
||||
void WrapRotation();
|
||||
|
||||
protected:
|
||||
void MoveToCorrectChunk();
|
||||
|
||||
friend class cReferenceManager;
|
||||
void AddReference( cEntity*& a_EntityPtr );
|
||||
void ReferencedBy( cEntity*& a_EntityPtr );
|
||||
void Dereference( cEntity*& a_EntityPtr );
|
||||
|
||||
static int m_EntityCount;
|
||||
int m_UniqueID;
|
||||
|
||||
cReferenceManager* m_Referencers;
|
||||
cReferenceManager* m_References;
|
||||
|
||||
int m_ChunkX, m_ChunkY, m_ChunkZ;
|
||||
Vector3d* m_Pos;
|
||||
bool m_bDirtyPosition;
|
||||
|
||||
Vector3f* m_Rot;
|
||||
bool m_bDirtyOrientation;
|
||||
|
||||
bool m_bDestroyed;
|
||||
|
||||
ENUM_ENTITY_TYPE m_EntityType;
|
||||
}; //tolua_export
|
112
source/cEvent.cpp
Normal file
112
source/cEvent.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
#include "cEvent.h"
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <semaphore.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
cEvent::cEvent( unsigned int a_NumEvents /* = 1 */ )
|
||||
: m_NumEvents( a_NumEvents )
|
||||
#ifndef _WIN32
|
||||
, m_bNamed( false )
|
||||
#endif
|
||||
{
|
||||
if( m_NumEvents < 1 ) m_NumEvents = 1;
|
||||
|
||||
#ifdef _WIN32
|
||||
m_Handle = new HANDLE[ m_NumEvents ];
|
||||
for( unsigned int i = 0; i < m_NumEvents; i++)
|
||||
{
|
||||
((HANDLE*)m_Handle)[i] = CreateEvent( 0, FALSE, FALSE, 0 );
|
||||
}
|
||||
#else
|
||||
m_Handle = new sem_t*[ m_NumEvents ];
|
||||
for( unsigned int i = 0; i < m_NumEvents; i++)
|
||||
{
|
||||
|
||||
sem_t* & HandlePtr = ((sem_t**)m_Handle)[i];
|
||||
HandlePtr = new sem_t;
|
||||
|
||||
if( sem_init( HandlePtr, 0, 0 ) )
|
||||
{
|
||||
LOG("WARNING cEvent: Could not create unnamed semaphore, fallback to named.");
|
||||
m_bNamed = true;
|
||||
delete HandlePtr; // named semaphores return their own address
|
||||
|
||||
char c_Str[32];
|
||||
sprintf( c_Str, "cEvent%p", &HandlePtr );
|
||||
HandlePtr = sem_open( c_Str, O_CREAT, 777, 0 );
|
||||
if( HandlePtr == SEM_FAILED )
|
||||
LOG("ERROR: Could not create Event. (%i)", errno);
|
||||
else
|
||||
if( sem_unlink( c_Str ) != 0 )
|
||||
LOG("ERROR: Could not unlink cEvent. (%i)", errno);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
cEvent::~cEvent()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
for( unsigned int i = 0; i < m_NumEvents; i++ )
|
||||
{
|
||||
CloseHandle( ((HANDLE*)m_Handle)[i] );
|
||||
}
|
||||
delete [] (HANDLE*)m_Handle;
|
||||
#else
|
||||
for( unsigned int i = 0; i < m_NumEvents; i++ )
|
||||
{
|
||||
if( m_bNamed )
|
||||
{
|
||||
sem_t* & HandlePtr = ((sem_t**)m_Handle)[i];
|
||||
char c_Str[32];
|
||||
sprintf( c_Str, "cEvent%p", &HandlePtr );
|
||||
// LOG("Closing event: %s", c_Str );
|
||||
// LOG("Sem ptr: %p", HandlePtr );
|
||||
if( sem_close( HandlePtr ) != 0 )
|
||||
{
|
||||
LOG("ERROR: Could not close cEvent. (%i)", errno);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sem_destroy( ((sem_t**)m_Handle)[i] );
|
||||
delete ((sem_t**)m_Handle)[i];
|
||||
}
|
||||
}
|
||||
delete [] (sem_t**)m_Handle; m_Handle = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cEvent::Wait()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WaitForMultipleObjects( m_NumEvents, (HANDLE*)m_Handle, true, INFINITE );
|
||||
#else
|
||||
for(unsigned int i = 0; i < m_NumEvents; i++)
|
||||
{
|
||||
if( sem_wait( ((sem_t**)m_Handle)[i] ) != 0 )
|
||||
{
|
||||
LOG("ERROR: Could not wait for cEvent. (%i)", errno);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void cEvent::Set(unsigned int a_EventNum /* = 0 */)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SetEvent( ((HANDLE*)m_Handle)[a_EventNum] );
|
||||
#else
|
||||
if( sem_post( ((sem_t**)m_Handle)[a_EventNum] ) != 0 )
|
||||
{
|
||||
LOG("ERROR: Could not set cEvent. (%i)", errno);
|
||||
}
|
||||
#endif
|
||||
}
|
18
source/cEvent.h
Normal file
18
source/cEvent.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
class cEvent
|
||||
{
|
||||
public:
|
||||
cEvent( unsigned int a_NumEvents = 1 );
|
||||
~cEvent();
|
||||
|
||||
void Wait();
|
||||
void Set(unsigned int a_EventNum = 0);
|
||||
private:
|
||||
unsigned int m_NumEvents;
|
||||
void* m_Handle; // HANDLE[] pointer
|
||||
|
||||
#ifndef _WIN32
|
||||
bool m_bNamed;
|
||||
#endif
|
||||
};
|
372
source/cFurnaceEntity.cpp
Normal file
372
source/cFurnaceEntity.cpp
Normal file
@ -0,0 +1,372 @@
|
||||
#include "cFurnaceEntity.h"
|
||||
#include "BlockID.h"
|
||||
#include "cItem.h"
|
||||
#include "cFurnaceWindow.h"
|
||||
#include "cPlayer.h"
|
||||
#include "cWorld.h"
|
||||
#include "cChunk.h"
|
||||
#include "cClientHandle.h"
|
||||
#include "cFurnaceRecipe.h"
|
||||
#include "cServer.h"
|
||||
#include "cPickup.h"
|
||||
#include "cRoot.h"
|
||||
|
||||
#include "packets/cPacket_InventoryProgressBar.h"
|
||||
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#include <json/json.h>
|
||||
|
||||
cFurnaceEntity::cFurnaceEntity(int a_X, int a_Y, int a_Z)
|
||||
: cBlockEntity( E_BLOCK_FURNACE, a_X, a_Y, a_Z )
|
||||
, m_Items( new cItem[3] )
|
||||
, m_CookingItem( 0 )
|
||||
, m_CookTime( 0 )
|
||||
, m_TimeCooked( 0 )
|
||||
, m_BurnTime( 0 )
|
||||
, m_TimeBurned( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
cFurnaceEntity::~cFurnaceEntity()
|
||||
{
|
||||
// Tell window its owner is destroyed
|
||||
if( GetWindow() )
|
||||
{
|
||||
GetWindow()->OwnerDestroyed();
|
||||
}
|
||||
|
||||
// Clean up items
|
||||
if( m_Items )
|
||||
{
|
||||
delete [] m_Items;
|
||||
}
|
||||
}
|
||||
|
||||
void cFurnaceEntity::Destroy()
|
||||
{
|
||||
// Drop items
|
||||
for( int i = 0; i < 3; i++)
|
||||
{
|
||||
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_Items[i].Empty();
|
||||
}
|
||||
}
|
||||
|
||||
// Remove from tick list
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
cChunk* Chunk = World->GetChunkOfBlock( m_PosX, m_PosY, m_PosZ );
|
||||
Chunk->RemoveTickBlockEntity( this );
|
||||
}
|
||||
|
||||
void cFurnaceEntity::UsedBy( cPlayer & a_Player )
|
||||
{
|
||||
LOG("Used a furnace");
|
||||
|
||||
if( !GetWindow() )
|
||||
{
|
||||
cWindow* Window = new cFurnaceWindow( this );
|
||||
Window->SetSlots( m_Items, 3 );
|
||||
Window->SetWindowTitle("UberFurnace");
|
||||
OpenWindow( Window );
|
||||
}
|
||||
if( GetWindow() )
|
||||
{
|
||||
if( a_Player.GetWindow() != GetWindow() )
|
||||
{
|
||||
a_Player.OpenWindow( GetWindow() );
|
||||
|
||||
GetWindow()->SendWholeWindow( a_Player.GetClientHandle() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 );
|
||||
if( m_CookingItem && ( (m_TimeBurned < m_BurnTime) || (m_TimeCooked + a_Dt >= m_CookTime) ) )
|
||||
{
|
||||
if( m_CookingItem->Equals( m_Items[2] ) || m_Items[2].IsEmpty() )
|
||||
{
|
||||
m_TimeCooked += a_Dt;
|
||||
if( m_TimeCooked >= m_CookTime )
|
||||
{
|
||||
m_Items[0].m_ItemCount--;
|
||||
if( m_Items[0].IsEmpty() ) m_Items[0].Empty();
|
||||
|
||||
m_Items[2].m_ItemHealth = m_CookingItem->m_ItemHealth;
|
||||
m_Items[2].m_ItemID = m_CookingItem->m_ItemID;
|
||||
m_Items[2].m_ItemCount += m_CookingItem->m_ItemCount;
|
||||
delete m_CookingItem;
|
||||
m_CookingItem = 0;
|
||||
|
||||
cWindow* Window = GetWindow();
|
||||
if( Window )
|
||||
{
|
||||
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
||||
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
||||
{
|
||||
Window->SendWholeWindow( (*itr)->GetClientHandle() );
|
||||
}
|
||||
}
|
||||
|
||||
m_TimeCooked = 0.f;
|
||||
StartCooking();
|
||||
}
|
||||
cWindow* Window = GetWindow();
|
||||
if( Window )
|
||||
{
|
||||
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
||||
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
||||
{
|
||||
cClientHandle* Client = (*itr)->GetClientHandle();
|
||||
|
||||
cPacket_InventoryProgressBar Progress;
|
||||
Progress.m_ProgressBar = 0;
|
||||
Progress.m_WindowID = (char)Window->GetWindowID();
|
||||
Progress.m_Value = (short)( m_TimeCooked * (180.f/m_CookTime) );
|
||||
if( Progress.m_Value > 180 ) Progress.m_Value = 180;
|
||||
if( Progress.m_Value < 0 ) Progress.m_Value = 0;
|
||||
Client->Send( Progress );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_TimeBurned += a_Dt;
|
||||
|
||||
cWindow* Window = GetWindow();
|
||||
if( m_TimeBurned >= m_BurnTime )
|
||||
{
|
||||
m_TimeBurned -= m_BurnTime;
|
||||
m_BurnTime = 0;
|
||||
if( StartCooking() && Window )
|
||||
{
|
||||
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
||||
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
||||
{
|
||||
Window->SendWholeWindow( (*itr)->GetClientHandle() );
|
||||
}
|
||||
}
|
||||
}
|
||||
if( Window )
|
||||
{
|
||||
const std::list< cPlayer* > & OpenedBy = Window->GetOpenedBy();
|
||||
for( std::list< cPlayer* >::const_iterator itr = OpenedBy.begin(); itr != OpenedBy.end(); ++itr )
|
||||
{
|
||||
cClientHandle* Client = (*itr)->GetClientHandle();
|
||||
|
||||
cPacket_InventoryProgressBar Progress;
|
||||
Progress.m_WindowID = (char)Window->GetWindowID();
|
||||
Progress.m_ProgressBar = 1;
|
||||
|
||||
if( m_BurnTime > 0.f ) Progress.m_Value = (short)( m_TimeBurned * (150.f/m_BurnTime) );
|
||||
else Progress.m_Value = 0;
|
||||
if( Progress.m_Value > 150 ) Progress.m_Value = 150;
|
||||
if( Progress.m_Value < 0 ) Progress.m_Value = 0;
|
||||
Client->Send( Progress );
|
||||
}
|
||||
}
|
||||
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();
|
||||
float BurnTime = FR->GetBurnTime( m_Items[1] );
|
||||
if( (m_TimeBurned < m_BurnTime) || BurnTime > 0.f ) // burnable material
|
||||
{
|
||||
const cFurnaceRecipe::Recipe* R = FR->GetRecipeFrom( m_Items[0] );
|
||||
if( R ) // cook able ingredient
|
||||
{
|
||||
if( m_Items[2].Equals( *R->Out ) || m_Items[2].IsEmpty() )
|
||||
{
|
||||
// good to go
|
||||
|
||||
if( m_TimeBurned >= m_BurnTime ) // burn new material
|
||||
{
|
||||
m_Items[1].m_ItemCount--;
|
||||
if( m_Items[1].m_ItemCount <= 0 ) m_Items[1].Empty();
|
||||
m_TimeBurned = 0;
|
||||
m_BurnTime = BurnTime;
|
||||
}
|
||||
|
||||
if( !m_CookingItem ) // Only cook new item if not already cooking
|
||||
{
|
||||
m_CookingItem = new cItem( *R->Out ); // Resulting item
|
||||
m_TimeCooked = 0.f;
|
||||
m_CookTime = R->CookTime;
|
||||
}
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
cChunk* Chunk = World->GetChunkOfBlock( m_PosX, m_PosY, m_PosZ );
|
||||
Chunk->AddTickBlockEntity( this );
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cFurnaceEntity::ResetCookTimer()
|
||||
{
|
||||
if( m_CookingItem )
|
||||
{
|
||||
delete m_CookingItem;
|
||||
m_CookingItem = 0;
|
||||
}
|
||||
m_TimeCooked = 0.f;
|
||||
m_CookTime = 0.f;
|
||||
}
|
||||
|
||||
void cFurnaceEntity::WriteToFile(FILE* a_File)
|
||||
{
|
||||
fwrite( &m_BlockType, sizeof( ENUM_BLOCK_ID ), 1, a_File );
|
||||
fwrite( &m_PosX, sizeof( int ), 1, a_File );
|
||||
fwrite( &m_PosY, sizeof( int ), 1, a_File );
|
||||
fwrite( &m_PosZ, sizeof( int ), 1, a_File );
|
||||
|
||||
unsigned int NumSlots = 3;
|
||||
fwrite( &NumSlots, sizeof(unsigned int), 1, a_File );
|
||||
for(unsigned int i = 0; i < NumSlots; i++)
|
||||
{
|
||||
cItem* Item = &m_Items[i];
|
||||
if( Item )
|
||||
{
|
||||
fwrite( &Item->m_ItemID, sizeof(Item->m_ItemID), 1, a_File );
|
||||
fwrite( &Item->m_ItemCount, sizeof(Item->m_ItemCount), 1, a_File );
|
||||
fwrite( &Item->m_ItemHealth, sizeof(Item->m_ItemHealth), 1, a_File );
|
||||
}
|
||||
}
|
||||
cItem Item;
|
||||
if( m_CookingItem ) Item = *m_CookingItem;
|
||||
fwrite( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File );
|
||||
fwrite( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File );
|
||||
fwrite( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File );
|
||||
|
||||
fwrite( &m_CookTime, sizeof(float), 1, a_File );
|
||||
fwrite( &m_TimeCooked, sizeof(float), 1, a_File );
|
||||
fwrite( &m_BurnTime, sizeof(float), 1, a_File );
|
||||
fwrite( &m_TimeBurned, sizeof(float), 1, a_File );
|
||||
}
|
||||
|
||||
bool cFurnaceEntity::LoadFromFile(FILE* a_File)
|
||||
{
|
||||
if( fread( &m_PosX, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &m_PosY, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &m_PosZ, sizeof(int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
|
||||
unsigned int NumSlots = 0;
|
||||
if( fread( &NumSlots, sizeof(unsigned int), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
m_Items = new cItem[ NumSlots ];
|
||||
for(unsigned int i = 0; i < NumSlots; i++)
|
||||
{
|
||||
cItem & Item = m_Items[ i ];
|
||||
if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File)!= 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
}
|
||||
cItem Item;
|
||||
if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File)!= 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( !Item.IsEmpty() ) m_CookingItem = new cItem( Item );
|
||||
|
||||
if( fread( &m_CookTime, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &m_TimeCooked, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &m_BurnTime, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
if( fread( &m_TimeBurned, sizeof(float), 1, a_File) != 1 ) { LOGERROR("ERROR READING FURNACE FROM FILE"); return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cFurnaceEntity::LoadFromJson( const Json::Value& a_Value )
|
||||
{
|
||||
m_PosX = a_Value.get("x", 0).asInt();
|
||||
m_PosY = a_Value.get("y", 0).asInt();
|
||||
m_PosZ = a_Value.get("z", 0).asInt();
|
||||
|
||||
Json::Value AllSlots = a_Value.get("Slots", 0);
|
||||
int SlotIdx = 0;
|
||||
for( Json::Value::iterator itr = AllSlots.begin(); itr != AllSlots.end(); ++itr )
|
||||
{
|
||||
Json::Value & Slot = *itr;
|
||||
cItem & Item = m_Items[ SlotIdx ];
|
||||
Item.m_ItemID = (ENUM_ITEM_ID)Slot.get("ID", -1 ).asInt();
|
||||
if( Item.m_ItemID > 0 )
|
||||
{
|
||||
Item.m_ItemCount = (char)Slot.get("Count", -1 ).asInt();
|
||||
Item.m_ItemHealth = (short)Slot.get("Health", -1 ).asInt();
|
||||
}
|
||||
SlotIdx++;
|
||||
}
|
||||
|
||||
// Get currently cooking item
|
||||
Json::Value JsonItem = a_Value.get("Cooking", Json::nullValue );
|
||||
if( !JsonItem.empty() )
|
||||
{
|
||||
cItem Item;
|
||||
Item.m_ItemID = (ENUM_ITEM_ID)JsonItem.get("ID", -1).asInt();
|
||||
if( Item.m_ItemID > 0 )
|
||||
{
|
||||
Item.m_ItemCount = (char)JsonItem.get("Count", -1).asInt();
|
||||
Item.m_ItemHealth = (short)JsonItem.get("Health", -1).asInt();
|
||||
}
|
||||
if( !Item.IsEmpty() )
|
||||
{
|
||||
m_CookingItem = new cItem( Item );
|
||||
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunkOfBlock( m_PosX, m_PosY, m_PosZ );
|
||||
Chunk->AddTickBlockEntity( this );
|
||||
}
|
||||
}
|
||||
|
||||
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_TimeBurned = (float)a_Value.get("TimeBurned", 0).asDouble();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void cFurnaceEntity::SaveToJson( Json::Value& a_Value )
|
||||
{
|
||||
a_Value["x"] = m_PosX;
|
||||
a_Value["y"] = m_PosY;
|
||||
a_Value["z"] = m_PosZ;
|
||||
|
||||
Json::Value AllSlots;
|
||||
for(unsigned int i = 0; i < 3; i++)
|
||||
{
|
||||
Json::Value Slot;
|
||||
cItem & Item = m_Items[ i ];
|
||||
Slot["ID"] = Item.m_ItemID;
|
||||
if( Item.m_ItemID > 0 )
|
||||
{
|
||||
Slot["Count"] = Item.m_ItemCount;
|
||||
Slot["Health"] = Item.m_ItemHealth;
|
||||
}
|
||||
AllSlots.append( Slot );
|
||||
}
|
||||
a_Value["Slots"] = AllSlots;
|
||||
|
||||
// Currently cooking item
|
||||
if( m_CookingItem )
|
||||
{
|
||||
Json::Value JsonItem;
|
||||
JsonItem["ID"] = m_CookingItem->m_ItemID;
|
||||
if( m_CookingItem->m_ItemID > 0 )
|
||||
{
|
||||
JsonItem["Count"] = m_CookingItem->m_ItemCount;
|
||||
JsonItem["Health"] = m_CookingItem->m_ItemHealth;
|
||||
}
|
||||
a_Value["Cooking"] = JsonItem;
|
||||
}
|
||||
|
||||
a_Value["CookTime"] = m_CookTime;
|
||||
a_Value["TimeCooked"] = m_TimeCooked;
|
||||
a_Value["BurnTime"] = m_BurnTime;
|
||||
a_Value["TimeBurned"] = m_TimeBurned;
|
||||
}
|
43
source/cFurnaceEntity.h
Normal file
43
source/cFurnaceEntity.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "cBlockEntity.h"
|
||||
#include "cWindowOwner.h"
|
||||
#include "FileDefine.h"
|
||||
|
||||
namespace Json
|
||||
{
|
||||
class Value;
|
||||
}
|
||||
|
||||
class cClientHandle;
|
||||
class cServer;
|
||||
class cItem;
|
||||
class cNBTData;
|
||||
class cFurnaceEntity : public cBlockEntity, public cWindowOwner
|
||||
{
|
||||
public:
|
||||
cFurnaceEntity(int a_X, int a_Y, int a_Z);
|
||||
virtual ~cFurnaceEntity();
|
||||
virtual void Destroy();
|
||||
|
||||
void WriteToFile(FILE* a_File);
|
||||
bool LoadFromFile(FILE* a_File);
|
||||
|
||||
bool LoadFromJson( const Json::Value& a_Value );
|
||||
void SaveToJson( Json::Value& a_Value );
|
||||
|
||||
bool Tick( float a_Dt );
|
||||
virtual void UsedBy( cPlayer & a_Player );
|
||||
|
||||
bool StartCooking();
|
||||
|
||||
void ResetCookTimer();
|
||||
private:
|
||||
cItem* m_Items;
|
||||
cItem* m_CookingItem;
|
||||
float m_CookTime;
|
||||
float m_TimeCooked;
|
||||
|
||||
float m_BurnTime;
|
||||
float m_TimeBurned;
|
||||
};
|
214
source/cFurnaceRecipe.cpp
Normal file
214
source/cFurnaceRecipe.cpp
Normal file
@ -0,0 +1,214 @@
|
||||
#include "cFurnaceRecipe.h"
|
||||
#include "cItem.h"
|
||||
#include "cMCLogger.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
typedef std::list< cFurnaceRecipe::Recipe > RecipeList;
|
||||
typedef std::list< cFurnaceRecipe::Fuel > FuelList;
|
||||
struct cFurnaceRecipe::sFurnaceRecipeState
|
||||
{
|
||||
RecipeList Recipes;
|
||||
FuelList Fuel;
|
||||
};
|
||||
|
||||
cFurnaceRecipe::cFurnaceRecipe()
|
||||
: m_pState( new sFurnaceRecipeState )
|
||||
{
|
||||
ReloadRecipes();
|
||||
}
|
||||
|
||||
cFurnaceRecipe::~cFurnaceRecipe()
|
||||
{
|
||||
ClearRecipes();
|
||||
delete m_pState;
|
||||
}
|
||||
|
||||
void cFurnaceRecipe::ReloadRecipes()
|
||||
{
|
||||
ClearRecipes();
|
||||
LOG("--Loading furnace recipes--");
|
||||
|
||||
std::ifstream f;
|
||||
char a_File[] = "furnace.txt";
|
||||
f.open(a_File, std::ios::in);
|
||||
std::string input;
|
||||
|
||||
if( !f.good() )
|
||||
{
|
||||
f.close();
|
||||
LOG("Could not open file for recipes: %s", a_File);
|
||||
return;
|
||||
}
|
||||
|
||||
bool bSyntaxError = false;
|
||||
while( f.good() )
|
||||
{
|
||||
char c;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// comments
|
||||
f >> c;
|
||||
f.unget();
|
||||
if( c == '#' )
|
||||
{
|
||||
while( f.good() && c != '\n' )
|
||||
{
|
||||
f.get( c );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Line breaks
|
||||
f.get( c );
|
||||
while( f.good() && ( c == '\n' || c == '\r' ) ) { f.get( c ); }
|
||||
if( f.eof() ) break;
|
||||
f.unget();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Check for fuel
|
||||
f >> c;
|
||||
if( c == '!' ) // It's fuel :)
|
||||
{
|
||||
// Read item
|
||||
int IItemID = 0, IItemCount = 0, IItemHealth = 0;
|
||||
f >> IItemID;
|
||||
f >> c; if( c != ':' ) { bSyntaxError = true; break; }
|
||||
f >> IItemCount;
|
||||
|
||||
// Optional health
|
||||
f >> c;
|
||||
if( c != ':' )
|
||||
f.unget();
|
||||
else
|
||||
{
|
||||
f >> IItemHealth;
|
||||
}
|
||||
|
||||
// Burn time
|
||||
float BurnTime;
|
||||
f >> c; if( c != '=' ) { bSyntaxError = true; break; }
|
||||
f >> BurnTime;
|
||||
|
||||
// Add to fuel list
|
||||
Fuel F;
|
||||
F.In = new cItem( (ENUM_ITEM_ID) IItemID, (char)IItemCount, (short)IItemHealth );
|
||||
F.BurnTime = BurnTime;
|
||||
m_pState->Fuel.push_back( F );
|
||||
continue;
|
||||
}
|
||||
f.unget();
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Read items
|
||||
int IItemID = 0, IItemCount = 0, IItemHealth = 0;
|
||||
f >> IItemID;
|
||||
f >> c; if( c != ':' ) { bSyntaxError = true; break; }
|
||||
f >> IItemCount;
|
||||
|
||||
// Optional health
|
||||
f >> c;
|
||||
if( c != ':' )
|
||||
f.unget();
|
||||
else
|
||||
{
|
||||
f >> IItemHealth;
|
||||
}
|
||||
|
||||
float CookTime;
|
||||
f >> c; if( c != '@' ) { bSyntaxError = true; break; }
|
||||
f >> CookTime;
|
||||
|
||||
int OItemID = 0, OItemCount = 0, OItemHealth = 0;
|
||||
f >> c; if( c != '=' ) { bSyntaxError = true; break; }
|
||||
f >> OItemID;
|
||||
f >> c; if( c != ':' ) { bSyntaxError = true; break; }
|
||||
f >> OItemCount;
|
||||
|
||||
// Optional health
|
||||
f >> c;
|
||||
if( c != ':' )
|
||||
f.unget();
|
||||
else
|
||||
{
|
||||
f >> OItemHealth;
|
||||
}
|
||||
|
||||
// Add to recipe list
|
||||
Recipe R;
|
||||
R.In = new cItem( (ENUM_ITEM_ID)IItemID, (char)IItemCount, (short)IItemHealth );
|
||||
R.Out = new cItem( (ENUM_ITEM_ID)OItemID, (char)OItemCount, (short)OItemHealth );
|
||||
R.CookTime = CookTime;
|
||||
m_pState->Recipes.push_back( R );
|
||||
}
|
||||
if( bSyntaxError )
|
||||
{
|
||||
LOGERROR("ERROR: FurnaceRecipe, syntax error" );
|
||||
}
|
||||
LOG("Got %i furnace recipes, and %i fuels.", m_pState->Recipes.size(), m_pState->Fuel.size() );
|
||||
|
||||
LOG("--Done loading furnace recipes--");
|
||||
}
|
||||
|
||||
void cFurnaceRecipe::ClearRecipes()
|
||||
{
|
||||
for( RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr )
|
||||
{
|
||||
Recipe R = *itr;
|
||||
delete R.In;
|
||||
delete R.Out;
|
||||
}
|
||||
m_pState->Recipes.clear();
|
||||
|
||||
for( FuelList::iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr )
|
||||
{
|
||||
Fuel F = *itr;
|
||||
delete F.In;
|
||||
}
|
||||
m_pState->Fuel.clear();
|
||||
}
|
||||
|
||||
const cFurnaceRecipe::Recipe* cFurnaceRecipe::GetRecipeFrom( const cItem & a_Ingredient ) const
|
||||
{
|
||||
const Recipe* BestRecipe = 0;
|
||||
for( RecipeList::const_iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr )
|
||||
{
|
||||
const Recipe & R = *itr;
|
||||
if( (R.In->m_ItemID == a_Ingredient.m_ItemID) && (R.In->m_ItemCount <= a_Ingredient.m_ItemCount ) )
|
||||
{
|
||||
if( BestRecipe && (BestRecipe->In->m_ItemCount > R.In->m_ItemCount) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
BestRecipe = &R;
|
||||
}
|
||||
}
|
||||
}
|
||||
return BestRecipe;
|
||||
}
|
||||
|
||||
float cFurnaceRecipe::GetBurnTime( const cItem & a_Fuel ) const
|
||||
{
|
||||
float BestFuel = 0.f;
|
||||
for( FuelList::const_iterator itr = m_pState->Fuel.begin(); itr != m_pState->Fuel.end(); ++itr )
|
||||
{
|
||||
const Fuel & F = *itr;
|
||||
if( (F.In->m_ItemID == a_Fuel.m_ItemID) && (F.In->m_ItemCount <= a_Fuel.m_ItemCount ) )
|
||||
{
|
||||
if( BestFuel > 0.f && (BestFuel > F.BurnTime ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
BestFuel = F.BurnTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
return BestFuel;
|
||||
}
|
34
source/cFurnaceRecipe.h
Normal file
34
source/cFurnaceRecipe.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
class cItem;
|
||||
class cFurnaceRecipe
|
||||
{
|
||||
public:
|
||||
cFurnaceRecipe();
|
||||
~cFurnaceRecipe();
|
||||
|
||||
void ReloadRecipes();
|
||||
|
||||
struct Fuel
|
||||
{
|
||||
cItem* In;
|
||||
float BurnTime;
|
||||
};
|
||||
|
||||
struct Recipe
|
||||
{
|
||||
cItem* In;
|
||||
cItem* Out;
|
||||
float CookTime;
|
||||
};
|
||||
const Recipe* GetRecipeFrom( const cItem & a_Ingredient ) const;
|
||||
float GetBurnTime( const cItem & a_Fuel ) const;
|
||||
|
||||
private:
|
||||
void ClearRecipes();
|
||||
|
||||
struct sFurnaceRecipeState;
|
||||
sFurnaceRecipeState* m_pState;
|
||||
};
|
42
source/cFurnaceWindow.cpp
Normal file
42
source/cFurnaceWindow.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "cFurnaceWindow.h"
|
||||
#include "cItem.h"
|
||||
#include "cFurnaceEntity.h"
|
||||
#include "cPlayer.h"
|
||||
|
||||
#include "packets/cPacket_WindowClick.h"
|
||||
|
||||
#include "cMCLogger.h"
|
||||
|
||||
cFurnaceWindow::cFurnaceWindow( cFurnaceEntity* a_Owner )
|
||||
: cWindow( a_Owner, true )
|
||||
, m_Furnace( a_Owner )
|
||||
{
|
||||
SetWindowID( 1 );
|
||||
SetWindowType( 2 ); // Furnace
|
||||
}
|
||||
|
||||
void cFurnaceWindow::Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player )
|
||||
{
|
||||
cItem Fuel = *GetSlot( 0 );
|
||||
|
||||
cWindow::Clicked( a_ClickPacket, a_Player );
|
||||
if( m_Furnace )
|
||||
{
|
||||
if( a_ClickPacket->m_SlotNum >= 0 && a_ClickPacket->m_SlotNum <= 2 ) // them important slots
|
||||
{
|
||||
if( Fuel.m_ItemID != GetSlot( 0 )->m_ItemID )
|
||||
m_Furnace->ResetCookTimer();
|
||||
|
||||
if( m_Furnace->StartCooking() )
|
||||
{
|
||||
SendWholeWindow( a_Player.GetClientHandle() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cFurnaceWindow::Close( cPlayer & a_Player )
|
||||
{
|
||||
m_Furnace = 0;
|
||||
cWindow::Close( a_Player );
|
||||
}
|
16
source/cFurnaceWindow.h
Normal file
16
source/cFurnaceWindow.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "cWindow.h"
|
||||
|
||||
class cFurnaceEntity;
|
||||
class cWindowOwner;
|
||||
class cFurnaceWindow : public cWindow
|
||||
{
|
||||
public:
|
||||
cFurnaceWindow( cFurnaceEntity* a_Owner );
|
||||
|
||||
virtual void Clicked( cPacket_WindowClick* a_ClickPacket, cPlayer & a_Player );
|
||||
virtual void Close( cPlayer & a_Player );
|
||||
private:
|
||||
cFurnaceEntity* m_Furnace;
|
||||
};
|
10
source/cGenSettings.cpp
Normal file
10
source/cGenSettings.cpp
Normal file
@ -0,0 +1,10 @@
|
||||
#include "cGenSettings.h"
|
||||
|
||||
|
||||
float cGenSettings::HeightFreq1 = 0.1f;
|
||||
float cGenSettings::HeightFreq2 = 1.f;
|
||||
float cGenSettings::HeightFreq3 = 2.f;
|
||||
|
||||
float cGenSettings::HeightAmp1 = 1.f;
|
||||
float cGenSettings::HeightAmp2 = 0.5f;
|
||||
float cGenSettings::HeightAmp3 = 0.5f;
|
9
source/cGenSettings.h
Normal file
9
source/cGenSettings.h
Normal file
@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
class cGenSettings
|
||||
{
|
||||
public:
|
||||
static float HeightFreq1, HeightAmp1;
|
||||
static float HeightFreq2, HeightAmp2;
|
||||
static float HeightFreq3, HeightAmp3;
|
||||
};
|
34
source/cGroup.cpp
Normal file
34
source/cGroup.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "cGroup.h"
|
||||
|
||||
void cGroup::AddCommand( std::string a_Command )
|
||||
{
|
||||
m_Commands[ a_Command ] = true;
|
||||
}
|
||||
|
||||
void cGroup::AddPermission( std::string a_Permission )
|
||||
{
|
||||
m_Permissions[ a_Permission ] = true;
|
||||
}
|
||||
|
||||
bool cGroup::HasCommand( std::string a_Command )
|
||||
{
|
||||
if( m_Commands.find("*") != m_Commands.end() ) return true;
|
||||
|
||||
CommandMap::iterator itr = m_Commands.find( a_Command );
|
||||
if( itr != m_Commands.end() )
|
||||
{
|
||||
if( itr->second ) return true;
|
||||
}
|
||||
|
||||
for( GroupList::iterator itr = m_Inherits.begin(); itr != m_Inherits.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->HasCommand( a_Command ) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cGroup::InheritFrom( cGroup* a_Group )
|
||||
{
|
||||
m_Inherits.remove( a_Group );
|
||||
m_Inherits.push_back( a_Group );
|
||||
}
|
39
source/cGroup.h
Normal file
39
source/cGroup.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <list>
|
||||
|
||||
class cGroup //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
cGroup() {}
|
||||
~cGroup() {}
|
||||
|
||||
void SetName( std::string a_Name ) { m_Name = a_Name; } //tolua_export
|
||||
const std::string & GetName() const { return m_Name; } //tolua_export
|
||||
void SetColor( std::string a_Color ) { m_Color = a_Color; } //tolua_export
|
||||
void AddCommand( std::string a_Command ); //tolua_export
|
||||
void AddPermission( std::string a_Permission ); //tolua_export
|
||||
void InheritFrom( cGroup* a_Group ); //tolua_export
|
||||
|
||||
bool HasCommand( std::string a_Command ); //tolua_export
|
||||
|
||||
typedef std::map< std::string, bool > PermissionMap;
|
||||
const PermissionMap & GetPermissions() const { return m_Permissions; }
|
||||
|
||||
typedef std::map< std::string, bool > CommandMap;
|
||||
const CommandMap & GetCommands() const { return m_Commands; }
|
||||
|
||||
std::string GetColor() const { return m_Color; } //tolua_export
|
||||
|
||||
typedef std::list< cGroup* > GroupList;
|
||||
const GroupList & GetInherits() const { return m_Inherits; }
|
||||
private:
|
||||
std::string m_Name;
|
||||
std::string m_Color;
|
||||
|
||||
PermissionMap m_Permissions;
|
||||
CommandMap m_Commands;
|
||||
GroupList m_Inherits;
|
||||
};//tolua_export
|
104
source/cGroupManager.cpp
Normal file
104
source/cGroupManager.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
#include "cGroupManager.h"
|
||||
#include "cGroup.h"
|
||||
#include "../iniFile/iniFile.h"
|
||||
#include "cChatColor.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cRoot.h"
|
||||
|
||||
extern std::vector< std::string > StringSplit( std::string str, std::string delim);
|
||||
|
||||
typedef std::map< std::string, cGroup* > GroupMap;
|
||||
struct cGroupManager::sGroupManagerState
|
||||
{
|
||||
GroupMap Groups;
|
||||
};
|
||||
|
||||
cGroupManager* cGroupManager::GetGroupManager()
|
||||
{
|
||||
LOGWARN("WARNING: Using deprecated function cGroupManager::GetGroupManager() use cRoot::Get()->GetGroupManager() instead!");
|
||||
return cRoot::Get()->GetGroupManager();
|
||||
}
|
||||
|
||||
cGroupManager::~cGroupManager()
|
||||
{
|
||||
for( GroupMap::iterator itr = m_pState->Groups.begin(); itr != m_pState->Groups.end(); ++itr )
|
||||
{
|
||||
delete itr->second;
|
||||
}
|
||||
m_pState->Groups.clear();
|
||||
|
||||
delete m_pState;
|
||||
}
|
||||
|
||||
cGroupManager::cGroupManager()
|
||||
: m_pState( new sGroupManagerState )
|
||||
{
|
||||
LOG("-- Loading Groups --");
|
||||
cIniFile IniFile("groups.ini");
|
||||
if( IniFile.ReadFile() )
|
||||
{
|
||||
unsigned int NumKeys = IniFile.GetNumKeys();
|
||||
for( unsigned int i = 0; i < NumKeys; i++ )
|
||||
{
|
||||
std::string KeyName = IniFile.GetKeyName( i );
|
||||
cGroup* Group = GetGroup( KeyName.c_str() );
|
||||
|
||||
LOG("Loading group: %s", KeyName.c_str() );
|
||||
|
||||
Group->SetName( KeyName );
|
||||
char Color = IniFile.GetValue( KeyName, "Color", "-" )[0];
|
||||
if( Color != '-' )
|
||||
Group->SetColor( cChatColor::MakeColor(Color) );
|
||||
else
|
||||
Group->SetColor( cChatColor::White );
|
||||
|
||||
std::string Commands = IniFile.GetValue( KeyName, "Commands", "" );
|
||||
if( Commands.size() > 0 )
|
||||
{
|
||||
std::vector< std::string > Split = StringSplit( Commands, "," );
|
||||
for( unsigned int i = 0; i < Split.size(); i++)
|
||||
{
|
||||
Group->AddCommand( Split[i] );
|
||||
//LOG("%s", Split[i].c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
std::string Permissions = IniFile.GetValue( KeyName, "Permissions", "" );
|
||||
if( Permissions.size() > 0 )
|
||||
{
|
||||
std::vector< std::string > Split = StringSplit( Permissions, "," );
|
||||
for( unsigned int i = 0; i < Split.size(); i++)
|
||||
{
|
||||
Group->AddPermission( Split[i] );
|
||||
LOGINFO("Permission: %s", Split[i].c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
std::string Groups = IniFile.GetValue( KeyName, "Inherits", "" );
|
||||
if( Groups.size() > 0 )
|
||||
{
|
||||
std::vector< std::string > Split = StringSplit( Groups, "," );
|
||||
for( unsigned int i = 0; i < Split.size(); i++)
|
||||
{
|
||||
Group->InheritFrom( GetGroup( Split[i].c_str() ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG("-- Done Loading Groups --");
|
||||
}
|
||||
|
||||
cGroup* cGroupManager::GetGroup( const char* a_Name )
|
||||
{
|
||||
GroupMap::iterator itr = m_pState->Groups.find( a_Name );
|
||||
if( itr != m_pState->Groups.end() )
|
||||
{
|
||||
return itr->second;
|
||||
}
|
||||
|
||||
cGroup* Group = new cGroup();
|
||||
m_pState->Groups[a_Name] = Group;
|
||||
|
||||
return Group;
|
||||
|
||||
}
|
17
source/cGroupManager.h
Normal file
17
source/cGroupManager.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
class cGroup;
|
||||
class cGroupManager
|
||||
{
|
||||
public:
|
||||
static cGroupManager * GetGroupManager(); //tolua_export
|
||||
|
||||
cGroup* GetGroup( const char* a_Name );
|
||||
private:
|
||||
friend class cRoot;
|
||||
cGroupManager();
|
||||
~cGroupManager();
|
||||
|
||||
struct sGroupManagerState;
|
||||
sGroupManagerState* m_pState;
|
||||
};
|
119
source/cHeartBeat.cpp
Normal file
119
source/cHeartBeat.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include "cHeartBeat.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "md5/md5.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cRoot.h"
|
||||
#include "cServer.h"
|
||||
#include "cSleep.h"
|
||||
|
||||
cHeartBeat::cHeartBeat()
|
||||
{
|
||||
m_State = 0;
|
||||
Authenticate();
|
||||
}
|
||||
|
||||
cHeartBeat::~cHeartBeat()
|
||||
{
|
||||
}
|
||||
|
||||
void cHeartBeat::ReceivedData( char a_Data[256], int a_Size )
|
||||
{
|
||||
if( a_Size < 0 ) // Disconnected
|
||||
return;
|
||||
|
||||
char MySalt[] = "1234567890";
|
||||
|
||||
if( a_Size == 0 )
|
||||
{
|
||||
Authenticate();
|
||||
return;
|
||||
}
|
||||
|
||||
bool bLoop = false;
|
||||
do
|
||||
{
|
||||
switch (m_State)
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
m_ServerID = std::string( a_Data, a_Size );
|
||||
LOGINFO("Got server ID %s", m_ServerID.c_str() );
|
||||
std::string Hash = md5( m_ServerID + std::string( MySalt ) );
|
||||
CloseSocket();
|
||||
if( Connect( "mc-server.org", 80 ) )
|
||||
{
|
||||
SendMessage( (std::string("GET http://master.mc-server.org/?hash=") + Hash + std::string("&server=") + m_ServerID + "\n").c_str() );
|
||||
m_State = 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
std::string ReturnedString = std::string( a_Data, a_Size );
|
||||
if( ReturnedString.compare("VALIDATED") == 0 )
|
||||
{
|
||||
LOGINFO("Successfully validated server on master server list");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGINFO("Could not validate server! Will try again later.");
|
||||
cSleep::MilliSleep( 10*1000 );
|
||||
Authenticate();
|
||||
return;
|
||||
}
|
||||
m_State = 3;
|
||||
} // Don't break, but fall through and update server info
|
||||
case 3:
|
||||
{
|
||||
cSleep::MilliSleep( 10*1000 );
|
||||
SendUpdate();
|
||||
m_State = 4;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
if( a_Data[0] == '0' )
|
||||
{
|
||||
LOGINFO("Successfully updated server info!");
|
||||
cSleep::MilliSleep( 10*1000 );
|
||||
SendUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGINFO("Failed to update server info, reauthenticating");
|
||||
Authenticate();
|
||||
}
|
||||
}
|
||||
default:
|
||||
break;
|
||||
};
|
||||
} while( bLoop );
|
||||
}
|
||||
|
||||
void cHeartBeat::SendUpdate()
|
||||
{
|
||||
CloseSocket();
|
||||
if( Connect( "mc-server.org", 80 ) )
|
||||
{
|
||||
int Port = cRoot::Get()->GetServer()->GetPort();
|
||||
char c_Port[16];
|
||||
sprintf_s( c_Port, 16, "%i", Port );
|
||||
|
||||
std::string sPort = std::string( c_Port );
|
||||
std::string sChecksum = md5( m_ServerID + sPort );
|
||||
SendMessage( (std::string("GET http://master.mc-server.org/?update=") + m_ServerID + std::string("&checksum=") + sChecksum + std::string("&port=") + sPort + "\n").c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
void cHeartBeat::Authenticate()
|
||||
{
|
||||
CloseSocket();
|
||||
if( Connect( "mc-server.org", 80 ) )
|
||||
{
|
||||
m_State = 1;
|
||||
int RetVal = SendMessage( "GET http://master.mc-server.org/\r\n\r\n");
|
||||
LOGINFO("Returned %i", RetVal );
|
||||
}
|
||||
}
|
21
source/cHeartBeat.h
Normal file
21
source/cHeartBeat.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "cTCPLink.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class cHeartBeat : public cTCPLink
|
||||
{
|
||||
public:
|
||||
cHeartBeat();
|
||||
~cHeartBeat();
|
||||
private:
|
||||
virtual void ReceivedData( char a_Data[256], int a_Size );
|
||||
|
||||
void Authenticate();
|
||||
int m_State;
|
||||
|
||||
void SendUpdate();
|
||||
|
||||
std::string m_ServerID;
|
||||
};
|
364
source/cInventory.cpp
Normal file
364
source/cInventory.cpp
Normal file
@ -0,0 +1,364 @@
|
||||
#include "cInventory.h"
|
||||
#include <string> //memset
|
||||
#include "cPlayer.h"
|
||||
#include "cClientHandle.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cWindow.h"
|
||||
#include "cItem.h"
|
||||
#include "cRecipeChecker.h"
|
||||
#include "cRoot.h"
|
||||
|
||||
#include "packets/cPacket_WindowClick.h"
|
||||
#include "packets/cPacket_WholeInventory.h"
|
||||
#include "packets/cPacket_InventorySlot.h"
|
||||
|
||||
cInventory::~cInventory()
|
||||
{
|
||||
delete [] m_Slots;
|
||||
delete m_EquippedItem;
|
||||
if( GetWindow() ) GetWindow()->Close( *m_Owner );
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
cInventory::cInventory(cPlayer* a_Owner)
|
||||
{
|
||||
m_Owner = a_Owner;
|
||||
|
||||
m_Slots = new cItem[c_NumSlots];
|
||||
for(unsigned int i = 0; i < c_NumSlots; i++)
|
||||
m_Slots[i].Empty();
|
||||
|
||||
m_CraftSlots = m_Slots + c_CraftOffset;
|
||||
m_ArmorSlots = m_Slots + c_ArmorOffset;
|
||||
m_MainSlots = m_Slots + c_MainOffset;
|
||||
m_HotSlots = m_Slots + c_HotOffset;
|
||||
|
||||
m_EquippedItem = new cItem();
|
||||
m_EquippedSlot = 0;
|
||||
|
||||
if( !GetWindow() )
|
||||
{
|
||||
cWindow* Window = new cWindow( this, false );
|
||||
Window->SetSlots( m_Slots, c_NumSlots );
|
||||
Window->SetWindowID( 0 );
|
||||
OpenWindow( Window );
|
||||
}
|
||||
}
|
||||
|
||||
void cInventory::Clear()
|
||||
{
|
||||
for(unsigned int i = 0; i < c_NumSlots; i++)
|
||||
m_Slots[i].Empty();
|
||||
}
|
||||
|
||||
cItem* cInventory::GetSlotsForType( int a_Type )
|
||||
{
|
||||
switch( a_Type )
|
||||
{
|
||||
case -1:
|
||||
return m_MainSlots;
|
||||
case -2:
|
||||
return m_CraftSlots;
|
||||
case -3:
|
||||
return m_ArmorSlots;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cInventory::GetSlotCountForType( int a_Type )
|
||||
{
|
||||
switch( a_Type )
|
||||
{
|
||||
case -1:
|
||||
return 36;
|
||||
case -2:
|
||||
case -3:
|
||||
return 4;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cInventory::Clicked( cPacket_WindowClick* a_ClickPacket )
|
||||
{
|
||||
bool bDontCook = false;
|
||||
if( GetWindow() )
|
||||
{
|
||||
// Override for craft result slot
|
||||
if( a_ClickPacket->m_SlotNum == (short)c_CraftOffset )
|
||||
{
|
||||
LOG("In craft slot: %i x %i !!", m_Slots[c_CraftOffset].m_ItemID, m_Slots[c_CraftOffset].m_ItemCount );
|
||||
cItem* DraggingItem = GetWindow()->GetDraggingItem();
|
||||
if( DraggingItem->IsEmpty() )
|
||||
{
|
||||
*DraggingItem = m_Slots[c_CraftOffset];
|
||||
m_Slots[c_CraftOffset].Empty();
|
||||
}
|
||||
else if( DraggingItem->Equals( m_Slots[c_CraftOffset] ) )
|
||||
{
|
||||
if( DraggingItem->m_ItemCount + m_Slots[c_CraftOffset].m_ItemCount <= 64 )
|
||||
{
|
||||
DraggingItem->m_ItemCount += m_Slots[c_CraftOffset].m_ItemCount;
|
||||
m_Slots[0].Empty();
|
||||
}
|
||||
else
|
||||
{
|
||||
bDontCook = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bDontCook = true;
|
||||
}
|
||||
LOG("Dragging Dish %i", DraggingItem->m_ItemCount );
|
||||
}
|
||||
else
|
||||
{
|
||||
GetWindow()->Clicked( a_ClickPacket, *m_Owner );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("No Inventory window! WTF");
|
||||
}
|
||||
|
||||
if( a_ClickPacket->m_SlotNum >= (short)c_CraftOffset && a_ClickPacket->m_SlotNum < (short)(c_CraftOffset+c_CraftSlots+1) )
|
||||
{
|
||||
cItem CookedItem;
|
||||
if( a_ClickPacket->m_SlotNum == 0 && !bDontCook )
|
||||
{
|
||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( m_Slots+c_CraftOffset+1, 2, 2, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
CookedItem = cRoot::Get()->GetRecipeChecker()->CookIngredients( m_Slots+c_CraftOffset+1, 2, 2 );
|
||||
}
|
||||
m_Slots[c_CraftOffset] = CookedItem;
|
||||
LOG("You cooked: %i x %i !!", m_Slots[c_CraftOffset].m_ItemID, m_Slots[c_CraftOffset].m_ItemCount );
|
||||
SendWholeInventory( m_Owner->GetClientHandle() );
|
||||
}
|
||||
SendSlot( 0 );
|
||||
}
|
||||
|
||||
bool cInventory::AddToBar( cItem & a_Item, const int a_Offset, const int a_Size, bool* a_bChangedSlots, int a_Mode /* = 0 */ )
|
||||
{
|
||||
// Fill already present stacks
|
||||
if( a_Mode < 2 )
|
||||
{
|
||||
for(int i = 0; i < a_Size; i++)
|
||||
{
|
||||
if( m_Slots[i + a_Offset].m_ItemID == a_Item.m_ItemID && m_Slots[i + a_Offset].m_ItemCount < 64 )
|
||||
{
|
||||
int NumFree = 64 - m_Slots[i + a_Offset].m_ItemCount;
|
||||
if( NumFree >= a_Item.m_ItemCount )
|
||||
{
|
||||
|
||||
//printf("1. Adding %i items ( free: %i )\n", a_Item.m_ItemCount, NumFree );
|
||||
m_Slots[i + a_Offset].m_ItemCount += a_Item.m_ItemCount;
|
||||
a_Item.m_ItemCount = 0;
|
||||
a_bChangedSlots[i + a_Offset] = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("2. Adding %i items\n", NumFree );
|
||||
m_Slots[i + a_Offset].m_ItemCount += (char)NumFree;
|
||||
a_Item.m_ItemCount -= (char)NumFree;
|
||||
a_bChangedSlots[i + a_Offset] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( a_Mode > 0 )
|
||||
{
|
||||
// If we got more left, find first empty slot
|
||||
for(int i = 0; i < a_Size && a_Item.m_ItemCount > 0; i++)
|
||||
{
|
||||
if( m_Slots[i + a_Offset].m_ItemID == -1 )
|
||||
{
|
||||
m_Slots[i + a_Offset] = a_Item;
|
||||
a_Item.m_ItemCount = 0;
|
||||
a_bChangedSlots[i + a_Offset] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cInventory::AddItem( cItem & a_Item )
|
||||
{
|
||||
cItem BackupSlots[c_NumSlots];
|
||||
memcpy( BackupSlots, m_Slots, c_NumSlots * sizeof( cItem ) );
|
||||
|
||||
bool ChangedSlots[c_NumSlots];
|
||||
memset( ChangedSlots, false, c_NumSlots * sizeof( bool ) );
|
||||
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_HotOffset, c_HotSlots, ChangedSlots, 0 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_MainOffset, c_MainSlots, ChangedSlots, 0 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_HotOffset, c_HotSlots, ChangedSlots, 2 );
|
||||
if( a_Item.m_ItemCount > 0 ) AddToBar( a_Item, c_MainOffset, c_MainSlots, ChangedSlots, 2 );
|
||||
|
||||
if( a_Item.m_ItemCount > 0 ) // Could not add all items
|
||||
{
|
||||
// retore backup
|
||||
memcpy( m_Slots, BackupSlots, c_NumSlots * sizeof( cItem ) );
|
||||
return false;
|
||||
}
|
||||
|
||||
for(unsigned int i = 0; i < c_NumSlots; i++)
|
||||
{
|
||||
if( ChangedSlots[i] )
|
||||
{
|
||||
LOG("Item was added to %i ID:%i Count:%i", i, m_Slots[i].m_ItemID, m_Slots[i].m_ItemCount );
|
||||
SendSlot(i);
|
||||
}
|
||||
}
|
||||
|
||||
return (a_Item.m_ItemCount == 0);
|
||||
}
|
||||
|
||||
// TODO: Right now if you dont have enough items, the items you did have are removed, and the function returns false anyway
|
||||
bool cInventory::RemoveItem( cItem & a_Item )
|
||||
{
|
||||
// First check equipped slot
|
||||
if( m_EquippedSlot >= 0 && m_EquippedSlot < 9 )
|
||||
{
|
||||
if( m_HotSlots[m_EquippedSlot].m_ItemID == a_Item.m_ItemID )
|
||||
{
|
||||
cItem & Item = m_HotSlots[m_EquippedSlot];
|
||||
if(Item.m_ItemCount > a_Item.m_ItemCount)
|
||||
{
|
||||
Item.m_ItemCount -= a_Item.m_ItemCount;
|
||||
SendSlot( m_EquippedSlot + c_HotOffset );
|
||||
return true;
|
||||
}
|
||||
else if(Item.m_ItemCount > 0 )
|
||||
{
|
||||
a_Item.m_ItemCount -= Item.m_ItemCount;
|
||||
Item.Empty();
|
||||
SendSlot( m_EquippedSlot + c_HotOffset );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then check other slotz
|
||||
if( a_Item.m_ItemCount > 0 )
|
||||
{
|
||||
for(int i = 0; i < 36; i++)
|
||||
{
|
||||
cItem & Item = m_MainSlots[i];
|
||||
if( Item.m_ItemID == a_Item.m_ItemID )
|
||||
{
|
||||
if(Item.m_ItemCount > a_Item.m_ItemCount)
|
||||
{
|
||||
Item.m_ItemCount -= a_Item.m_ItemCount;
|
||||
SendSlot( i + c_MainOffset );
|
||||
return true;
|
||||
}
|
||||
else if(Item.m_ItemCount > 0 )
|
||||
{
|
||||
a_Item.m_ItemCount -= Item.m_ItemCount;
|
||||
Item.Empty();
|
||||
SendSlot( i + c_MainOffset );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( a_Item.m_ItemCount == 0 )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
cItem* cInventory::GetSlot( int a_SlotNum )
|
||||
{
|
||||
if( a_SlotNum < 0 || a_SlotNum >= (short)c_NumSlots ) return 0;
|
||||
return &m_Slots[a_SlotNum];
|
||||
}
|
||||
|
||||
cItem* cInventory::GetFromHotBar( int a_SlotNum )
|
||||
{
|
||||
if( a_SlotNum < 0 || a_SlotNum >= 9 ) return 0;
|
||||
return &m_HotSlots[a_SlotNum];
|
||||
}
|
||||
|
||||
void cInventory::SetEquippedSlot( int a_SlotNum )
|
||||
{
|
||||
if( a_SlotNum < 0 || a_SlotNum >= 9 ) m_EquippedSlot = 0;
|
||||
else m_EquippedSlot = (short)a_SlotNum;
|
||||
}
|
||||
|
||||
cItem & cInventory::GetEquippedItem()
|
||||
{
|
||||
cItem* Item = GetFromHotBar( m_EquippedSlot );
|
||||
if( Item )
|
||||
{
|
||||
*m_EquippedItem = *Item;
|
||||
return *Item;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_EquippedItem->Empty();
|
||||
}
|
||||
return *m_EquippedItem;
|
||||
}
|
||||
|
||||
void cInventory::SendWholeInventory( cClientHandle* a_Client )
|
||||
{
|
||||
cPacket_WholeInventory Inventory( this );
|
||||
a_Client->Send( Inventory );
|
||||
}
|
||||
|
||||
void cInventory::SendSlot( int a_SlotNum )
|
||||
{
|
||||
cItem* Item = GetSlot( a_SlotNum );
|
||||
if( Item )
|
||||
{
|
||||
cPacket_InventorySlot InventorySlot;
|
||||
InventorySlot.m_ItemCount = Item->m_ItemCount;
|
||||
InventorySlot.m_ItemID = (short)Item->m_ItemID;
|
||||
InventorySlot.m_ItemUses = (char)Item->m_ItemHealth;
|
||||
InventorySlot.m_SlotNum = (short)a_SlotNum;
|
||||
InventorySlot.m_WindowID = 0; // Inventory window ID
|
||||
m_Owner->GetClientHandle()->Send( InventorySlot );
|
||||
}
|
||||
}
|
||||
|
||||
void cInventory::DrawInventory()
|
||||
{
|
||||
printf("%i %i %i %i\n", m_ArmorSlots[0].m_ItemCount, m_ArmorSlots[1].m_ItemCount, m_CraftSlots[0].m_ItemCount, m_CraftSlots[1].m_ItemCount );
|
||||
printf("%i %i %i %i\n", m_ArmorSlots[2].m_ItemCount, m_ArmorSlots[3].m_ItemCount, m_CraftSlots[2].m_ItemCount, m_CraftSlots[3].m_ItemCount );
|
||||
for(int y = 0; y < 4; y++)
|
||||
{
|
||||
for(int x = 0; x < 9; x++)
|
||||
{
|
||||
printf("%i ", m_MainSlots[x + y*9].m_ItemCount );
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
void cInventory::WriteToFile(FILE* a_File)
|
||||
{
|
||||
for(unsigned int i = 0; i < c_NumSlots; i++)
|
||||
{
|
||||
cItem & Item = m_Slots[i];
|
||||
fwrite( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File );
|
||||
fwrite( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File );
|
||||
fwrite( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File );
|
||||
}
|
||||
}
|
||||
|
||||
bool cInventory::LoadFromFile(FILE* a_File)
|
||||
{
|
||||
for(unsigned int i = 0; i < c_NumSlots; i++)
|
||||
{
|
||||
cItem & Item = m_Slots[i];
|
||||
if( fread( &Item.m_ItemID, sizeof(Item.m_ItemID), 1, a_File) != 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemCount, sizeof(Item.m_ItemCount), 1, a_File) != 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return false; }
|
||||
if( fread( &Item.m_ItemHealth, sizeof(Item.m_ItemHealth), 1, a_File)!= 1 ) { LOGERROR("ERROR READING INVENTORY FROM FILE"); return false; }
|
||||
}
|
||||
return true;
|
||||
}
|
67
source/cInventory.h
Normal file
67
source/cInventory.h
Normal file
@ -0,0 +1,67 @@
|
||||
#pragma once
|
||||
|
||||
#include "MemoryLeak.h"
|
||||
#include "cWindowOwner.h"
|
||||
#include "FileDefine.h"
|
||||
|
||||
class cItem;
|
||||
class cClientHandle;
|
||||
class cPlayer;
|
||||
class cPacket_WindowClick;
|
||||
class cPacket_EntityEquipment;
|
||||
class cInventory //tolua_export
|
||||
: public cWindowOwner
|
||||
{ //tolua_export
|
||||
public:
|
||||
cInventory(cPlayer* a_Owner);
|
||||
~cInventory();
|
||||
|
||||
void Clear(); //tolua_export
|
||||
|
||||
cItem* GetSlotsForType( int a_Type );
|
||||
int GetSlotCountForType( int a_Type );
|
||||
|
||||
bool AddItem( cItem & a_Item ); //tolua_export
|
||||
bool RemoveItem( cItem & a_Item ); //tolua_export
|
||||
void DrawInventory();
|
||||
|
||||
void WriteToFile(FILE* a_File);
|
||||
bool LoadFromFile(FILE* a_File);
|
||||
|
||||
void SendWholeInventory( cClientHandle* a_Client );
|
||||
|
||||
cItem* GetSlot( int a_SlotNum ); //tolua_export
|
||||
cItem* GetSlots() { return m_Slots; }
|
||||
cItem* GetFromHotBar( int a_SlotNum ); //tolua_export
|
||||
|
||||
cItem & GetEquippedItem(); //tolua_export
|
||||
void SetEquippedSlot( int a_SlotNum ); //tolua_export
|
||||
|
||||
void Clicked( cPacket_WindowClick* a_ClickPacket );
|
||||
|
||||
void SendSlot( int a_SlotNum ); //tolua_export
|
||||
|
||||
static const unsigned int c_NumSlots = 45;
|
||||
static const unsigned int c_MainSlots = 27;
|
||||
static const unsigned int c_HotSlots = 9;
|
||||
static const unsigned int c_CraftSlots = 4;
|
||||
static const unsigned int c_ArmorSlots = 4;
|
||||
|
||||
static const unsigned int c_CraftOffset = 0;
|
||||
static const unsigned int c_ArmorOffset = 5;
|
||||
static const unsigned int c_MainOffset = 9;
|
||||
static const unsigned int c_HotOffset = 36;
|
||||
private:
|
||||
bool AddToBar( cItem & a_Item, const int a_Offset, const int a_Size, bool* a_bChangedSlots, int a_Mode = 0 );
|
||||
|
||||
cItem* m_Slots;
|
||||
cItem* m_MainSlots;
|
||||
cItem* m_CraftSlots;
|
||||
cItem* m_ArmorSlots;
|
||||
cItem* m_HotSlots;
|
||||
|
||||
cItem* m_EquippedItem;
|
||||
short m_EquippedSlot;
|
||||
|
||||
cPlayer* m_Owner;
|
||||
}; //tolua_export
|
33
source/cItem.h
Normal file
33
source/cItem.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include "Defines.h"
|
||||
#include "BlockID.h"
|
||||
|
||||
class cItem //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
cItem( ENUM_ITEM_ID a_ItemID = E_ITEM_EMPTY, char a_ItemCount = 0, short a_ItemHealth = 0 ) //tolua_export
|
||||
: m_ItemID ( a_ItemID )
|
||||
, m_ItemCount ( a_ItemCount )
|
||||
, m_ItemHealth ( a_ItemHealth )
|
||||
{ //tolua_export
|
||||
if(!isValidItem( m_ItemID ) ) m_ItemID = E_ITEM_EMPTY;
|
||||
} //tolua_export
|
||||
void Empty() //tolua_export
|
||||
{ //tolua_export
|
||||
m_ItemID = E_ITEM_EMPTY;
|
||||
m_ItemCount = 0;
|
||||
m_ItemHealth = 0;
|
||||
} //tolua_export
|
||||
bool IsEmpty() //tolua_export
|
||||
{ //tolua_export
|
||||
return (m_ItemID <= 0 || m_ItemCount <= 0);
|
||||
} //tolua_export
|
||||
bool Equals( cItem & a_Item ) //tolua_export
|
||||
{ //tolua_export
|
||||
return ( (m_ItemID == a_Item.m_ItemID) && (m_ItemHealth == a_Item.m_ItemHealth) );
|
||||
} //tolua_export
|
||||
ENUM_ITEM_ID m_ItemID; //tolua_export
|
||||
char m_ItemCount; //tolua_export
|
||||
short m_ItemHealth; //tolua_export
|
||||
}; //tolua_export
|
43
source/cLadder.h
Normal file
43
source/cLadder.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
class cLadder //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
|
||||
static char DirectionToMetaData( char a_Direction ) //tolua_export
|
||||
{ //tolua_export
|
||||
switch( a_Direction )
|
||||
{
|
||||
case 0x2:
|
||||
return 0x2;
|
||||
case 0x3:
|
||||
return 0x3;
|
||||
case 0x4:
|
||||
return 0x4;
|
||||
case 0x5:
|
||||
return 0x5;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return 0x2;
|
||||
} //tolua_export
|
||||
|
||||
static char MetaDataToDirection( char a_MetaData ) //tolua_export
|
||||
{ //tolua_export
|
||||
switch( a_MetaData )
|
||||
{
|
||||
case 0x2:
|
||||
return 0x2;
|
||||
case 0x3:
|
||||
return 0x3;
|
||||
case 0x4:
|
||||
return 0x4;
|
||||
case 0x5:
|
||||
return 0x5;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
return 0x2;
|
||||
} //tolua_export
|
||||
|
||||
}; //tolua_export
|
136
source/cLog.cpp
Normal file
136
source/cLog.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
#include "cLog.h"
|
||||
#include <fstream>
|
||||
#include <ctime>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <sys/stat.h> // for mkdir
|
||||
#include <sys/types.h>
|
||||
|
||||
#define sprintf_s(buffer, buffer_size, stringbuffer, ...) (sprintf(buffer, stringbuffer, __VA_ARGS__))
|
||||
#define vsnprintf_s(buffer, buffer_size, maxcount, stringbuffer, ...) (vsnprintf(buffer, maxcount, stringbuffer, __VA_ARGS__))
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
cLog* cLog::s_Log = NULL;
|
||||
|
||||
cLog::cLog( const char* a_FileName )
|
||||
: m_File(NULL)
|
||||
{
|
||||
s_Log = this;
|
||||
|
||||
// create logs directory
|
||||
#ifdef _WIN32
|
||||
{
|
||||
SECURITY_ATTRIBUTES Attrib;
|
||||
Attrib.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
Attrib.lpSecurityDescriptor = NULL;
|
||||
Attrib.bInheritHandle = false;
|
||||
::CreateDirectory("logs", &Attrib);
|
||||
}
|
||||
#else
|
||||
{
|
||||
mkdir("logs", S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
}
|
||||
#endif
|
||||
|
||||
OpenLog( (std::string("logs/") + std::string(a_FileName)).c_str() );
|
||||
}
|
||||
|
||||
cLog::~cLog()
|
||||
{
|
||||
CloseLog();
|
||||
s_Log = NULL;
|
||||
}
|
||||
|
||||
cLog* cLog::GetInstance()
|
||||
{
|
||||
if(s_Log)
|
||||
return s_Log;
|
||||
|
||||
new cLog("log.txt");
|
||||
return s_Log;
|
||||
}
|
||||
|
||||
void cLog::CloseLog()
|
||||
{
|
||||
if( m_File )
|
||||
fclose (m_File);
|
||||
m_File = 0;
|
||||
}
|
||||
|
||||
void cLog::OpenLog( const char* a_FileName )
|
||||
{
|
||||
if(m_File) fclose (m_File);
|
||||
#ifdef _WIN32
|
||||
fopen_s( &m_File, a_FileName, "a+" );
|
||||
#else
|
||||
m_File = fopen(a_FileName, "a+" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void cLog::ClearLog()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if( fopen_s( &m_File, "log.txt", "w" ) == 0)
|
||||
fclose (m_File);
|
||||
#else
|
||||
m_File = fopen("log.txt", "w" );
|
||||
if( m_File )
|
||||
fclose (m_File);
|
||||
#endif
|
||||
m_File = 0;
|
||||
}
|
||||
|
||||
void cLog::Log(const char* a_Format, va_list argList )
|
||||
{
|
||||
char c_Buffer[1024];
|
||||
|
||||
if( argList != 0 )
|
||||
{
|
||||
vsnprintf_s(c_Buffer, 1024, 1024, a_Format, argList );
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf_s( c_Buffer, 1024, "%s", a_Format );
|
||||
}
|
||||
|
||||
time_t rawtime;
|
||||
time ( &rawtime );
|
||||
#ifdef _WIN32
|
||||
struct tm timeinfo;
|
||||
localtime_s( &timeinfo, &rawtime );
|
||||
#else
|
||||
struct tm* timeinfo;
|
||||
timeinfo = localtime( &rawtime );
|
||||
#endif
|
||||
char c_Buffer2[1024];
|
||||
#ifdef _WIN32
|
||||
sprintf_s(c_Buffer2, 1024, "[%02d:%02d:%02d] %s\n", timeinfo.tm_hour, timeinfo.tm_min, timeinfo.tm_sec, c_Buffer);
|
||||
#else
|
||||
sprintf(c_Buffer2, "[%02d:%02d:%02d] %s\n", timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec, c_Buffer);
|
||||
#endif
|
||||
if(m_File){
|
||||
fputs(c_Buffer2, m_File);
|
||||
fflush(m_File);
|
||||
}
|
||||
|
||||
|
||||
printf("%s", c_Buffer2 );
|
||||
}
|
||||
|
||||
void cLog::Log(const char* a_Format, ...)
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, a_Format);
|
||||
Log( a_Format, argList );
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
void cLog::SimpleLog(const char* a_String)
|
||||
{
|
||||
Log("%s", a_String );
|
||||
}
|
30
source/cLog.h
Normal file
30
source/cLog.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include "MemoryLeak.h"
|
||||
#include "FileDefine.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
class cLog { // tolua_export
|
||||
private:
|
||||
FILE* m_File;
|
||||
static cLog* s_Log;
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef char* va_list;
|
||||
#endif
|
||||
public:
|
||||
cLog( const char* a_FileName );
|
||||
~cLog();
|
||||
void Log(const char* a_Format, va_list argList );
|
||||
void Log(const char* a_Format, ...);
|
||||
//tolua_begin
|
||||
void SimpleLog(const char* a_String);
|
||||
void OpenLog( const char* a_FileName );
|
||||
void CloseLog();
|
||||
void ClearLog();
|
||||
static cLog* GetInstance();
|
||||
};
|
||||
//tolua_end
|
106
source/cLuaCommandBinder.cpp
Normal file
106
source/cLuaCommandBinder.cpp
Normal file
@ -0,0 +1,106 @@
|
||||
#include "cLuaCommandBinder.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cPlayer.h"
|
||||
#include "cPlugin_Lua.h"
|
||||
|
||||
#include "tolua++.h"
|
||||
|
||||
extern std::vector<std::string> StringSplit(std::string str, std::string delim);
|
||||
extern bool report_errors(lua_State* lua, int status);
|
||||
|
||||
cLuaCommandBinder::cLuaCommandBinder()
|
||||
{
|
||||
}
|
||||
|
||||
cLuaCommandBinder::~cLuaCommandBinder()
|
||||
{
|
||||
}
|
||||
|
||||
void cLuaCommandBinder::ClearBindings()
|
||||
{
|
||||
m_BoundCommands.clear();
|
||||
}
|
||||
|
||||
void cLuaCommandBinder::RemoveBindingsForPlugin( cPlugin* a_Plugin )
|
||||
{
|
||||
for( CommandMap::iterator itr = m_BoundCommands.begin(); itr != m_BoundCommands.end(); )
|
||||
{
|
||||
if( itr->second.Plugin == a_Plugin )
|
||||
{
|
||||
LOGINFO("Unbinding %s ", itr->first.c_str( ) );
|
||||
luaL_unref( itr->second.LuaState, LUA_REGISTRYINDEX, itr->second.Reference ); // unreference
|
||||
CommandMap::iterator eraseme = itr;
|
||||
++itr;
|
||||
m_BoundCommands.erase( eraseme );
|
||||
continue;
|
||||
}
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
bool cLuaCommandBinder::BindCommand( const std::string & a_Command, const std::string & a_Permission, cPlugin* a_Plugin, lua_State * a_LuaState, int a_FunctionReference )
|
||||
{
|
||||
if( m_BoundCommands.find( a_Command ) != m_BoundCommands.end() )
|
||||
{
|
||||
LOGERROR("ERROR: Trying to bind command \"%s\" that has already been bound.", a_Command.c_str() );
|
||||
return false;
|
||||
}
|
||||
LOGINFO("Binding %s (%s)", a_Command.c_str(), a_Permission.c_str() );
|
||||
m_BoundCommands[ a_Command ] = BoundFunction( a_Plugin, a_LuaState, a_FunctionReference, a_Permission );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cLuaCommandBinder::HandleCommand( const std::string & a_Command, cPlayer* a_Player )
|
||||
{
|
||||
std::vector<std::string> Split = StringSplit( a_Command, " ");
|
||||
CommandMap::iterator FoundCommand = m_BoundCommands.find( Split[0] );
|
||||
if( FoundCommand != m_BoundCommands.end() )
|
||||
{
|
||||
const BoundFunction & func = FoundCommand->second;
|
||||
if( func.Permission.size() > 0 )
|
||||
{
|
||||
if( !a_Player->HasPermission( func.Permission.c_str() ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// For enabling 'self' in the function, it's kind of a hack I'm not sure this is the way to go
|
||||
lua_pushvalue(func.LuaState, LUA_GLOBALSINDEX);
|
||||
lua_pushstring(func.LuaState, "self");
|
||||
tolua_pushusertype( func.LuaState, func.Plugin, "cPlugin" );
|
||||
lua_rawset(func.LuaState, -3);
|
||||
lua_pop(func.LuaState, 1);
|
||||
|
||||
LOGINFO("1. Stack size: %i", lua_gettop(func.LuaState) );
|
||||
lua_rawgeti( func.LuaState, LUA_REGISTRYINDEX, func.Reference); // same as lua_getref()
|
||||
|
||||
// Push the split
|
||||
LOGINFO("2. Stack size: %i", lua_gettop(func.LuaState) );
|
||||
lua_createtable(func.LuaState, Split.size(), 0);
|
||||
int newTable = lua_gettop(func.LuaState);
|
||||
int index = 1;
|
||||
std::vector<std::string>::const_iterator iter = Split.begin();
|
||||
while(iter != Split.end()) {
|
||||
tolua_pushstring( func.LuaState, (*iter).c_str() );
|
||||
lua_rawseti(func.LuaState, newTable, index);
|
||||
++iter;
|
||||
++index;
|
||||
}
|
||||
LOGINFO("3. Stack size: %i", lua_gettop(func.LuaState) );
|
||||
// Push player
|
||||
tolua_pushusertype( func.LuaState, a_Player, "cPlayer" );
|
||||
LOGINFO("Calling bound function! :D");
|
||||
int s = lua_pcall(func.LuaState, 2, 1, 0);
|
||||
if( report_errors( func.LuaState, s ) )
|
||||
{
|
||||
LOGINFO("error. Stack size: %i", lua_gettop(func.LuaState) );
|
||||
return false;
|
||||
}
|
||||
bool RetVal = (tolua_toboolean(func.LuaState, -1, 0) > 0);
|
||||
lua_pop(func.LuaState, 1); // Pop return value
|
||||
LOGINFO("ok. Stack size: %i", lua_gettop(func.LuaState) );
|
||||
return RetVal;
|
||||
}
|
||||
return false;
|
||||
}
|
36
source/cLuaCommandBinder.h
Normal file
36
source/cLuaCommandBinder.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
struct lua_State;
|
||||
class cPlugin;
|
||||
class cPlayer;
|
||||
class cLuaCommandBinder
|
||||
{
|
||||
public:
|
||||
cLuaCommandBinder();
|
||||
~cLuaCommandBinder();
|
||||
|
||||
bool HandleCommand( const std::string & a_Command, cPlayer* a_Player );
|
||||
|
||||
bool BindCommand( const std::string & a_Command, const std::string & a_Permission, cPlugin* a_Plugin, lua_State * a_LuaState, int a_FunctionReference );
|
||||
|
||||
void ClearBindings();
|
||||
void RemoveBindingsForPlugin( cPlugin* a_Plugin );
|
||||
private:
|
||||
struct BoundFunction
|
||||
{
|
||||
BoundFunction() : Plugin( 0 ), LuaState( 0 ), Reference( 0 ) {}
|
||||
BoundFunction( cPlugin* a_Plugin, lua_State * a_LuaState, int a_Reference, const std::string & a_Permission ) : Plugin( a_Plugin ), LuaState( a_LuaState ), Reference( a_Reference ), Permission( a_Permission ) {}
|
||||
cPlugin* Plugin;
|
||||
lua_State* LuaState;
|
||||
int Reference;
|
||||
std::string Permission;
|
||||
};
|
||||
|
||||
typedef std::map< std::string, BoundFunction > CommandMap;
|
||||
CommandMap m_BoundCommands;
|
||||
|
||||
};
|
155
source/cMCLogger.cpp
Normal file
155
source/cMCLogger.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
#include "cMCLogger.h"
|
||||
#include "cLog.h"
|
||||
#include "cCriticalSection.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <cstdarg>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#define sprintf_s(buffer, buffer_size, stringbuffer, ...) (sprintf(buffer, stringbuffer, __VA_ARGS__))
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
cMCLogger* cMCLogger::s_MCLogger = 0;
|
||||
|
||||
cMCLogger* cMCLogger::GetInstance()
|
||||
{
|
||||
return s_MCLogger;
|
||||
}
|
||||
|
||||
cMCLogger::cMCLogger()
|
||||
{
|
||||
m_CriticalSection = new cCriticalSection();
|
||||
char c_Buffer[128];
|
||||
sprintf_s(c_Buffer, 128, "LOG_%d.txt", (int)time(0) );
|
||||
m_Log = new cLog(c_Buffer);
|
||||
m_Log->Log("--- Started Log ---");
|
||||
|
||||
s_MCLogger = this;
|
||||
}
|
||||
|
||||
cMCLogger::cMCLogger( char* a_File )
|
||||
{
|
||||
m_CriticalSection = new cCriticalSection();
|
||||
m_Log = new cLog( a_File );
|
||||
}
|
||||
|
||||
cMCLogger::~cMCLogger()
|
||||
{
|
||||
m_Log->Log("--- Stopped Log ---");
|
||||
delete m_Log;
|
||||
delete m_CriticalSection;
|
||||
if( this == s_MCLogger )
|
||||
s_MCLogger = 0;
|
||||
}
|
||||
|
||||
void cMCLogger::LogSimple(const char* a_Text, int a_LogType /* = 0 */ )
|
||||
{
|
||||
switch( a_LogType )
|
||||
{
|
||||
case 0:
|
||||
Log(a_Text, 0);
|
||||
break;
|
||||
case 1:
|
||||
Info(a_Text, 0);
|
||||
break;
|
||||
case 2:
|
||||
Warn(a_Text, 0);
|
||||
break;
|
||||
case 3:
|
||||
Error(a_Text, 0);
|
||||
break;
|
||||
default:
|
||||
Log(a_Text, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void cMCLogger::Log(const char* a_Format, va_list a_ArgList)
|
||||
{
|
||||
m_CriticalSection->Lock();
|
||||
SetColor( 0x7 ); // 0x7 is default grey color
|
||||
m_Log->Log( a_Format, a_ArgList );
|
||||
m_CriticalSection->Unlock();
|
||||
}
|
||||
|
||||
void cMCLogger::Info(const char* a_Format, va_list a_ArgList)
|
||||
{
|
||||
m_CriticalSection->Lock();
|
||||
// for( int i = 0; i < 16; i++)
|
||||
// {
|
||||
// for( int j = 0; j < 16; j++ )
|
||||
// {
|
||||
// SetConsoleTextAttribute( hConsole, i | (j<<4) );
|
||||
// printf("0x%x", (i|j<<4));
|
||||
// }
|
||||
// printf("\n");
|
||||
// }
|
||||
|
||||
SetColor( 0xe ); // 0xe is yellow
|
||||
m_Log->Log( a_Format, a_ArgList );
|
||||
m_CriticalSection->Unlock();
|
||||
}
|
||||
|
||||
void cMCLogger::Warn(const char* a_Format, va_list a_ArgList)
|
||||
{
|
||||
m_CriticalSection->Lock();
|
||||
SetColor( 0xc ); // 0xc is red
|
||||
m_Log->Log( a_Format, a_ArgList );
|
||||
m_CriticalSection->Unlock();
|
||||
}
|
||||
|
||||
void cMCLogger::Error(const char* a_Format, va_list a_ArgList)
|
||||
{
|
||||
m_CriticalSection->Lock();
|
||||
SetColor( 0xc0 ); // 0xc0 is red bg and black text
|
||||
m_Log->Log( a_Format, a_ArgList );
|
||||
m_CriticalSection->Unlock();
|
||||
}
|
||||
|
||||
void cMCLogger::SetColor( unsigned char a_Color )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HANDLE hConsole = GetStdHandle( STD_OUTPUT_HANDLE );
|
||||
SetConsoleTextAttribute( hConsole, a_Color );
|
||||
#else
|
||||
(void)a_Color;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Global functions
|
||||
void LOG(const char* a_Format, ...)
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, a_Format);
|
||||
cMCLogger::GetInstance()->Log( a_Format, argList );
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
void LOGINFO(const char* a_Format, ...)
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, a_Format);
|
||||
cMCLogger::GetInstance()->Info( a_Format, argList );
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
void LOGWARN(const char* a_Format, ...)
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, a_Format);
|
||||
cMCLogger::GetInstance()->Warn( a_Format, argList );
|
||||
va_end(argList);
|
||||
}
|
||||
|
||||
void LOGERROR(const char* a_Format, ...)
|
||||
{
|
||||
va_list argList;
|
||||
va_start(argList, a_Format);
|
||||
cMCLogger::GetInstance()->Error( a_Format, argList );
|
||||
va_end(argList);
|
||||
}
|
39
source/cMCLogger.h
Normal file
39
source/cMCLogger.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
class cCriticalSection;
|
||||
class cLog;
|
||||
class cMCLogger //tolua_export
|
||||
{ //tolua_export
|
||||
private:
|
||||
#ifdef _WIN32
|
||||
typedef char* va_list;
|
||||
#endif
|
||||
public: //tolua_export
|
||||
cMCLogger();
|
||||
cMCLogger( char* a_File ); //tolua_export
|
||||
~cMCLogger(); //tolua_export
|
||||
|
||||
void Log(const char* a_Format, va_list a_ArgList);
|
||||
void Info(const char* a_Format, va_list a_ArgList);
|
||||
void Warn(const char* a_Format, va_list a_ArgList);
|
||||
void Error(const char* a_Format, va_list a_ArgList);
|
||||
|
||||
void LogSimple(const char* a_Text, int a_LogType = 0 ); //tolua_export
|
||||
|
||||
static cMCLogger* GetInstance();
|
||||
private:
|
||||
void SetColor( unsigned char a_Color );
|
||||
|
||||
cCriticalSection* m_CriticalSection;
|
||||
cLog* m_Log;
|
||||
static cMCLogger* s_MCLogger;
|
||||
}; //tolua_export
|
||||
|
||||
extern void LOG(const char* a_Format, ...);
|
||||
extern void LOGINFO(const char* a_Format, ...);
|
||||
extern void LOGWARN(const char* a_Format, ...);
|
||||
extern void LOGERROR(const char* a_Format, ...);
|
24
source/cMakeDir.cpp
Normal file
24
source/cMakeDir.cpp
Normal file
@ -0,0 +1,24 @@
|
||||
#include "cMakeDir.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
//#include <cstring> // If something is missing, uncomment some of these!
|
||||
//#include <cstdlib>
|
||||
//#include <stdio.h>
|
||||
#include <sys/stat.h> // for mkdir
|
||||
//#include <sys/types.h>
|
||||
#else
|
||||
#include <Windows.h>
|
||||
#endif
|
||||
|
||||
void cMakeDir::MakeDir( const char* a_Directory )
|
||||
{
|
||||
#ifdef _WIN32
|
||||
SECURITY_ATTRIBUTES Attrib;
|
||||
Attrib.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
Attrib.lpSecurityDescriptor = NULL;
|
||||
Attrib.bInheritHandle = false;
|
||||
::CreateDirectory("world", &Attrib);
|
||||
#else
|
||||
mkdir("world", S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
#endif
|
||||
}
|
7
source/cMakeDir.h
Normal file
7
source/cMakeDir.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
class cMakeDir
|
||||
{
|
||||
public:
|
||||
static void MakeDir( const char* a_Directory );
|
||||
};
|
609
source/cMonster.cpp
Normal file
609
source/cMonster.cpp
Normal file
@ -0,0 +1,609 @@
|
||||
#include "cMonster.h"
|
||||
#include "cRoot.h"
|
||||
#include "cServer.h"
|
||||
#include "cClientHandle.h"
|
||||
#include "cWorld.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cChunk.h"
|
||||
#include "cPlayer.h"
|
||||
#include "BlockID.h"
|
||||
#include "Defines.h"
|
||||
|
||||
#include "packets/cPacket_SpawnMob.h"
|
||||
#include "packets/cPacket_EntityLook.h"
|
||||
#include "packets/cPacket_TeleportEntity.h"
|
||||
#include "packets/cPacket_RelativeEntityMoveLook.h"
|
||||
#include "packets/cPacket_RelativeEntityMove.h"
|
||||
#include "packets/cPacket_Metadata.h"
|
||||
|
||||
#include "Vector3f.h"
|
||||
#include "Vector3i.h"
|
||||
#include "Vector3d.h"
|
||||
|
||||
#include "cTracer.h"
|
||||
#include "../iniFile/iniFile.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstdlib> // rand
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
cMonster::cMonster()
|
||||
: m_Target(0)
|
||||
, m_Destination( new Vector3f() )
|
||||
, m_bMovingToDestination(false)
|
||||
, m_Speed( new Vector3f() )
|
||||
, m_DestinationTime( 0 )
|
||||
, m_Gravity( -9.81 )
|
||||
, m_bOnGround( false )
|
||||
, m_DestroyTimer( 0 )
|
||||
, m_Jump(0)
|
||||
, m_MobType( 0 )
|
||||
, m_EMState(IDLE)
|
||||
, m_SightDistance(25)
|
||||
,m_SeePlayerInterval (0)
|
||||
,m_EMPersonality(AGGRESSIVE)
|
||||
,m_AttackDamage(1.0)
|
||||
,m_AttackRange(5.0)
|
||||
,m_AttackInterval(0)
|
||||
,m_AttackRate(3)
|
||||
,m_bPassiveAggressive(false)
|
||||
,idle_interval(0)
|
||||
,m_bBurnable(true)
|
||||
,m_EMMetaState(NORMAL)
|
||||
,m_FireDamageInterval(0)
|
||||
,m_BurnPeriod(0)
|
||||
{
|
||||
LOG("cMonster::cMonster()");
|
||||
LOG("In state: %s",GetState());
|
||||
m_Health = 10;
|
||||
|
||||
int RandVal = rand() % 4;
|
||||
if( RandVal == 0 )
|
||||
m_MobType = 90; // Pig
|
||||
else if( RandVal == 1 )
|
||||
m_MobType = 91; // Sheep
|
||||
else if( RandVal == 2 )
|
||||
m_MobType = 92; // Cow
|
||||
else
|
||||
m_MobType = 93; // Hen
|
||||
}
|
||||
|
||||
cMonster::~cMonster()
|
||||
{
|
||||
|
||||
LOG("cMonster::~cMonster()");
|
||||
delete m_Destination;
|
||||
delete m_Speed;
|
||||
}
|
||||
|
||||
bool cMonster::IsA( const char* a_EntityType )
|
||||
{
|
||||
//LOG("IsA( cMonster ) : %s", a_EntityType);
|
||||
if( strcmp( a_EntityType, "cMonster" ) == 0 ) return true;
|
||||
return cPawn::IsA( a_EntityType );
|
||||
}
|
||||
|
||||
void cMonster::SpawnOn( cClientHandle* a_Target )
|
||||
{
|
||||
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
|
||||
//Spawn.m_MetaData[1] = 0x7f; // terminator
|
||||
if( a_Target == 0 )
|
||||
{
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
Chunk->Broadcast( Spawn );
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Target->Send( Spawn );
|
||||
}
|
||||
}
|
||||
|
||||
void cMonster::MoveToPosition( const Vector3f & a_Position )
|
||||
{
|
||||
m_bMovingToDestination = true;
|
||||
|
||||
*m_Destination = a_Position;
|
||||
}
|
||||
|
||||
bool cMonster::ReachedDestination()
|
||||
{
|
||||
Vector3f Distance = (*m_Destination) - Vector3f( m_Pos );
|
||||
if( Distance.SqrLength() < 2.f )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void cMonster::Tick(float a_Dt)
|
||||
{
|
||||
if( m_Health <= 0 )
|
||||
{
|
||||
m_DestroyTimer += a_Dt/1000;
|
||||
if( m_DestroyTimer > 1 )
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//a_Dt/=1000;
|
||||
a_Dt/=1000;
|
||||
|
||||
if( m_bMovingToDestination )
|
||||
{
|
||||
Vector3f Pos( m_Pos );
|
||||
Vector3f Distance = *m_Destination - Pos;
|
||||
if( !ReachedDestination() )
|
||||
{
|
||||
Distance.y = 0;
|
||||
Distance.Normalize();
|
||||
Distance*=3;
|
||||
m_Speed->x = Distance.x;
|
||||
m_Speed->z = Distance.z;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bMovingToDestination = false;
|
||||
}
|
||||
|
||||
if( m_Speed->SqrLength() > 0.f )
|
||||
{
|
||||
if( m_bOnGround )
|
||||
{
|
||||
Vector3f NormSpeed = m_Speed->NormalizeCopy();
|
||||
Vector3f NextBlock = Vector3f( *m_Pos ) + NormSpeed;
|
||||
double NextHeight = (double)cRoot::Get()->GetWorld()->GetHeight( (int)NextBlock.x, (int)NextBlock.z );
|
||||
if( NextHeight > m_Pos->y - 1.2 && NextHeight - m_Pos->y < 2.5 )
|
||||
{
|
||||
m_bOnGround = false;
|
||||
m_Speed->y = 7.f; // Jump!!
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HandlePhysics( a_Dt );
|
||||
|
||||
ReplicateMovement();
|
||||
|
||||
Vector3f Distance = *m_Destination - Vector3f( m_Pos );
|
||||
if( Distance.SqrLength() > 0.1f )
|
||||
{
|
||||
float Rotation, Pitch;
|
||||
Distance.Normalize();
|
||||
VectorToEuler( Distance.x, Distance.y, Distance.z, Rotation, Pitch );
|
||||
SetRotation( Rotation );
|
||||
SetPitch( Pitch );
|
||||
}
|
||||
|
||||
CheckMetaDataBurn(); //Check to see if Enemy should burn based on block they are on
|
||||
|
||||
if(m_EMMetaState == BURNING) {
|
||||
InStateBurning(a_Dt);
|
||||
}
|
||||
|
||||
if(m_EMState == IDLE) { //If enemy passive we ignore checks for player visibility
|
||||
InStateIdle(a_Dt);
|
||||
}
|
||||
|
||||
if(m_EMState == CHASING) { //If we do not see a player anymore skip chasing action
|
||||
InStateChasing(a_Dt);
|
||||
}
|
||||
|
||||
if(m_EMState == ESCAPING) {
|
||||
InStateEscaping(a_Dt);
|
||||
}
|
||||
|
||||
m_SeePlayerInterval += a_Dt;
|
||||
if(m_SeePlayerInterval > 1) {
|
||||
int rem = rand()%3 + 1; //check most of the time but miss occasionally
|
||||
//LOG("See Player Interval: %3.3f",m_SeePlayerInterval);
|
||||
m_SeePlayerInterval = 0.0;
|
||||
if(rem >= 2) {
|
||||
if(m_EMState == IDLE && m_EMPersonality != PASSIVE) {
|
||||
CheckEventSeePlayer();
|
||||
return;
|
||||
}
|
||||
if(m_EMState == CHASING || m_EMState == ESCAPING){
|
||||
CheckEventLostPlayer();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void cMonster::ReplicateMovement()
|
||||
{
|
||||
cChunk* InChunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( !InChunk ) return;
|
||||
|
||||
if(m_bDirtyOrientation && !m_bDirtyPosition)
|
||||
{
|
||||
cPacket_EntityLook EntityLook( this );
|
||||
InChunk->Broadcast( EntityLook );
|
||||
m_bDirtyOrientation = false;
|
||||
}
|
||||
if( m_bDirtyPosition )
|
||||
{
|
||||
|
||||
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
|
||||
{
|
||||
//LOG("Teleported %f", sqrtf(SqrDist) );
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
InChunk->Broadcast( TeleportEntity );
|
||||
m_TimeLastTeleportPacket = cWorld::GetTime();
|
||||
}
|
||||
else
|
||||
{ // Relative move sucks balls! It's always wrong wtf!
|
||||
if( m_bDirtyOrientation )
|
||||
{
|
||||
cPacket_RelativeEntityMoveLook RelativeEntityMoveLook;
|
||||
RelativeEntityMoveLook.m_UniqueID = GetUniqueID();
|
||||
RelativeEntityMoveLook.m_MoveX = (char)(DiffX*32);
|
||||
RelativeEntityMoveLook.m_MoveY = (char)(DiffY*32);
|
||||
RelativeEntityMoveLook.m_MoveZ = (char)(DiffZ*32);
|
||||
RelativeEntityMoveLook.m_Yaw = (char)((GetRotation()/360.f)*256);
|
||||
RelativeEntityMoveLook.m_Pitch = (char)((GetPitch()/360.f)*256);
|
||||
InChunk->Broadcast( RelativeEntityMoveLook );
|
||||
}
|
||||
else
|
||||
{
|
||||
cPacket_RelativeEntityMove RelativeEntityMove;
|
||||
RelativeEntityMove.m_UniqueID = GetUniqueID();
|
||||
RelativeEntityMove.m_MoveX = (char)(DiffX*32);
|
||||
RelativeEntityMove.m_MoveY = (char)(DiffY*32);
|
||||
RelativeEntityMove.m_MoveZ = (char)(DiffZ*32);
|
||||
InChunk->Broadcast( RelativeEntityMove );
|
||||
}
|
||||
}
|
||||
m_LastPosX = GetPosX();
|
||||
m_LastPosY = GetPosY();
|
||||
m_LastPosZ = GetPosZ();
|
||||
m_bDirtyPosition = false;
|
||||
}
|
||||
}
|
||||
|
||||
void cMonster::HandlePhysics(float a_Dt)
|
||||
{
|
||||
if( m_bOnGround ) // check if it's still on the ground
|
||||
{
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
if( World->GetBlock( (int)m_Pos->x, (int)m_Pos->y -1, (int)m_Pos->z ) == E_BLOCK_AIR )
|
||||
{
|
||||
m_bOnGround = false;
|
||||
}
|
||||
if( World->GetBlock( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z ) != E_BLOCK_AIR ) // If in ground itself, push it out
|
||||
{
|
||||
m_bOnGround = true;
|
||||
m_Pos->y += 0.2;
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
m_Speed->x *= 0.7f/(1+a_Dt);
|
||||
if( fabs(m_Speed->x) < 0.05 ) m_Speed->x = 0;
|
||||
m_Speed->z *= 0.7f/(1+a_Dt);
|
||||
if( fabs(m_Speed->z) < 0.05 ) m_Speed->z = 0;
|
||||
}
|
||||
|
||||
if( !m_bOnGround )
|
||||
{
|
||||
float Gravity = -9.81f*a_Dt;
|
||||
m_Speed->y += Gravity;
|
||||
}
|
||||
|
||||
if( m_Speed->SqrLength() > 0.f )
|
||||
{
|
||||
cTracer Tracer( cRoot::Get()->GetWorld() );
|
||||
int Ret = Tracer.Trace( *m_Pos, *m_Speed, 2 );
|
||||
if( Ret ) // Oh noez! we hit something
|
||||
{
|
||||
// Set to hit position
|
||||
if( (*Tracer.RealHit - Vector3f(*m_Pos)).SqrLength() <= ( *m_Speed * a_Dt ).SqrLength() )
|
||||
{
|
||||
if( Ret == 1 )
|
||||
{
|
||||
|
||||
if( Tracer.HitNormal->x != 0.f ) m_Speed->x = 0.f;
|
||||
if( Tracer.HitNormal->y != 0.f ) m_Speed->y = 0.f;
|
||||
if( Tracer.HitNormal->z != 0.f ) m_Speed->z = 0.f;
|
||||
|
||||
if( Tracer.HitNormal->y > 0 ) // means on ground
|
||||
{
|
||||
m_bOnGround = true;
|
||||
}
|
||||
}
|
||||
*m_Pos = Tracer.RealHit;
|
||||
*m_Pos += *Tracer.HitNormal * 0.2;
|
||||
|
||||
}
|
||||
else
|
||||
*m_Pos += *m_Speed*a_Dt;
|
||||
}
|
||||
else
|
||||
{ // We didn't hit anything, so move =]
|
||||
*m_Pos += *m_Speed*a_Dt;
|
||||
}
|
||||
|
||||
m_bDirtyPosition = true;
|
||||
}
|
||||
}
|
||||
|
||||
void cMonster::TakeDamage( int a_Damage, cEntity* a_Instigator )
|
||||
{
|
||||
cPawn::TakeDamage( a_Damage, a_Instigator );
|
||||
m_Target = a_Instigator;
|
||||
AddReference( m_Target );
|
||||
if(m_EMPersonality == AGGRESSIVE) {
|
||||
m_EMState = CHASING;
|
||||
}
|
||||
if(m_EMPersonality == COWARDLY || m_EMPersonality == PASSIVE) {
|
||||
//m_bPassiveAggressive can be set so if the monster based on time of day for example
|
||||
//so the monster will only attack if provoked
|
||||
m_EMState = (m_bPassiveAggressive)? CHASING : ESCAPING;
|
||||
}
|
||||
//LOG("Take damage");
|
||||
}
|
||||
|
||||
void cMonster::KilledBy( cEntity* a_Killer )
|
||||
{
|
||||
cPawn::KilledBy( a_Killer );
|
||||
m_DestroyTimer = 0;
|
||||
}
|
||||
|
||||
//----State Logic
|
||||
|
||||
const char *cMonster::GetState() {
|
||||
switch(m_EMState) {
|
||||
case IDLE:
|
||||
return "Idle";
|
||||
break;
|
||||
case ATTACKING:
|
||||
return "Attacking";
|
||||
break;
|
||||
case CHASING:
|
||||
return "Chasing";
|
||||
break;
|
||||
default:
|
||||
return "Unknown";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//for debugging
|
||||
void cMonster::SetState(const char* a_str) {
|
||||
std::string str = a_str;
|
||||
if(str.compare("Idle") == 0 ) {
|
||||
m_EMState = IDLE;
|
||||
} else if(str.compare("Attacking") == 0 ) {
|
||||
m_EMState = ATTACKING;
|
||||
} else if(str.compare("Chasing") == 0 ) {
|
||||
m_EMState = CHASING;
|
||||
} else {
|
||||
printf("Invalid State");
|
||||
}
|
||||
}
|
||||
|
||||
//Checks to see if EventSeePlayer should be fired
|
||||
//monster sez: Do I see the player
|
||||
void cMonster::CheckEventSeePlayer() {
|
||||
|
||||
//LOG("Checking if I see any players");
|
||||
cMonster::ListClosePlayers(this);
|
||||
|
||||
}
|
||||
|
||||
void cMonster::CheckEventLostPlayer() {
|
||||
Vector3f pos;
|
||||
cTracer LineOfSight(cRoot::Get()->GetWorld() );
|
||||
|
||||
//LOG("Checking if I lost my enemy");
|
||||
if(m_Target != 0) {
|
||||
pos = m_Target->GetPosition();
|
||||
if((pos - *m_Pos).Length() > m_SightDistance || LineOfSight.Trace(*m_Pos,(pos - *m_Pos), (int)(pos - *m_Pos).Length())){
|
||||
//LOG("Losing Player: %5.5f",(pos - *m_Pos).Length());
|
||||
EventLosePlayer();
|
||||
}
|
||||
} else {
|
||||
LOG("Enemy went poof");
|
||||
EventLosePlayer();
|
||||
}
|
||||
}
|
||||
|
||||
//What to do if player is seen
|
||||
//default to change state to chasing
|
||||
void cMonster::EventSeePlayer(cEntity *a_SeenPlayer) {
|
||||
m_Target = a_SeenPlayer;
|
||||
AddReference( m_Target );
|
||||
if(m_EMPersonality == AGGRESSIVE) {
|
||||
m_EMState = CHASING;
|
||||
}
|
||||
if(m_EMPersonality == COWARDLY) {
|
||||
m_EMState = ESCAPING;
|
||||
}
|
||||
//LOG("Saw Player: %s",GetState());
|
||||
}
|
||||
|
||||
void cMonster::EventLosePlayer(){
|
||||
Dereference(m_Target);
|
||||
m_Target = 0;
|
||||
//LOG("Lost Player");
|
||||
m_EMState = IDLE;
|
||||
}
|
||||
|
||||
//What to do if in Idle State
|
||||
void cMonster::InStateIdle(float a_Dt) {
|
||||
idle_interval += a_Dt;
|
||||
if(idle_interval > 1) { //at this interval the results are predictable
|
||||
int rem = rand()%6 + 1;
|
||||
//LOG("Moving: int: %3.3f rem: %i",idle_interval,rem);
|
||||
idle_interval = 0;
|
||||
Vector3f Dist;
|
||||
Dist.x = (float)((rand()%11)-5);
|
||||
Dist.z = (float)((rand()%11)-5);
|
||||
if( Dist.SqrLength() > 2 && rem >= 3)
|
||||
{
|
||||
m_Destination->x = (float)(m_Pos->x + Dist.x);
|
||||
m_Destination->z = (float)(m_Pos->z + Dist.z);
|
||||
m_Destination->y = (float)cRoot::Get()->GetWorld()->GetHeight( (int)m_Destination->x, (int)m_Destination->z ) + 1.2f;
|
||||
MoveToPosition( *m_Destination );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//What to do if On fire
|
||||
void cMonster::InStateBurning(float a_Dt) {
|
||||
m_FireDamageInterval += a_Dt;
|
||||
char block = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z );
|
||||
char bblock = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y -1, (int)m_Pos->z );
|
||||
if(m_FireDamageInterval > 1) {
|
||||
|
||||
m_FireDamageInterval = 0;
|
||||
int rem = rand()%3 + 1; //Burn most of the time
|
||||
if(rem >= 2) {
|
||||
//printf("OUCH burning!!!\n");
|
||||
TakeDamage(1, this);
|
||||
}
|
||||
m_BurnPeriod++;
|
||||
if(block == E_BLOCK_LAVA || block == E_BLOCK_STATIONARY_LAVA || block == E_BLOCK_FIRE
|
||||
|| bblock == E_BLOCK_LAVA || bblock == E_BLOCK_STATIONARY_LAVA || bblock == E_BLOCK_FIRE)
|
||||
m_BurnPeriod = 0;
|
||||
|
||||
if(m_BurnPeriod > 5) {
|
||||
|
||||
cChunk* InChunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
m_EMMetaState = NORMAL;
|
||||
cPacket_Metadata md(NORMAL, GetUniqueID());
|
||||
//md.m_UniqueID = GetUniqueID();
|
||||
InChunk->Broadcast(md);
|
||||
m_BurnPeriod = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//What to do if in Chasing State
|
||||
//This state should always be defined in each child class
|
||||
void cMonster::InStateChasing(float a_Dt) {
|
||||
(void)a_Dt;
|
||||
}
|
||||
|
||||
//What to do if in Escaping State
|
||||
void cMonster::InStateEscaping(float a_Dt) {
|
||||
(void)a_Dt;
|
||||
if(m_Target) {
|
||||
Vector3d newloc = *m_Pos;
|
||||
newloc.x = (m_Target->GetPosition().x < newloc.x)? (newloc.x + m_SightDistance): (newloc.x - m_SightDistance);
|
||||
newloc.z = (m_Target->GetPosition().z < newloc.z)? (newloc.z + m_SightDistance): (newloc.z - m_SightDistance);
|
||||
MoveToPosition(newloc);
|
||||
} else {
|
||||
m_EMState = IDLE; //this shouldnt be required but just to be safe
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Do attack here
|
||||
//a_Dt is passed so we can set attack rate
|
||||
void cMonster::Attack(float a_Dt) {
|
||||
m_AttackInterval += a_Dt*m_AttackRate;
|
||||
if(m_Target != 0 && m_AttackInterval > 3.0) { //Setting this higher gives us more wiggle room for attackrate
|
||||
//LOG("ATTACK!");
|
||||
m_AttackInterval = 0.0;
|
||||
((cPawn *)m_Target)->TakeDamage((int)m_AttackDamage,this);
|
||||
}
|
||||
}
|
||||
//----Change Entity MetaData
|
||||
void cMonster::CheckMetaDataBurn() {
|
||||
char block = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z );
|
||||
char bblock = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y -1, (int)m_Pos->z );
|
||||
if(m_bBurnable && m_EMMetaState != BURNING && (block == E_BLOCK_LAVA || block == E_BLOCK_STATIONARY_LAVA || block == E_BLOCK_FIRE
|
||||
|| bblock == E_BLOCK_LAVA || bblock == E_BLOCK_STATIONARY_LAVA || bblock == E_BLOCK_FIRE)) {
|
||||
cChunk* InChunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if(!InChunk)
|
||||
return;
|
||||
//printf("I should burn");
|
||||
m_EMMetaState = BURNING;
|
||||
cPacket_Metadata md(BURNING,GetUniqueID());
|
||||
InChunk->Broadcast(md);
|
||||
}
|
||||
}
|
||||
|
||||
//----Debug
|
||||
|
||||
void cMonster::ListMonsters() {
|
||||
|
||||
cWorld::EntityList Entities = cRoot::Get()->GetWorld()->GetEntities();
|
||||
cRoot::Get()->GetWorld()->LockEntities();
|
||||
for( cWorld::EntityList::iterator itr = Entities.begin(); itr != Entities.end(); ++itr) {
|
||||
if((*itr)->GetEntityType() == cEntity::E_ENTITY){
|
||||
LOG("In state: %s type: %i attack rate: %i",((cMonster *)(*itr))->GetState(), ((cMonster *)(*itr))->GetMobType(),((cMonster *)(*itr))->GetAttackRate());
|
||||
|
||||
}
|
||||
}
|
||||
cRoot::Get()->GetWorld()->UnlockEntities();
|
||||
}
|
||||
|
||||
//Checks for Players close by and if they are visible
|
||||
void cMonster::ListClosePlayers(cMonster *m) {
|
||||
int tries = 0;
|
||||
cTracer LineOfSight(cRoot::Get()->GetWorld() );
|
||||
cWorld::EntityList Entities = cRoot::Get()->GetWorld()->GetEntities();
|
||||
for( cWorld::EntityList::iterator itr = Entities.begin(); itr != Entities.end(); ++itr) {
|
||||
tries++;
|
||||
if((*itr)->GetEntityType() == cEntity::E_PLAYER){
|
||||
Vector3f pos = (*itr)->GetPosition();
|
||||
if((pos - *(m->m_Pos)).Length() <= m->m_SightDistance){
|
||||
if(!LineOfSight.Trace(*(m->m_Pos),(pos - *(m->m_Pos)),(int)(pos - *(m->m_Pos)).Length())){
|
||||
//LOG("I SEE PLAYER !!!!!!!!!!!!!!!!!");
|
||||
m->EventSeePlayer(*itr);
|
||||
return; //get the first one in sight later we can reiterate and check
|
||||
//for the closest out of all that match and make it more realistic
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(tries > 100) {
|
||||
//LOG("I Give Up");
|
||||
m->EventLosePlayer();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cMonster::GetMonsterConfig(const char* pm_name) {
|
||||
(void)pm_name;
|
||||
}
|
||||
|
||||
void cMonster::SetAttackRate(int ar) {
|
||||
m_AttackRate = (float)ar;
|
||||
}
|
||||
void cMonster::SetAttackRange(float ar) {
|
||||
m_AttackRange = ar;
|
||||
}
|
||||
void cMonster::SetAttackDamage(float ad) {
|
||||
m_AttackDamage = ad;
|
||||
}
|
||||
void cMonster::SetSightDistance(float sd) {
|
||||
m_SightDistance = sd;
|
||||
}
|
85
source/cMonster.h
Normal file
85
source/cMonster.h
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
#include "cPawn.h"
|
||||
|
||||
class Vector3f;
|
||||
class cClientHandle;
|
||||
class cMonster : public cPawn //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
|
||||
cMonster();
|
||||
virtual ~cMonster();
|
||||
|
||||
virtual bool IsA( const char* a_EntityType );
|
||||
|
||||
virtual void SpawnOn( cClientHandle* a_Target );
|
||||
|
||||
virtual void Tick(float a_Dt);
|
||||
virtual void HandlePhysics(float a_Dt);
|
||||
virtual void ReplicateMovement();
|
||||
|
||||
virtual void TakeDamage( int a_Damage, cEntity* a_Instigator );
|
||||
virtual void KilledBy( cEntity* a_Killer );
|
||||
|
||||
virtual void MoveToPosition( const Vector3f & a_Position );
|
||||
virtual bool ReachedDestination();
|
||||
|
||||
const char *GetState();
|
||||
void SetState(const char* str);
|
||||
static void ListMonsters();
|
||||
|
||||
virtual void CheckEventSeePlayer();
|
||||
virtual void EventSeePlayer(cEntity *);
|
||||
float m_SightDistance;
|
||||
static void ListClosePlayers(cMonster *);
|
||||
virtual void GetMonsterConfig(const char* pm_name);
|
||||
virtual void EventLosePlayer();
|
||||
virtual void CheckEventLostPlayer();
|
||||
|
||||
virtual void InStateIdle(float a_Dt);
|
||||
virtual void InStateChasing(float a_Dt);
|
||||
virtual void InStateEscaping(float a_Dt);
|
||||
virtual void InStateBurning(float a_Dt);
|
||||
|
||||
virtual void Attack(float a_Dt);
|
||||
int GetMobType() {return m_MobType;}
|
||||
int GetAttackRate(){return (int)m_AttackRate;}
|
||||
void SetAttackRate(int ar);
|
||||
void SetAttackRange(float ar);
|
||||
void SetAttackDamage(float ad);
|
||||
void SetSightDistance(float sd);
|
||||
virtual void CheckMetaDataBurn();
|
||||
|
||||
enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState;
|
||||
enum MPersonality{PASSIVE,AGGRESSIVE,COWARDLY} m_EMPersonality;
|
||||
enum MMetaState{NORMAL,BURNING,CROUCHED,RIDING} m_EMMetaState;
|
||||
|
||||
protected:
|
||||
|
||||
cEntity* m_Target;
|
||||
float m_AttackRate;
|
||||
float idle_interval;
|
||||
|
||||
Vector3f* m_Destination;
|
||||
bool m_bMovingToDestination;
|
||||
bool m_bPassiveAggressive;
|
||||
bool m_bBurnable;
|
||||
|
||||
Vector3f* m_Speed;
|
||||
float m_DestinationTime;
|
||||
|
||||
float m_Gravity;
|
||||
bool m_bOnGround;
|
||||
|
||||
float m_DestroyTimer;
|
||||
float m_Jump;
|
||||
|
||||
char m_MobType;
|
||||
|
||||
float m_SeePlayerInterval;
|
||||
float m_AttackDamage;
|
||||
float m_AttackRange;
|
||||
float m_AttackInterval;
|
||||
float m_FireDamageInterval;
|
||||
float m_BurnPeriod;
|
||||
}; //tolua_export
|
93
source/cMonsterConfig.cpp
Normal file
93
source/cMonsterConfig.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
#include "cMonsterConfig.h"
|
||||
#include "cMonster.h"
|
||||
#include "../iniFile/iniFile.h"
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
//#include "../source/cprintf.h"
|
||||
#include <string>
|
||||
using namespace std;
|
||||
|
||||
extern std::vector<std::string> StringSplit(std::string str, std::string delim);
|
||||
|
||||
struct cMonsterConfig::sAttributesStruct
|
||||
{
|
||||
string m_name;
|
||||
float m_SightDistance;
|
||||
float m_AttackDamage;
|
||||
float m_AttackRange;
|
||||
float m_AttackRate;
|
||||
};
|
||||
|
||||
struct cMonsterConfig::sMonsterConfigState
|
||||
{
|
||||
int TypeCount;
|
||||
string MonsterTypes;
|
||||
list< sAttributesStruct > AttributesList;
|
||||
};
|
||||
|
||||
cMonsterConfig::cMonsterConfig(int TypeC)
|
||||
: m_pState( new sMonsterConfigState )
|
||||
{
|
||||
m_pState->TypeCount = TypeC;
|
||||
Initialize();
|
||||
}
|
||||
|
||||
cMonsterConfig::~cMonsterConfig() {
|
||||
delete m_pState;
|
||||
}
|
||||
|
||||
void cMonsterConfig::Initialize() {
|
||||
|
||||
sAttributesStruct Attributes;
|
||||
cIniFile SettingsIniFile("settings.ini");
|
||||
cIniFile MonstersIniFile("monsters.ini");
|
||||
|
||||
if(!SettingsIniFile.ReadFile() || !MonstersIniFile.ReadFile()) {
|
||||
printf("Error: Must have both settings.ini and monsters.ini to configure attributes\n\tusing default attributes \n");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pState->MonsterTypes = SettingsIniFile.GetValue("Monsters","Types","");
|
||||
|
||||
if( m_pState->MonsterTypes.empty() ) {
|
||||
printf("Error: No Monster types listed in config file, using default attributes \n");
|
||||
return;
|
||||
}
|
||||
|
||||
vector<string> SplitList = StringSplit(m_pState->MonsterTypes,",");
|
||||
for(unsigned int i = 0; i < SplitList.size(); ++i) {
|
||||
if(!SplitList[i].empty()) {
|
||||
printf("Getting Attributes for: %s \n",SplitList[i].c_str());
|
||||
Attributes.m_name = SplitList[i].c_str();
|
||||
Attributes.m_AttackDamage = (float)MonstersIniFile.GetValueF(SplitList[i].c_str(),"AttackDamage",0);
|
||||
printf("Got AttackDamage: %3.3f \n",Attributes.m_AttackDamage);
|
||||
Attributes.m_AttackRange = (float)MonstersIniFile.GetValueF(SplitList[i].c_str(),"AttackRange",0);
|
||||
printf("Got AttackRange: %3.3f \n",Attributes.m_AttackRange);
|
||||
Attributes.m_SightDistance = (float)MonstersIniFile.GetValueF(SplitList[i].c_str(),"SightDistance",0);
|
||||
printf("Got SightDistance: %3.3f \n",Attributes.m_SightDistance);
|
||||
Attributes.m_AttackRate = (float)MonstersIniFile.GetValueF(SplitList[i].c_str(),"AttackRate",0);
|
||||
printf("Got AttackRate: %3.3f \n",Attributes.m_AttackRate);
|
||||
m_pState->AttributesList.push_front(Attributes);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cMonsterConfig::AssignAttributes(cMonster *m, const char* n)
|
||||
{
|
||||
list<sAttributesStruct>::iterator itr;
|
||||
for(itr = m_pState->AttributesList.begin(); itr != m_pState->AttributesList.end(); ++itr) {
|
||||
if(itr->m_name.compare(n) == 0) {
|
||||
//printf("found my attribs: %s :\n",itr->m_name.c_str());
|
||||
m->SetAttackDamage(itr->m_AttackDamage);
|
||||
m->SetAttackRange(itr->m_AttackRange);
|
||||
m->SetSightDistance(itr->m_SightDistance);
|
||||
m->SetAttackRate((int)itr->m_AttackRate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cMonsterConfig *cMonsterConfig::Get() {
|
||||
return this;
|
||||
}
|
18
source/cMonsterConfig.h
Normal file
18
source/cMonsterConfig.h
Normal file
@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
class cMonster;
|
||||
class cMonsterConfig
|
||||
{
|
||||
public:
|
||||
cMonsterConfig(int TypeC);
|
||||
~cMonsterConfig();
|
||||
cMonsterConfig *Get();
|
||||
|
||||
void AssignAttributes(cMonster *m, const char* n);
|
||||
|
||||
private:
|
||||
struct sAttributesStruct;
|
||||
struct sMonsterConfigState;
|
||||
sMonsterConfigState* m_pState;
|
||||
void Initialize();
|
||||
};
|
253
source/cNoise.cpp
Normal file
253
source/cNoise.cpp
Normal file
@ -0,0 +1,253 @@
|
||||
#include "cNoise.h"
|
||||
#include <math.h>
|
||||
|
||||
#define FAST_FLOOR( x ) ( (x) < 0 ? ((int)x)-1 : ((int)x) )
|
||||
|
||||
cNoise::cNoise( unsigned int a_Seed )
|
||||
: m_Seed( a_Seed )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
cNoise::~cNoise()
|
||||
{
|
||||
}
|
||||
|
||||
/****************
|
||||
* Random value generator
|
||||
**/
|
||||
float cNoise::IntNoise( int a_X ) const
|
||||
{
|
||||
int x = ((a_X*m_Seed)<<13) ^ a_X;
|
||||
return ( 1.0f - ( (x * (x * x * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
||||
}
|
||||
|
||||
float cNoise::IntNoise2D( int a_X, int a_Y ) const
|
||||
{
|
||||
int n = a_X + a_Y * 57 + m_Seed*57*57;
|
||||
n = (n<<13) ^ n;
|
||||
return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
||||
}
|
||||
|
||||
float cNoise::IntNoise3D( int a_X, int a_Y, int a_Z ) const
|
||||
{
|
||||
int n = a_X + a_Y * 57 + a_Z * 57*57 + m_Seed*57*57*57;
|
||||
n = (n<<13) ^ n;
|
||||
return ( 1.0f - ( (n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff) / 1073741824.0f);
|
||||
}
|
||||
|
||||
/***************
|
||||
* Interpolated (and 1 smoothed) noise in 1-dimension
|
||||
**/
|
||||
float cNoise::LinearNoise1D( float a_X ) const
|
||||
{
|
||||
int BaseX = FAST_FLOOR( a_X );
|
||||
float FracX = (a_X) - BaseX;
|
||||
return LinearInterpolate( IntNoise( BaseX ), IntNoise( BaseX+1 ), FracX);
|
||||
}
|
||||
|
||||
float cNoise::CosineNoise1D( float a_X ) const
|
||||
{
|
||||
int BaseX = FAST_FLOOR( a_X );
|
||||
float FracX = (a_X) - BaseX;
|
||||
return CosineInterpolate( IntNoise( BaseX ), IntNoise( BaseX+1 ), FracX);
|
||||
}
|
||||
|
||||
float cNoise::CubicNoise1D( float a_X ) const
|
||||
{
|
||||
int BaseX = FAST_FLOOR( a_X );
|
||||
float FracX = (a_X) - BaseX;
|
||||
return CubicInterpolate( IntNoise( BaseX-1 ), IntNoise( BaseX ), IntNoise( BaseX+1 ), IntNoise( BaseX+2 ), FracX);
|
||||
}
|
||||
|
||||
float cNoise::SmoothNoise1D( int a_X ) const
|
||||
{
|
||||
return IntNoise(a_X)/2 + IntNoise(a_X-1)/4 + IntNoise(a_X+1)/4;
|
||||
}
|
||||
|
||||
/******************
|
||||
* Interpolated (and 1 smoothed) noise in 2-dimensions
|
||||
**/
|
||||
float cNoise::LinearNoise2D( float a_X, float a_Y ) const
|
||||
{
|
||||
const int BaseX = FAST_FLOOR( a_X );
|
||||
const int BaseY = FAST_FLOOR( a_Y );
|
||||
|
||||
const float tl = IntNoise2D( BaseX, BaseY );
|
||||
const float tr = IntNoise2D( BaseX+1, BaseY );
|
||||
const float bl = IntNoise2D( BaseX, BaseY+1 );
|
||||
const float br = IntNoise2D( BaseX+1, BaseY+1 );
|
||||
|
||||
const float FracX = (a_X) - BaseX;
|
||||
const float interp1 = LinearInterpolate( tl, tr, FracX );
|
||||
const float interp2 = LinearInterpolate( bl, br, FracX );
|
||||
|
||||
const float FracY = (a_Y) - BaseY;
|
||||
return LinearInterpolate( interp1, interp2, FracY );
|
||||
}
|
||||
|
||||
float cNoise::CosineNoise2D( float a_X, float a_Y ) const
|
||||
{
|
||||
const int BaseX = FAST_FLOOR( a_X );
|
||||
const int BaseY = FAST_FLOOR( a_Y );
|
||||
|
||||
const float tl = IntNoise2D( BaseX, BaseY );
|
||||
const float tr = IntNoise2D( BaseX+1, BaseY );
|
||||
const float bl = IntNoise2D( BaseX, BaseY+1 );
|
||||
const float br = IntNoise2D( BaseX+1, BaseY+1 );
|
||||
|
||||
const float FracX = (a_X) - BaseX;
|
||||
const float interp1 = CosineInterpolate( tl, tr, FracX );
|
||||
const float interp2 = CosineInterpolate( bl, br, FracX );
|
||||
|
||||
const float FracY = (a_Y) - BaseY;
|
||||
return CosineInterpolate( interp1, interp2, FracY );
|
||||
}
|
||||
|
||||
float cNoise::CubicNoise2D( float a_X, float a_Y ) const
|
||||
{
|
||||
const int BaseX = FAST_FLOOR( a_X );
|
||||
const int BaseY = FAST_FLOOR( a_Y );
|
||||
|
||||
const float points[4][4] = {
|
||||
|
||||
IntNoise2D( BaseX-1, BaseY-1 ), IntNoise2D( BaseX, BaseY-1 ), IntNoise2D( BaseX+1, BaseY-1 ), IntNoise2D( BaseX+2, BaseY-1 ),
|
||||
IntNoise2D( BaseX-1, BaseY ), IntNoise2D( BaseX, BaseY ), IntNoise2D( BaseX+1, BaseY ), IntNoise2D( BaseX+2, BaseY ),
|
||||
IntNoise2D( BaseX-1, BaseY+1 ), IntNoise2D( BaseX, BaseY+1 ), IntNoise2D( BaseX+1, BaseY+1 ), IntNoise2D( BaseX+2, BaseY+1 ),
|
||||
IntNoise2D( BaseX-1, BaseY+2 ), IntNoise2D( BaseX, BaseY+2 ), IntNoise2D( BaseX+1, BaseY+2 ), IntNoise2D( BaseX+2, BaseY+2 ),
|
||||
|
||||
};
|
||||
|
||||
const float FracX = (a_X) - BaseX;
|
||||
const float interp1 = CubicInterpolate( points[0][0], points[0][1], points[0][2], points[0][3], FracX );
|
||||
const float interp2 = CubicInterpolate( points[1][0], points[1][1], points[1][2], points[1][3], FracX );
|
||||
const float interp3 = CubicInterpolate( points[2][0], points[2][1], points[2][2], points[2][3], FracX );
|
||||
const float interp4 = CubicInterpolate( points[3][0], points[3][1], points[3][2], points[3][3], FracX );
|
||||
|
||||
|
||||
const float FracY = (a_Y) - BaseY;
|
||||
return CubicInterpolate( interp1, interp2, interp3, interp4, FracY );
|
||||
}
|
||||
|
||||
/******************
|
||||
* Interpolated (and 1 smoothed) noise in 3-dimensions
|
||||
**/
|
||||
float cNoise::CosineNoise3D( float a_X, float a_Y, float a_Z ) const
|
||||
{
|
||||
const int BaseX = FAST_FLOOR( a_X );
|
||||
const int BaseY = FAST_FLOOR( a_Y );
|
||||
const int BaseZ = FAST_FLOOR( a_Z );
|
||||
|
||||
const float ftl = IntNoise3D( BaseX, BaseY, BaseZ );
|
||||
const float ftr = IntNoise3D( BaseX+1, BaseY, BaseZ );
|
||||
const float fbl = IntNoise3D( BaseX, BaseY+1, BaseZ );
|
||||
const float fbr = IntNoise3D( BaseX+1, BaseY+1, BaseZ );
|
||||
|
||||
const float btl = IntNoise3D( BaseX, BaseY, BaseZ+1 );
|
||||
const float btr = IntNoise3D( BaseX+1, BaseY, BaseZ+1 );
|
||||
const float bbl = IntNoise3D( BaseX, BaseY+1, BaseZ+1 );
|
||||
const float bbr = IntNoise3D( BaseX+1, BaseY+1, BaseZ+1 );
|
||||
|
||||
const float FracX = (a_X) - BaseX;
|
||||
const float finterp1 = CosineInterpolate( ftl, ftr, FracX );
|
||||
const float finterp2 = CosineInterpolate( fbl, fbr, FracX );
|
||||
const float binterp1 = CosineInterpolate( btl, btr, FracX );
|
||||
const float binterp2 = CosineInterpolate( bbl, bbr, FracX );
|
||||
|
||||
const float FracY = (a_Y) - BaseY;
|
||||
const float interp1 = CosineInterpolate( finterp1, finterp2, FracY );
|
||||
const float interp2 = CosineInterpolate( binterp1, binterp2, FracY );
|
||||
|
||||
const float FracZ = (a_Z) - BaseZ;
|
||||
return CosineInterpolate( interp1, interp2, FracZ );
|
||||
}
|
||||
|
||||
float cNoise::CubicNoise3D( float a_X, float a_Y, float a_Z ) const
|
||||
{
|
||||
const int BaseX = FAST_FLOOR( a_X );
|
||||
const int BaseY = FAST_FLOOR( a_Y );
|
||||
const int BaseZ = FAST_FLOOR( a_Z );
|
||||
|
||||
const float points1[4][4] = {
|
||||
IntNoise3D( BaseX-1, BaseY-1, BaseZ-1 ), IntNoise3D( BaseX, BaseY-1, BaseZ-1 ), IntNoise3D( BaseX+1, BaseY-1, BaseZ-1 ), IntNoise3D( BaseX+2, BaseY-1, BaseZ-1 ),
|
||||
IntNoise3D( BaseX-1, BaseY, BaseZ-1 ), IntNoise3D( BaseX, BaseY, BaseZ-1 ), IntNoise3D( BaseX+1, BaseY, BaseZ-1 ), IntNoise3D( BaseX+2, BaseY, BaseZ-1 ),
|
||||
IntNoise3D( BaseX-1, BaseY+1, BaseZ-1 ), IntNoise3D( BaseX, BaseY+1, BaseZ-1 ), IntNoise3D( BaseX+1, BaseY+1, BaseZ-1 ), IntNoise3D( BaseX+2, BaseY+1, BaseZ-1 ),
|
||||
IntNoise3D( BaseX-1, BaseY+2, BaseZ-1 ), IntNoise3D( BaseX, BaseY+2, BaseZ-1 ), IntNoise3D( BaseX+1, BaseY+2, BaseZ-1 ), IntNoise3D( BaseX+2, BaseY+2, BaseZ-1 ),
|
||||
};
|
||||
|
||||
const float FracX = (a_X) - BaseX;
|
||||
const float x1interp1 = CubicInterpolate( points1[0][0], points1[0][1], points1[0][2], points1[0][3], FracX );
|
||||
const float x1interp2 = CubicInterpolate( points1[1][0], points1[1][1], points1[1][2], points1[1][3], FracX );
|
||||
const float x1interp3 = CubicInterpolate( points1[2][0], points1[2][1], points1[2][2], points1[2][3], FracX );
|
||||
const float x1interp4 = CubicInterpolate( points1[3][0], points1[3][1], points1[3][2], points1[3][3], FracX );
|
||||
|
||||
const float points2[4][4] = {
|
||||
IntNoise3D( BaseX-1, BaseY-1, BaseZ ), IntNoise3D( BaseX, BaseY-1, BaseZ ), IntNoise3D( BaseX+1, BaseY-1, BaseZ ), IntNoise3D( BaseX+2, BaseY-1, BaseZ ),
|
||||
IntNoise3D( BaseX-1, BaseY, BaseZ ), IntNoise3D( BaseX, BaseY, BaseZ ), IntNoise3D( BaseX+1, BaseY, BaseZ ), IntNoise3D( BaseX+2, BaseY, BaseZ ),
|
||||
IntNoise3D( BaseX-1, BaseY+1, BaseZ ), IntNoise3D( BaseX, BaseY+1, BaseZ ), IntNoise3D( BaseX+1, BaseY+1, BaseZ ), IntNoise3D( BaseX+2, BaseY+1, BaseZ ),
|
||||
IntNoise3D( BaseX-1, BaseY+2, BaseZ ), IntNoise3D( BaseX, BaseY+2, BaseZ ), IntNoise3D( BaseX+1, BaseY+2, BaseZ ), IntNoise3D( BaseX+2, BaseY+2, BaseZ ),
|
||||
};
|
||||
|
||||
const float x2interp1 = CubicInterpolate( points2[0][0], points2[0][1], points2[0][2], points2[0][3], FracX );
|
||||
const float x2interp2 = CubicInterpolate( points2[1][0], points2[1][1], points2[1][2], points2[1][3], FracX );
|
||||
const float x2interp3 = CubicInterpolate( points2[2][0], points2[2][1], points2[2][2], points2[2][3], FracX );
|
||||
const float x2interp4 = CubicInterpolate( points2[3][0], points2[3][1], points2[3][2], points2[3][3], FracX );
|
||||
|
||||
const float points3[4][4] = {
|
||||
IntNoise3D( BaseX-1, BaseY-1, BaseZ+1 ), IntNoise3D( BaseX, BaseY-1, BaseZ+1 ), IntNoise3D( BaseX+1, BaseY-1, BaseZ+1 ), IntNoise3D( BaseX+2, BaseY-1, BaseZ+1 ),
|
||||
IntNoise3D( BaseX-1, BaseY, BaseZ+1 ), IntNoise3D( BaseX, BaseY, BaseZ+1 ), IntNoise3D( BaseX+1, BaseY, BaseZ+1 ), IntNoise3D( BaseX+2, BaseY, BaseZ+1 ),
|
||||
IntNoise3D( BaseX-1, BaseY+1, BaseZ+1 ), IntNoise3D( BaseX, BaseY+1, BaseZ+1 ), IntNoise3D( BaseX+1, BaseY+1, BaseZ+1 ), IntNoise3D( BaseX+2, BaseY+1, BaseZ+1 ),
|
||||
IntNoise3D( BaseX-1, BaseY+2, BaseZ+1 ), IntNoise3D( BaseX, BaseY+2, BaseZ+1 ), IntNoise3D( BaseX+1, BaseY+2, BaseZ+1 ), IntNoise3D( BaseX+2, BaseY+2, BaseZ+1 ),
|
||||
};
|
||||
|
||||
const float x3interp1 = CubicInterpolate( points3[0][0], points3[0][1], points3[0][2], points3[0][3], FracX );
|
||||
const float x3interp2 = CubicInterpolate( points3[1][0], points3[1][1], points3[1][2], points3[1][3], FracX );
|
||||
const float x3interp3 = CubicInterpolate( points3[2][0], points3[2][1], points3[2][2], points3[2][3], FracX );
|
||||
const float x3interp4 = CubicInterpolate( points3[3][0], points3[3][1], points3[3][2], points3[3][3], FracX );
|
||||
|
||||
const float points4[4][4] = {
|
||||
IntNoise3D( BaseX-1, BaseY-1, BaseZ+2 ), IntNoise3D( BaseX, BaseY-1, BaseZ+2 ), IntNoise3D( BaseX+1, BaseY-1, BaseZ+2 ), IntNoise3D( BaseX+2, BaseY-1, BaseZ+2 ),
|
||||
IntNoise3D( BaseX-1, BaseY, BaseZ+2 ), IntNoise3D( BaseX, BaseY, BaseZ+2 ), IntNoise3D( BaseX+1, BaseY, BaseZ+2 ), IntNoise3D( BaseX+2, BaseY, BaseZ+2 ),
|
||||
IntNoise3D( BaseX-1, BaseY+1, BaseZ+2 ), IntNoise3D( BaseX, BaseY+1, BaseZ+2 ), IntNoise3D( BaseX+1, BaseY+1, BaseZ+2 ), IntNoise3D( BaseX+2, BaseY+1, BaseZ+2 ),
|
||||
IntNoise3D( BaseX-1, BaseY+2, BaseZ+2 ), IntNoise3D( BaseX, BaseY+2, BaseZ+2 ), IntNoise3D( BaseX+1, BaseY+2, BaseZ+2 ), IntNoise3D( BaseX+2, BaseY+2, BaseZ+2 ),
|
||||
};
|
||||
|
||||
const float x4interp1 = CubicInterpolate( points4[0][0], points4[0][1], points4[0][2], points4[0][3], FracX );
|
||||
const float x4interp2 = CubicInterpolate( points4[1][0], points4[1][1], points4[1][2], points4[1][3], FracX );
|
||||
const float x4interp3 = CubicInterpolate( points4[2][0], points4[2][1], points4[2][2], points4[2][3], FracX );
|
||||
const float x4interp4 = CubicInterpolate( points4[3][0], points4[3][1], points4[3][2], points4[3][3], FracX );
|
||||
|
||||
const float FracY = (a_Y) - BaseY;
|
||||
const float yinterp1 = CubicInterpolate( x1interp1, x1interp2, x1interp3, x1interp4, FracY );
|
||||
const float yinterp2 = CubicInterpolate( x2interp1, x2interp2, x2interp3, x2interp4, FracY );
|
||||
const float yinterp3 = CubicInterpolate( x3interp1, x3interp2, x3interp3, x3interp4, FracY );
|
||||
const float yinterp4 = CubicInterpolate( x4interp1, x4interp2, x4interp3, x4interp4, FracY );
|
||||
|
||||
const float FracZ = (a_Z) - BaseZ;
|
||||
return CubicInterpolate( yinterp1, yinterp2, yinterp3, yinterp4, FracZ );
|
||||
}
|
||||
|
||||
/******************
|
||||
* Private
|
||||
**/
|
||||
float cNoise::CubicInterpolate( float a_A, float a_B, float a_C, float a_D, float a_Pct ) const
|
||||
{
|
||||
float P = (a_D - a_C) - (a_A - a_B);
|
||||
float Q = (a_A - a_B) - P;
|
||||
float R = a_C - a_A;
|
||||
float S = a_B;
|
||||
|
||||
return P*(a_Pct*a_Pct*a_Pct) + Q*(a_Pct*a_Pct) + R*a_Pct + S;
|
||||
}
|
||||
|
||||
float cNoise::CosineInterpolate( float a_A, float a_B, float a_Pct ) const
|
||||
{
|
||||
const float ft = a_Pct * 3.1415927f;
|
||||
const float f = (1.f - cosf(ft)) * 0.5f;
|
||||
return a_A*(1-f) + a_B*f;
|
||||
}
|
||||
|
||||
float cNoise::LinearInterpolate( float a_A, float a_B, float a_Pct ) const
|
||||
{
|
||||
return a_A*(1.f-a_Pct) + a_B*a_Pct;
|
||||
}
|
33
source/cNoise.h
Normal file
33
source/cNoise.h
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
class cNoise
|
||||
{
|
||||
public:
|
||||
cNoise( unsigned int a_Seed );
|
||||
~cNoise();
|
||||
|
||||
float IntNoise( int a_X ) const;
|
||||
float IntNoise2D( int a_X, int a_Y ) const;
|
||||
float IntNoise3D( int a_X, int a_Y, int a_Z ) const;
|
||||
|
||||
float LinearNoise1D( float a_X ) const;
|
||||
float CosineNoise1D( float a_X ) const;
|
||||
float CubicNoise1D( float a_X ) const;
|
||||
float SmoothNoise1D( int a_X ) const;
|
||||
|
||||
float LinearNoise2D( float a_X, float a_Y ) const;
|
||||
float CosineNoise2D( float a_X, float a_Y ) const;
|
||||
float CubicNoise2D( float a_X, float a_Y ) const;
|
||||
|
||||
float CosineNoise3D( float a_X, float a_Y, float a_Z ) const;
|
||||
float CubicNoise3D( float a_X, float a_Y, float a_Z ) const;
|
||||
|
||||
void SetSeed( unsigned int a_Seed ) { m_Seed = a_Seed; }
|
||||
private:
|
||||
float CubicInterpolate( float a_A, float a_B, float a_C, float a_D, float a_Pct ) const;
|
||||
float CosineInterpolate( float a_A, float a_B, float a_Pct ) const;
|
||||
float LinearInterpolate( float a_A, float a_B, float a_Pct ) const;
|
||||
|
||||
unsigned int m_Seed;
|
||||
};
|
||||
|
96
source/cPawn.cpp
Normal file
96
source/cPawn.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
#include "cPawn.h"
|
||||
#include "cRoot.h"
|
||||
#include "cServer.h"
|
||||
#include "cWorld.h"
|
||||
#include "cPlayer.h"
|
||||
#include "cChunk.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cPluginManager.h"
|
||||
|
||||
#include "packets/cPacket_TeleportEntity.h"
|
||||
#include "packets/cPacket_EntityStatus.h"
|
||||
|
||||
CLASS_DEFINITION( cPawn, cEntity )
|
||||
|
||||
cPawn::cPawn()
|
||||
: cEntity( 0, 0, 0 )
|
||||
, m_LastPosX( 0.0 )
|
||||
, m_LastPosY( 0.0 )
|
||||
, m_LastPosZ( 0.0 )
|
||||
, m_TimeLastTeleportPacket( 0.f )
|
||||
{
|
||||
m_Health = 20;
|
||||
}
|
||||
|
||||
cPawn::~cPawn()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void cPawn::Heal( int a_Health )
|
||||
{
|
||||
(void)a_Health;
|
||||
}
|
||||
|
||||
void cPawn::TakeDamage( int a_Damage, cEntity* a_Instigator )
|
||||
{
|
||||
TakeDamageInfo TDI;
|
||||
TDI.Damage = a_Damage;
|
||||
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
|
||||
|
||||
m_Health -= (short)TDI.Damage;
|
||||
if( m_Health < 0 ) m_Health = 0;
|
||||
|
||||
cPacket_EntityStatus Status;
|
||||
Status.m_UniqueID = GetUniqueID();
|
||||
Status.m_Status = cPacket_EntityStatus::STATUS_TAKEDAMAGE;
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
Chunk->Broadcast( Status );
|
||||
|
||||
if( m_Health <= 0 )
|
||||
KilledBy( TDI.Instigator );
|
||||
}
|
||||
|
||||
void cPawn::KilledBy( cEntity* a_Killer )
|
||||
{
|
||||
m_Health = 0;
|
||||
|
||||
if( cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_KILLED, 2, this, a_Killer ) )
|
||||
{
|
||||
return; // Give plugins a chance to 'unkill' the pawn.
|
||||
}
|
||||
|
||||
cPacket_EntityStatus Status;
|
||||
Status.m_UniqueID = GetUniqueID();
|
||||
Status.m_Status = cPacket_EntityStatus::STATUS_DIE;
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
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 );
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
if( IsA("cPlayer") )
|
||||
{
|
||||
cPlayer* Player = (cPlayer*)this;
|
||||
cRoot::Get()->GetServer()->Broadcast( TeleportEntity, Player->GetClientHandle() );
|
||||
}
|
||||
else
|
||||
{
|
||||
cRoot::Get()->GetServer()->Broadcast( TeleportEntity );
|
||||
}
|
||||
}
|
31
source/cPawn.h
Normal file
31
source/cPawn.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include "cEntity.h"
|
||||
|
||||
struct TakeDamageInfo //tolua_export
|
||||
{ //tolua_export
|
||||
int Damage; //tolua_export
|
||||
cEntity* Instigator; //tolua_export
|
||||
}; //tolua_export
|
||||
|
||||
class cPawn : public cEntity //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
CLASS_PROTOTYPE();
|
||||
|
||||
cPawn();
|
||||
virtual ~cPawn();
|
||||
|
||||
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
|
||||
|
||||
void Heal( int a_Health ); //tolua_export
|
||||
virtual void TakeDamage( int a_Damage, cEntity* a_Instigator ); //tolua_export
|
||||
virtual void KilledBy( cEntity* a_Killer ); //tolua_export
|
||||
int GetHealth() { return m_Health; } //tolua_export
|
||||
|
||||
protected:
|
||||
short m_Health;
|
||||
|
||||
double m_LastPosX, m_LastPosY, m_LastPosZ;
|
||||
float m_TimeLastTeleportPacket;
|
||||
}; //tolua_export
|
229
source/cPickup.cpp
Normal file
229
source/cPickup.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#ifndef _WIN32
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "cPickup.h"
|
||||
#include "cClientHandle.h"
|
||||
#include "cInventory.h"
|
||||
#include "cWorld.h"
|
||||
#include "cServer.h"
|
||||
#include "cPlayer.h"
|
||||
#include "cPluginManager.h"
|
||||
#include "cItem.h"
|
||||
#include "cRoot.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cTracer.h"
|
||||
#include "cChunk.h"
|
||||
|
||||
#include "packets/cPacket_TeleportEntity.h"
|
||||
#include "packets/cPacket_PickupSpawn.h"
|
||||
#include "packets/cPacket_CollectItem.h"
|
||||
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3f.h"
|
||||
|
||||
CLASS_DEFINITION( cPickup, cEntity )
|
||||
|
||||
cPickup::~cPickup()
|
||||
{
|
||||
delete m_Item;
|
||||
}
|
||||
|
||||
cPickup::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 */)
|
||||
: cEntity( ((double)(a_X))/32, ((double)(a_Y))/32, ((double)(a_Z))/32 )
|
||||
, m_Speed( new Vector3f( a_SpeedX, a_SpeedY, a_SpeedZ ) )
|
||||
, m_bOnGround( false )
|
||||
, m_bReplicated( false )
|
||||
, m_Timer( 0.f )
|
||||
, m_Item( new cItem( a_Item ) )
|
||||
, m_bCollected( false )
|
||||
{
|
||||
|
||||
//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);
|
||||
cRoot::Get()->GetServer()->Broadcast( PickupSpawn );
|
||||
|
||||
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_bOnGround( false )
|
||||
, m_bReplicated( false )
|
||||
, m_Timer( 0.f )
|
||||
, m_bCollected( false )
|
||||
{
|
||||
a_PickupSpawnPacket->m_UniqueID = m_UniqueID;
|
||||
|
||||
m_Item = new cItem();
|
||||
m_Item->m_ItemID = (ENUM_ITEM_ID)a_PickupSpawnPacket->m_Item;
|
||||
m_Item->m_ItemCount = a_PickupSpawnPacket->m_Count;
|
||||
m_Item->m_ItemHealth = 0x0;
|
||||
|
||||
m_Speed->x = (float)(a_PickupSpawnPacket->m_Rotation) / 8;
|
||||
m_Speed->y = (float)(a_PickupSpawnPacket->m_Pitch) / 8;
|
||||
m_Speed->z = (float)(a_PickupSpawnPacket->m_Roll) / 8;
|
||||
|
||||
// Spawn it on clients
|
||||
cRoot::Get()->GetServer()->Broadcast( *a_PickupSpawnPacket );
|
||||
|
||||
m_EntityType = E_PICKUP;
|
||||
}
|
||||
|
||||
void cPickup::SpawnOn( cClientHandle* a_Target )
|
||||
{
|
||||
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);
|
||||
a_Target->Send( PickupSpawn );
|
||||
}
|
||||
|
||||
void cPickup::Tick(float a_Dt)
|
||||
{
|
||||
m_Timer+=a_Dt;
|
||||
a_Dt = a_Dt / 1000.f;
|
||||
if(m_bCollected)
|
||||
{
|
||||
if(m_Timer > 500.f) // 0.5 second
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_Timer > 1000*60*5 ) // 5 minutes
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
if( m_Pos->y < 0 ) // Out of this world!
|
||||
{
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
|
||||
HandlePhysics( a_Dt );
|
||||
|
||||
if( !m_bReplicated || m_bDirtyPosition )
|
||||
{
|
||||
MoveToCorrectChunk();
|
||||
m_bReplicated = true;
|
||||
m_bDirtyPosition = false;
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
{
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
Chunk->Broadcast( TeleportEntity );
|
||||
}
|
||||
}
|
||||
|
||||
//printf("YSpeed: %f, OnGround: %i\n", m_SpeedY, m_bOnGround );
|
||||
}
|
||||
|
||||
void cPickup::HandlePhysics(float a_Dt)
|
||||
{
|
||||
if( m_bOnGround ) // check if it's still on the ground
|
||||
{
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
int BlockX = (int)m_Pos->x;
|
||||
if( m_Pos->x < 0 ) BlockX--;
|
||||
int BlockZ = (int)m_Pos->z;
|
||||
if( m_Pos->z < 0 ) BlockZ--;
|
||||
if( World->GetBlock( BlockX, (int)m_Pos->y -1, BlockZ ) == E_BLOCK_AIR )
|
||||
{
|
||||
m_bOnGround = false;
|
||||
}
|
||||
if( World->GetBlock( BlockX, (int)m_Pos->y, BlockZ ) != E_BLOCK_AIR ) // If in ground itself, push it out
|
||||
{
|
||||
m_bOnGround = true;
|
||||
m_Pos->y += 0.2;
|
||||
m_bReplicated = false;
|
||||
}
|
||||
m_Speed->x *= 0.7f/(1+a_Dt);
|
||||
if( fabs(m_Speed->x) < 0.05 ) m_Speed->x = 0;
|
||||
m_Speed->z *= 0.7f/(1+a_Dt);
|
||||
if( fabs(m_Speed->z) < 0.05 ) m_Speed->z = 0;
|
||||
}
|
||||
|
||||
if( !m_bOnGround )
|
||||
{
|
||||
|
||||
float Gravity = -9.81f*a_Dt;
|
||||
m_Speed->y += Gravity;
|
||||
|
||||
cTracer Tracer( cRoot::Get()->GetWorld() );
|
||||
int Ret = Tracer.Trace( *m_Pos, *m_Speed, 2 );
|
||||
if( Ret ) // Oh noez! we hit something
|
||||
{
|
||||
// Set to hit position
|
||||
if( (*Tracer.RealHit - Vector3f(*m_Pos)).SqrLength() <= ( *m_Speed * a_Dt ).SqrLength() )
|
||||
{
|
||||
m_bReplicated = false; // It's only interesting to replicate when we actually hit something...
|
||||
if( Ret == 1 )
|
||||
{
|
||||
|
||||
if( Tracer.HitNormal->x != 0.f ) m_Speed->x = 0.f;
|
||||
if( Tracer.HitNormal->y != 0.f ) m_Speed->y = 0.f;
|
||||
if( Tracer.HitNormal->z != 0.f ) m_Speed->z = 0.f;
|
||||
|
||||
if( Tracer.HitNormal->y > 0 ) // means on ground
|
||||
{
|
||||
m_bOnGround = true;
|
||||
}
|
||||
}
|
||||
*m_Pos = Tracer.RealHit;
|
||||
*m_Pos += *Tracer.HitNormal * 0.2;
|
||||
|
||||
}
|
||||
else
|
||||
*m_Pos += *m_Speed*a_Dt;
|
||||
}
|
||||
else
|
||||
{ // We didn't hit anything, so move =]
|
||||
*m_Pos += *m_Speed*a_Dt;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cPickup::CollectedBy( cPlayer* a_Dest )
|
||||
{
|
||||
if(m_bCollected) return false; // It's already collected!
|
||||
if(m_Timer < 1000.f) return false; // Not old enough
|
||||
|
||||
if( cRoot::Get()->GetPluginManager()->CallHook( cPluginManager::E_PLUGIN_COLLECT_ITEM, 2, this, a_Dest ) ) return false;
|
||||
|
||||
if( a_Dest->GetInventory().AddItem( *m_Item ) )
|
||||
{
|
||||
cPacket_CollectItem CollectItem;
|
||||
CollectItem.m_CollectedID = m_UniqueID;
|
||||
CollectItem.m_CollectorID = a_Dest->GetUniqueID();
|
||||
cRoot::Get()->GetServer()->Broadcast( CollectItem );
|
||||
|
||||
m_bCollected = true;
|
||||
m_Timer = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
34
source/cPickup.h
Normal file
34
source/cPickup.h
Normal file
@ -0,0 +1,34 @@
|
||||
#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(); //tolua_export
|
||||
|
||||
cItem* GetItem() { return m_Item; } //tolua_export
|
||||
|
||||
void SpawnOn( cClientHandle* a_Target );
|
||||
virtual bool CollectedBy( cPlayer* a_Dest ); //tolua_export
|
||||
|
||||
void Tick(float a_Dt);
|
||||
void HandlePhysics(float a_Dt);
|
||||
private:
|
||||
Vector3f* m_Speed;
|
||||
bool m_bOnGround;
|
||||
bool m_bReplicated;
|
||||
|
||||
float m_Timer;
|
||||
|
||||
cItem* m_Item;
|
||||
|
||||
bool m_bCollected;
|
||||
};//tolua_export
|
713
source/cPlayer.cpp
Normal file
713
source/cPlayer.cpp
Normal file
@ -0,0 +1,713 @@
|
||||
#include "cPlayer.h"
|
||||
#include "cServer.h"
|
||||
#include "cInventory.h"
|
||||
#include "cClientHandle.h"
|
||||
#include "cWorld.h"
|
||||
#include "cPickup.h"
|
||||
#include "cPluginManager.h"
|
||||
#include "cChunk.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cWindow.h"
|
||||
#include "cBlockEntity.h"
|
||||
#include "cGroupManager.h"
|
||||
#include "cGroup.h"
|
||||
#include "cChatColor.h"
|
||||
#include "cItem.h"
|
||||
#include "cTracer.h"
|
||||
#include "cRoot.h"
|
||||
|
||||
#include "packets/cPacket_NamedEntitySpawn.h"
|
||||
#include "packets/cPacket_EntityLook.h"
|
||||
#include "packets/cPacket_TeleportEntity.h"
|
||||
#include "packets/cPacket_RelativeEntityMove.h"
|
||||
#include "packets/cPacket_RelativeEntityMoveLook.h"
|
||||
#include "packets/cPacket_UpdateHealth.h"
|
||||
#include "packets/cPacket_Respawn.h"
|
||||
#include "packets/cPacket_PlayerPosition.h"
|
||||
#include "packets/cPacket_DestroyEntity.h"
|
||||
#include "packets/cPacket_Metadata.h"
|
||||
#include "packets/cPacket_Chat.h"
|
||||
|
||||
#include "Vector3d.h"
|
||||
#include "Vector3f.h"
|
||||
|
||||
#include "../iniFile/iniFile.h"
|
||||
|
||||
#ifndef _WIN32 // for mkdir
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
extern std::vector< std::string > StringSplit( std::string str, std::string delim);
|
||||
|
||||
CLASS_DEFINITION( cPlayer, cPawn );
|
||||
|
||||
typedef std::map< std::string, bool > PermissionMap;
|
||||
struct cPlayer::sPlayerState
|
||||
{
|
||||
PermissionMap ResolvedPermissions;
|
||||
PermissionMap Permissions;
|
||||
|
||||
cPlayer::GroupList ResolvedGroups;
|
||||
cPlayer::GroupList Groups;
|
||||
|
||||
std::string PlayerName;
|
||||
};
|
||||
|
||||
cPlayer::cPlayer(cClientHandle* a_Client, const char* a_PlayerName)
|
||||
: m_bBurnable(true)
|
||||
, e_EPMetaState(NORMAL)
|
||||
, m_bVisible( true )
|
||||
, m_LastGroundHeight( 0 )
|
||||
, m_bTouchGround( false )
|
||||
, m_Stance( 0.0 )
|
||||
, m_Inventory( 0 )
|
||||
, m_CurrentWindow( 0 )
|
||||
, m_TimeLastPickupCheck( 0.f )
|
||||
, m_Color('-')
|
||||
, m_FireDamageInterval(0)
|
||||
, m_BurnPeriod(0)
|
||||
, m_ClientHandle( a_Client )
|
||||
, m_pState( new sPlayerState )
|
||||
{
|
||||
m_EntityType = E_PLAYER;
|
||||
m_Inventory = new cInventory( this );
|
||||
|
||||
m_TimeLastTeleportPacket = cWorld::GetTime();
|
||||
m_TimeLastPickupCheck = cWorld::GetTime();
|
||||
|
||||
m_pState->PlayerName = a_PlayerName;
|
||||
m_bDirtyPosition = true; // So chunks are streamed to player at spawn
|
||||
|
||||
if( !LoadFromDisk() )
|
||||
{
|
||||
m_Inventory->Clear();
|
||||
SetPosX( cRoot::Get()->GetWorld()->GetSpawnX() );
|
||||
SetPosY( cRoot::Get()->GetWorld()->GetSpawnY() );
|
||||
SetPosZ( cRoot::Get()->GetWorld()->GetSpawnZ() );
|
||||
}
|
||||
|
||||
MoveToCorrectChunk();
|
||||
cRoot::Get()->GetWorld()->AddPlayer( this );
|
||||
}
|
||||
|
||||
cPlayer::~cPlayer(void)
|
||||
{
|
||||
SaveToDisk();
|
||||
m_ClientHandle = 0;
|
||||
CloseWindow();
|
||||
if( m_Inventory )
|
||||
{
|
||||
delete m_Inventory;
|
||||
m_Inventory = 0;
|
||||
}
|
||||
delete m_pState;
|
||||
cRoot::Get()->GetWorld()->RemovePlayer( this );
|
||||
}
|
||||
|
||||
void cPlayer::SpawnOn( cClientHandle* a_Target )
|
||||
{
|
||||
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():"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 )
|
||||
{
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
Chunk->Broadcast( SpawnPacket, m_ClientHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
a_Target->Send( SpawnPacket );
|
||||
}
|
||||
}
|
||||
|
||||
void cPlayer::Tick(float a_Dt)
|
||||
{
|
||||
cChunk* InChunk = cRoot::Get()->GetWorld()->GetChunk( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if(m_bDirtyOrientation && !m_bDirtyPosition)
|
||||
{
|
||||
cPacket_EntityLook EntityLook( this );
|
||||
InChunk->Broadcast( EntityLook, m_ClientHandle );
|
||||
m_bDirtyOrientation = false;
|
||||
}
|
||||
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
|
||||
{
|
||||
//LOG("Teleported %f", sqrtf(SqrDist) );
|
||||
cPacket_TeleportEntity TeleportEntity( this );
|
||||
InChunk->Broadcast( TeleportEntity, m_ClientHandle );
|
||||
m_TimeLastTeleportPacket = cWorld::GetTime();
|
||||
}
|
||||
else
|
||||
{ // Relative move sucks balls! It's always wrong wtf!
|
||||
if( m_bDirtyOrientation )
|
||||
{
|
||||
cPacket_RelativeEntityMoveLook RelativeEntityMoveLook;
|
||||
RelativeEntityMoveLook.m_UniqueID = GetUniqueID();
|
||||
RelativeEntityMoveLook.m_MoveX = (char)(DiffX*32);
|
||||
RelativeEntityMoveLook.m_MoveY = (char)(DiffY*32);
|
||||
RelativeEntityMoveLook.m_MoveZ = (char)(DiffZ*32);
|
||||
RelativeEntityMoveLook.m_Yaw = (char)((GetRotation()/360.f)*256);
|
||||
RelativeEntityMoveLook.m_Pitch = (char)((GetPitch()/360.f)*256);
|
||||
InChunk->Broadcast( RelativeEntityMoveLook, m_ClientHandle );
|
||||
}
|
||||
else
|
||||
{
|
||||
cPacket_RelativeEntityMove RelativeEntityMove;
|
||||
RelativeEntityMove.m_UniqueID = GetUniqueID();
|
||||
RelativeEntityMove.m_MoveX = (char)(DiffX*32);
|
||||
RelativeEntityMove.m_MoveY = (char)(DiffY*32);
|
||||
RelativeEntityMove.m_MoveZ = (char)(DiffZ*32);
|
||||
InChunk->Broadcast( RelativeEntityMove, m_ClientHandle );
|
||||
}
|
||||
}
|
||||
m_LastPosX = GetPosX();
|
||||
m_LastPosY = GetPosY();
|
||||
m_LastPosZ = GetPosZ();
|
||||
m_bDirtyPosition = false;
|
||||
m_ClientHandle->StreamChunks();
|
||||
}
|
||||
|
||||
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 = cRoot::Get()->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();
|
||||
}
|
||||
}
|
||||
CheckMetaDataBurn();
|
||||
if(e_EPMetaState == BURNING){
|
||||
InStateBurning(a_Dt);
|
||||
}
|
||||
}
|
||||
|
||||
void cPlayer::InStateBurning(float a_Dt) {
|
||||
m_FireDamageInterval += a_Dt;
|
||||
char block = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z );
|
||||
char bblock = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y -1, (int)m_Pos->z );
|
||||
if(m_FireDamageInterval > 1000) {
|
||||
|
||||
m_FireDamageInterval = 0;
|
||||
int rem = rand()%3 + 1; //Burn most of the time
|
||||
if(rem >= 2) {
|
||||
//printf("OUCH burning!!!\n");
|
||||
TakeDamage(1, this);
|
||||
}
|
||||
m_BurnPeriod++;
|
||||
if(block == E_BLOCK_LAVA || block == E_BLOCK_STATIONARY_LAVA || block == E_BLOCK_FIRE
|
||||
|| bblock == E_BLOCK_LAVA || bblock == E_BLOCK_STATIONARY_LAVA || bblock == E_BLOCK_FIRE)
|
||||
m_BurnPeriod = 0;
|
||||
|
||||
if(m_BurnPeriod > 5) {
|
||||
|
||||
cChunk* InChunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
e_EPMetaState = NORMAL;
|
||||
cPacket_Metadata md(NORMAL, GetUniqueID());
|
||||
//md.m_UniqueID = GetUniqueID();
|
||||
InChunk->Broadcast(md);
|
||||
m_BurnPeriod = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//----Change Entity MetaData
|
||||
void cPlayer::CheckMetaDataBurn() {
|
||||
char block = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z );
|
||||
char bblock = cRoot::Get()->GetWorld()->GetBlock( (int)m_Pos->x, (int)m_Pos->y -1, (int)m_Pos->z );
|
||||
if(m_bBurnable && e_EPMetaState != BURNING && (block == E_BLOCK_LAVA || block == E_BLOCK_STATIONARY_LAVA || block == E_BLOCK_FIRE
|
||||
|| bblock == E_BLOCK_LAVA || bblock == E_BLOCK_STATIONARY_LAVA || bblock == E_BLOCK_FIRE)) {
|
||||
cChunk* InChunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if(!InChunk)
|
||||
return;
|
||||
printf("I should burn");
|
||||
e_EPMetaState = BURNING;
|
||||
cPacket_Metadata md(BURNING,GetUniqueID());
|
||||
InChunk->Broadcast(md);
|
||||
}
|
||||
}
|
||||
|
||||
void cPlayer::SetTouchGround( bool a_bTouchGround )
|
||||
{
|
||||
m_bTouchGround = a_bTouchGround;
|
||||
|
||||
if( !m_bTouchGround )
|
||||
{
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
char BlockID = World->GetBlock( (int)m_Pos->x, (int)m_Pos->y, (int)m_Pos->z );
|
||||
if( BlockID != E_BLOCK_AIR )
|
||||
{
|
||||
m_bTouchGround = true;
|
||||
}
|
||||
if( BlockID == E_BLOCK_WATER || BlockID == E_BLOCK_STATIONARY_WATER || BlockID == E_BLOCK_LADDER || BlockID == E_BLOCK_TORCH )
|
||||
{
|
||||
m_LastGroundHeight = (float)m_Pos->y;
|
||||
}
|
||||
}
|
||||
|
||||
if( m_bTouchGround )
|
||||
{
|
||||
float Dist = (float)(m_LastGroundHeight - m_Pos->y);
|
||||
if( Dist > 4.f ) // Player dropped
|
||||
{
|
||||
int Damage = (int)(Dist - 4.f);
|
||||
if( Damage > 0 )
|
||||
{
|
||||
TakeDamage( Damage, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
m_LastGroundHeight = (float)m_Pos->y;
|
||||
}
|
||||
}
|
||||
|
||||
void cPlayer::Heal( int a_Health )
|
||||
{
|
||||
if( m_Health < 20 )
|
||||
{
|
||||
m_Health += (short)a_Health;
|
||||
if( m_Health > 20 )
|
||||
{
|
||||
m_Health = 20;
|
||||
}
|
||||
|
||||
cPacket_UpdateHealth Health;
|
||||
Health.m_Health = m_Health;
|
||||
m_ClientHandle->Send( Health );
|
||||
}
|
||||
}
|
||||
|
||||
void cPlayer::TakeDamage( int a_Damage, cEntity* a_Instigator )
|
||||
{
|
||||
cPawn::TakeDamage( a_Damage, a_Instigator );
|
||||
|
||||
cPacket_UpdateHealth Health;
|
||||
Health.m_Health = m_Health;
|
||||
m_ClientHandle->Send( Health );
|
||||
}
|
||||
|
||||
void cPlayer::KilledBy( cEntity* a_Killer )
|
||||
{
|
||||
cPawn::KilledBy( a_Killer );
|
||||
|
||||
if( m_Health > 0 ) return; // not dead yet =]
|
||||
|
||||
m_bVisible = false; // So new clients don't see the player
|
||||
|
||||
// Puke out all the items
|
||||
cItem* Items = m_Inventory->GetSlots();
|
||||
for( unsigned int i = 1; i < m_Inventory->c_NumSlots; ++i )
|
||||
{
|
||||
if( !Items[i].IsEmpty() )
|
||||
{
|
||||
float SpeedX = ((rand()%1000)-500) /100.f;
|
||||
float SpeedY = ((rand()%1000)) /100.f;
|
||||
float SpeedZ = ((rand()%1000)-500) /100.f;
|
||||
cPickup* Pickup = new cPickup( (int)(m_Pos->x*32), (int)(m_Pos->y*32), (int)(m_Pos->z*32), Items[i], SpeedX, SpeedY, SpeedZ );
|
||||
Pickup->Initialize();
|
||||
}
|
||||
Items[i].Empty();
|
||||
}
|
||||
SaveToDisk(); // Save it, yeah the world is a tough place !
|
||||
}
|
||||
|
||||
void cPlayer::Respawn()
|
||||
{
|
||||
m_Health = 20;
|
||||
|
||||
cWorld* World = cRoot::Get()->GetWorld();
|
||||
m_ClientHandle->Send( cPacket_Respawn() );
|
||||
TeleportTo( World->GetSpawnX(), World->GetSpawnY(), World->GetSpawnZ() );
|
||||
SetVisible( true );
|
||||
}
|
||||
|
||||
double cPlayer::GetEyeHeight()
|
||||
{
|
||||
return m_Stance;
|
||||
}
|
||||
|
||||
Vector3d cPlayer::GetEyePosition()
|
||||
{
|
||||
return Vector3d( m_Pos->x, m_Stance, m_Pos->z );
|
||||
}
|
||||
|
||||
void cPlayer::OpenWindow( cWindow* a_Window )
|
||||
{
|
||||
CloseWindow();
|
||||
a_Window->Open( *this );
|
||||
m_CurrentWindow = a_Window;
|
||||
}
|
||||
|
||||
void cPlayer::CloseWindow()
|
||||
{
|
||||
if( m_CurrentWindow ) m_CurrentWindow->Close( *this );
|
||||
m_CurrentWindow = 0;
|
||||
}
|
||||
|
||||
#ifdef SendMessage // Cause stupid windows.h defines SendMessage as SendMessageA
|
||||
#undef SendMessage
|
||||
#endif
|
||||
void cPlayer::SendMessage( const char* a_Message )
|
||||
{
|
||||
m_ClientHandle->Send( cPacket_Chat( a_Message ) );
|
||||
}
|
||||
|
||||
void cPlayer::TeleportTo( cEntity* a_Entity )
|
||||
{
|
||||
cPawn::TeleportTo( a_Entity );
|
||||
cPacket_PlayerPosition PlayerPosition( this );
|
||||
m_ClientHandle->Send( PlayerPosition );
|
||||
}
|
||||
|
||||
void cPlayer::TeleportTo( const double & a_PosX, const double & a_PosY, const double & a_PosZ )
|
||||
{
|
||||
cPawn::TeleportTo( a_PosX, a_PosY, a_PosZ );
|
||||
cPacket_PlayerPosition PlayerPosition( this );
|
||||
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
|
||||
{
|
||||
m_bVisible = true;
|
||||
SpawnOn( 0 ); // Spawn on everybody
|
||||
}
|
||||
if( a_bVisible == false && m_bVisible == true )
|
||||
{
|
||||
m_bVisible = false;
|
||||
cPacket_DestroyEntity DestroyEntity( this );
|
||||
cChunk* Chunk = cRoot::Get()->GetWorld()->GetChunkUnreliable( m_ChunkX, m_ChunkY, m_ChunkZ );
|
||||
if( Chunk )
|
||||
{
|
||||
Chunk->Broadcast( DestroyEntity ); // Destroy on all clients
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cPlayer::AddToGroup( const char* a_GroupName )
|
||||
{
|
||||
cGroup* Group = cRoot::Get()->GetGroupManager()->GetGroup( a_GroupName );
|
||||
m_pState->Groups.push_back( Group );
|
||||
LOG("Added %s to group %s", m_pState->PlayerName.c_str(), a_GroupName );
|
||||
ResolveGroups();
|
||||
ResolvePermissions();
|
||||
}
|
||||
|
||||
bool cPlayer::CanUseCommand( const char* a_Command )
|
||||
{
|
||||
for( GroupList::iterator itr = m_pState->Groups.begin(); itr != m_pState->Groups.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->HasCommand( a_Command ) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPlayer::HasPermission( const char* a_Permission )
|
||||
{
|
||||
std::vector< std::string > Split = StringSplit( a_Permission, "." );
|
||||
PermissionMap Possibilities = m_pState->ResolvedPermissions;
|
||||
// Now search the namespaces
|
||||
while( Possibilities.begin() != Possibilities.end() )
|
||||
{
|
||||
PermissionMap::iterator itr = Possibilities.begin();
|
||||
if( itr->second )
|
||||
{
|
||||
std::vector< std::string > OtherSplit = StringSplit( itr->first, "." );
|
||||
if( OtherSplit.size() <= Split.size() )
|
||||
{
|
||||
unsigned int i;
|
||||
for( i = 0; i < OtherSplit.size(); ++i )
|
||||
{
|
||||
if( OtherSplit[i].compare( Split[i] ) != 0 )
|
||||
{
|
||||
if( OtherSplit[i].compare("*") == 0 ) return true; // WildCard man!! WildCard!
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( i == Split.size() ) return true;
|
||||
}
|
||||
}
|
||||
Possibilities.erase( itr );
|
||||
}
|
||||
|
||||
// Nothing that matched :(
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPlayer::IsInGroup( const char* a_Group )
|
||||
{
|
||||
for( GroupList::iterator itr = m_pState->ResolvedGroups.begin(); itr != m_pState->ResolvedGroups.end(); ++itr )
|
||||
{
|
||||
if( strcmp( a_Group, (*itr)->GetName().c_str() ) == 0 )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPlayer::ResolvePermissions()
|
||||
{
|
||||
m_pState->ResolvedPermissions.clear(); // Start with an empty map yo~
|
||||
|
||||
// Copy all player specific permissions into the resolved permissions map
|
||||
for( PermissionMap::iterator itr = m_pState->Permissions.begin(); itr != m_pState->Permissions.end(); ++itr )
|
||||
{
|
||||
m_pState->ResolvedPermissions[ itr->first ] = itr->second;
|
||||
}
|
||||
|
||||
for( GroupList::iterator GroupItr = m_pState->ResolvedGroups.begin(); GroupItr != m_pState->ResolvedGroups.end(); ++GroupItr )
|
||||
{
|
||||
const cGroup::PermissionMap & Permissions = (*GroupItr)->GetPermissions();
|
||||
for( cGroup::PermissionMap::const_iterator itr = Permissions.begin(); itr != Permissions.end(); ++itr )
|
||||
{
|
||||
m_pState->ResolvedPermissions[ itr->first ] = itr->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cPlayer::ResolveGroups()
|
||||
{
|
||||
// Clear resolved groups first
|
||||
m_pState->ResolvedGroups.clear();
|
||||
|
||||
// Get a complete resolved list of all groups the player is in
|
||||
std::map< cGroup*, bool > AllGroups; // Use a map, because it's faster than iterating through a list to find duplicates
|
||||
GroupList ToIterate;
|
||||
for( GroupList::iterator GroupItr = m_pState->Groups.begin(); GroupItr != m_pState->Groups.end(); ++GroupItr )
|
||||
{
|
||||
ToIterate.push_back( *GroupItr );
|
||||
}
|
||||
while( ToIterate.begin() != ToIterate.end() )
|
||||
{
|
||||
cGroup* CurrentGroup = *ToIterate.begin();
|
||||
if( AllGroups.find( CurrentGroup ) != AllGroups.end() )
|
||||
{
|
||||
LOGERROR("ERROR: Player %s is in the same group multiple times (%s). FIX IT!", m_pState->PlayerName.c_str(), CurrentGroup->GetName().c_str() );
|
||||
}
|
||||
else
|
||||
{
|
||||
AllGroups[ CurrentGroup ] = true;
|
||||
m_pState->ResolvedGroups.push_back( CurrentGroup ); // Add group to resolved list
|
||||
const cGroup::GroupList & Inherits = CurrentGroup->GetInherits();
|
||||
for( cGroup::GroupList::const_iterator itr = Inherits.begin(); itr != Inherits.end(); ++itr )
|
||||
{
|
||||
if( AllGroups.find( *itr ) != AllGroups.end() )
|
||||
{
|
||||
LOGERROR("ERROR: Player %s is in the same group multiple times due to inheritance (%s). FIX IT!", m_pState->PlayerName.c_str(), (*itr)->GetName().c_str() );
|
||||
continue;
|
||||
}
|
||||
ToIterate.push_back( *itr );
|
||||
}
|
||||
}
|
||||
ToIterate.erase( ToIterate.begin() );
|
||||
}
|
||||
}
|
||||
|
||||
std::string cPlayer::GetColor()
|
||||
{
|
||||
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 )
|
||||
{
|
||||
cItem* Item = GetInventory().GetWindow()->GetDraggingItem();
|
||||
if( Item->m_ItemID > 0 && Item->m_ItemCount >= a_Amount )
|
||||
{
|
||||
float vX = 0, vY = 0, vZ = 0;
|
||||
EulerToVector( -GetRotation(), GetPitch(), vZ, vX, vY );
|
||||
vY = -vY*2 + 1.f;
|
||||
cPickup* Pickup = new cPickup( (int)(GetPosX()*32), (int)(GetPosY()*32) + (int)(1.6f*32), (int)(GetPosZ()*32), cItem( Item->m_ItemID, (char)a_Amount, Item->m_ItemHealth), vX*2, vY*2, vZ*2 );
|
||||
Pickup->Initialize();
|
||||
if( Item->m_ItemCount > a_Amount )
|
||||
Item->m_ItemCount -= (char)a_Amount;
|
||||
else
|
||||
Item->Empty();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Else drop equipped item
|
||||
cItem DroppedItem = GetInventory().GetEquippedItem();
|
||||
if( DroppedItem.m_ItemID > 0 && DroppedItem.m_ItemCount > 0 )
|
||||
{
|
||||
DroppedItem.m_ItemCount = 1;
|
||||
if( GetInventory().RemoveItem( DroppedItem ) )
|
||||
{
|
||||
DroppedItem.m_ItemCount = 1; // RemoveItem decreases the count, so set it to 1 again
|
||||
float vX = 0, vY = 0, vZ = 0;
|
||||
EulerToVector( -GetRotation(), GetPitch(), vZ, vX, vY );
|
||||
vY = -vY*2 + 1.f;
|
||||
cPickup* Pickup = new cPickup( (int)(GetPosX()*32), (int)(GetPosY()*32) + (int)(1.6f*32), (int)(GetPosZ()*32), DroppedItem, vX*2, vY*2, vZ*2 );
|
||||
Pickup->Initialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cPlayer::LoadFromDisk()
|
||||
{
|
||||
cIniFile IniFile("users.ini");
|
||||
if( IniFile.ReadFile() )
|
||||
{
|
||||
std::string Groups = IniFile.GetValue(m_pState->PlayerName, "Groups", "");
|
||||
if( Groups.size() > 0 )
|
||||
{
|
||||
std::vector< std::string > Split = StringSplit( Groups, "," );
|
||||
for( unsigned int i = 0; i < Split.size(); i++ )
|
||||
{
|
||||
AddToGroup( Split[i].c_str() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
AddToGroup("Default");
|
||||
}
|
||||
|
||||
m_Color = IniFile.GetValue(m_pState->PlayerName, "Color", "-")[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
AddToGroup("Default");
|
||||
}
|
||||
ResolvePermissions();
|
||||
|
||||
// Log player permissions, cause it's what the cool kids do
|
||||
LOGINFO("Player %s has permissions:", m_pState->PlayerName.c_str() );
|
||||
for( PermissionMap::iterator itr = m_pState->ResolvedPermissions.begin(); itr != m_pState->ResolvedPermissions.end(); ++itr )
|
||||
{
|
||||
if( itr->second ) LOGINFO("%s", itr->first.c_str() );
|
||||
}
|
||||
|
||||
char SourceFile[128];
|
||||
sprintf_s(SourceFile, 128, "world/player/%s.bin", m_pState->PlayerName.c_str() );
|
||||
|
||||
FILE* f;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, SourceFile, "rb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(SourceFile, "rb" ) ) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
if( fread( &m_Pos->x, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &m_Pos->y, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &m_Pos->z, sizeof(double), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &m_Rot->x, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &m_Rot->y, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &m_Rot->z, sizeof(float), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( fread( &m_Health, sizeof(m_Health), 1, f) != 1 ) { LOGERROR("ERROR READING FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
if( !m_Inventory->LoadFromFile( f ) ) { LOGERROR("ERROR READING INVENTORY FROM FILE %s", SourceFile); fclose(f); return false; }
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPlayer::SaveToDisk()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
{ // Make sure some folders exist
|
||||
SECURITY_ATTRIBUTES Attrib;
|
||||
Attrib.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
Attrib.lpSecurityDescriptor = NULL;
|
||||
Attrib.bInheritHandle = false;
|
||||
::CreateDirectory("world", &Attrib);
|
||||
::CreateDirectory("world/player", &Attrib);
|
||||
}
|
||||
#else
|
||||
{
|
||||
mkdir("world", S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
mkdir("world/player", S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
}
|
||||
#endif
|
||||
|
||||
char SourceFile[128];
|
||||
sprintf_s(SourceFile, 128, "world/player/%s.bin", m_pState->PlayerName.c_str() );
|
||||
|
||||
FILE* f;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, SourceFile, "wb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(SourceFile, "wb" ) ) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
fwrite( &m_Pos->x, sizeof(double), 1, f );
|
||||
fwrite( &m_Pos->y, sizeof(double), 1, f );
|
||||
fwrite( &m_Pos->z, sizeof(double), 1, f );
|
||||
fwrite( &m_Rot->x, sizeof(float), 1, f );
|
||||
fwrite( &m_Rot->y, sizeof(float), 1, f );
|
||||
fwrite( &m_Rot->z, sizeof(float), 1, f );
|
||||
fwrite( &m_Health, sizeof(m_Health), 1, f );
|
||||
m_Inventory->WriteToFile( f );
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
LOGERROR("ERROR WRITING PLAYER %s TO FILE %s", m_pState->PlayerName.c_str(), SourceFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const char* cPlayer::GetName()
|
||||
{
|
||||
return m_pState->PlayerName.c_str();
|
||||
}
|
||||
|
||||
void cPlayer::SetName( const char* a_Name )
|
||||
{
|
||||
m_pState->PlayerName = a_Name;
|
||||
}
|
||||
|
||||
const cPlayer::GroupList & cPlayer::GetGroups()
|
||||
{
|
||||
return m_pState->Groups;
|
||||
}
|
96
source/cPlayer.h
Normal file
96
source/cPlayer.h
Normal file
@ -0,0 +1,96 @@
|
||||
#pragma once
|
||||
|
||||
#include "cPawn.h"
|
||||
#include <list>
|
||||
|
||||
class cGroup;
|
||||
class cWindow;
|
||||
class cInventory;
|
||||
class cClientHandle;
|
||||
class cPlayer : public cPawn //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
CLASS_PROTOTYPE();
|
||||
|
||||
cPlayer(cClientHandle* a_Client, const char* a_PlayerName);
|
||||
virtual ~cPlayer();
|
||||
|
||||
virtual void SpawnOn( cClientHandle* a_Target );
|
||||
virtual void Tick(float a_Dt);
|
||||
|
||||
void SetTouchGround( bool a_bTouchGround );
|
||||
inline void SetStance( const double & a_Stance ) { m_Stance = a_Stance; }
|
||||
double GetEyeHeight(); //tolua_export
|
||||
Vector3d GetEyePosition(); //tolua_export
|
||||
inline bool GetFlying() { return m_bTouchGround; } //tolua_export
|
||||
inline const double & GetStance() { return m_Stance; } //tolua_export
|
||||
cInventory & GetInventory() { return *m_Inventory; } //tolua_export
|
||||
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
|
||||
|
||||
// Tries to move to a new position, with collision checks and stuff
|
||||
virtual void MoveTo( const Vector3d & a_NewPos ); //tolua_export
|
||||
|
||||
cWindow* GetWindow() { return m_CurrentWindow; }
|
||||
void OpenWindow( cWindow* a_Window );
|
||||
void CloseWindow();
|
||||
|
||||
cClientHandle* GetClientHandle() { return m_ClientHandle; } //tolua_export
|
||||
void SetClientHandle( cClientHandle* a_Client ) { m_ClientHandle = a_Client; }
|
||||
|
||||
void SendMessage( const char* a_Message ); //tolua_export
|
||||
|
||||
const char* GetName(); //tolua_export
|
||||
void SetName( const char* a_Name ); //tolua_export
|
||||
|
||||
typedef std::list< cGroup* > GroupList;
|
||||
void AddToGroup( const char* a_GroupName ); //tolua_export
|
||||
bool CanUseCommand( const char* a_Command ); //tolua_export
|
||||
bool HasPermission( const char* a_Permission ); //tolua_export
|
||||
const GroupList & GetGroups(); // >> EXPORTED IN MANUALBINDINGS <<
|
||||
bool IsInGroup( const char* a_Group ); //tolua_export
|
||||
|
||||
std::string GetColor(); //tolua_export
|
||||
|
||||
void TossItem( bool a_bDraggingItem, int a_Amount = 1 ); //tolua_export
|
||||
|
||||
void Heal( int a_Health ); //tolua_export
|
||||
void TakeDamage( int a_Damage, cEntity* a_Instigator ); //tolua_export
|
||||
void KilledBy( cEntity* a_Killer ); //tolua_export
|
||||
void Respawn(); //tolua_export
|
||||
|
||||
void SetVisible( bool a_bVisible ); //tolua_export
|
||||
bool IsVisible() { return m_bVisible; } //tolua_export
|
||||
|
||||
bool SaveToDisk();
|
||||
bool LoadFromDisk();
|
||||
|
||||
//Burning logic
|
||||
bool m_bBurnable;
|
||||
enum PMetaState{NORMAL,BURNING,CROUCHED,RIDING} e_EPMetaState;
|
||||
virtual void CheckMetaDataBurn();
|
||||
virtual void InStateBurning(float a_Dt);
|
||||
|
||||
protected:
|
||||
struct sPlayerState;
|
||||
sPlayerState* m_pState;
|
||||
|
||||
bool m_bVisible;
|
||||
|
||||
float m_LastGroundHeight;
|
||||
bool m_bTouchGround;
|
||||
double m_Stance;
|
||||
cInventory* m_Inventory;
|
||||
cWindow* m_CurrentWindow;
|
||||
|
||||
float m_TimeLastPickupCheck;
|
||||
|
||||
void ResolvePermissions();
|
||||
|
||||
void ResolveGroups();
|
||||
char m_Color;
|
||||
float m_FireDamageInterval;
|
||||
float m_BurnPeriod;
|
||||
|
||||
cClientHandle* m_ClientHandle;
|
||||
}; //tolua_export
|
78
source/cPlugin.cpp
Normal file
78
source/cPlugin.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include "cPlugin.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#include "cMCLogger.h"
|
||||
|
||||
cPlugin::cPlugin()
|
||||
: m_Version( 0 )
|
||||
{
|
||||
}
|
||||
|
||||
cPlugin::~cPlugin()
|
||||
{
|
||||
}
|
||||
|
||||
// bool cPlugin::Initialize()
|
||||
// {
|
||||
// LOG("cPlugin::Initialize()");
|
||||
// return false;
|
||||
// }
|
||||
|
||||
void cPlugin::Tick(float a_Dt)
|
||||
{
|
||||
(void)a_Dt;
|
||||
}
|
||||
|
||||
bool cPlugin::OnBlockPlace( cPacket_BlockPlace* a_PacketData, cPlayer* a_Player )
|
||||
{
|
||||
(void)a_PacketData;
|
||||
(void)a_Player;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPlugin::OnCollectItem( cPickup* a_Pickup, cPlayer* a_Player )
|
||||
{
|
||||
(void)a_Pickup;
|
||||
(void)a_Player;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPlugin::OnDisconnect( std::string a_Reason, cPlayer* a_Player )
|
||||
{
|
||||
(void)a_Reason;
|
||||
(void)a_Player;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPlugin::OnChat( std::string a_Chat, cPlayer* a_Player )
|
||||
{
|
||||
(void)a_Chat;
|
||||
(void)a_Player;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPlugin::OnLogin( cPacket_Login* a_PacketData )
|
||||
{
|
||||
(void)a_PacketData;
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPlugin::OnPlayerSpawn( cPlayer* a_Player )
|
||||
{
|
||||
(void)a_Player;
|
||||
}
|
||||
|
||||
bool cPlugin::OnPlayerJoin( cPlayer* a_Player )
|
||||
{
|
||||
(void)a_Player;
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPlugin::AddCommand( std::string & a_Command, std::string & a_Description, std::string & a_Permission )
|
||||
{
|
||||
CommandStruct Command;
|
||||
Command.Command = a_Command;
|
||||
Command.Description = a_Description;
|
||||
Command.Permission = a_Permission;
|
||||
m_Commands.push_back( Command );
|
||||
}
|
76
source/cPlugin.h
Normal file
76
source/cPlugin.h
Normal file
@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include "MemoryLeak.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class cPacket_BlockPlace;
|
||||
class cPacket_PickupSpawn;
|
||||
class cPacket_EntityEquipment;
|
||||
class cPacket_Disconnect;
|
||||
class cPacket_Chat;
|
||||
class cPacket_BlockDig;
|
||||
class cPacket_Login;
|
||||
class cClientHandle;
|
||||
class cPlayer;
|
||||
class cPickup;
|
||||
class cItem;
|
||||
class cEntity;
|
||||
class cPawn;
|
||||
struct TakeDamageInfo;
|
||||
|
||||
// tolua_begin
|
||||
class cPlugin
|
||||
{
|
||||
public:
|
||||
cPlugin();
|
||||
virtual ~cPlugin();
|
||||
|
||||
virtual void OnDisable() {}
|
||||
virtual bool Initialize() = 0;
|
||||
|
||||
// Called each tick
|
||||
virtual void Tick(float a_Dt);
|
||||
|
||||
/**
|
||||
* On all these functions, return true if you want to override default behavior
|
||||
* You can also return false, so default behavior is used, but with changed PacketData
|
||||
**/
|
||||
virtual bool OnCollectItem( cPickup* a_Pickup, cPlayer* a_Player );
|
||||
virtual bool OnDisconnect( std::string a_Reason, cPlayer* a_Player );
|
||||
virtual bool OnBlockPlace( cPacket_BlockPlace* a_PacketData, cPlayer* a_Player );
|
||||
virtual bool OnBlockDig( cPacket_BlockDig* a_PacketData, cPlayer* a_Player, cItem* a_PickupItem ) { (void)a_PacketData; (void)a_Player; (void)a_PickupItem; return false; }
|
||||
virtual bool OnChat( std::string a_Chat, cPlayer* a_Player );
|
||||
virtual bool OnLogin( cPacket_Login* a_PacketData );
|
||||
virtual void OnPlayerSpawn( cPlayer* a_Player );
|
||||
virtual bool OnPlayerJoin( cPlayer* a_Player );
|
||||
virtual void OnPlayerMove( cPlayer* a_Player ) { (void)a_Player; }
|
||||
virtual void OnTakeDamage( cPawn* a_Pawn, TakeDamageInfo* a_TakeDamageInfo ) { (void)a_Pawn; (void)a_TakeDamageInfo; }
|
||||
virtual bool OnKilled( cPawn* a_Killed, cEntity* a_Killer ) { (void)a_Killed; (void)a_Killer; return false; }
|
||||
|
||||
// Accessors
|
||||
std::string GetName() const { return m_Name; }
|
||||
void SetName( std::string a_Name ) { m_Name = a_Name; }
|
||||
|
||||
int GetVersion() const { return m_Version; }
|
||||
void SetVersion( int a_Version ) { m_Version = a_Version; }
|
||||
|
||||
struct CommandStruct
|
||||
{
|
||||
std::string Command;
|
||||
std::string Description;
|
||||
std::string Permission;
|
||||
};
|
||||
|
||||
void AddCommand( std::string & a_Command, std::string & a_Description, std::string & a_Permission );
|
||||
// tolua_end
|
||||
typedef bool (FuncCommandHandler)( std::string & a_Command, std::vector< std::string > & a_Split );
|
||||
void BindCommand( FuncCommandHandler* a_Function, std::string & a_Command ); // >> EXPORTED IN MANUALBINDINGS <<
|
||||
const std::vector< CommandStruct > & GetCommands() const { return m_Commands; } // >> EXPORTED IN MANUALBINDINGS <<
|
||||
|
||||
private:
|
||||
std::vector< CommandStruct > m_Commands;
|
||||
std::string m_Name;
|
||||
int m_Version;
|
||||
}; //tolua_export
|
423
source/cPluginManager.cpp
Normal file
423
source/cPluginManager.cpp
Normal file
@ -0,0 +1,423 @@
|
||||
#include "cPluginManager.h"
|
||||
#include "cPlugin.h"
|
||||
#include "cPlugin_Lua.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cWebAdmin.h"
|
||||
#include "cItem.h"
|
||||
#include "cRoot.h"
|
||||
#include "cLuaCommandBinder.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "../iniFile/iniFile.h"
|
||||
|
||||
extern std::vector<std::string> StringSplit(std::string str, std::string delim);
|
||||
|
||||
typedef std::list< cPlugin_Lua* > LuaPluginList;
|
||||
typedef std::map< cPluginManager::PluginHook, cPluginManager::PluginList > HookMap;
|
||||
|
||||
struct cPluginManager::sPluginManagerState
|
||||
{
|
||||
LuaPluginList LuaPlugins;
|
||||
cPluginManager::PluginList Plugins;
|
||||
HookMap Hooks;
|
||||
};
|
||||
|
||||
cPluginManager* cPluginManager::GetPluginManager()
|
||||
{
|
||||
LOGWARN("WARNING: Using deprecated function cPluginManager::GetPluginManager() use cRoot::Get()->GetPluginManager() instead!");
|
||||
return cRoot::Get()->GetPluginManager();
|
||||
}
|
||||
|
||||
cPluginManager::cPluginManager()
|
||||
: m_pState( new sPluginManagerState )
|
||||
, m_LuaCommandBinder( new cLuaCommandBinder() )
|
||||
, m_bReloadPlugins(false)
|
||||
{
|
||||
}
|
||||
|
||||
cPluginManager::~cPluginManager()
|
||||
{
|
||||
UnloadPluginsNow();
|
||||
delete m_LuaCommandBinder;
|
||||
delete m_pState;
|
||||
}
|
||||
|
||||
void cPluginManager::ReloadPlugins()
|
||||
{
|
||||
m_bReloadPlugins = true;
|
||||
}
|
||||
|
||||
void cPluginManager::ReloadPluginsNow()
|
||||
{
|
||||
LOG("--Loading plugins--");
|
||||
m_bReloadPlugins = false;
|
||||
UnloadPluginsNow();
|
||||
|
||||
cIniFile IniFile("settings.ini");
|
||||
if( IniFile.ReadFile() )
|
||||
{
|
||||
unsigned int KeyNum = IniFile.FindKey("Plugins");
|
||||
unsigned int NumPlugins = IniFile.GetNumValues( KeyNum );
|
||||
if( NumPlugins > 0 )
|
||||
{
|
||||
for(unsigned int i = 0; i < NumPlugins; i++)
|
||||
{
|
||||
std::string ValueName = IniFile.GetValueName(KeyNum, i );
|
||||
if( ValueName.compare("Plugin") == 0 )
|
||||
{ // It's a plugin
|
||||
std::string PluginFile = IniFile.GetValue(KeyNum, i );
|
||||
if( PluginFile.compare("") != 0 )
|
||||
{
|
||||
// allow for comma separated plugin list
|
||||
// degrades and works fine for the plugin
|
||||
// per line
|
||||
std::vector< std::string > split = StringSplit( PluginFile, "," );
|
||||
for (unsigned int j = 0; j < split.size(); j++) {
|
||||
cPlugin_Lua* Plugin = new cPlugin_Lua( (split[j] + std::string(".lua") ).c_str() );
|
||||
if( !AddLuaPlugin( Plugin ) )
|
||||
{
|
||||
delete Plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( GetNumPlugins() == 0 )
|
||||
{
|
||||
LOG("No plugins loaded");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Loaded %i plugin(s)", GetNumPlugins() );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("WARNING: Can't find settings.ini, so can't load any plugins.");
|
||||
}
|
||||
LOG("--Done loading plugins--");
|
||||
}
|
||||
|
||||
void cPluginManager::Tick(float a_Dt)
|
||||
{
|
||||
if( m_bReloadPlugins )
|
||||
{
|
||||
ReloadPluginsNow();
|
||||
}
|
||||
|
||||
|
||||
HookMap::iterator Plugins = m_pState->Hooks.find( E_PLUGIN_TICK );
|
||||
if( Plugins != m_pState->Hooks.end() )
|
||||
{
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
(*itr)->Tick( a_Dt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cPluginManager::CallHook( PluginHook a_Hook, unsigned int a_NumArgs, ... )
|
||||
{
|
||||
HookMap::iterator Plugins = m_pState->Hooks.find( a_Hook );
|
||||
|
||||
// Special case for chat hook, since you can also bind commands (bound commands don't use chat hook)
|
||||
if( a_Hook == E_PLUGIN_CHAT )
|
||||
{
|
||||
if( a_NumArgs != 2 ) return false;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
const char* Message = va_arg(argptr, const char* );
|
||||
cPlayer* Player = va_arg(argptr, cPlayer* );
|
||||
va_end (argptr);
|
||||
|
||||
if( m_LuaCommandBinder->HandleCommand( std::string( Message ), Player ) )
|
||||
return true;
|
||||
|
||||
if( Plugins != m_pState->Hooks.end() )
|
||||
{
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnChat( Message, Player ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if( Plugins != m_pState->Hooks.end() )
|
||||
{
|
||||
switch( a_Hook )
|
||||
{
|
||||
case E_PLUGIN_COLLECT_ITEM:
|
||||
{
|
||||
if( a_NumArgs != 2 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPickup* Pickup = va_arg(argptr, cPickup* );
|
||||
cPlayer* Player = va_arg(argptr, cPlayer* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnCollectItem( Pickup, Player ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_BLOCK_DIG:
|
||||
{
|
||||
if( a_NumArgs != 2 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPacket_BlockDig* Packet = va_arg(argptr, cPacket_BlockDig* );
|
||||
cPlayer* Player = va_arg(argptr, cPlayer* );
|
||||
cItem* Item = va_arg( argptr, cItem* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnBlockDig( Packet, Player, Item ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_BLOCK_PLACE:
|
||||
{
|
||||
if( a_NumArgs != 2 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPacket_BlockPlace* Packet = va_arg(argptr, cPacket_BlockPlace* );
|
||||
cPlayer* Player = va_arg(argptr, cPlayer* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnBlockPlace( Packet, Player ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_DISCONNECT:
|
||||
{
|
||||
if( a_NumArgs != 2 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
const char* Reason = va_arg(argptr, const char* );
|
||||
cPlayer* Player = va_arg(argptr, cPlayer* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnDisconnect( Reason, Player ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_LOGIN:
|
||||
{
|
||||
if( a_NumArgs != 1 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPacket_Login* Packet = va_arg(argptr, cPacket_Login* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnLogin( Packet ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_PLAYER_JOIN:
|
||||
{
|
||||
if( a_NumArgs != 1 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPlayer* Player = va_arg(argptr, cPlayer* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnPlayerJoin( Player ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_PLAYER_MOVE:
|
||||
{
|
||||
if( a_NumArgs != 1 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPlayer* Player = va_arg(argptr, cPlayer* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
(*itr)->OnPlayerMove( Player );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_TAKE_DAMAGE:
|
||||
{
|
||||
if( a_NumArgs != 2 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPawn* Pawn = va_arg(argptr, cPawn* );
|
||||
TakeDamageInfo* TDI = va_arg(argptr, TakeDamageInfo* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
(*itr)->OnTakeDamage( Pawn, TDI );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case E_PLUGIN_KILLED:
|
||||
{
|
||||
if( a_NumArgs != 2 ) break;
|
||||
va_list argptr;
|
||||
va_start( argptr, a_NumArgs);
|
||||
cPawn* Killed = va_arg(argptr, cPawn* );
|
||||
cEntity* Killer = va_arg(argptr, cEntity* );
|
||||
va_end (argptr);
|
||||
for( PluginList::iterator itr = Plugins->second.begin(); itr != Plugins->second.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->OnKilled( Killed, Killer ) )
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG("WARNING: Calling Unknown hook: %i", a_Hook );
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
cPlugin* cPluginManager::GetPlugin( std::string a_Plugin )
|
||||
{
|
||||
for( PluginList::iterator itr = m_pState->Plugins.begin(); itr != m_pState->Plugins.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->GetName().compare( a_Plugin ) == 0 )
|
||||
{
|
||||
return *itr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const cPluginManager::PluginList & cPluginManager::GetAllPlugins()
|
||||
{
|
||||
return m_pState->Plugins;
|
||||
}
|
||||
|
||||
void cPluginManager::UnloadPluginsNow()
|
||||
{
|
||||
m_pState->Hooks.clear();
|
||||
|
||||
while( m_pState->LuaPlugins.size() > 0 )
|
||||
{
|
||||
cPlugin_Lua* LuaPlugin = *m_pState->LuaPlugins.begin();
|
||||
if( LuaPlugin )
|
||||
{
|
||||
cWebAdmin* WebAdmin = cRoot::Get()->GetWebAdmin();
|
||||
if( WebAdmin ) WebAdmin->RemovePlugin( LuaPlugin->GetLuaState() );
|
||||
delete LuaPlugin;
|
||||
}
|
||||
m_pState->LuaPlugins.remove( LuaPlugin );
|
||||
}
|
||||
|
||||
while( m_pState->Plugins.size() > 0 )
|
||||
{
|
||||
RemovePlugin( *m_pState->Plugins.begin(), true );
|
||||
}
|
||||
}
|
||||
|
||||
void cPluginManager::RemovePlugin( cPlugin* a_Plugin, bool a_bDelete /* = false */ )
|
||||
{
|
||||
if( a_bDelete )
|
||||
{
|
||||
m_LuaCommandBinder->RemoveBindingsForPlugin( a_Plugin );
|
||||
m_pState->Plugins.remove( a_Plugin );
|
||||
a_Plugin->OnDisable();
|
||||
delete a_Plugin;
|
||||
}
|
||||
else
|
||||
{
|
||||
for( LuaPluginList::iterator itr = m_pState->LuaPlugins.begin(); itr != m_pState->LuaPlugins.end(); ++itr )
|
||||
{
|
||||
(*itr)->RemovePlugin( a_Plugin );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool cPluginManager::AddPlugin( cPlugin* a_Plugin )
|
||||
{
|
||||
if( a_Plugin->Initialize() )
|
||||
{
|
||||
m_pState->Plugins.remove( a_Plugin );
|
||||
m_pState->Plugins.push_back( a_Plugin );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPluginManager::AddPlugin( lua_State* a_LuaState, cPlugin* a_Plugin )
|
||||
{
|
||||
cPlugin_Lua* LuaPlugin = GetLuaPlugin( a_LuaState );
|
||||
if( LuaPlugin && a_Plugin->Initialize() )
|
||||
{
|
||||
m_pState->Plugins.remove( a_Plugin );
|
||||
m_pState->Plugins.push_back( a_Plugin );
|
||||
LuaPlugin->AddPlugin( a_Plugin );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cPluginManager::AddLuaPlugin( cPlugin_Lua* a_Plugin )
|
||||
{
|
||||
m_pState->LuaPlugins.push_back( a_Plugin ); // It HAS to be in here before calling Initialize, so it can be found by AddPlugin()
|
||||
if(a_Plugin->Initialize() )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
LOG(">>>>>>> Could not initialize a plugin! ");
|
||||
m_pState->LuaPlugins.remove( a_Plugin );
|
||||
return false;
|
||||
}
|
||||
|
||||
void cPluginManager::RemoveLuaPlugin( std::string a_FileName )
|
||||
{
|
||||
for( LuaPluginList::iterator itr = m_pState->LuaPlugins.begin(); itr != m_pState->LuaPlugins.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->GetFileName() == a_FileName )
|
||||
{
|
||||
cPlugin_Lua* Plugin = *itr;
|
||||
delete Plugin;
|
||||
m_pState->LuaPlugins.remove( Plugin );
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cPlugin_Lua* cPluginManager::GetLuaPlugin( lua_State* a_State )
|
||||
{
|
||||
for( LuaPluginList::iterator itr = m_pState->LuaPlugins.begin(); itr != m_pState->LuaPlugins.end(); ++itr )
|
||||
{
|
||||
if( (*itr)->GetLuaState() == a_State )
|
||||
{
|
||||
return *itr;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void cPluginManager::AddHook( cPlugin* a_Plugin, PluginHook a_Hook )
|
||||
{
|
||||
PluginList & Plugins = m_pState->Hooks[ a_Hook ];
|
||||
Plugins.remove( a_Plugin );
|
||||
Plugins.push_back( a_Plugin );
|
||||
}
|
||||
|
||||
unsigned int cPluginManager::GetNumPlugins()
|
||||
{
|
||||
return m_pState->Plugins.size();
|
||||
}
|
68
source/cPluginManager.h
Normal file
68
source/cPluginManager.h
Normal file
@ -0,0 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
|
||||
struct lua_State;
|
||||
class cLuaCommandBinder;
|
||||
class cPlugin;
|
||||
class cPlugin_Lua;
|
||||
class cPluginManager //tolua_export
|
||||
{ //tolua_export
|
||||
public: //tolua_export
|
||||
|
||||
// Called each tick
|
||||
virtual void Tick(float a_Dt);
|
||||
|
||||
enum PluginHook //tolua_export
|
||||
{ //tolua_export
|
||||
E_PLUGIN_TICK, //tolua_export
|
||||
E_PLUGIN_CHAT, //tolua_export
|
||||
E_PLUGIN_COLLECT_ITEM, //tolua_export
|
||||
E_PLUGIN_BLOCK_DIG, //tolua_export
|
||||
E_PLUGIN_BLOCK_PLACE, //tolua_export
|
||||
E_PLUGIN_DISCONNECT, //tolua_export
|
||||
E_PLUGIN_HANDSHAKE, //tolua_export
|
||||
E_PLUGIN_LOGIN, //tolua_export
|
||||
E_PLUGIN_PLAYER_SPAWN, //tolua_export
|
||||
E_PLUGIN_PLAYER_JOIN, //tolua_export
|
||||
E_PLUGIN_PLAYER_MOVE, //tolua_export
|
||||
E_PLUGIN_TAKE_DAMAGE, //tolua_export
|
||||
E_PLUGIN_KILLED, //tolua_export
|
||||
}; //tolua_export
|
||||
|
||||
static cPluginManager * GetPluginManager(); //tolua_export
|
||||
|
||||
typedef std::list< cPlugin* > PluginList;
|
||||
cPlugin* GetPlugin( std::string a_Plugin ); //tolua_export
|
||||
const PluginList & GetAllPlugins(); // >> EXPORTED IN MANUALBINDINGS <<
|
||||
|
||||
void ReloadPlugins(); //tolua_export
|
||||
bool AddPlugin( cPlugin* a_Plugin );
|
||||
bool AddPlugin( lua_State* a_LuaState, cPlugin* a_Plugin ); //tolua_export
|
||||
bool AddLuaPlugin( cPlugin_Lua* a_Plugin );
|
||||
void AddHook( cPlugin* a_Plugin, PluginHook a_Hook ); //tolua_export
|
||||
|
||||
unsigned int GetNumPlugins(); //tolua_export
|
||||
|
||||
bool CallHook( PluginHook a_Hook, unsigned int a_NumArgs, ... );
|
||||
|
||||
void RemovePlugin( cPlugin* a_Plugin, bool a_bDelete = false ); //tolua_export
|
||||
void RemoveLuaPlugin( std::string a_FileName ); //tolua_export
|
||||
cPlugin_Lua* GetLuaPlugin( lua_State* a_State ); //tolua_export
|
||||
|
||||
cLuaCommandBinder* GetLuaCommandBinder() { return m_LuaCommandBinder; }
|
||||
private:
|
||||
friend class cRoot;
|
||||
cPluginManager();
|
||||
~cPluginManager();
|
||||
|
||||
struct sPluginManagerState;
|
||||
sPluginManagerState* m_pState;
|
||||
|
||||
void ReloadPluginsNow();
|
||||
void UnloadPluginsNow();
|
||||
|
||||
cLuaCommandBinder* m_LuaCommandBinder;
|
||||
|
||||
bool m_bReloadPlugins;
|
||||
}; //tolua_export
|
97
source/cPlugin_Lua.cpp
Normal file
97
source/cPlugin_Lua.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#define LUA_USE_POSIX
|
||||
#include "cMCLogger.h"
|
||||
#include <string>
|
||||
#include "cPlugin_Lua.h"
|
||||
#include "cPluginManager.h"
|
||||
#include "cRoot.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "lualib.h"
|
||||
}
|
||||
|
||||
#include "tolua++.h"
|
||||
#include "Bindings.h"
|
||||
#include "ManualBindings.h"
|
||||
|
||||
bool report_errors(lua_State* lua, int status)
|
||||
{
|
||||
if ( status!=0 )
|
||||
{
|
||||
std::string s = lua_tostring(lua, -1);
|
||||
LOGERROR("-- %s", s.c_str() );
|
||||
lua_pop(lua, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
cPlugin_Lua::~cPlugin_Lua()
|
||||
{
|
||||
UnloadPlugins();
|
||||
if( m_LuaState )
|
||||
{
|
||||
lua_close( m_LuaState );
|
||||
m_LuaState = 0;
|
||||
}
|
||||
}
|
||||
|
||||
cPlugin_Lua::cPlugin_Lua(const char* a_Plugin)
|
||||
: m_LuaState( 0 )
|
||||
{
|
||||
m_FileName.assign( a_Plugin );
|
||||
}
|
||||
|
||||
bool cPlugin_Lua::Initialize()
|
||||
{
|
||||
if( !m_LuaState )
|
||||
{
|
||||
m_LuaState = lua_open();
|
||||
luaL_openlibs( m_LuaState );
|
||||
tolua_AllToLua_open(m_LuaState);
|
||||
ManualBindings::Bind( m_LuaState );
|
||||
}
|
||||
|
||||
int s = luaL_loadfile(m_LuaState, (std::string("Plugins/") + m_FileName ).c_str() );
|
||||
if( report_errors( m_LuaState, s ) )
|
||||
{
|
||||
LOGERROR("Can't load plugin %s", m_FileName.c_str() );
|
||||
lua_close( m_LuaState );
|
||||
m_LuaState = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
s = lua_pcall(m_LuaState, 0, LUA_MULTRET, 0);
|
||||
if( report_errors( m_LuaState, s ) )
|
||||
{
|
||||
LOGERROR("Error in plugin %s", m_FileName.c_str() );
|
||||
lua_close( m_LuaState );
|
||||
m_LuaState = 0;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void cPlugin_Lua::AddPlugin( cPlugin* a_Plugin )
|
||||
{
|
||||
m_Plugins.push_back( a_Plugin );
|
||||
}
|
||||
|
||||
void cPlugin_Lua::RemovePlugin( cPlugin* a_Plugin )
|
||||
{
|
||||
m_Plugins.remove( a_Plugin );
|
||||
cRoot::Get()->GetPluginManager()->RemovePlugin( a_Plugin, true );
|
||||
}
|
||||
|
||||
void cPlugin_Lua::UnloadPlugins()
|
||||
{
|
||||
while( m_Plugins.begin() != m_Plugins.end() )
|
||||
{
|
||||
RemovePlugin( *m_Plugins.begin() );
|
||||
}
|
||||
}
|
||||
|
||||
lua_State* cPlugin_Lua::GetLuaState()
|
||||
{
|
||||
return m_LuaState;
|
||||
}
|
34
source/cPlugin_Lua.h
Normal file
34
source/cPlugin_Lua.h
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
class cPickup;
|
||||
class cPlayer;
|
||||
class cPacket_BlockPlace;
|
||||
class cPacket_BlockDig;
|
||||
class cPacket_Login;
|
||||
class cPlugin;
|
||||
class cPlugin_Lua //tolua_export
|
||||
{ //tolua_export
|
||||
public:
|
||||
cPlugin_Lua(const char* a_Plugin);
|
||||
~cPlugin_Lua();
|
||||
|
||||
virtual bool Initialize();
|
||||
|
||||
std::string GetFileName() { return m_FileName; } //tolua_export
|
||||
typedef struct lua_State lua_State;
|
||||
lua_State* GetLuaState();
|
||||
|
||||
void AddPlugin( cPlugin* a_Plugin );
|
||||
void RemovePlugin( cPlugin* a_Plugin );
|
||||
private:
|
||||
void UnloadPlugins();
|
||||
|
||||
std::string m_FileName;
|
||||
lua_State* m_LuaState;
|
||||
|
||||
typedef std::list< cPlugin* > PluginList;
|
||||
PluginList m_Plugins;
|
||||
}; //tolua_export
|
458
source/cRecipeChecker.cpp
Normal file
458
source/cRecipeChecker.cpp
Normal file
@ -0,0 +1,458 @@
|
||||
#include "cRecipeChecker.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <list>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
#endif
|
||||
|
||||
#include "Defines.h"
|
||||
#include "cMCLogger.h"
|
||||
#include "cRoot.h"
|
||||
|
||||
typedef std::list< cRecipeChecker::Recipe* > RecipeList;
|
||||
struct cRecipeChecker::sRecipeCheckerState
|
||||
{
|
||||
RecipeList Recipes;
|
||||
};
|
||||
|
||||
cRecipeChecker* cRecipeChecker::GetRecipeChecker()
|
||||
{
|
||||
LOGWARN("WARNING: Using deprecated function cRecipeChecker::GetRecipeChecker() use cRoot::Get()->GetRecipeChecker() instead!");
|
||||
return cRoot::Get()->GetRecipeChecker();
|
||||
}
|
||||
|
||||
cRecipeChecker::Recipe::~Recipe()
|
||||
{
|
||||
delete [] Slots;
|
||||
Slots = 0;
|
||||
}
|
||||
|
||||
cRecipeChecker::~cRecipeChecker()
|
||||
{
|
||||
ClearRecipes();
|
||||
delete m_pState;
|
||||
}
|
||||
|
||||
cRecipeChecker::cRecipeChecker()
|
||||
: m_pState( new sRecipeCheckerState )
|
||||
{
|
||||
ReloadRecipes();
|
||||
}
|
||||
|
||||
void cRecipeChecker::ClearRecipes()
|
||||
{
|
||||
while( m_pState->Recipes.size() > 0 )
|
||||
{
|
||||
delete *m_pState->Recipes.begin();
|
||||
m_pState->Recipes.remove( *m_pState->Recipes.begin() );
|
||||
}
|
||||
}
|
||||
|
||||
void PrintRecipe( std::vector< cRecipeChecker::RecipeSlot > & RecipeSlots )
|
||||
{
|
||||
LOG("Recipe:");
|
||||
for(unsigned int i = 0; i < RecipeSlots.size(); i++)
|
||||
{
|
||||
cRecipeChecker::RecipeSlot Slot = RecipeSlots[i];
|
||||
LOG("x:%i y:%i id:%i #%i", Slot.x, Slot.y, Slot.Item.m_ItemID, Slot.Item.m_ItemCount );
|
||||
}
|
||||
}
|
||||
|
||||
void PrintNear( std::ifstream & f, int a_History = 64 )
|
||||
{
|
||||
f.clear();
|
||||
|
||||
// Calculate how far we can move pointer back
|
||||
std::streamoff Position = f.tellg();
|
||||
f.seekg( 0, std::ios_base::beg );
|
||||
std::streamoff Difference = Position - f.tellg();
|
||||
if( Difference > a_History ) Difference = a_History;
|
||||
f.seekg( Position - Difference, std::ios_base::beg );
|
||||
|
||||
std::string Near;
|
||||
if( f.good() )
|
||||
{
|
||||
while( f.good() && Near.size() < (unsigned int)Difference )
|
||||
{
|
||||
char c;
|
||||
f.get(c);
|
||||
Near.push_back( c );
|
||||
}
|
||||
}
|
||||
LOGERROR("Error near: \"%s\"", Near.c_str() );
|
||||
}
|
||||
|
||||
void cRecipeChecker::ReloadRecipes()
|
||||
{
|
||||
LOG("--Loading recipes--");
|
||||
ClearRecipes();
|
||||
|
||||
/*
|
||||
char a_File[] = "recipes.txt";
|
||||
|
||||
FILE* f = 0;
|
||||
#ifdef _WIN32
|
||||
if( fopen_s(&f, a_File, "rb" ) == 0 ) // no error
|
||||
#else
|
||||
if( (f = fopen(a_File, "rb" )) != 0 ) // no error
|
||||
#endif
|
||||
{
|
||||
char c;
|
||||
while( fread( &c, sizeof(char), 1, f) == 1 )
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Could not open file for recipes: %s", a_File);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
std::ifstream f;
|
||||
|
||||
char a_File[] = "recipes.txt";
|
||||
f.open(a_File, std::ios::in);
|
||||
std::string input;
|
||||
|
||||
if( !f.good() )
|
||||
{
|
||||
f.close();
|
||||
LOG("Could not open file for recipes: %s", a_File);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector< RecipeSlot > RecipeSlots;
|
||||
|
||||
bool bError = false;
|
||||
while( f.good() )
|
||||
{
|
||||
bool bLoadSlot = false;
|
||||
bool bLoadResult = false;
|
||||
|
||||
char c;
|
||||
f >> c;
|
||||
f.unget();
|
||||
if( c == '#' )
|
||||
{
|
||||
//LOG("Ignoring comment");
|
||||
while( f.good() && c != '\n' )
|
||||
{
|
||||
f.get( c );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
f.get( c );
|
||||
while( f.good() && ( c == '\n' || c == '\r' ) ) { f.get( c ); }
|
||||
if( f.eof() ) break;
|
||||
f.unget();
|
||||
|
||||
int width, height;
|
||||
f >> width;
|
||||
f >> c; if( c != 'x' ) { bError=true; break; }
|
||||
f >> height;
|
||||
f >> c;
|
||||
if( c == ',' ) bLoadSlot = true;
|
||||
|
||||
while( f.good() && bLoadSlot )
|
||||
{
|
||||
bool bDontAddRecipe = false;
|
||||
int x, y, ItemID, Amount;
|
||||
if( f.peek() == '*' )
|
||||
{
|
||||
f >> c;
|
||||
x = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
f >> x;
|
||||
}
|
||||
f >> c; if( c != ':' ) { bError=true; break; }
|
||||
if( f.peek() == '*' )
|
||||
{
|
||||
f >> c;
|
||||
y = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
f >> y;
|
||||
}
|
||||
f >> c; if( c != ':' ) { bError=true; break; }
|
||||
f >> ItemID;
|
||||
f >> c; if( c != ':' ) { bError=true; break; }
|
||||
f >> Amount;
|
||||
|
||||
f >> c;
|
||||
if( c == '@' ) bLoadResult = true;
|
||||
if( c != ',' ) bLoadSlot = false;
|
||||
|
||||
if( !isValidItem( ItemID ) )
|
||||
{
|
||||
LOGERROR("Error in recipes file (%s): Invalid Item ID %i", a_File, ItemID );
|
||||
bDontAddRecipe = true;
|
||||
}
|
||||
if( x < 0 && y < 0 )
|
||||
{
|
||||
if( Amount < 0 )
|
||||
{
|
||||
LOGERROR("Error in recipes file (%s): Invalid use of negative amount on wildcard coordinates", a_File );
|
||||
bDontAddRecipe = true;
|
||||
}
|
||||
for(int x = 0; x < width; ++x) for(int y = 0; y < height; ++y )
|
||||
{
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)Amount );
|
||||
RecipeSlot Slot;
|
||||
Slot.Item = Item;
|
||||
Slot.x = x;
|
||||
Slot.y = y;
|
||||
RecipeSlots.push_back( Slot );
|
||||
}
|
||||
}
|
||||
else if( x < 0 )
|
||||
{
|
||||
if( Amount < 0 )
|
||||
{
|
||||
for(int x = 0; x < width; ++x) for(int yy = 0; yy < height; ++yy )
|
||||
{
|
||||
if( yy == y-1 ) continue;
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)abs(Amount) );
|
||||
RecipeSlot Slot;
|
||||
Slot.Item = Item;
|
||||
Slot.x = x;
|
||||
Slot.y = yy;
|
||||
RecipeSlots.push_back( Slot );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int x = 0; x < width; ++x)
|
||||
{
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)Amount );
|
||||
RecipeSlot Slot;
|
||||
Slot.Item = Item;
|
||||
Slot.x = x;
|
||||
Slot.y = y-1;
|
||||
RecipeSlots.push_back( Slot );
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( y < 0 )
|
||||
{
|
||||
if( Amount < 0 )
|
||||
{
|
||||
for(int xx = 0; xx < width; ++xx) for(int y = 0; y < height; ++y )
|
||||
{
|
||||
if( xx == x-1 ) continue;
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)abs(Amount) );
|
||||
RecipeSlot Slot;
|
||||
Slot.Item = Item;
|
||||
Slot.x = xx;
|
||||
Slot.y = y;
|
||||
RecipeSlots.push_back( Slot );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(int y = 0; y < height; ++y)
|
||||
{
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)Amount );
|
||||
RecipeSlot Slot;
|
||||
Slot.Item = Item;
|
||||
Slot.x = x-1;
|
||||
Slot.y = y;
|
||||
RecipeSlots.push_back( Slot );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( Amount < 0 )
|
||||
{
|
||||
for(int xx = 0; xx < width; ++xx) for(int yy = 0; yy < height; ++yy )
|
||||
{
|
||||
if( xx == x-1 && yy == y-1 ) continue;
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)abs(Amount) );
|
||||
RecipeSlot Slot;
|
||||
Slot.Item = Item;
|
||||
Slot.x = xx;
|
||||
Slot.y = yy;
|
||||
RecipeSlots.push_back( Slot );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)Amount );
|
||||
RecipeSlot Slot;
|
||||
Slot.Item = Item;
|
||||
Slot.x = x-1;
|
||||
Slot.y = y-1;
|
||||
RecipeSlots.push_back( Slot );
|
||||
}
|
||||
}
|
||||
//LOG("%i %i %i %i", x, y, ItemID, Amount );
|
||||
|
||||
if( bLoadResult )
|
||||
{
|
||||
bLoadResult = false;
|
||||
f >> ItemID;
|
||||
f >> c; if( c != ':' ) { bError=true; break; }
|
||||
f >> Amount;
|
||||
//LOG("%i %i", ItemID, Amount );
|
||||
if( !isValidItem( ItemID ) )
|
||||
{
|
||||
LOGERROR("Error in recipes file (%s): Invalid Item ID %i", a_File, ItemID );
|
||||
bDontAddRecipe = true;
|
||||
}
|
||||
|
||||
// Do a sanity check - Handshake algorithm :)
|
||||
bool bDuplicateEntries = false;
|
||||
for(unsigned int i = 0; i < RecipeSlots.size(); i++)
|
||||
{
|
||||
for(unsigned int j = i+1; j < RecipeSlots.size(); j++)
|
||||
{
|
||||
if( RecipeSlots[i].x == RecipeSlots[j].x && RecipeSlots[i].y == RecipeSlots[j].y )
|
||||
{
|
||||
LOGERROR("Error in recipes file (%s): Duplicate item on coordinates %i:%i", a_File, RecipeSlots[i].x+1, RecipeSlots[i].y+1 );
|
||||
bDontAddRecipe = true;
|
||||
bDuplicateEntries = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if( bDuplicateEntries )
|
||||
{
|
||||
PrintNear( f, 64 );
|
||||
PrintRecipe( RecipeSlots );
|
||||
}
|
||||
|
||||
if( bDontAddRecipe == false )
|
||||
{
|
||||
cItem Item( (ENUM_ITEM_ID)ItemID, (char)Amount );
|
||||
Recipe* recipe = new Recipe;
|
||||
recipe->Result = Item;
|
||||
recipe->NumItems = RecipeSlots.size();
|
||||
recipe->Slots = new RecipeSlot[ recipe->NumItems ];
|
||||
memcpy( recipe->Slots, &RecipeSlots[0], sizeof(RecipeSlot)*recipe->NumItems );
|
||||
m_pState->Recipes.push_back( recipe );
|
||||
//LOG("Loaded recipe for %i times %i", Amount, ItemID );
|
||||
}
|
||||
|
||||
RecipeSlots.clear();
|
||||
}
|
||||
}
|
||||
if( bError ) break;
|
||||
}
|
||||
if( bError || ( !f.eof() && !f.good() ) )
|
||||
{
|
||||
LOGERROR("Error: Wrong format");
|
||||
PrintNear( f, 128 );
|
||||
}
|
||||
f.close();
|
||||
|
||||
LOG("Found %i recipes", m_pState->Recipes.size() );
|
||||
// for(RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr )
|
||||
// {
|
||||
// LOG("Recipe for %i times %i", (*itr)->Result.m_ItemCount, (*itr)->Result.m_ItemID );
|
||||
// for(unsigned int j = 0; j < (*itr)->NumItems; j++)
|
||||
// {
|
||||
// RecipeSlot Slot = (*itr)->Slots[j];
|
||||
// LOG("%i %i %i %i", Slot.x, Slot.y, Slot.Item.m_ItemID, Slot.Item.m_ItemCount );
|
||||
// }
|
||||
// }
|
||||
LOG("--Done loading recipes--");
|
||||
}
|
||||
|
||||
cItem cRecipeChecker::CookIngredients( cItem* a_Items, int a_Width, int a_Height, bool a_bConsumeIngredients /* = false */ )
|
||||
{
|
||||
int iLeft = 999, iTop = 999;
|
||||
int iRight = 0, iBottom = 0;
|
||||
for(int y = 0; y < a_Height; y++ ) for(int x = 0; x < a_Width; x++)
|
||||
{
|
||||
cItem Item = a_Items[x + y*a_Width];
|
||||
if( Item.m_ItemID != E_ITEM_EMPTY && Item.m_ItemCount > 0 )
|
||||
{
|
||||
iRight = MAX(x, iRight);
|
||||
iBottom = MAX(y, iBottom);
|
||||
iLeft = MIN(x, iLeft);
|
||||
iTop = MIN(y, iTop);
|
||||
}
|
||||
}
|
||||
|
||||
for(RecipeList::iterator itr = m_pState->Recipes.begin(); itr != m_pState->Recipes.end(); ++itr )
|
||||
{
|
||||
Recipe* recipe = (*itr);
|
||||
int Left = 999, Top = 999;
|
||||
int Right = 0, Bottom = 0;
|
||||
for(unsigned int i = 0; i < recipe->NumItems; i++)
|
||||
{
|
||||
Right = MAX(recipe->Slots[i].x, Right);
|
||||
Bottom = MAX(recipe->Slots[i].y, Bottom);
|
||||
Left = MIN(recipe->Slots[i].x, Left);
|
||||
Top = MIN(recipe->Slots[i].y, Top);
|
||||
}
|
||||
if( Right-Left != iRight-iLeft || Bottom-Top != iBottom-iTop ) continue;
|
||||
// it has the right dimensions
|
||||
|
||||
// Check for empty spaces
|
||||
unsigned int Hash = 0;
|
||||
for(unsigned int i = 0; i < recipe->NumItems; i++)
|
||||
{
|
||||
int x = recipe->Slots[i].x - Left + iLeft +1;
|
||||
int y = recipe->Slots[i].y - Top + iTop +1;
|
||||
Hash += x + y * a_Width;
|
||||
}
|
||||
for(int y = 0; y < a_Height; y++ ) for(int x = 0; x < a_Width; x++)
|
||||
{
|
||||
cItem & Item = a_Items[x + y*a_Width];
|
||||
if( Item.m_ItemID != E_ITEM_EMPTY && Item.m_ItemCount > 0 )
|
||||
{
|
||||
Hash -= (x+1) + (y+1)*a_Width;
|
||||
}
|
||||
}
|
||||
if( Hash != 0 ) continue; // Empty spaces not in right place
|
||||
|
||||
bool bWrong = false;
|
||||
for(unsigned int i = 0; i < recipe->NumItems; i++)
|
||||
{
|
||||
int x = recipe->Slots[i].x - Left + iLeft;
|
||||
int y = recipe->Slots[i].y - Top + iTop;
|
||||
cItem Item = a_Items[x + y*a_Width];
|
||||
if( Item.m_ItemID != recipe->Slots[i].Item.m_ItemID
|
||||
|| Item.m_ItemCount < recipe->Slots[i].Item.m_ItemCount )
|
||||
{
|
||||
bWrong = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( bWrong ) continue;
|
||||
|
||||
cItem Dish = recipe->Result;
|
||||
|
||||
// else
|
||||
if( a_bConsumeIngredients )
|
||||
{
|
||||
// Consume! nomnom~
|
||||
for(unsigned int i = 0; i < recipe->NumItems; i++)
|
||||
{
|
||||
int x = recipe->Slots[i].x - Left + iLeft;
|
||||
int y = recipe->Slots[i].y - Top + iTop;
|
||||
a_Items[x + y*a_Width].m_ItemCount -= recipe->Slots[i].Item.m_ItemCount;
|
||||
if( a_Items[x + y*a_Width].m_ItemCount <= 0 ) a_Items[x + y*a_Width].Empty();
|
||||
}
|
||||
Dish = CookIngredients( a_Items, a_Width, a_Height, false );
|
||||
}
|
||||
|
||||
// Return the resulting dish!
|
||||
return Dish;
|
||||
}
|
||||
return cItem();
|
||||
}
|
39
source/cRecipeChecker.h
Normal file
39
source/cRecipeChecker.h
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "cItem.h"
|
||||
|
||||
class cRecipeChecker
|
||||
{
|
||||
public:
|
||||
static cRecipeChecker * GetRecipeChecker();
|
||||
|
||||
// Grid of cItems of a_Width width and a_Height Height
|
||||
cItem CookIngredients( cItem* a_Items, int a_Width, int a_Height, bool a_bConsumeIngredients = false );
|
||||
|
||||
struct RecipeSlot
|
||||
{
|
||||
cItem Item;
|
||||
int x, y;
|
||||
};
|
||||
|
||||
struct Recipe
|
||||
{
|
||||
Recipe() : Slots( 0 ), NumItems( 0 ) {}
|
||||
~Recipe();
|
||||
RecipeSlot* Slots; // Array of RecipeSlots
|
||||
unsigned int NumItems;
|
||||
cItem Result;
|
||||
};
|
||||
|
||||
void ReloadRecipes();
|
||||
static void DeleteMe();
|
||||
private:
|
||||
friend class cRoot;
|
||||
cRecipeChecker();
|
||||
~cRecipeChecker();
|
||||
|
||||
struct sRecipeCheckerState;
|
||||
sRecipeCheckerState* m_pState;
|
||||
|
||||
void ClearRecipes();
|
||||
};
|
36
source/cReferenceManager.cpp
Normal file
36
source/cReferenceManager.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "cReferenceManager.h"
|
||||
#include "cEntity.h"
|
||||
|
||||
cReferenceManager::cReferenceManager( ENUM_REFERENCE_MANAGER_TYPE a_Type )
|
||||
: m_Type( a_Type )
|
||||
{
|
||||
}
|
||||
|
||||
cReferenceManager::~cReferenceManager()
|
||||
{
|
||||
if( m_Type == RFMNGR_REFERENCERS )
|
||||
{
|
||||
for( std::list< cEntity** >::iterator itr = m_References.begin(); itr != m_References.end(); ++itr )
|
||||
{
|
||||
*(*itr) = 0; // Set referenced pointer to 0
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for( std::list< cEntity** >::iterator itr = m_References.begin(); itr != m_References.end(); ++itr )
|
||||
{
|
||||
cEntity* Ptr = (*(*itr));
|
||||
if( Ptr ) Ptr->Dereference( *(*itr) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cReferenceManager::AddReference( cEntity*& a_EntityPtr )
|
||||
{
|
||||
m_References.push_back( &a_EntityPtr );
|
||||
}
|
||||
|
||||
void cReferenceManager::Dereference( cEntity*& a_EntityPtr )
|
||||
{
|
||||
m_References.remove( &a_EntityPtr );
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user