diff options
Diffstat (limited to 'source')
96 files changed, 3542 insertions, 1531 deletions
diff --git a/source/AllToLua.pkg b/source/AllToLua.pkg index 00257e460..6d4a4083a 100644 --- a/source/AllToLua.pkg +++ b/source/AllToLua.pkg @@ -47,6 +47,7 @@ $cfile "BlockEntities/DropSpenserEntity.h" $cfile "BlockEntities/DispenserEntity.h" $cfile "BlockEntities/DropperEntity.h" $cfile "BlockEntities/FurnaceEntity.h" +$cfile "BlockEntities/HopperEntity.h" $cfile "WebAdmin.h" $cfile "WebPlugin.h" $cfile "Root.h" diff --git a/source/Authenticator.cpp b/source/Authenticator.cpp index a45617f93..e09fd0871 100644 --- a/source/Authenticator.cpp +++ b/source/Authenticator.cpp @@ -28,7 +28,6 @@ cAuthenticator::cAuthenticator(void) : m_Address(DEFAULT_AUTH_ADDRESS), m_ShouldAuthenticate(true) { - ReadINI(); } @@ -45,14 +44,8 @@ cAuthenticator::~cAuthenticator() /// Read custom values from INI -void cAuthenticator::ReadINI(void) +void cAuthenticator::ReadINI(cIniFile & IniFile) { - cIniFile IniFile("settings.ini"); - if (!IniFile.ReadFile()) - { - return; - } - m_Server = IniFile.GetValue("Authentication", "Server"); m_Address = IniFile.GetValue("Authentication", "Address"); m_ShouldAuthenticate = IniFile.GetValueB("Authentication", "Authenticate", true); @@ -74,7 +67,6 @@ void cAuthenticator::ReadINI(void) if (bSave) { IniFile.SetValueB("Authentication", "Authenticate", m_ShouldAuthenticate); - IniFile.WriteFile(); } } @@ -100,8 +92,9 @@ void cAuthenticator::Authenticate(int a_ClientID, const AString & a_UserName, co -void cAuthenticator::Start(void) +void cAuthenticator::Start(cIniFile & IniFile) { + ReadINI(IniFile); m_ShouldTerminate = false; super::Start(); } diff --git a/source/Authenticator.h b/source/Authenticator.h index 868476d80..02cd6f4c5 100644 --- a/source/Authenticator.h +++ b/source/Authenticator.h @@ -37,13 +37,13 @@ public: ~cAuthenticator(); /// (Re-)read server and address from INI: - void ReadINI(void); + void ReadINI(cIniFile & IniFile); /// Queues a request for authenticating a user. If the auth fails, the user is kicked void Authenticate(int a_ClientID, const AString & a_UserName, const AString & a_ServerHash); /// Starts the authenticator thread. The thread may be started and stopped repeatedly - void Start(void); + void Start(cIniFile & IniFile); /// Stops the authenticator thread. The thread may be started and stopped repeatedly void Stop(void); diff --git a/source/Bindings.cpp b/source/Bindings.cpp index c241bad75..8259eda81 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 10/13/13 18:01:21. +** Generated automatically by tolua++-1.0.92 on 10/28/13 13:11:03. */ #ifndef __cplusplus @@ -46,6 +46,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S); #include "BlockEntities/DispenserEntity.h" #include "BlockEntities/DropperEntity.h" #include "BlockEntities/FurnaceEntity.h" +#include "BlockEntities/HopperEntity.h" #include "WebAdmin.h" #include "WebPlugin.h" #include "Root.h" @@ -74,9 +75,9 @@ static int tolua_collect_cItem (lua_State* tolua_S) return 0; } -static int tolua_collect_cFurnaceEntity (lua_State* tolua_S) +static int tolua_collect_Vector3f (lua_State* tolua_S) { - cFurnaceEntity* self = (cFurnaceEntity*) tolua_tousertype(tolua_S,1,0); + Vector3f* self = (Vector3f*) tolua_tousertype(tolua_S,1,0); Mtolua_delete(self); return 0; } @@ -144,9 +145,9 @@ static int tolua_collect_cPickup (lua_State* tolua_S) return 0; } -static int tolua_collect_sWebAdminPage (lua_State* tolua_S) +static int tolua_collect_cItems (lua_State* tolua_S) { - sWebAdminPage* self = (sWebAdminPage*) tolua_tousertype(tolua_S,1,0); + cItems* self = (cItems*) tolua_tousertype(tolua_S,1,0); Mtolua_delete(self); return 0; } @@ -172,9 +173,16 @@ static int tolua_collect_cBoundingBox (lua_State* tolua_S) return 0; } -static int tolua_collect_Vector3f (lua_State* tolua_S) +static int tolua_collect_sWebAdminPage (lua_State* tolua_S) { - Vector3f* self = (Vector3f*) tolua_tousertype(tolua_S,1,0); + sWebAdminPage* self = (sWebAdminPage*) tolua_tousertype(tolua_S,1,0); + Mtolua_delete(self); + return 0; +} + +static int tolua_collect_cHopperEntity (lua_State* tolua_S) +{ + cHopperEntity* self = (cHopperEntity*) tolua_tousertype(tolua_S,1,0); Mtolua_delete(self); return 0; } @@ -186,16 +194,16 @@ static int tolua_collect_Vector3i (lua_State* tolua_S) return 0; } -static int tolua_collect_cIniFile (lua_State* tolua_S) +static int tolua_collect_cFurnaceEntity (lua_State* tolua_S) { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); + cFurnaceEntity* self = (cFurnaceEntity*) tolua_tousertype(tolua_S,1,0); Mtolua_delete(self); return 0; } -static int tolua_collect_cItems (lua_State* tolua_S) +static int tolua_collect_cIniFile (lua_State* tolua_S) { - cItems* self = (cItems*) tolua_tousertype(tolua_S,1,0); + cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); Mtolua_delete(self); return 0; } @@ -222,7 +230,7 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cRoot"); tolua_usertype(tolua_S,"std::vector<cIniFile::key>"); tolua_usertype(tolua_S,"cPickup"); - tolua_usertype(tolua_S,"cItems"); + tolua_usertype(tolua_S,"sWebAdminPage"); tolua_usertype(tolua_S,"cFireChargeEntity"); tolua_usertype(tolua_S,"cWorld"); tolua_usertype(tolua_S,"cChunkDesc"); @@ -244,40 +252,40 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cHTTPServer::cCallbacks"); tolua_usertype(tolua_S,"cLuaWindow"); tolua_usertype(tolua_S,"cInventory"); - tolua_usertype(tolua_S,"cBoundingBox"); + tolua_usertype(tolua_S,"cHopperEntity"); + tolua_usertype(tolua_S,"std::vector<AString>"); tolua_usertype(tolua_S,"cBlockEntityWithItems"); tolua_usertype(tolua_S,"cWindow"); - tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"HTTPFormData"); - tolua_usertype(tolua_S,"cCraftingGrid"); + tolua_usertype(tolua_S,"cGroup"); tolua_usertype(tolua_S,"cArrowEntity"); tolua_usertype(tolua_S,"cDropSpenserEntity"); + tolua_usertype(tolua_S,"cCraftingGrid"); + tolua_usertype(tolua_S,"cPlayer"); tolua_usertype(tolua_S,"cBlockArea"); tolua_usertype(tolua_S,"cTracer"); tolua_usertype(tolua_S,"cStringMap"); - tolua_usertype(tolua_S,"cServer"); - tolua_usertype(tolua_S,"Vector3i"); tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"cCriticalSection"); tolua_usertype(tolua_S,"HTTPTemplateRequest"); + tolua_usertype(tolua_S,"cBoundingBox"); + tolua_usertype(tolua_S,"cServer"); + tolua_usertype(tolua_S,"Vector3i"); tolua_usertype(tolua_S,"cFile"); - tolua_usertype(tolua_S,"std::vector<std::string>"); + tolua_usertype(tolua_S,"cItems"); tolua_usertype(tolua_S,"cClientHandle"); + tolua_usertype(tolua_S,"cIniFile"); tolua_usertype(tolua_S,"cChatColor"); tolua_usertype(tolua_S,"cWebPlugin"); - tolua_usertype(tolua_S,"cWebAdmin"); - tolua_usertype(tolua_S,"cIniFile"); - tolua_usertype(tolua_S,"sWebAdminPage"); - tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"cPawn"); - tolua_usertype(tolua_S,"cPlayer"); + tolua_usertype(tolua_S,"cThrownEggEntity"); tolua_usertype(tolua_S,"cGroupManager"); - tolua_usertype(tolua_S,"cBlockEntityWindowOwner"); - tolua_usertype(tolua_S,"HTTPRequest"); + tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"cProjectileEntity"); + tolua_usertype(tolua_S,"HTTPRequest"); tolua_usertype(tolua_S,"cItemGrid::cListener"); tolua_usertype(tolua_S,"cDropperEntity"); - tolua_usertype(tolua_S,"cThrownEggEntity"); } /* method: new of class cIniFile */ @@ -337,59 +345,6 @@ static int tolua_AllToLua_cIniFile_new00_local(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: new of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_new01 -static int tolua_AllToLua_cIniFile_new01(lua_State* tolua_S) -{ - tolua_Error tolua_err; - if ( - !tolua_isusertable(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else - { - const std::string a_Path = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - { - cIniFile* tolua_ret = (cIniFile*) Mtolua_new((cIniFile)(a_Path)); - tolua_pushusertype(tolua_S,(void*)tolua_ret,"cIniFile"); - tolua_pushcppstring(tolua_S,(const char*)a_Path); - } - } - return 2; -tolua_lerror: - return tolua_AllToLua_cIniFile_new00(tolua_S); -} -#endif //#ifndef TOLUA_DISABLE - -/* method: new_local of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_new01_local -static int tolua_AllToLua_cIniFile_new01_local(lua_State* tolua_S) -{ - tolua_Error tolua_err; - if ( - !tolua_isusertable(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else - { - const std::string a_Path = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - { - cIniFile* tolua_ret = (cIniFile*) Mtolua_new((cIniFile)(a_Path)); - tolua_pushusertype(tolua_S,(void*)tolua_ret,"cIniFile"); - tolua_register_gc(tolua_S,lua_gettop(tolua_S)); - tolua_pushcppstring(tolua_S,(const char*)a_Path); - } - } - return 2; -tolua_lerror: - return tolua_AllToLua_cIniFile_new00_local(tolua_S); -} -#endif //#ifndef TOLUA_DISABLE - /* method: CaseSensitive of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_CaseSensitive00 static int tolua_AllToLua_cIniFile_CaseSensitive00(lua_State* tolua_S) @@ -452,101 +407,6 @@ static int tolua_AllToLua_cIniFile_CaseInsensitive00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: Path of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_Path00 -static int tolua_AllToLua_cIniFile_Path00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string newPath = ((const std::string) tolua_tocppstring(tolua_S,2,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Path'", NULL); -#endif - { - self->Path(newPath); - tolua_pushcppstring(tolua_S,(const char*)newPath); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'Path'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: Path of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_Path01 -static int tolua_AllToLua_cIniFile_Path01(lua_State* tolua_S) -{ - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else - { - const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Path'", NULL); -#endif - { - const std::string tolua_ret = (const std::string) self->Path(); - tolua_pushcppstring(tolua_S,(const char*)tolua_ret); - } - } - return 1; -tolua_lerror: - return tolua_AllToLua_cIniFile_Path00(tolua_S); -} -#endif //#ifndef TOLUA_DISABLE - -/* method: SetPath of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_SetPath00 -static int tolua_AllToLua_cIniFile_SetPath00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string newPath = ((const std::string) tolua_tocppstring(tolua_S,2,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetPath'", NULL); -#endif - { - self->SetPath(newPath); - tolua_pushcppstring(tolua_S,(const char*)newPath); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'SetPath'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: ReadFile of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_ReadFile00 static int tolua_AllToLua_cIniFile_ReadFile00(lua_State* tolua_S) @@ -555,24 +415,27 @@ static int tolua_AllToLua_cIniFile_ReadFile00(lua_State* tolua_S) tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_isboolean(tolua_S,2,1,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isboolean(tolua_S,3,1,&tolua_err) || + !tolua_isnoobj(tolua_S,4,&tolua_err) ) goto tolua_lerror; else #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - bool a_AllowExampleRedirect = ((bool) tolua_toboolean(tolua_S,2,true)); + const AString a_FileName = ((const AString) tolua_tocppstring(tolua_S,2,0)); + bool a_AllowExampleRedirect = ((bool) tolua_toboolean(tolua_S,3,true)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'ReadFile'", NULL); #endif { - bool tolua_ret = (bool) self->ReadFile(a_AllowExampleRedirect); + bool tolua_ret = (bool) self->ReadFile(a_FileName,a_AllowExampleRedirect); tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_FileName); } } - return 1; + return 2; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'ReadFile'.",&tolua_err); @@ -589,22 +452,25 @@ static int tolua_AllToLua_cIniFile_WriteFile00(lua_State* tolua_S) tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) ) goto tolua_lerror; else #endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); + const AString a_FileName = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'WriteFile'", NULL); #endif { - bool tolua_ret = (bool) self->WriteFile(); + bool tolua_ret = (bool) self->WriteFile(a_FileName); tolua_pushboolean(tolua_S,(bool)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_FileName); } } - return 1; + return 2; #ifndef TOLUA_RELEASE tolua_lerror: tolua_error(tolua_S,"#ferror in function 'WriteFile'.",&tolua_err); @@ -644,68 +510,6 @@ static int tolua_AllToLua_cIniFile_Clear00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: Reset of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_Reset00 -static int tolua_AllToLua_cIniFile_Reset00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Reset'", NULL); -#endif - { - self->Reset(); - } - } - return 0; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'Reset'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - -/* method: Erase of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_Erase00 -static int tolua_AllToLua_cIniFile_Erase00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Erase'", NULL); -#endif - { - self->Erase(); - } - } - return 0; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'Erase'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: FindKey of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_FindKey00 static int tolua_AllToLua_cIniFile_FindKey00(lua_State* tolua_S) @@ -722,12 +526,12 @@ static int tolua_AllToLua_cIniFile_FindKey00(lua_State* tolua_S) #endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'FindKey'", NULL); #endif { - long tolua_ret = (long) self->FindKey(keyname); + int tolua_ret = (int) self->FindKey(keyname); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)keyname); } @@ -758,13 +562,13 @@ static int tolua_AllToLua_cIniFile_FindValue00(lua_State* tolua_S) #endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const std::string valuename = ((const std::string) tolua_tocppstring(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const AString valuename = ((const AString) tolua_tocppstring(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'FindValue'", NULL); #endif { - long tolua_ret = (long) self->FindValue(keyID,valuename); + int tolua_ret = (int) self->FindValue(keyID,valuename); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)valuename); } @@ -778,38 +582,6 @@ static int tolua_AllToLua_cIniFile_FindValue00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: NumKeys of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_NumKeys00 -static int tolua_AllToLua_cIniFile_NumKeys00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'NumKeys'", NULL); -#endif - { - unsigned tolua_ret = (unsigned) self->NumKeys(); - tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'NumKeys'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetNumKeys of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetNumKeys00 static int tolua_AllToLua_cIniFile_GetNumKeys00(lua_State* tolua_S) @@ -829,7 +601,7 @@ static int tolua_AllToLua_cIniFile_GetNumKeys00(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumKeys'", NULL); #endif { - unsigned tolua_ret = (unsigned) self->GetNumKeys(); + int tolua_ret = (int) self->GetNumKeys(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } @@ -858,12 +630,12 @@ static int tolua_AllToLua_cIniFile_AddKeyName00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddKeyName'", NULL); #endif { - unsigned tolua_ret = (unsigned) self->AddKeyName(keyname); + int tolua_ret = (int) self->AddKeyName(keyname); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)keyname); } @@ -877,40 +649,6 @@ static int tolua_AllToLua_cIniFile_AddKeyName00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: KeyName of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_KeyName00 -static int tolua_AllToLua_cIniFile_KeyName00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'KeyName'", NULL); -#endif - { - std::string tolua_ret = (std::string) self->KeyName(keyID); - tolua_pushcppstring(tolua_S,(const char*)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'KeyName'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetKeyName of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetKeyName00 static int tolua_AllToLua_cIniFile_GetKeyName00(lua_State* tolua_S) @@ -927,12 +665,12 @@ static int tolua_AllToLua_cIniFile_GetKeyName00(lua_State* tolua_S) #endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetKeyName'", NULL); #endif { - std::string tolua_ret = (std::string) self->GetKeyName(keyID); + AString tolua_ret = (AString) self->GetKeyName(keyID); tolua_pushcppstring(tolua_S,(const char*)tolua_ret); } } @@ -945,41 +683,6 @@ static int tolua_AllToLua_cIniFile_GetKeyName00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: NumValues of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_NumValues00 -static int tolua_AllToLua_cIniFile_NumValues00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'NumValues'", NULL); -#endif - { - unsigned tolua_ret = (unsigned) self->NumValues(keyname); - tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); - tolua_pushcppstring(tolua_S,(const char*)keyname); - } - } - return 2; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'NumValues'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetNumValues of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetNumValues00 static int tolua_AllToLua_cIniFile_GetNumValues00(lua_State* tolua_S) @@ -987,7 +690,7 @@ static int tolua_AllToLua_cIniFile_GetNumValues00(lua_State* tolua_S) #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || + !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || !tolua_iscppstring(tolua_S,2,0,&tolua_err) || !tolua_isnoobj(tolua_S,3,&tolua_err) ) @@ -995,13 +698,13 @@ static int tolua_AllToLua_cIniFile_GetNumValues00(lua_State* tolua_S) else #endif { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); + const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumValues'", NULL); #endif { - unsigned tolua_ret = (unsigned) self->GetNumValues(keyname); + int tolua_ret = (int) self->GetNumValues(keyname); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)keyname); } @@ -1015,55 +718,26 @@ static int tolua_AllToLua_cIniFile_GetNumValues00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: NumValues of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_NumValues01 -static int tolua_AllToLua_cIniFile_NumValues01(lua_State* tolua_S) -{ - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) - ) - goto tolua_lerror; - else - { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'NumValues'", NULL); -#endif - { - unsigned tolua_ret = (unsigned) self->NumValues(keyID); - tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); - } - } - return 1; -tolua_lerror: - return tolua_AllToLua_cIniFile_NumValues00(tolua_S); -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetNumValues of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetNumValues01 static int tolua_AllToLua_cIniFile_GetNumValues01(lua_State* tolua_S) { tolua_Error tolua_err; if ( - !tolua_isusertype(tolua_S,1,"cIniFile",0,&tolua_err) || + !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || !tolua_isnumber(tolua_S,2,0,&tolua_err) || !tolua_isnoobj(tolua_S,3,&tolua_err) ) goto tolua_lerror; else { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); + const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumValues'", NULL); #endif { - unsigned tolua_ret = (unsigned) self->GetNumValues(keyID); + int tolua_ret = (int) self->GetNumValues(keyID); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } @@ -1073,43 +747,6 @@ tolua_lerror: } #endif //#ifndef TOLUA_DISABLE -/* method: ValueName of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_ValueName00 -static int tolua_AllToLua_cIniFile_ValueName00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,0,&tolua_err) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnoobj(tolua_S,4,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'ValueName'", NULL); -#endif - { - std::string tolua_ret = (std::string) self->ValueName(keyname,valueID); - tolua_pushcppstring(tolua_S,(const char*)tolua_ret); - tolua_pushcppstring(tolua_S,(const char*)keyname); - } - } - return 2; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'ValueName'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetValueName of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetValueName00 static int tolua_AllToLua_cIniFile_GetValueName00(lua_State* tolua_S) @@ -1127,13 +764,13 @@ static int tolua_AllToLua_cIniFile_GetValueName00(lua_State* tolua_S) #endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const int valueID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetValueName'", NULL); #endif { - std::string tolua_ret = (std::string) self->GetValueName(keyname,valueID); + AString tolua_ret = (AString) self->GetValueName(keyname,valueID); tolua_pushcppstring(tolua_S,(const char*)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)keyname); } @@ -1147,37 +784,6 @@ static int tolua_AllToLua_cIniFile_GetValueName00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: ValueName of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_ValueName01 -static int tolua_AllToLua_cIniFile_ValueName01(lua_State* tolua_S) -{ - tolua_Error tolua_err; - if ( - !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || - !tolua_isnumber(tolua_S,2,0,&tolua_err) || - !tolua_isnumber(tolua_S,3,0,&tolua_err) || - !tolua_isnoobj(tolua_S,4,&tolua_err) - ) - goto tolua_lerror; - else - { - const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'ValueName'", NULL); -#endif - { - std::string tolua_ret = (std::string) self->ValueName(keyID,valueID); - tolua_pushcppstring(tolua_S,(const char*)tolua_ret); - } - } - return 1; -tolua_lerror: - return tolua_AllToLua_cIniFile_ValueName00(tolua_S); -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetValueName of class cIniFile */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetValueName01 static int tolua_AllToLua_cIniFile_GetValueName01(lua_State* tolua_S) @@ -1193,13 +799,13 @@ static int tolua_AllToLua_cIniFile_GetValueName01(lua_State* tolua_S) else { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const int valueID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetValueName'", NULL); #endif { - std::string tolua_ret = (std::string) self->GetValueName(keyID,valueID); + AString tolua_ret = (AString) self->GetValueName(keyID,valueID); tolua_pushcppstring(tolua_S,(const char*)tolua_ret); } } @@ -1298,8 +904,8 @@ static int tolua_AllToLua_cIniFile_GetValue02(lua_State* tolua_S) else { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const int valueID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetValue'", NULL); #endif @@ -1330,8 +936,8 @@ static int tolua_AllToLua_cIniFile_GetValue03(lua_State* tolua_S) else { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const int valueID = ((const int) tolua_tonumber(tolua_S,3,0)); const AString defValue = ((const AString) tolua_tocppstring(tolua_S,4,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetValue'", NULL); @@ -1680,9 +1286,9 @@ static int tolua_AllToLua_cIniFile_SetValue00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); - const std::string value = ((const std::string) tolua_tocppstring(tolua_S,4,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const int valueID = ((const int) tolua_tonumber(tolua_S,3,0)); + const AString value = ((const AString) tolua_tocppstring(tolua_S,4,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetValue'", NULL); #endif @@ -1718,9 +1324,9 @@ static int tolua_AllToLua_cIniFile_SetValue01(lua_State* tolua_S) else { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const std::string valuename = ((const std::string) tolua_tocppstring(tolua_S,3,0)); - const std::string value = ((const std::string) tolua_tocppstring(tolua_S,4,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const AString valuename = ((const AString) tolua_tocppstring(tolua_S,3,0)); + const AString value = ((const AString) tolua_tocppstring(tolua_S,4,0)); const bool create = ((const bool) tolua_toboolean(tolua_S,5,true)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SetValue'", NULL); @@ -1758,8 +1364,8 @@ static int tolua_AllToLua_cIniFile_SetValueI00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const std::string valuename = ((const std::string) tolua_tocppstring(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const AString valuename = ((const AString) tolua_tocppstring(tolua_S,3,0)); const int value = ((const int) tolua_tonumber(tolua_S,4,0)); const bool create = ((const bool) tolua_toboolean(tolua_S,5,true)); #ifndef TOLUA_RELEASE @@ -1800,8 +1406,8 @@ static int tolua_AllToLua_cIniFile_SetValueB00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const std::string valuename = ((const std::string) tolua_tocppstring(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const AString valuename = ((const AString) tolua_tocppstring(tolua_S,3,0)); const bool value = ((const bool) tolua_toboolean(tolua_S,4,0)); const bool create = ((const bool) tolua_toboolean(tolua_S,5,true)); #ifndef TOLUA_RELEASE @@ -1842,8 +1448,8 @@ static int tolua_AllToLua_cIniFile_SetValueF00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const std::string valuename = ((const std::string) tolua_tocppstring(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const AString valuename = ((const AString) tolua_tocppstring(tolua_S,3,0)); const double value = ((const double) tolua_tonumber(tolua_S,4,0)); const bool create = ((const bool) tolua_toboolean(tolua_S,5,true)); #ifndef TOLUA_RELEASE @@ -1882,8 +1488,8 @@ static int tolua_AllToLua_cIniFile_DeleteValueByID00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned valueID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const int valueID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteValueByID'", NULL); #endif @@ -1918,8 +1524,8 @@ static int tolua_AllToLua_cIniFile_DeleteValue00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const std::string valuename = ((const std::string) tolua_tocppstring(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const AString valuename = ((const AString) tolua_tocppstring(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteValue'", NULL); #endif @@ -1955,7 +1561,7 @@ static int tolua_AllToLua_cIniFile_DeleteKey00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteKey'", NULL); #endif @@ -1974,9 +1580,9 @@ static int tolua_AllToLua_cIniFile_DeleteKey00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: NumHeaderComments of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_NumHeaderComments00 -static int tolua_AllToLua_cIniFile_NumHeaderComments00(lua_State* tolua_S) +/* method: GetNumHeaderComments of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetNumHeaderComments00 +static int tolua_AllToLua_cIniFile_GetNumHeaderComments00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -1990,25 +1596,25 @@ static int tolua_AllToLua_cIniFile_NumHeaderComments00(lua_State* tolua_S) { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'NumHeaderComments'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumHeaderComments'", NULL); #endif { - unsigned tolua_ret = (unsigned) self->NumHeaderComments(); + int tolua_ret = (int) self->GetNumHeaderComments(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'NumHeaderComments'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetNumHeaderComments'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: HeaderComment of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_HeaderComment00 -static int tolua_AllToLua_cIniFile_HeaderComment00(lua_State* tolua_S) +/* method: AddHeaderComment of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_AddHeaderComment00 +static int tolua_AllToLua_cIniFile_AddHeaderComment00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -2022,28 +1628,29 @@ static int tolua_AllToLua_cIniFile_HeaderComment00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string comment = ((const std::string) tolua_tocppstring(tolua_S,2,0)); + const AString comment = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'HeaderComment'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddHeaderComment'", NULL); #endif { - self->HeaderComment(comment); + self->AddHeaderComment(comment); tolua_pushcppstring(tolua_S,(const char*)comment); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'HeaderComment'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'AddHeaderComment'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: HeaderComment of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_HeaderComment01 -static int tolua_AllToLua_cIniFile_HeaderComment01(lua_State* tolua_S) +/* method: GetHeaderComment of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetHeaderComment00 +static int tolua_AllToLua_cIniFile_GetHeaderComment00(lua_State* tolua_S) { +#ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || @@ -2052,20 +1659,24 @@ static int tolua_AllToLua_cIniFile_HeaderComment01(lua_State* tolua_S) ) goto tolua_lerror; else +#endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned commentID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); + const int commentID = ((const int) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'HeaderComment'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetHeaderComment'", NULL); #endif { - std::string tolua_ret = (std::string) self->HeaderComment(commentID); + AString tolua_ret = (AString) self->GetHeaderComment(commentID); tolua_pushcppstring(tolua_S,(const char*)tolua_ret); } } return 1; -tolua_lerror: - return tolua_AllToLua_cIniFile_HeaderComment00(tolua_S); +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetHeaderComment'.",&tolua_err); + return 0; +#endif } #endif //#ifndef TOLUA_DISABLE @@ -2085,7 +1696,7 @@ static int tolua_AllToLua_cIniFile_DeleteHeaderComment00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - unsigned commentID = ((unsigned) tolua_tonumber(tolua_S,2,0)); + int commentID = ((int) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteHeaderComment'", NULL); #endif @@ -2134,9 +1745,9 @@ static int tolua_AllToLua_cIniFile_DeleteHeaderComments00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: NumKeyComments of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_NumKeyComments00 -static int tolua_AllToLua_cIniFile_NumKeyComments00(lua_State* tolua_S) +/* method: GetNumKeyComments of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetNumKeyComments00 +static int tolua_AllToLua_cIniFile_GetNumKeyComments00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -2150,27 +1761,27 @@ static int tolua_AllToLua_cIniFile_NumKeyComments00(lua_State* tolua_S) #endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'NumKeyComments'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumKeyComments'", NULL); #endif { - unsigned tolua_ret = (unsigned) self->NumKeyComments(keyID); + int tolua_ret = (int) self->GetNumKeyComments(keyID); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'NumKeyComments'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetNumKeyComments'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: NumKeyComments of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_NumKeyComments01 -static int tolua_AllToLua_cIniFile_NumKeyComments01(lua_State* tolua_S) +/* method: GetNumKeyComments of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetNumKeyComments01 +static int tolua_AllToLua_cIniFile_GetNumKeyComments01(lua_State* tolua_S) { tolua_Error tolua_err; if ( @@ -2182,25 +1793,25 @@ static int tolua_AllToLua_cIniFile_NumKeyComments01(lua_State* tolua_S) else { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'NumKeyComments'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetNumKeyComments'", NULL); #endif { - unsigned tolua_ret = (unsigned) self->NumKeyComments(keyname); + int tolua_ret = (int) self->GetNumKeyComments(keyname); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)keyname); } } return 2; tolua_lerror: - return tolua_AllToLua_cIniFile_NumKeyComments00(tolua_S); + return tolua_AllToLua_cIniFile_GetNumKeyComments00(tolua_S); } #endif //#ifndef TOLUA_DISABLE -/* method: KeyComment of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_KeyComment00 -static int tolua_AllToLua_cIniFile_KeyComment00(lua_State* tolua_S) +/* method: AddKeyComment of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_AddKeyComment00 +static int tolua_AllToLua_cIniFile_AddKeyComment00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -2215,13 +1826,13 @@ static int tolua_AllToLua_cIniFile_KeyComment00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const std::string comment = ((const std::string) tolua_tocppstring(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const AString comment = ((const AString) tolua_tocppstring(tolua_S,3,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'KeyComment'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddKeyComment'", NULL); #endif { - bool tolua_ret = (bool) self->KeyComment(keyID,comment); + bool tolua_ret = (bool) self->AddKeyComment(keyID,comment); tolua_pushboolean(tolua_S,(bool)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)comment); } @@ -2229,15 +1840,15 @@ static int tolua_AllToLua_cIniFile_KeyComment00(lua_State* tolua_S) return 2; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'KeyComment'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'AddKeyComment'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: KeyComment of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_KeyComment01 -static int tolua_AllToLua_cIniFile_KeyComment01(lua_State* tolua_S) +/* method: AddKeyComment of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_AddKeyComment01 +static int tolua_AllToLua_cIniFile_AddKeyComment01(lua_State* tolua_S) { tolua_Error tolua_err; if ( @@ -2250,13 +1861,13 @@ static int tolua_AllToLua_cIniFile_KeyComment01(lua_State* tolua_S) else { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const std::string comment = ((const std::string) tolua_tocppstring(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const AString comment = ((const AString) tolua_tocppstring(tolua_S,3,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'KeyComment'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'AddKeyComment'", NULL); #endif { - bool tolua_ret = (bool) self->KeyComment(keyname,comment); + bool tolua_ret = (bool) self->AddKeyComment(keyname,comment); tolua_pushboolean(tolua_S,(bool)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)keyname); tolua_pushcppstring(tolua_S,(const char*)comment); @@ -2264,14 +1875,15 @@ static int tolua_AllToLua_cIniFile_KeyComment01(lua_State* tolua_S) } return 3; tolua_lerror: - return tolua_AllToLua_cIniFile_KeyComment00(tolua_S); + return tolua_AllToLua_cIniFile_AddKeyComment00(tolua_S); } #endif //#ifndef TOLUA_DISABLE -/* method: KeyComment of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_KeyComment02 -static int tolua_AllToLua_cIniFile_KeyComment02(lua_State* tolua_S) +/* method: GetKeyComment of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetKeyComment00 +static int tolua_AllToLua_cIniFile_GetKeyComment00(lua_State* tolua_S) { +#ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( !tolua_isusertype(tolua_S,1,"const cIniFile",0,&tolua_err) || @@ -2281,27 +1893,31 @@ static int tolua_AllToLua_cIniFile_KeyComment02(lua_State* tolua_S) ) goto tolua_lerror; else +#endif { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned commentID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const int commentID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'KeyComment'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetKeyComment'", NULL); #endif { - std::string tolua_ret = (std::string) self->KeyComment(keyID,commentID); + AString tolua_ret = (AString) self->GetKeyComment(keyID,commentID); tolua_pushcppstring(tolua_S,(const char*)tolua_ret); } } return 1; -tolua_lerror: - return tolua_AllToLua_cIniFile_KeyComment01(tolua_S); +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetKeyComment'.",&tolua_err); + return 0; +#endif } #endif //#ifndef TOLUA_DISABLE -/* method: KeyComment of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_KeyComment03 -static int tolua_AllToLua_cIniFile_KeyComment03(lua_State* tolua_S) +/* method: GetKeyComment of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_GetKeyComment01 +static int tolua_AllToLua_cIniFile_GetKeyComment01(lua_State* tolua_S) { tolua_Error tolua_err; if ( @@ -2314,20 +1930,20 @@ static int tolua_AllToLua_cIniFile_KeyComment03(lua_State* tolua_S) else { const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const unsigned commentID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const int commentID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'KeyComment'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetKeyComment'", NULL); #endif { - std::string tolua_ret = (std::string) self->KeyComment(keyname,commentID); + AString tolua_ret = (AString) self->GetKeyComment(keyname,commentID); tolua_pushcppstring(tolua_S,(const char*)tolua_ret); tolua_pushcppstring(tolua_S,(const char*)keyname); } } return 2; tolua_lerror: - return tolua_AllToLua_cIniFile_KeyComment02(tolua_S); + return tolua_AllToLua_cIniFile_GetKeyComment00(tolua_S); } #endif //#ifndef TOLUA_DISABLE @@ -2348,8 +1964,8 @@ static int tolua_AllToLua_cIniFile_DeleteKeyComment00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); - const unsigned commentID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); + const int commentID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteKeyComment'", NULL); #endif @@ -2382,8 +1998,8 @@ static int tolua_AllToLua_cIniFile_DeleteKeyComment01(lua_State* tolua_S) else { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); - const unsigned commentID = ((const unsigned) tolua_tonumber(tolua_S,3,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); + const int commentID = ((const int) tolua_tonumber(tolua_S,3,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteKeyComment'", NULL); #endif @@ -2415,7 +2031,7 @@ static int tolua_AllToLua_cIniFile_DeleteKeyComments00(lua_State* tolua_S) #endif { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const unsigned keyID = ((const unsigned) tolua_tonumber(tolua_S,2,0)); + const int keyID = ((const int) tolua_tonumber(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteKeyComments'", NULL); #endif @@ -2447,7 +2063,7 @@ static int tolua_AllToLua_cIniFile_DeleteKeyComments01(lua_State* tolua_S) else { cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); - const std::string keyname = ((const std::string) tolua_tocppstring(tolua_S,2,0)); + const AString keyname = ((const AString) tolua_tocppstring(tolua_S,2,0)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'DeleteKeyComments'", NULL); #endif @@ -10065,24 +9681,26 @@ static int tolua_AllToLua_cPickup_new00(lua_State* tolua_S) !tolua_isnumber(tolua_S,3,0,&tolua_err) || !tolua_isnumber(tolua_S,4,0,&tolua_err) || (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) || - !tolua_isnumber(tolua_S,6,1,&tolua_err) || + !tolua_isboolean(tolua_S,6,0,&tolua_err) || !tolua_isnumber(tolua_S,7,1,&tolua_err) || !tolua_isnumber(tolua_S,8,1,&tolua_err) || - !tolua_isnoobj(tolua_S,9,&tolua_err) + !tolua_isnumber(tolua_S,9,1,&tolua_err) || + !tolua_isnoobj(tolua_S,10,&tolua_err) ) goto tolua_lerror; else #endif { - double a_X = ((double) tolua_tonumber(tolua_S,2,0)); - double a_Y = ((double) tolua_tonumber(tolua_S,3,0)); - double a_Z = ((double) tolua_tonumber(tolua_S,4,0)); + double a_PosX = ((double) tolua_tonumber(tolua_S,2,0)); + double a_PosY = ((double) tolua_tonumber(tolua_S,3,0)); + double a_PosZ = ((double) tolua_tonumber(tolua_S,4,0)); const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0)); - float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f)); - float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f)); - float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f)); + bool IsPlayerCreated = ((bool) tolua_toboolean(tolua_S,6,0)); + float a_SpeedX = ((float) tolua_tonumber(tolua_S,7,0.f)); + float a_SpeedY = ((float) tolua_tonumber(tolua_S,8,0.f)); + float a_SpeedZ = ((float) tolua_tonumber(tolua_S,9,0.f)); { - cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_X,a_Y,a_Z,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ)); + cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_PosX,a_PosY,a_PosZ,*a_Item,IsPlayerCreated,a_SpeedX,a_SpeedY,a_SpeedZ)); tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup"); } } @@ -10107,24 +9725,26 @@ static int tolua_AllToLua_cPickup_new00_local(lua_State* tolua_S) !tolua_isnumber(tolua_S,3,0,&tolua_err) || !tolua_isnumber(tolua_S,4,0,&tolua_err) || (tolua_isvaluenil(tolua_S,5,&tolua_err) || !tolua_isusertype(tolua_S,5,"const cItem",0,&tolua_err)) || - !tolua_isnumber(tolua_S,6,1,&tolua_err) || + !tolua_isboolean(tolua_S,6,0,&tolua_err) || !tolua_isnumber(tolua_S,7,1,&tolua_err) || !tolua_isnumber(tolua_S,8,1,&tolua_err) || - !tolua_isnoobj(tolua_S,9,&tolua_err) + !tolua_isnumber(tolua_S,9,1,&tolua_err) || + !tolua_isnoobj(tolua_S,10,&tolua_err) ) goto tolua_lerror; else #endif { - double a_X = ((double) tolua_tonumber(tolua_S,2,0)); - double a_Y = ((double) tolua_tonumber(tolua_S,3,0)); - double a_Z = ((double) tolua_tonumber(tolua_S,4,0)); + double a_PosX = ((double) tolua_tonumber(tolua_S,2,0)); + double a_PosY = ((double) tolua_tonumber(tolua_S,3,0)); + double a_PosZ = ((double) tolua_tonumber(tolua_S,4,0)); const cItem* a_Item = ((const cItem*) tolua_tousertype(tolua_S,5,0)); - float a_SpeedX = ((float) tolua_tonumber(tolua_S,6,0.f)); - float a_SpeedY = ((float) tolua_tonumber(tolua_S,7,0.f)); - float a_SpeedZ = ((float) tolua_tonumber(tolua_S,8,0.f)); + bool IsPlayerCreated = ((bool) tolua_toboolean(tolua_S,6,0)); + float a_SpeedX = ((float) tolua_tonumber(tolua_S,7,0.f)); + float a_SpeedY = ((float) tolua_tonumber(tolua_S,8,0.f)); + float a_SpeedZ = ((float) tolua_tonumber(tolua_S,9,0.f)); { - cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_X,a_Y,a_Z,*a_Item,a_SpeedX,a_SpeedY,a_SpeedZ)); + cPickup* tolua_ret = (cPickup*) Mtolua_new((cPickup)(a_PosX,a_PosY,a_PosZ,*a_Item,IsPlayerCreated,a_SpeedX,a_SpeedY,a_SpeedZ)); tolua_pushusertype(tolua_S,(void*)tolua_ret,"cPickup"); tolua_register_gc(tolua_S,lua_gettop(tolua_S)); } @@ -10268,6 +9888,38 @@ static int tolua_AllToLua_cPickup_IsCollected00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: IsPlayerCreated of class cPickup */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cPickup_IsPlayerCreated00 +static int tolua_AllToLua_cPickup_IsPlayerCreated00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cPickup",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const cPickup* self = (const cPickup*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'IsPlayerCreated'", NULL); +#endif + { + bool tolua_ret = (bool) self->IsPlayerCreated(); + tolua_pushboolean(tolua_S,(bool)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'IsPlayerCreated'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetProjectileKind of class cProjectileEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cProjectileEntity_GetProjectileKind00 static int tolua_AllToLua_cProjectileEntity_GetProjectileKind00(lua_State* tolua_S) @@ -12533,7 +12185,8 @@ static int tolua_AllToLua_cWorld_SpawnItemPickups00(lua_State* tolua_S) !tolua_isnumber(tolua_S,4,0,&tolua_err) || !tolua_isnumber(tolua_S,5,0,&tolua_err) || !tolua_isnumber(tolua_S,6,1,&tolua_err) || - !tolua_isnoobj(tolua_S,7,&tolua_err) + !tolua_isboolean(tolua_S,7,1,&tolua_err) || + !tolua_isnoobj(tolua_S,8,&tolua_err) ) goto tolua_lerror; else @@ -12545,11 +12198,12 @@ static int tolua_AllToLua_cWorld_SpawnItemPickups00(lua_State* tolua_S) double a_BlockY = ((double) tolua_tonumber(tolua_S,4,0)); double a_BlockZ = ((double) tolua_tonumber(tolua_S,5,0)); double a_FlyAwaySpeed = ((double) tolua_tonumber(tolua_S,6,1.0)); + bool IsPlayerCreated = ((bool) tolua_toboolean(tolua_S,7,false)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SpawnItemPickups'", NULL); #endif { - self->SpawnItemPickups(*a_Pickups,a_BlockX,a_BlockY,a_BlockZ,a_FlyAwaySpeed); + self->SpawnItemPickups(*a_Pickups,a_BlockX,a_BlockY,a_BlockZ,a_FlyAwaySpeed,IsPlayerCreated); } } return 0; @@ -12575,7 +12229,8 @@ static int tolua_AllToLua_cWorld_SpawnItemPickups01(lua_State* tolua_S) !tolua_isnumber(tolua_S,6,0,&tolua_err) || !tolua_isnumber(tolua_S,7,0,&tolua_err) || !tolua_isnumber(tolua_S,8,0,&tolua_err) || - !tolua_isnoobj(tolua_S,9,&tolua_err) + !tolua_isboolean(tolua_S,9,1,&tolua_err) || + !tolua_isnoobj(tolua_S,10,&tolua_err) ) goto tolua_lerror; else @@ -12588,11 +12243,12 @@ static int tolua_AllToLua_cWorld_SpawnItemPickups01(lua_State* tolua_S) double a_SpeedX = ((double) tolua_tonumber(tolua_S,6,0)); double a_SpeedY = ((double) tolua_tonumber(tolua_S,7,0)); double a_SpeedZ = ((double) tolua_tonumber(tolua_S,8,0)); + bool IsPlayerCreated = ((bool) tolua_toboolean(tolua_S,9,false)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'SpawnItemPickups'", NULL); #endif { - self->SpawnItemPickups(*a_Pickups,a_BlockX,a_BlockY,a_BlockZ,a_SpeedX,a_SpeedY,a_SpeedZ); + self->SpawnItemPickups(*a_Pickups,a_BlockX,a_BlockY,a_BlockZ,a_SpeedX,a_SpeedY,a_SpeedZ,IsPlayerCreated); } } return 0; @@ -18309,23 +17965,6 @@ static int tolua_AllToLua_cDropSpenserEntity_SetRedstonePower00(lua_State* tolua } #endif //#ifndef TOLUA_DISABLE -/* get function: __cBlockEntityWindowOwner__ of class cDropSpenserEntity */ -#ifndef TOLUA_DISABLE_tolua_get_cDropSpenserEntity___cBlockEntityWindowOwner__ -static int tolua_get_cDropSpenserEntity___cBlockEntityWindowOwner__(lua_State* tolua_S) -{ - cDropSpenserEntity* self = (cDropSpenserEntity*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable '__cBlockEntityWindowOwner__'",NULL); -#endif -#ifdef __cplusplus - tolua_pushusertype(tolua_S,(void*)static_cast<cBlockEntityWindowOwner*>(self), "cBlockEntityWindowOwner"); -#else - tolua_pushusertype(tolua_S,(void*)((cBlockEntityWindowOwner*)self), "cBlockEntityWindowOwner"); -#endif - return 1; -} -#endif //#ifndef TOLUA_DISABLE - /* method: new of class cDispenserEntity */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cDispenserEntity_new00 static int tolua_AllToLua_cDispenserEntity_new00(lua_State* tolua_S) @@ -18864,6 +18503,75 @@ static int tolua_AllToLua_cFurnaceEntity_HasFuelTimeLeft00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: new of class cHopperEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cHopperEntity_new00 +static int tolua_AllToLua_cHopperEntity_new00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cHopperEntity",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0)); + int a_BlockY = ((int) tolua_tonumber(tolua_S,3,0)); + int a_BlockZ = ((int) tolua_tonumber(tolua_S,4,0)); + { + cHopperEntity* tolua_ret = (cHopperEntity*) Mtolua_new((cHopperEntity)(a_BlockX,a_BlockY,a_BlockZ)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cHopperEntity"); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: new_local of class cHopperEntity */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cHopperEntity_new00_local +static int tolua_AllToLua_cHopperEntity_new00_local(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cHopperEntity",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnumber(tolua_S,3,0,&tolua_err) || + !tolua_isnumber(tolua_S,4,0,&tolua_err) || + !tolua_isnoobj(tolua_S,5,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + int a_BlockX = ((int) tolua_tonumber(tolua_S,2,0)); + int a_BlockY = ((int) tolua_tonumber(tolua_S,3,0)); + int a_BlockZ = ((int) tolua_tonumber(tolua_S,4,0)); + { + cHopperEntity* tolua_ret = (cHopperEntity*) Mtolua_new((cHopperEntity)(a_BlockX,a_BlockY,a_BlockZ)); + tolua_pushusertype(tolua_S,(void*)tolua_ret,"cHopperEntity"); + tolua_register_gc(tolua_S,lua_gettop(tolua_S)); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'new'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* get function: Name of class HTTPFormData */ #ifndef TOLUA_DISABLE_tolua_get_HTTPFormData_Name static int tolua_get_HTTPFormData_Name(lua_State* tolua_S) @@ -19164,34 +18872,6 @@ static int tolua_set_sWebAdminPage_TabName(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* method: GetMemoryUsage of class cWebAdmin */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cWebAdmin_GetMemoryUsage00 -static int tolua_AllToLua_cWebAdmin_GetMemoryUsage00(lua_State* tolua_S) -{ -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if ( - !tolua_isusertable(tolua_S,1,"cWebAdmin",0,&tolua_err) || - !tolua_isnoobj(tolua_S,2,&tolua_err) - ) - goto tolua_lerror; - else -#endif - { - { - int tolua_ret = (int) cWebAdmin::GetMemoryUsage(); - tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); - } - } - return 1; -#ifndef TOLUA_RELEASE - tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetMemoryUsage'.",&tolua_err); - return 0; -#endif -} -#endif //#ifndef TOLUA_DISABLE - /* method: GetPage of class cWebAdmin */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWebAdmin_GetPage00 static int tolua_AllToLua_cWebAdmin_GetPage00(lua_State* tolua_S) @@ -19303,6 +18983,37 @@ static int tolua_AllToLua_cWebAdmin_GetBaseURL00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE +/* method: GetHTMLEscapedString of class cWebAdmin */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cWebAdmin_GetHTMLEscapedString00 +static int tolua_AllToLua_cWebAdmin_GetHTMLEscapedString00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cWebAdmin",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const AString a_Input = ((const AString) tolua_tocppstring(tolua_S,2,0)); + { + AString tolua_ret = (AString) cWebAdmin::GetHTMLEscapedString(a_Input); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_Input); + } + } + return 2; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetHTMLEscapedString'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + /* method: GetWebTitle of class cWebPlugin */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cWebPlugin_GetWebTitle00 static int tolua_AllToLua_cWebPlugin_GetWebTitle00(lua_State* tolua_S) @@ -19400,36 +19111,6 @@ static int tolua_AllToLua_cWebPlugin_SafeString00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* get function: m_PrimaryServerVersion of class cRoot */ -#ifndef TOLUA_DISABLE_tolua_get_cRoot_m_PrimaryServerVersion -static int tolua_get_cRoot_m_PrimaryServerVersion(lua_State* tolua_S) -{ - cRoot* self = (cRoot*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'm_PrimaryServerVersion'",NULL); -#endif - tolua_pushnumber(tolua_S,(lua_Number)self->m_PrimaryServerVersion); - return 1; -} -#endif //#ifndef TOLUA_DISABLE - -/* set function: m_PrimaryServerVersion of class cRoot */ -#ifndef TOLUA_DISABLE_tolua_set_cRoot_m_PrimaryServerVersion -static int tolua_set_cRoot_m_PrimaryServerVersion(lua_State* tolua_S) -{ - cRoot* self = (cRoot*) tolua_tousertype(tolua_S,1,0); -#ifndef TOLUA_RELEASE - tolua_Error tolua_err; - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable 'm_PrimaryServerVersion'",NULL); - if (!tolua_isnumber(tolua_S,2,0,&tolua_err)) - tolua_error(tolua_S,"#vinvalid type in variable assignment.",&tolua_err); -#endif - self->m_PrimaryServerVersion = ((int) tolua_tonumber(tolua_S,2,0)) -; - return 0; -} -#endif //#ifndef TOLUA_DISABLE - /* method: Get of class cRoot */ #ifndef TOLUA_DISABLE_tolua_AllToLua_cRoot_Get00 static int tolua_AllToLua_cRoot_Get00(lua_State* tolua_S) @@ -29145,50 +28826,186 @@ static int tolua_AllToLua_cLuaWindow_GetContents00(lua_State* tolua_S) } #endif //#ifndef TOLUA_DISABLE -/* get function: __cItemGrid of class cLuaWindow */ -#ifndef TOLUA_DISABLE_tolua_get_cLuaWindow___cItemGrid__cListener__ -static int tolua_get_cLuaWindow___cItemGrid__cListener__(lua_State* tolua_S) +/* method: GetMobType of class cMonster */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cMonster_GetMobType00 +static int tolua_AllToLua_cMonster_GetMobType00(lua_State* tolua_S) { - cLuaWindow* self = (cLuaWindow*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in accessing variable '__cItemGrid'",NULL); + tolua_Error tolua_err; + if ( + !tolua_isusertype(tolua_S,1,"const cMonster",0,&tolua_err) || + !tolua_isnoobj(tolua_S,2,&tolua_err) + ) + goto tolua_lerror; + else #endif -#ifdef __cplusplus - tolua_pushusertype(tolua_S,(void*)static_cast<cItemGrid::cListener*>(self), "cItemGrid::cListener"); -#else - tolua_pushusertype(tolua_S,(void*)((cItemGrid::cListener*)self), "cItemGrid::cListener"); + { + const cMonster* self = (const cMonster*) tolua_tousertype(tolua_S,1,0); +#ifndef TOLUA_RELEASE + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetMobType'", NULL); #endif + { + cMonster::eType tolua_ret = (cMonster::eType) self->GetMobType(); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetMobType'.",&tolua_err); + return 0; +#endif } #endif //#ifndef TOLUA_DISABLE -/* method: GetMobType of class cMonster */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cMonster_GetMobType00 -static int tolua_AllToLua_cMonster_GetMobType00(lua_State* tolua_S) +/* method: GetMobFamily of class cMonster */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cMonster_GetMobFamily00 +static int tolua_AllToLua_cMonster_GetMobFamily00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; if ( - !tolua_isusertype(tolua_S,1,"cMonster",0,&tolua_err) || + !tolua_isusertype(tolua_S,1,"const cMonster",0,&tolua_err) || !tolua_isnoobj(tolua_S,2,&tolua_err) ) goto tolua_lerror; else #endif { - cMonster* self = (cMonster*) tolua_tousertype(tolua_S,1,0); + const cMonster* self = (const cMonster*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE - if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetMobType'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'GetMobFamily'", NULL); #endif { - int tolua_ret = (int) self->GetMobType(); + cMonster::eFamily tolua_ret = (cMonster::eFamily) self->GetMobFamily(); tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); } } return 1; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'GetMobType'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'GetMobFamily'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: MobTypeToString of class cMonster */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cMonster_MobTypeToString00 +static int tolua_AllToLua_cMonster_MobTypeToString00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cMonster",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cMonster::eType a_MobType = ((cMonster::eType) (int) tolua_tonumber(tolua_S,2,0)); + { + AString tolua_ret = (AString) cMonster::MobTypeToString(a_MobType); + tolua_pushcppstring(tolua_S,(const char*)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'MobTypeToString'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: StringToMobType of class cMonster */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cMonster_StringToMobType00 +static int tolua_AllToLua_cMonster_StringToMobType00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cMonster",0,&tolua_err) || + !tolua_iscppstring(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + const AString a_MobTypeName = ((const AString) tolua_tocppstring(tolua_S,2,0)); + { + cMonster::eType tolua_ret = (cMonster::eType) cMonster::StringToMobType(a_MobTypeName); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + tolua_pushcppstring(tolua_S,(const char*)a_MobTypeName); + } + } + return 2; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'StringToMobType'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: FamilyFromType of class cMonster */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cMonster_FamilyFromType00 +static int tolua_AllToLua_cMonster_FamilyFromType00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cMonster",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cMonster::eType a_MobType = ((cMonster::eType) (int) tolua_tonumber(tolua_S,2,0)); + { + cMonster::eFamily tolua_ret = (cMonster::eFamily) cMonster::FamilyFromType(a_MobType); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'FamilyFromType'.",&tolua_err); + return 0; +#endif +} +#endif //#ifndef TOLUA_DISABLE + +/* method: GetSpawnDelay of class cMonster */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cMonster_GetSpawnDelay00 +static int tolua_AllToLua_cMonster_GetSpawnDelay00(lua_State* tolua_S) +{ +#ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertable(tolua_S,1,"cMonster",0,&tolua_err) || + !tolua_isnumber(tolua_S,2,0,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&tolua_err) + ) + goto tolua_lerror; + else +#endif + { + cMonster::eFamily a_MobFamily = ((cMonster::eFamily) (int) tolua_tonumber(tolua_S,2,0)); + { + int tolua_ret = (int) cMonster::GetSpawnDelay(a_MobFamily); + tolua_pushnumber(tolua_S,(lua_Number)tolua_ret); + } + } + return 1; +#ifndef TOLUA_RELEASE + tolua_lerror: + tolua_error(tolua_S,"#ferror in function 'GetSpawnDelay'.",&tolua_err); return 0; #endif } @@ -29278,33 +29095,19 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"new",tolua_AllToLua_cIniFile_new00); tolua_function(tolua_S,"new_local",tolua_AllToLua_cIniFile_new00_local); tolua_function(tolua_S,".call",tolua_AllToLua_cIniFile_new00_local); - tolua_function(tolua_S,"new",tolua_AllToLua_cIniFile_new01); - tolua_function(tolua_S,"new_local",tolua_AllToLua_cIniFile_new01_local); - tolua_function(tolua_S,".call",tolua_AllToLua_cIniFile_new01_local); tolua_function(tolua_S,"CaseSensitive",tolua_AllToLua_cIniFile_CaseSensitive00); tolua_function(tolua_S,"CaseInsensitive",tolua_AllToLua_cIniFile_CaseInsensitive00); - tolua_function(tolua_S,"Path",tolua_AllToLua_cIniFile_Path00); - tolua_function(tolua_S,"Path",tolua_AllToLua_cIniFile_Path01); - tolua_function(tolua_S,"SetPath",tolua_AllToLua_cIniFile_SetPath00); tolua_function(tolua_S,"ReadFile",tolua_AllToLua_cIniFile_ReadFile00); tolua_function(tolua_S,"WriteFile",tolua_AllToLua_cIniFile_WriteFile00); tolua_function(tolua_S,"Clear",tolua_AllToLua_cIniFile_Clear00); - tolua_function(tolua_S,"Reset",tolua_AllToLua_cIniFile_Reset00); - tolua_function(tolua_S,"Erase",tolua_AllToLua_cIniFile_Erase00); tolua_function(tolua_S,"FindKey",tolua_AllToLua_cIniFile_FindKey00); tolua_function(tolua_S,"FindValue",tolua_AllToLua_cIniFile_FindValue00); - tolua_function(tolua_S,"NumKeys",tolua_AllToLua_cIniFile_NumKeys00); tolua_function(tolua_S,"GetNumKeys",tolua_AllToLua_cIniFile_GetNumKeys00); tolua_function(tolua_S,"AddKeyName",tolua_AllToLua_cIniFile_AddKeyName00); - tolua_function(tolua_S,"KeyName",tolua_AllToLua_cIniFile_KeyName00); tolua_function(tolua_S,"GetKeyName",tolua_AllToLua_cIniFile_GetKeyName00); - tolua_function(tolua_S,"NumValues",tolua_AllToLua_cIniFile_NumValues00); tolua_function(tolua_S,"GetNumValues",tolua_AllToLua_cIniFile_GetNumValues00); - tolua_function(tolua_S,"NumValues",tolua_AllToLua_cIniFile_NumValues01); tolua_function(tolua_S,"GetNumValues",tolua_AllToLua_cIniFile_GetNumValues01); - tolua_function(tolua_S,"ValueName",tolua_AllToLua_cIniFile_ValueName00); tolua_function(tolua_S,"GetValueName",tolua_AllToLua_cIniFile_GetValueName00); - tolua_function(tolua_S,"ValueName",tolua_AllToLua_cIniFile_ValueName01); tolua_function(tolua_S,"GetValueName",tolua_AllToLua_cIniFile_GetValueName01); tolua_function(tolua_S,"GetValue",tolua_AllToLua_cIniFile_GetValue00); tolua_function(tolua_S,"GetValue",tolua_AllToLua_cIniFile_GetValue01); @@ -29326,17 +29129,17 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"DeleteValueByID",tolua_AllToLua_cIniFile_DeleteValueByID00); tolua_function(tolua_S,"DeleteValue",tolua_AllToLua_cIniFile_DeleteValue00); tolua_function(tolua_S,"DeleteKey",tolua_AllToLua_cIniFile_DeleteKey00); - tolua_function(tolua_S,"NumHeaderComments",tolua_AllToLua_cIniFile_NumHeaderComments00); - tolua_function(tolua_S,"HeaderComment",tolua_AllToLua_cIniFile_HeaderComment00); - tolua_function(tolua_S,"HeaderComment",tolua_AllToLua_cIniFile_HeaderComment01); + tolua_function(tolua_S,"GetNumHeaderComments",tolua_AllToLua_cIniFile_GetNumHeaderComments00); + tolua_function(tolua_S,"AddHeaderComment",tolua_AllToLua_cIniFile_AddHeaderComment00); + tolua_function(tolua_S,"GetHeaderComment",tolua_AllToLua_cIniFile_GetHeaderComment00); tolua_function(tolua_S,"DeleteHeaderComment",tolua_AllToLua_cIniFile_DeleteHeaderComment00); tolua_function(tolua_S,"DeleteHeaderComments",tolua_AllToLua_cIniFile_DeleteHeaderComments00); - tolua_function(tolua_S,"NumKeyComments",tolua_AllToLua_cIniFile_NumKeyComments00); - tolua_function(tolua_S,"NumKeyComments",tolua_AllToLua_cIniFile_NumKeyComments01); - tolua_function(tolua_S,"KeyComment",tolua_AllToLua_cIniFile_KeyComment00); - tolua_function(tolua_S,"KeyComment",tolua_AllToLua_cIniFile_KeyComment01); - tolua_function(tolua_S,"KeyComment",tolua_AllToLua_cIniFile_KeyComment02); - tolua_function(tolua_S,"KeyComment",tolua_AllToLua_cIniFile_KeyComment03); + tolua_function(tolua_S,"GetNumKeyComments",tolua_AllToLua_cIniFile_GetNumKeyComments00); + tolua_function(tolua_S,"GetNumKeyComments",tolua_AllToLua_cIniFile_GetNumKeyComments01); + tolua_function(tolua_S,"AddKeyComment",tolua_AllToLua_cIniFile_AddKeyComment00); + tolua_function(tolua_S,"AddKeyComment",tolua_AllToLua_cIniFile_AddKeyComment01); + tolua_function(tolua_S,"GetKeyComment",tolua_AllToLua_cIniFile_GetKeyComment00); + tolua_function(tolua_S,"GetKeyComment",tolua_AllToLua_cIniFile_GetKeyComment01); tolua_function(tolua_S,"DeleteKeyComment",tolua_AllToLua_cIniFile_DeleteKeyComment00); tolua_function(tolua_S,"DeleteKeyComment",tolua_AllToLua_cIniFile_DeleteKeyComment01); tolua_function(tolua_S,"DeleteKeyComments",tolua_AllToLua_cIniFile_DeleteKeyComments00); @@ -30320,6 +30123,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"CollectedBy",tolua_AllToLua_cPickup_CollectedBy00); tolua_function(tolua_S,"GetAge",tolua_AllToLua_cPickup_GetAge00); tolua_function(tolua_S,"IsCollected",tolua_AllToLua_cPickup_IsCollected00); + tolua_function(tolua_S,"IsPlayerCreated",tolua_AllToLua_cPickup_IsPlayerCreated00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cProjectileEntity","cProjectileEntity","cEntity",NULL); tolua_beginmodule(tolua_S,"cProjectileEntity"); @@ -30747,7 +30551,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"AddDropSpenserDir",tolua_AllToLua_cDropSpenserEntity_AddDropSpenserDir00); tolua_function(tolua_S,"Activate",tolua_AllToLua_cDropSpenserEntity_Activate00); tolua_function(tolua_S,"SetRedstonePower",tolua_AllToLua_cDropSpenserEntity_SetRedstonePower00); - tolua_variable(tolua_S,"__cBlockEntityWindowOwner__",tolua_get_cDropSpenserEntity___cBlockEntityWindowOwner__,NULL); tolua_endmodule(tolua_S); #ifdef __cplusplus tolua_cclass(tolua_S,"cDispenserEntity","cDispenserEntity","cDropSpenserEntity",tolua_collect_cDispenserEntity); @@ -30794,6 +30597,19 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,"GetFuelBurnTimeLeft",tolua_AllToLua_cFurnaceEntity_GetFuelBurnTimeLeft00); tolua_function(tolua_S,"HasFuelTimeLeft",tolua_AllToLua_cFurnaceEntity_HasFuelTimeLeft00); tolua_endmodule(tolua_S); + #ifdef __cplusplus + tolua_cclass(tolua_S,"cHopperEntity","cHopperEntity","cBlockEntityWithItems",tolua_collect_cHopperEntity); + #else + tolua_cclass(tolua_S,"cHopperEntity","cHopperEntity","cBlockEntityWithItems",NULL); + #endif + tolua_beginmodule(tolua_S,"cHopperEntity"); + tolua_constant(tolua_S,"ContentsHeight",cHopperEntity::ContentsHeight); + tolua_constant(tolua_S,"ContentsWidth",cHopperEntity::ContentsWidth); + tolua_constant(tolua_S,"TICKS_PER_TRANSFER",cHopperEntity::TICKS_PER_TRANSFER); + tolua_function(tolua_S,"new",tolua_AllToLua_cHopperEntity_new00); + tolua_function(tolua_S,"new_local",tolua_AllToLua_cHopperEntity_new00_local); + tolua_function(tolua_S,".call",tolua_AllToLua_cHopperEntity_new00_local); + tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"HTTPFormData","HTTPFormData","",NULL); tolua_beginmodule(tolua_S,"HTTPFormData"); tolua_variable(tolua_S,"Name",tolua_get_HTTPFormData_Name,tolua_set_HTTPFormData_Name); @@ -30822,10 +30638,10 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cWebAdmin","cWebAdmin","cHTTPServer::cCallbacks",NULL); tolua_beginmodule(tolua_S,"cWebAdmin"); - tolua_function(tolua_S,"GetMemoryUsage",tolua_AllToLua_cWebAdmin_GetMemoryUsage00); tolua_function(tolua_S,"GetPage",tolua_AllToLua_cWebAdmin_GetPage00); tolua_function(tolua_S,"GetDefaultPage",tolua_AllToLua_cWebAdmin_GetDefaultPage00); tolua_function(tolua_S,"GetBaseURL",tolua_AllToLua_cWebAdmin_GetBaseURL00); + tolua_function(tolua_S,"GetHTMLEscapedString",tolua_AllToLua_cWebAdmin_GetHTMLEscapedString00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cWebPlugin","cWebPlugin","",NULL); tolua_beginmodule(tolua_S,"cWebPlugin"); @@ -30835,7 +30651,6 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cRoot","cRoot","",NULL); tolua_beginmodule(tolua_S,"cRoot"); - tolua_variable(tolua_S,"m_PrimaryServerVersion",tolua_get_cRoot_m_PrimaryServerVersion,tolua_set_cRoot_m_PrimaryServerVersion); tolua_function(tolua_S,"Get",tolua_AllToLua_cRoot_Get00); tolua_function(tolua_S,"GetServer",tolua_AllToLua_cRoot_GetServer00); tolua_function(tolua_S,"GetDefaultWorld",tolua_AllToLua_cRoot_GetDefaultWorld00); @@ -31210,17 +31025,17 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cWindow","cWindow","",NULL); tolua_beginmodule(tolua_S,"cWindow"); - tolua_constant(tolua_S,"Inventory",cWindow::Inventory); - tolua_constant(tolua_S,"Chest",cWindow::Chest); - tolua_constant(tolua_S,"Workbench",cWindow::Workbench); - tolua_constant(tolua_S,"Furnace",cWindow::Furnace); - tolua_constant(tolua_S,"DropSpenser",cWindow::DropSpenser); - tolua_constant(tolua_S,"Enchantment",cWindow::Enchantment); - tolua_constant(tolua_S,"Brewery",cWindow::Brewery); - tolua_constant(tolua_S,"NPCTrade",cWindow::NPCTrade); - tolua_constant(tolua_S,"Beacon",cWindow::Beacon); - tolua_constant(tolua_S,"Anvil",cWindow::Anvil); - tolua_constant(tolua_S,"Hopper",cWindow::Hopper); + tolua_constant(tolua_S,"wtInventory",cWindow::wtInventory); + tolua_constant(tolua_S,"wtChest",cWindow::wtChest); + tolua_constant(tolua_S,"wtWorkbench",cWindow::wtWorkbench); + tolua_constant(tolua_S,"wtFurnace",cWindow::wtFurnace); + tolua_constant(tolua_S,"wtDropSpenser",cWindow::wtDropSpenser); + tolua_constant(tolua_S,"wtEnchantment",cWindow::wtEnchantment); + tolua_constant(tolua_S,"wtBrewery",cWindow::wtBrewery); + tolua_constant(tolua_S,"wtNPCTrade",cWindow::wtNPCTrade); + tolua_constant(tolua_S,"wtBeacon",cWindow::wtBeacon); + tolua_constant(tolua_S,"wtAnvil",cWindow::wtAnvil); + tolua_constant(tolua_S,"wtHopper",cWindow::wtHopper); tolua_function(tolua_S,"GetWindowID",tolua_AllToLua_cWindow_GetWindowID00); tolua_function(tolua_S,"GetWindowType",tolua_AllToLua_cWindow_GetWindowType00); tolua_function(tolua_S,"GetSlot",tolua_AllToLua_cWindow_GetSlot00); @@ -31244,10 +31059,10 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_function(tolua_S,".call",tolua_AllToLua_cLuaWindow_new00_local); tolua_function(tolua_S,"delete",tolua_AllToLua_cLuaWindow_delete00); tolua_function(tolua_S,"GetContents",tolua_AllToLua_cLuaWindow_GetContents00); - tolua_variable(tolua_S,"__cItemGrid__cListener__",tolua_get_cLuaWindow___cItemGrid__cListener__,NULL); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cMonster","cMonster","cPawn",NULL); tolua_beginmodule(tolua_S,"cMonster"); + tolua_constant(tolua_S,"mtInvalidType",cMonster::mtInvalidType); tolua_constant(tolua_S,"mtBat",cMonster::mtBat); tolua_constant(tolua_S,"mtBlaze",cMonster::mtBlaze); tolua_constant(tolua_S,"mtCaveSpider",cMonster::mtCaveSpider); @@ -31277,7 +31092,17 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"mtWolf",cMonster::mtWolf); tolua_constant(tolua_S,"mtZombie",cMonster::mtZombie); tolua_constant(tolua_S,"mtZombiePigman",cMonster::mtZombiePigman); + tolua_constant(tolua_S,"mfHostile",cMonster::mfHostile); + tolua_constant(tolua_S,"mfPassive",cMonster::mfPassive); + tolua_constant(tolua_S,"mfAmbient",cMonster::mfAmbient); + tolua_constant(tolua_S,"mfWater",cMonster::mfWater); + tolua_constant(tolua_S,"mfMaxplusone",cMonster::mfMaxplusone); tolua_function(tolua_S,"GetMobType",tolua_AllToLua_cMonster_GetMobType00); + tolua_function(tolua_S,"GetMobFamily",tolua_AllToLua_cMonster_GetMobFamily00); + tolua_function(tolua_S,"MobTypeToString",tolua_AllToLua_cMonster_MobTypeToString00); + tolua_function(tolua_S,"StringToMobType",tolua_AllToLua_cMonster_StringToMobType00); + tolua_function(tolua_S,"FamilyFromType",tolua_AllToLua_cMonster_FamilyFromType00); + tolua_function(tolua_S,"GetSpawnDelay",tolua_AllToLua_cMonster_GetSpawnDelay00); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"cLineBlockTracer","cLineBlockTracer","",NULL); tolua_beginmodule(tolua_S,"cLineBlockTracer"); diff --git a/source/Bindings.h b/source/Bindings.h index 1d567520c..411e608d9 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /*
** Lua binding: AllToLua
-** Generated automatically by tolua++-1.0.92 on 10/13/13 18:01:22.
+** Generated automatically by tolua++-1.0.92 on 10/28/13 13:11:04.
*/
/* Exported function */
diff --git a/source/BlockEntities/DropSpenserEntity.h b/source/BlockEntities/DropSpenserEntity.h index f2f1eba36..0e9039915 100644 --- a/source/BlockEntities/DropSpenserEntity.h +++ b/source/BlockEntities/DropSpenserEntity.h @@ -29,10 +29,10 @@ class cServer; -// tolua_begin -class cDropSpenserEntity : - public cBlockEntityWithItems, - public cBlockEntityWindowOwner +class cDropSpenserEntity : // tolua_export + public cBlockEntityWindowOwner, + // tolua_begin + public cBlockEntityWithItems { typedef cBlockEntityWithItems super; diff --git a/source/BlockEntities/HopperEntity.h b/source/BlockEntities/HopperEntity.h index a49868660..1a7650581 100644 --- a/source/BlockEntities/HopperEntity.h +++ b/source/BlockEntities/HopperEntity.h @@ -38,15 +38,12 @@ public: /// Constructor used for normal operation cHopperEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cWorld * a_World); - // tolua_begin - /** Returns the block coords of the block receiving the output items, based on the meta - Returns false if unattached + Returns false if unattached. + Exported in ManualBindings.cpp */ bool GetOutputBlockPos(NIBBLETYPE a_BlockMeta, int & a_OutputX, int & a_OutputY, int & a_OutputZ); - // tolua_end - static const char * GetClassStatic(void) { return "cHopperEntity"; } protected: @@ -95,7 +92,7 @@ protected: /// Moves one piece to the specified entity's contents' slot. Returns true if contents have changed. bool MoveItemsToSlot(cBlockEntityWithItems & a_Entity, int a_DstSlotNum); -} ; +} ; // tolua_export diff --git a/source/BlockID.cpp b/source/BlockID.cpp index 177652a46..7193094d8 100644 --- a/source/BlockID.cpp +++ b/source/BlockID.cpp @@ -42,20 +42,20 @@ class cBlockIDMap public: cBlockIDMap(void) { - cIniFile Ini("items.ini"); - if (!Ini.ReadFile()) + cIniFile Ini; + if (!Ini.ReadFile("items.ini")) { return; } - long KeyID = Ini.FindKey("Items"); + int KeyID = Ini.FindKey("Items"); if (KeyID == cIniFile::noID) { return; } - unsigned NumValues = Ini.GetNumValues(KeyID); - for (unsigned i = 0; i < NumValues; i++) + int NumValues = Ini.GetNumValues(KeyID); + for (int i = 0; i < NumValues; i++) { - AString Name = Ini.ValueName(KeyID, i); + AString Name = Ini.GetValueName(KeyID, i); if (Name.empty()) { continue; @@ -79,40 +79,43 @@ public: bool ResolveItem(const AString & a_ItemName, cItem & a_Item) { - ItemMap::iterator itr = m_Map.find(a_ItemName); + // Split into parts divided by either ':' or '^' + AStringVector Split = StringSplitAndTrim(a_ItemName, ":^"); + if (Split.empty()) + { + return false; + } + + ItemMap::iterator itr = m_Map.find(Split[0]); if (itr != m_Map.end()) { + // Resolved as a string, assign the type and the default damage / count a_Item.m_ItemType = itr->second.first; a_Item.m_ItemDamage = itr->second.second; if (a_Item.m_ItemDamage == -1) { a_Item.m_ItemDamage = 0; } - a_Item.m_ItemCount = 1; - return true; - } - - // Not a resolvable string, try pure numbers: "45:6", "45^6" etc. - AStringVector Split = StringSplit(a_ItemName, ":"); - if (Split.size() == 1) - { - Split = StringSplit(a_ItemName, "^"); } - if (Split.empty()) - { - return false; - } - a_Item.m_ItemType = (short)atoi(Split[0].c_str()); - if ((a_Item.m_ItemType == 0) && (Split[0] != "0")) + else { - // Parsing the number failed - return false; + // Not a resolvable string, try pure numbers: "45:6", "45^6" etc. + a_Item.m_ItemType = (short)atoi(Split[0].c_str()); + if ((a_Item.m_ItemType == 0) && (Split[0] != "0")) + { + // Parsing the number failed + return false; + } } + + // Parse the damage, if present: if (Split.size() < 2) { + // Not present, set the item as valid and return success: a_Item.m_ItemCount = 1; return true; } + a_Item.m_ItemDamage = atoi(Split[1].c_str()); if ((a_Item.m_ItemDamage == 0) && (Split[1] != "0")) { @@ -662,6 +665,7 @@ public: g_BlockTransparent[E_BLOCK_GLASS_PANE] = true; g_BlockTransparent[E_BLOCK_ICE] = true; g_BlockTransparent[E_BLOCK_IRON_DOOR] = true; + g_BlockTransparent[E_BLOCK_LAVA] = true; g_BlockTransparent[E_BLOCK_LEAVES] = true; g_BlockTransparent[E_BLOCK_LEVER] = true; g_BlockTransparent[E_BLOCK_MELON_STEM] = true; @@ -674,11 +678,14 @@ public: g_BlockTransparent[E_BLOCK_RED_MUSHROOM] = true; g_BlockTransparent[E_BLOCK_RED_ROSE] = true; g_BlockTransparent[E_BLOCK_SIGN_POST] = true; + g_BlockTransparent[E_BLOCK_STATIONARY_LAVA] = true; + g_BlockTransparent[E_BLOCK_STATIONARY_WATER] = true; g_BlockTransparent[E_BLOCK_STONE_PRESSURE_PLATE] = true; g_BlockTransparent[E_BLOCK_SNOW] = true; g_BlockTransparent[E_BLOCK_TALL_GRASS] = true; g_BlockTransparent[E_BLOCK_TORCH] = true; g_BlockTransparent[E_BLOCK_VINES] = true; + g_BlockTransparent[E_BLOCK_WATER] = true; g_BlockTransparent[E_BLOCK_WALLSIGN] = true; g_BlockTransparent[E_BLOCK_WOODEN_DOOR] = true; g_BlockTransparent[E_BLOCK_WOODEN_PRESSURE_PLATE] = true; diff --git a/source/Blocks/BlockDirt.h b/source/Blocks/BlockDirt.h index b2bc4756c..c694d79f6 100644 --- a/source/Blocks/BlockDirt.h +++ b/source/Blocks/BlockDirt.h @@ -37,7 +37,7 @@ public: if (a_BlockY < cChunkDef::Height - 1) { BLOCKTYPE Above = a_World->GetBlock(a_BlockX, a_BlockY + 1, a_BlockZ); - if (!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above]) + if ((!g_BlockTransparent[Above] && !g_BlockOneHitDig[Above]) || IsBlockWater(Above)) { a_World->FastSetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_DIRT, 0); return; @@ -69,7 +69,7 @@ public: NIBBLETYPE AboveMeta; IsValid = a_World->GetBlockTypeMeta(a_BlockX + OfsX, a_BlockY + OfsY + 1, a_BlockZ + OfsZ, AboveDest, AboveMeta); ASSERT(IsValid); // WTF - how did we get the DestBlock if AboveBlock is not valid? - if (g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest]) + if ((g_BlockOneHitDig[AboveDest] || g_BlockTransparent[AboveDest]) && !IsBlockWater(AboveDest)) { a_World->FastSetBlock(a_BlockX + OfsX, a_BlockY + OfsY, a_BlockZ + OfsZ, E_BLOCK_GRASS, 0); } diff --git a/source/ByteBuffer.cpp b/source/ByteBuffer.cpp index c82951271..bccd1c48b 100644 --- a/source/ByteBuffer.cpp +++ b/source/ByteBuffer.cpp @@ -13,8 +13,54 @@ -#define NEEDBYTES(Num) if (!CanReadBytes(Num)) return false; -#define PUTBYTES(Num) if (!CanWriteBytes(Num)) return false; +// If a string sent over the protocol is larger than this, a warning is emitted to the console +#define MAX_STRING_SIZE (512 KiB) + +#define NEEDBYTES(Num) if (!CanReadBytes(Num)) return false; // Check if at least Num bytes can be read from the buffer, return false if not +#define PUTBYTES(Num) if (!CanWriteBytes(Num)) return false; // Check if at least Num bytes can be written to the buffer, return false if not + + + + + +#if 0 + +/// Self-test of the VarInt-reading and writing code +class cByteBufferSelfTest +{ +public: + cByteBufferSelfTest(void) + { + TestRead(); + TestWrite(); + } + + void TestRead(void) + { + cByteBuffer buf(50); + buf.Write("\x05\xac\x02\x00", 4); + UInt32 v1; + ASSERT(buf.ReadVarInt(v1) && (v1 == 5)); + UInt32 v2; + ASSERT(buf.ReadVarInt(v2) && (v2 == 300)); + UInt32 v3; + ASSERT(buf.ReadVarInt(v3) && (v3 == 0)); + } + + void TestWrite(void) + { + cByteBuffer buf(50); + buf.WriteVarInt(5); + buf.WriteVarInt(300); + buf.WriteVarInt(0); + AString All; + buf.ReadAll(All); + ASSERT(All.size() == 4); + ASSERT(memcmp(All.data(), "\x05\xac\x02\x00", All.size()) == 0); + } +} g_ByteBufferTest; + +#endif @@ -328,6 +374,48 @@ bool cByteBuffer::ReadBEUTF16String16(AString & a_Value) +bool cByteBuffer::ReadVarInt(UInt32 & a_Value) +{ + CHECK_THREAD; + CheckValid(); + UInt32 Value = 0; + int Shift = 0; + unsigned char b = 0; + do + { + NEEDBYTES(1); + ReadBuf(&b, 1); + Value = Value | (((Int64)(b & 0x7f)) << Shift); + Shift += 7; + } while ((b & 0x80) != 0); + a_Value = Value; + return true; +} + + + + + +bool cByteBuffer::ReadVarUTF8String(AString & a_Value) +{ + CHECK_THREAD; + CheckValid(); + UInt32 Size = 0; + if (!ReadVarInt(Size)) + { + return false; + } + if (Size > MAX_STRING_SIZE) + { + LOGWARNING("%s: String too large: %llu (%llu KiB)", __FUNCTION__, Size, Size / 1024); + } + return ReadString(a_Value, (int)Size); +} + + + + + bool cByteBuffer::WriteChar(char a_Value) { CHECK_THREAD; @@ -446,6 +534,44 @@ bool cByteBuffer::WriteBEUTF16String16(const AString & a_Value) +bool cByteBuffer::WriteVarInt(UInt32 a_Value) +{ + CHECK_THREAD; + CheckValid(); + + // A 32-bit integer can be encoded by at most 5 bytes: + unsigned char b[5]; + int idx = 0; + do + { + b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); + a_Value = a_Value >> 7; + idx++; + } while (a_Value > 0); + + return WriteBuf(b, idx); +} + + + + +bool cByteBuffer::WriteVarUTF8String(const AString & a_Value) +{ + CHECK_THREAD; + CheckValid(); + PUTBYTES(a_Value.size() + 1); // This is a lower-bound on the bytes that will be actually written. Fail early. + bool res = WriteVarInt(a_Value.size()); + if (!res) + { + return false; + } + return WriteBuf(a_Value.data(), a_Value.size()); +} + + + + + bool cByteBuffer::ReadBuf(void * a_Buffer, int a_Count) { CHECK_THREAD; diff --git a/source/ByteBuffer.h b/source/ByteBuffer.h index 650eda5b0..21abb0377 100644 --- a/source/ByteBuffer.h +++ b/source/ByteBuffer.h @@ -57,8 +57,22 @@ public: bool ReadBEFloat (float & a_Value); bool ReadBEDouble (double & a_Value); bool ReadBool (bool & a_Value); - bool ReadBEUTF16String16(AString & a_Value); - + bool ReadBEUTF16String16(AString & a_Value); // string length as BE short, then string as UTF-16BE + bool ReadVarInt (UInt32 & a_Value); + bool ReadVarUTF8String (AString & a_Value); // string length as VarInt, then string as UTF-8 + + /// Reads VarInt, assigns it to anything that can be assigned from an UInt32 (unsigned short, char, Byte, double, ...) + template <typename T> bool ReadVarInt(T & a_Value) + { + UInt32 v; + bool res = ReadVarInt(v); + if (res) + { + a_Value = v; + } + return res; + } + // Write the specified datatype; return true if successfully written bool WriteChar (char a_Value); bool WriteByte (unsigned char a_Value); @@ -68,7 +82,9 @@ public: bool WriteBEFloat (float a_Value); bool WriteBEDouble (double a_Value); bool WriteBool (bool a_Value); - bool WriteBEUTF16String16(const AString & a_Value); + bool WriteBEUTF16String16(const AString & a_Value); // string length as BE short, then string as UTF-16BE + bool WriteVarInt (UInt32 a_Value); + bool WriteVarUTF8String (const AString & a_Value); // string length as VarInt, then string as UTF-8 /// Reads a_Count bytes into a_Buffer; returns true if successful bool ReadBuf(void * a_Buffer, int a_Count); diff --git a/source/Chunk.cpp b/source/Chunk.cpp index db533f642..be75eae41 100644 --- a/source/Chunk.cpp +++ b/source/Chunk.cpp @@ -30,6 +30,9 @@ #include "PluginManager.h" #include "Blocks/BlockHandler.h" #include "Simulator/FluidSimulator.h" +#include "MobCensus.h" +#include "MobSpawner.h" + #include <json/json.h> @@ -429,6 +432,129 @@ void cChunk::Stay(bool a_Stay) +void cChunk::CollectMobCensus(cMobCensus& toFill) +{ + toFill.CollectSpawnableChunk(*this); + std::list<const Vector3d*> playerPositions; + cPlayer* currentPlayer; + for (cClientHandleList::iterator itr = m_LoadedByClient.begin(), end = m_LoadedByClient.end(); itr != end; ++itr) + { + currentPlayer = (*itr)->GetPlayer(); + playerPositions.push_back(&(currentPlayer->GetPosition())); + } + + Vector3d currentPosition; + for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) + { + //LOGD("Counting entity #%i (%s)", (*itr)->GetUniqueID(), (*itr)->GetClass()); + if ((*itr)->IsMob()) + { + cMonster& Monster = (cMonster&)(**itr); + currentPosition = Monster.GetPosition(); + for (std::list<const Vector3d*>::const_iterator itr2 = playerPositions.begin(); itr2 != playerPositions.end(); itr2 ++) + { + toFill.CollectMob(Monster,*this,(currentPosition-**itr2).SqrLength()); + } + } + } // for itr - m_Entitites[] +} + + + + +void cChunk::getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ) +{ + ASSERT(a_MaxX * a_MaxY * a_MaxZ * 8 < 0x00ffffff); + int Random = m_World->GetTickRandomNumber(0x00ffffff); + a_X = Random % (a_MaxX * 2); + a_Y = (Random / (a_MaxX * 2)) % (a_MaxY * 2); + a_Z = ((Random / (a_MaxX * 2)) / (a_MaxY * 2)) % (a_MaxZ * 2); + a_X /= 2; + a_Y /= 2; + a_Z /= 2; +} + + + + + +void cChunk::getRandomBlockCoords(int& a_X, int& a_Y, int& a_Z) +{ + // MG TODO : check if this kind of optimization (only one random call) is still needed + // MG TODO : if so propagate it + + getThreeRandomNumber(a_X, a_Y, a_Z, Width, Height-2, Width); + a_Y++; +} + + + + + +void cChunk::SpawnMobs(cMobSpawner& a_MobSpawner) +{ + int Center_X,Center_Y,Center_Z; + getRandomBlockCoords(Center_X,Center_Y,Center_Z); + + BLOCKTYPE PackCenterBlock = GetBlock(Center_X, Center_Y, Center_Z); + if (a_MobSpawner.CheckPackCenter(PackCenterBlock)) + { + a_MobSpawner.NewPack(); + int NumberOfTries = 0; + int NumberOfSuccess = 0; + int MaxNbOfSuccess = 4; // this can be changed during the process for Wolves and Ghass + while (NumberOfTries < 12 && NumberOfSuccess < MaxNbOfSuccess) + { + const int HorizontalRange = 20; // MG TODO : relocate + const int VerticalRange = 0; // MG TODO : relocate + int Try_X, Try_Y, Try_Z; + getThreeRandomNumber(Try_X, Try_Y, Try_Z, 2*HorizontalRange+1 , 2*VerticalRange+1 , 2*HorizontalRange+1); + Try_X -= HorizontalRange; + Try_Y -= VerticalRange; + Try_Z -= HorizontalRange; + Try_X += Center_X; + Try_Y += Center_Y; + Try_Z += Center_Z; + + ASSERT(Try_Y > 0); + ASSERT(Try_Y < cChunkDef::Height-1); + + EMCSBiome Biome = m_ChunkMap->GetBiomeAt (Try_X, Try_Z); + // MG TODO : + // Moon cycle (for slime) + // check player and playerspawn presence < 24 blocks + // check mobs presence on the block + + // MG TODO : check that "Level" really means Y + + NIBBLETYPE SkyLight = 0; + + NIBBLETYPE BlockLight = 0; + + if (IsLightValid()) + { + cEntity* newMob = a_MobSpawner.TryToSpawnHere(this, Try_X, Try_Y, Try_Z, Biome, MaxNbOfSuccess); + if (newMob) + { + int WorldX, WorldY, WorldZ; + PositionToWorldPosition(Try_X, Try_Y, Try_Z, WorldX, WorldY, WorldZ); + double ActualX = WorldX + 0.5; + double ActualZ = WorldZ + 0.5; + newMob->SetPosition(ActualX, WorldY, ActualZ); + LOGD("Spawning %s #%i at %d,%d,%d",newMob->GetClass(),newMob->GetUniqueID(),WorldX, WorldY, WorldZ); + NumberOfSuccess++; + } + } + + NumberOfTries++; + } + } + +} + + + + void cChunk::Tick(float a_Dt) { @@ -457,10 +583,14 @@ void cChunk::Tick(float a_Dt) m_IsDirty = (*itr)->Tick(a_Dt, *this) | m_IsDirty; } - // Tick all entities in this chunk: + // Tick all entities in this chunk (except mobs): for (cEntityList::iterator itr = m_Entities.begin(); itr != m_Entities.end(); ++itr) { - (*itr)->Tick(a_Dt, *this); + // Mobs are tickes inside MobTick (as we don't have to tick them if they are far away from players) + if (!((*itr)->IsMob())) + { + (*itr)->Tick(a_Dt, *this); + } } // for itr - m_Entitites[] // Remove all entities that were scheduled for removal: @@ -923,45 +1053,14 @@ bool cChunk::UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE LOGWARNING("%s: requesting a block with a_RelY out of range: %d", __FUNCTION__, a_RelY); return false; } - - // Is it in this chunk? - if ((a_RelX >= 0) && (a_RelX < cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ < cChunkDef::Width)) - { - if (!IsValid()) - { - return false; - } - int BlockIdx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockType = GetBlock(BlockIdx); - a_BlockMeta = GetMeta(BlockIdx); - return true; - } - - // Not in this chunk, try walking the neighbors first: - if ((a_RelX < 0) && (m_NeighborXM != NULL)) - { - return m_NeighborXM->UnboundedRelGetBlock(a_RelX + cChunkDef::Width, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - } - if ((a_RelX >= cChunkDef::Width) && (m_NeighborXP != NULL)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - return m_NeighborXP->UnboundedRelGetBlock(a_RelX - cChunkDef::Width, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - } - if ((a_RelZ < 0) && (m_NeighborZM != NULL)) - { - return m_NeighborZM->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ + cChunkDef::Width, a_BlockType, a_BlockMeta); - } - if ((a_RelZ >= cChunkDef::Width) && (m_NeighborZP != NULL)) - { - return m_NeighborZP->UnboundedRelGetBlock(a_RelX, a_RelY, a_RelZ - cChunkDef::Width, a_BlockType, a_BlockMeta); + // The chunk is not available, bail out + return false; } - - // Neighbors not available, use the chunkmap to locate the chunk: - return m_ChunkMap->LockedGetBlock( - m_PosX * cChunkDef::Width + a_RelX, - ZERO_CHUNK_Y * cChunkDef::Height + a_RelY, - m_PosZ * cChunkDef::Width + a_RelZ, - a_BlockType, a_BlockMeta - ); + Chunk->GetBlockTypeMeta(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); + return true; } @@ -975,95 +1074,100 @@ bool cChunk::UnboundedRelGetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKT LOGWARNING("%s: requesting a block with a_RelY out of range: %d", __FUNCTION__, a_RelY); return false; } - - // Is it in this chunk? - if ((a_RelX >= 0) && (a_RelX < cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ < cChunkDef::Width)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - if (!IsValid()) - { - return false; - } - int BlockIdx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockType = GetBlock(BlockIdx); - return true; + // The chunk is not available, bail out + return false; } + a_BlockType = Chunk->GetBlock(a_RelX, a_RelY, a_RelZ); + return true; +} - // Not in this chunk, try walking the neighbors first: - if ((a_RelX < 0) && (m_NeighborXM != NULL)) - { - return m_NeighborXM->UnboundedRelGetBlockType(a_RelX + cChunkDef::Width, a_RelY, a_RelZ, a_BlockType); - } - if ((a_RelX >= cChunkDef::Width) && (m_NeighborXP != NULL)) - { - return m_NeighborXP->UnboundedRelGetBlockType(a_RelX - cChunkDef::Width, a_RelY, a_RelZ, a_BlockType); - } - if ((a_RelZ < 0) && (m_NeighborZM != NULL)) + + + + +bool cChunk::UnboundedRelGetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockMeta) const +{ + if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height)) { - return m_NeighborZM->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ + cChunkDef::Width, a_BlockType); + LOGWARNING("%s: requesting a block with a_RelY out of range: %d", __FUNCTION__, a_RelY); + return false; } - if ((a_RelZ >= cChunkDef::Width) && (m_NeighborZP != NULL)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - return m_NeighborZP->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ - cChunkDef::Width, a_BlockType); + // The chunk is not available, bail out + return false; } - - // Neighbors not available, use the chunkmap to locate the chunk: - return m_ChunkMap->LockedGetBlockType( - m_PosX * cChunkDef::Width + a_RelX, - ZERO_CHUNK_Y * cChunkDef::Height + a_RelY, - m_PosZ * cChunkDef::Width + a_RelZ, - a_BlockType - ); + a_BlockMeta = Chunk->GetMeta(a_RelX, a_RelY, a_RelZ); + return true; } -bool cChunk::UnboundedRelGetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockMeta) const +bool cChunk::UnboundedRelGetBlockBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockBlockLight) const { if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height)) { LOGWARNING("%s: requesting a block with a_RelY out of range: %d", __FUNCTION__, a_RelY); return false; } - - // Is it in this chunk? - if ((a_RelX >= 0) && (a_RelX < cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ < cChunkDef::Width)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - if (!IsValid()) - { - return false; - } - int BlockIdx = cChunkDef::MakeIndexNoCheck(a_RelX, a_RelY, a_RelZ); - a_BlockMeta = GetMeta(BlockIdx); - return true; + // The chunk is not available, bail out + return false; } + a_BlockBlockLight = Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ); + return true; +} + + + - // Not in this chunk, try walking the neighbors first: - if ((a_RelX < 0) && (m_NeighborXM != NULL)) + +bool cChunk::UnboundedRelGetBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockSkyLight) const +{ + if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height)) { - return m_NeighborXM->UnboundedRelGetBlockMeta(a_RelX + cChunkDef::Width, a_RelY, a_RelZ, a_BlockMeta); + LOGWARNING("%s: requesting a block with a_RelY out of range: %d", __FUNCTION__, a_RelY); + return false; } - if ((a_RelX >= cChunkDef::Width) && (m_NeighborXP != NULL)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - return m_NeighborXP->UnboundedRelGetBlockMeta(a_RelX - cChunkDef::Width, a_RelY, a_RelZ, a_BlockMeta); + // The chunk is not available, bail out + return false; } - if ((a_RelZ < 0) && (m_NeighborZM != NULL)) + a_BlockSkyLight = Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ); + return true; +} + + + + + +bool cChunk::UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockLight, NIBBLETYPE & a_SkyLight) const +{ + if ((a_RelY < 0) || (a_RelY >= cChunkDef::Height)) { - return m_NeighborZM->UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ + cChunkDef::Width, a_BlockMeta); + LOGWARNING("%s: requesting a block with a_RelY out of range: %d", __FUNCTION__, a_RelY); + return false; } - if ((a_RelZ >= cChunkDef::Width) && (m_NeighborZP != NULL)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - return m_NeighborZP->UnboundedRelGetBlockMeta(a_RelX, a_RelY, a_RelZ - cChunkDef::Width, a_BlockMeta); + // The chunk is not available, bail out + return false; } - - // Neighbors not available, use the chunkmap to locate the chunk: - return m_ChunkMap->LockedGetBlockMeta( - m_PosX * cChunkDef::Width + a_RelX, - ZERO_CHUNK_Y * cChunkDef::Height + a_RelY, - m_PosZ * cChunkDef::Width + a_RelZ, - a_BlockMeta - ); + int idx = Chunk->MakeIndex(a_RelX, a_RelY, a_RelZ); + a_BlockLight = Chunk->GetBlockLight(idx); + a_SkyLight = Chunk->GetSkyLight(idx); + return true; } @@ -1077,44 +1181,15 @@ bool cChunk::UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE LOGWARNING("UnboundedRelSetBlock(): requesting a block with a_RelY out of range: %d", a_RelY); return false; } - - // Is it in this chunk? - if ((a_RelX >= 0) && (a_RelX < cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ < cChunkDef::Width)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - if (!IsValid()) - { - return false; - } - SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - return true; - } - - // Not in this chunk, try walking the neighbors first: - if ((a_RelX < 0) && (m_NeighborXM != NULL)) - { - return m_NeighborXM->UnboundedRelSetBlock(a_RelX + cChunkDef::Width, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - } - if ((a_RelX >= cChunkDef::Width) && (m_NeighborXP != NULL)) - { - return m_NeighborXP->UnboundedRelSetBlock(a_RelX - cChunkDef::Width, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - } - if ((a_RelZ < 0) && (m_NeighborZM != NULL)) - { - return m_NeighborZM->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ + cChunkDef::Width, a_BlockType, a_BlockMeta); - } - if ((a_RelZ >= cChunkDef::Width) && (m_NeighborZP != NULL)) - { - return m_NeighborZP->UnboundedRelSetBlock(a_RelX, a_RelY, a_RelZ - cChunkDef::Width, a_BlockType, a_BlockMeta); + // The chunk is not available, bail out + return false; } - - // Neighbors not available, use the chunkmap to locate the chunk: - return m_ChunkMap->LockedSetBlock( - m_PosX * cChunkDef::Width + a_RelX, - ZERO_CHUNK_Y * cChunkDef::Height + a_RelY, - m_PosZ * cChunkDef::Width + a_RelZ, - a_BlockType, a_BlockMeta - ); -} + Chunk->SetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); + return true; +} @@ -1127,43 +1202,14 @@ bool cChunk::UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKT LOGWARNING("UnboundedRelFastSetBlock(): requesting a block with a_RelY out of range: %d", a_RelY); return false; } - - // Is it in this chunk? - if ((a_RelX >= 0) && (a_RelX < cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ < cChunkDef::Width)) - { - if (!IsValid()) - { - return false; - } - FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - return true; - } - - // Not in this chunk, try walking the neighbors first: - if ((a_RelX < 0) && (m_NeighborXM != NULL)) - { - return m_NeighborXM->UnboundedRelFastSetBlock(a_RelX + cChunkDef::Width, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - } - if ((a_RelX >= cChunkDef::Width) && (m_NeighborXP != NULL)) - { - return m_NeighborXP->UnboundedRelFastSetBlock(a_RelX - cChunkDef::Width, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); - } - if ((a_RelZ < 0) && (m_NeighborZM != NULL)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk == NULL) || !Chunk->IsValid()) { - return m_NeighborZM->UnboundedRelFastSetBlock(a_RelX, a_RelY, a_RelZ + cChunkDef::Width, a_BlockType, a_BlockMeta); - } - if ((a_RelZ >= cChunkDef::Width) && (m_NeighborZP != NULL)) - { - return m_NeighborZP->UnboundedRelFastSetBlock(a_RelX, a_RelY, a_RelZ - cChunkDef::Width, a_BlockType, a_BlockMeta); + // The chunk is not available, bail out + return false; } - - // Neighbors not available, use the chunkmap to locate the chunk: - return m_ChunkMap->LockedFastSetBlock( - m_PosX * cChunkDef::Width + a_RelX, - ZERO_CHUNK_Y * cChunkDef::Height + a_RelY, - m_PosZ * cChunkDef::Width + a_RelZ, - a_BlockType, a_BlockMeta - ); + Chunk->FastSetBlock(a_RelX, a_RelY, a_RelZ, a_BlockType, a_BlockMeta); + return true; } @@ -1177,44 +1223,18 @@ void cChunk::UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ) // Outside of chunkmap return; } - - // Is it in this chunk? - if ((a_RelX >= 0) && (a_RelX < cChunkDef::Width) && (a_RelZ >= 0) && (a_RelZ < cChunkDef::Width)) - { - QueueTickBlock(a_RelX, a_RelY, a_RelZ); - return; - } - - // Not in this chunk, try walking the neighbors first: - if ((a_RelX < 0) && (m_NeighborXM != NULL)) - { - m_NeighborXM->UnboundedQueueTickBlock(a_RelX + cChunkDef::Width, a_RelY, a_RelZ); - return; - } - if ((a_RelX >= cChunkDef::Width) && (m_NeighborXP != NULL)) - { - m_NeighborXP->UnboundedQueueTickBlock(a_RelX - cChunkDef::Width, a_RelY, a_RelZ); - return; - } - if ((a_RelZ < 0) && (m_NeighborZM != NULL)) - { - m_NeighborZM->UnboundedQueueTickBlock(a_RelX, a_RelY, a_RelZ + cChunkDef::Width); - return; - } - if ((a_RelZ >= cChunkDef::Width) && (m_NeighborZP != NULL)) + cChunk * Chunk = GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + if ((Chunk != NULL) && Chunk->IsValid()) { - m_NeighborZP->UnboundedQueueTickBlock(a_RelX, a_RelY, a_RelZ - cChunkDef::Width); - return; + Chunk->QueueTickBlock(a_RelX, a_RelY, a_RelZ); } - - // Neighbors not available, ignore altogether } -int cChunk::GetHeight( int a_X, int a_Z ) +int cChunk::GetHeight(int a_X, int a_Z) { ASSERT((a_X >= 0) && (a_X < Width) && (a_Z >= 0) && (a_Z < Width)); @@ -2340,66 +2360,58 @@ cChunk * cChunk::GetRelNeighborChunk(int a_RelX, int a_RelZ) -cChunk * cChunk::GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) +cChunk * cChunk::GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) const { - bool ReturnThis = true; - int RelX = a_RelX; + cChunk * ToReturn = const_cast<cChunk *>(this); + + // The most common case: inside this chunk: + if ( + (a_RelX >= 0) && (a_RelX < Width) && + (a_RelZ >= 0) && (a_RelZ < Width) + ) + { + return ToReturn; + } + + // Request for a different chunk, calculate chunk offset: + int RelX = a_RelX; // Make a local copy of the coords (faster access) int RelZ = a_RelZ; - if (a_RelX < 0) + while ((RelX >= Width) && (ToReturn != NULL)) { - if (m_NeighborXM != NULL) - { - RelX = a_RelX + cChunkDef::Width; - cChunk * Candidate = m_NeighborXM->GetRelNeighborChunkAdjustCoords(RelX, RelZ); - if (Candidate != NULL) - { - a_RelX = RelX; - a_RelZ = RelZ; - return Candidate; - } - } - // Going X-first failed, but if the request is crossing Z as well, let's try the Z-first later on. - ReturnThis = false; + RelX -= Width; + ToReturn = ToReturn->m_NeighborXP; } - else if (a_RelX >= cChunkDef::Width) + while ((RelX < 0) && (ToReturn != NULL)) { - if (m_NeighborXP != NULL) - { - RelX = a_RelX - cChunkDef::Width; - cChunk * Candidate = m_NeighborXP->GetRelNeighborChunkAdjustCoords(RelX, RelZ); - if (Candidate != NULL) - { - a_RelX = RelX; - a_RelZ = RelZ; - return Candidate; - } - } - // Going X-first failed, but if the request is crossing Z as well, let's try the Z-first later on. - ReturnThis = false; + RelX += Width; + ToReturn = ToReturn->m_NeighborXM; } - - if (a_RelZ < 0) + while ((RelZ >= Width) && (ToReturn != NULL)) { - if (m_NeighborZM != NULL) - { - a_RelZ += cChunkDef::Width; - return m_NeighborZM->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - // For requests crossing both X and Z, the X-first way has been already tried - } - return NULL; + RelZ -= Width; + ToReturn = ToReturn->m_NeighborZP; } - else if (a_RelZ >= cChunkDef::Width) + while ((RelZ < 0) && (ToReturn != NULL)) { - if (m_NeighborZP != NULL) - { - a_RelZ -= cChunkDef::Width; - return m_NeighborZP->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); - // For requests crossing both X and Z, the X-first way has been already tried - } - return NULL; + RelZ += Width; + ToReturn = ToReturn->m_NeighborZM; + } + if (ToReturn != NULL) + { + a_RelX = RelX; + a_RelZ = RelZ; + return ToReturn; } - return (ReturnThis ? this : NULL); + // The chunk cannot be walked through neighbors, find it through the chunkmap: + int AbsX = a_RelX + m_PosX * Width; + int AbsZ = a_RelZ + m_PosZ * Width; + int DstChunkX, DstChunkZ; + BlockToChunk(AbsX, AbsZ, DstChunkX, DstChunkZ); + ToReturn = m_ChunkMap->FindChunk(DstChunkX, DstChunkZ); + a_RelX = AbsX - DstChunkX * Width; + a_RelZ = AbsZ - DstChunkZ * Width; + return ToReturn; } @@ -2774,6 +2786,17 @@ Vector3i cChunk::PositionToWorldPosition(int a_RelX, int a_RelY, int a_RelZ) +NIBBLETYPE cChunk::GetTimeAlteredLight(NIBBLETYPE a_Skylight) const +{ + a_Skylight -= m_World->GetSkyDarkness(); + // Because NIBBLETYPE is unsigned, we clamp it to 0 .. 15 by checking for values above 15 + return (a_Skylight < 16)? a_Skylight : 0; +} + + + + + #if !C_CHUNK_USE_INLINE # include "cChunk.inl.h" #endif diff --git a/source/Chunk.h b/source/Chunk.h index c979b7928..63a8f75cd 100644 --- a/source/Chunk.h +++ b/source/Chunk.h @@ -49,6 +49,8 @@ class cPickup; class cChunkDataSerializer; class cBlockArea; class cFluidSimulatorData; +class cMobCensus; +class cMobSpawner; typedef std::list<cClientHandle *> cClientHandleList; typedef cItemCallback<cEntity> cEntityCallback; @@ -124,6 +126,12 @@ public: /// Sets or resets the internal flag that prevents chunk from being unloaded void Stay(bool a_Stay = true); + /// Recence all mobs proximities to players in order to know what to do with them + void CollectMobCensus(cMobCensus& toFill); + + /// Try to Spawn Monsters inside chunk + void SpawnMobs(cMobSpawner& a_MobSpawner); + void Tick(float a_Dt); int GetPosX(void) const { return m_PosX; } @@ -163,11 +171,12 @@ public: cChunk * GetRelNeighborChunk(int a_RelX, int a_RelZ); /** - Returns the chunk into which the relatively-specified block belongs, by walking the neighbors. + Returns the chunk into which the relatively-specified block belongs. Also modifies the relative coords from this-relative to return-relative. - Will return self if appropriate. Returns NULL if not reachable through neighbors. + Will return self if appropriate. + Will try walking the neighbors first; if that fails, will query the chunkmap */ - cChunk * GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ); + cChunk * GetRelNeighborChunkAdjustCoords(int & a_RelX, int & a_RelZ) const; EMCSBiome GetBiomeAt(int a_RelX, int a_RelZ) const {return cChunkDef::GetBiome(m_BiomeMap, a_RelX, a_RelZ); } @@ -290,25 +299,40 @@ public: inline NIBBLETYPE GetBlockLight(int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockLight, a_RelX, a_RelY, a_RelZ); } inline NIBBLETYPE GetSkyLight (int a_RelX, int a_RelY, int a_RelZ) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_RelX, a_RelY, a_RelZ); } + inline NIBBLETYPE GetBlockLight(int a_Idx) const {return cChunkDef::GetNibble(m_BlockLight, a_Idx); } + inline NIBBLETYPE GetSkyLight (int a_Idx) const {return cChunkDef::GetNibble(m_BlockSkyLight, a_Idx); } - /// Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick() + /// Same as GetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success bool UnboundedRelGetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta) const; - /// Same as GetBlockType(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick() + /// Same as GetBlockType(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success bool UnboundedRelGetBlockType(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE & a_BlockType) const; - /// Same as GetBlockMeta(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick() + /// Same as GetBlockMeta(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success bool UnboundedRelGetBlockMeta(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockMeta) const; - /// Same as SetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick() + /// Same as GetBlockBlockLight(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success + bool UnboundedRelGetBlockBlockLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockLight) const; + + /// Same as GetBlockSkyLight(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success + bool UnboundedRelGetBlockSkyLight(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_SkyLight) const; + + /// Queries both BlockLight and SkyLight, relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success + bool UnboundedRelGetBlockLights(int a_RelX, int a_RelY, int a_RelZ, NIBBLETYPE & a_BlockLight, NIBBLETYPE & a_SkyLight) const; + + /// Same as SetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success bool UnboundedRelSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); - /// Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success; only usable in Tick() + /// Same as FastSetBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s or m_ChunkMap in such a case); returns true on success bool UnboundedRelFastSetBlock(int a_RelX, int a_RelY, int a_RelZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta); /// Same as QueueTickBlock(), but relative coords needn't be in this chunk (uses m_Neighbor-s in such a case), ignores unsuccessful attempts void UnboundedQueueTickBlock(int a_RelX, int a_RelY, int a_RelZ); + /// Light alterations based on time + NIBBLETYPE GetTimeAlteredLight(NIBBLETYPE a_Skylight) const; + + // Simulator data: cFireSimulatorChunkData & GetFireSimulatorData (void) { return m_FireSimulatorData; } cFluidSimulatorData * GetWaterSimulatorData(void) { return m_WaterSimulatorData; } @@ -385,6 +409,10 @@ private: cSandSimulatorChunkData m_SandSimulatorData; + // pick up a random block of this chunk + void getRandomBlockCoords(int& a_X, int& a_Y, int& a_Z); + void getThreeRandomNumber(int& a_X, int& a_Y, int& a_Z,int a_MaxX, int a_MaxY, int a_MaxZ); + void RemoveBlockEntity(cBlockEntity * a_BlockEntity); void AddBlockEntity (cBlockEntity * a_BlockEntity); diff --git a/source/ChunkDef.h b/source/ChunkDef.h index 9db88f293..d6630df7e 100644 --- a/source/ChunkDef.h +++ b/source/ChunkDef.h @@ -208,10 +208,15 @@ public: inline static unsigned int MakeIndex(int x, int y, int z ) { - if( x < cChunkDef::Width && x > -1 && y < cChunkDef::Height && y > -1 && z < cChunkDef::Width && z > -1 ) + if ( + (x < Width) && (x > -1) && + (y < Height) && (y > -1) && + (z < Width) && (z > -1) + ) { return MakeIndexNoCheck(x, y, z); } + ASSERT(!"cChunkDef::MakeIndex(): coords out of chunk range!"); return INDEX_OUT_OF_RANGE; } @@ -256,6 +261,7 @@ public: inline static void SetBlock(BLOCKTYPE * a_BlockTypes, int a_Index, BLOCKTYPE a_Type) { + ASSERT((a_Index >= 0) && (a_Index <= NumBlocks)); a_BlockTypes[a_Index] = a_Type; } @@ -271,41 +277,50 @@ public: inline static BLOCKTYPE GetBlock(const BLOCKTYPE * a_BlockTypes, int a_Idx) { - ASSERT((a_Idx >= 0) && (a_Idx < Width * Width * Height)); + ASSERT((a_Idx >= 0) && (a_Idx < NumBlocks)); return a_BlockTypes[a_Idx]; } inline static int GetHeight(const HeightMap & a_HeightMap, int a_X, int a_Z) { + ASSERT((a_X >= 0) && (a_X <= Width)); + ASSERT((a_Z >= 0) && (a_Z <= Width)); return a_HeightMap[a_X + Width * a_Z]; } inline static void SetHeight(HeightMap & a_HeightMap, int a_X, int a_Z, unsigned char a_Height) { + ASSERT((a_X >= 0) && (a_X <= Width)); + ASSERT((a_Z >= 0) && (a_Z <= Width)); a_HeightMap[a_X + Width * a_Z] = a_Height; } inline static EMCSBiome GetBiome(const BiomeMap & a_BiomeMap, int a_X, int a_Z) { + ASSERT((a_X >= 0) && (a_X <= Width)); + ASSERT((a_Z >= 0) && (a_Z <= Width)); return a_BiomeMap[a_X + Width * a_Z]; } inline static void SetBiome(BiomeMap & a_BiomeMap, int a_X, int a_Z, EMCSBiome a_Biome) { + ASSERT((a_X >= 0) && (a_X <= Width)); + ASSERT((a_Z >= 0) && (a_Z <= Width)); a_BiomeMap[a_X + Width * a_Z] = a_Biome; } static NIBBLETYPE GetNibble(const NIBBLETYPE * a_Buffer, int a_BlockIdx) { - if ((a_BlockIdx > -1) && (a_BlockIdx < cChunkDef::NumBlocks)) + if ((a_BlockIdx > -1) && (a_BlockIdx < NumBlocks)) { return (a_Buffer[a_BlockIdx / 2] >> ((a_BlockIdx & 1) * 4)) & 0x0f; } + ASSERT(!"cChunkDef::GetNibble(): index out of chunk range!"); return 0; } @@ -317,38 +332,48 @@ public: int Index = MakeIndexNoCheck(x, y, z); return (a_Buffer[Index / 2] >> ((Index & 1) * 4)) & 0x0f; } + ASSERT(!"cChunkDef::GetNibble(): coords out of chunk range!"); return 0; } static void SetNibble(NIBBLETYPE * a_Buffer, int a_BlockIdx, NIBBLETYPE a_Nibble) { - if ((a_BlockIdx > -1) && (a_BlockIdx < cChunkDef::NumBlocks)) + if ((a_BlockIdx < 0) || (a_BlockIdx >= NumBlocks)) { - a_Buffer[a_BlockIdx / 2] = ( - (a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set - ); + ASSERT(!"cChunkDef::SetNibble(): index out of range!"); + return; } + a_Buffer[a_BlockIdx / 2] = ( + (a_Buffer[a_BlockIdx / 2] & (0xf0 >> ((a_BlockIdx & 1) * 4))) | // The untouched nibble + ((a_Nibble & 0x0f) << ((a_BlockIdx & 1) * 4)) // The nibble being set + ); } static void SetNibble(NIBBLETYPE * a_Buffer, int x, int y, int z, NIBBLETYPE a_Nibble) { - if ((x < cChunkDef::Width) && (x > -1) && (y < cChunkDef::Height) && (y > -1) && (z < cChunkDef::Width) && (z > -1)) + if ( + (x >= Width) || (x < 0) || + (y >= Height) || (y < 0) || + (z >= Width) || (z < 0) + ) { - int Index = MakeIndexNoCheck(x, y, z); - a_Buffer[Index / 2] = ( - (a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble - ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set - ); + ASSERT(!"cChunkDef::SetNibble(): index out of range!"); + return; } + + int Index = MakeIndexNoCheck(x, y, z); + a_Buffer[Index / 2] = ( + (a_Buffer[Index / 2] & (0xf0 >> ((Index & 1) * 4))) | // The untouched nibble + ((a_Nibble & 0x0f) << ((Index & 1) * 4)) // The nibble being set + ); } inline static char GetNibble(const NIBBLETYPE * a_Buffer, const Vector3i & a_BlockPos ) { - return GetNibble( a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); + return GetNibble(a_Buffer, a_BlockPos.x, a_BlockPos.y, a_BlockPos.z ); } diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index 8f451fce9..d9de24cff 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -13,6 +13,8 @@ #include "PluginManager.h" #include "Entities/TNTEntity.h" #include "Blocks/BlockHandler.h" +#include "MobCensus.h" +#include "MobSpawner.h" #ifndef _WIN32 #include <cstdlib> // abs @@ -1645,18 +1647,21 @@ void cChunkMap::DoExplosionAt(double a_ExplosionSize, double a_BlockX, double a_ break; } + case E_BLOCK_AIR: + { + // No pickups for air + break; + } + default: { - if (Block != E_BLOCK_AIR) // No pickups for air + if (m_World->GetTickRandomNumber(10) == 5) { - if (m_World->GetTickRandomNumber(10) == 5) - { - cItems Drops; - cBlockHandler * Handler = BlockHandler(Block); - - Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); // Saves us from a massive switch - m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z); - } + cItems Drops; + cBlockHandler * Handler = BlockHandler(Block); + + Handler->ConvertToPickups(Drops, area.GetBlockMeta(bx + x, by + y, bz + z)); + m_World->SpawnItemPickups(Drops, bx + x, by + y, bz + z); } area.SetBlockType(bx + x, by + y, bz + z, E_BLOCK_AIR); a_BlocksAffected.push_back(Vector3i(bx + x, by + y, bz + z)); @@ -2166,6 +2171,32 @@ void cChunkMap::SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ) +void cChunkMap::CollectMobCensus(cMobCensus& a_ToFill) +{ + cCSLock Lock(m_CSLayers); + for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) + { + (*itr)->CollectMobCensus(a_ToFill); + } // for itr - m_Layers +} + + + + + + +void cChunkMap::SpawnMobs(cMobSpawner& a_MobSpawner) +{ + cCSLock Lock(m_CSLayers); + for (cChunkLayerList::iterator itr = m_Layers.begin(); itr != m_Layers.end(); ++itr) + { + (*itr)->SpawnMobs(a_MobSpawner); + } // for itr - m_Layers +} + + + + void cChunkMap::Tick(float a_Dt) { @@ -2324,6 +2355,38 @@ cChunk * cChunkMap::cChunkLayer::FindChunk(int a_ChunkX, int a_ChunkZ) +void cChunkMap::cChunkLayer::CollectMobCensus(cMobCensus& a_ToFill) +{ + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + // We do count every Mobs in the world. But we are assuming that every chunk not loaded by any client + // doesn't affect us. Normally they should not have mobs because every "too far" mobs despawn + // If they have (f.i. when player disconnect) we assume we don't have to make them live or despawn + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) + { + m_Chunks[i]->CollectMobCensus(a_ToFill); + } + } // for i - m_Chunks[] +} + + + + + + +void cChunkMap::cChunkLayer::SpawnMobs(cMobSpawner& a_MobSpawner) +{ + for (int i = 0; i < ARRAYCOUNT(m_Chunks); i++) + { + // We only spawn close to players + if ((m_Chunks[i] != NULL) && m_Chunks[i]->IsValid() && m_Chunks[i]->HasAnyClients()) + { + m_Chunks[i]->SpawnMobs(a_MobSpawner); + } + } // for i - m_Chunks[] +} + + void cChunkMap::cChunkLayer::Tick(float a_Dt) { diff --git a/source/ChunkMap.h b/source/ChunkMap.h index fcb164f7b..f68cb6472 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -26,6 +26,8 @@ class cPawn; class cPickup; class cChunkDataSerializer; class cBlockArea; +class cMobCensus; +class cMobSpawner; typedef std::list<cClientHandle *> cClientHandleList; typedef cChunk * cChunkPtr; @@ -263,9 +265,15 @@ public: /// Grows a cactus present at the block specified by the amount of blocks specified, up to the max height specified in the config void GrowCactus(int a_BlockX, int a_BlockY, int a_BlockZ, int a_NumBlocksToGrow); - /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call + /// Sets the blockticking to start at the specified block. Only one blocktick per chunk may be set, second call overwrites the first call void SetNextBlockTick(int a_BlockX, int a_BlockY, int a_BlockZ); + /// Make a Mob census, of all mobs, their family, their chunk and theyr distance to closest player + void CollectMobCensus(cMobCensus& a_ToFill); + + /// Try to Spawn Monsters inside all Chunks + void SpawnMobs(cMobSpawner& a_MobSpawner); + void Tick(float a_Dt); void UnloadUnusedChunks(void); @@ -309,6 +317,11 @@ private: void Save(void); void UnloadUnusedChunks(void); + /// Collect a mob census, of all mobs, their megatype, their chunk and their distance o closest player + void CollectMobCensus(cMobCensus& a_ToFill); + /// Try to Spawn Monsters inside all Chunks + void SpawnMobs(cMobSpawner& a_MobSpawner); + void Tick(float a_Dt); void RemoveClient(cClientHandle * a_Client); diff --git a/source/ClientHandle.cpp b/source/ClientHandle.cpp index f67a546fd..ea8b48f9d 100644 --- a/source/ClientHandle.cpp +++ b/source/ClientHandle.cpp @@ -469,12 +469,12 @@ bool cClientHandle::HandleLogin(int a_ProtocolVersion, const AString & a_Usernam void cClientHandle::HandleCreativeInventory(short a_SlotNum, const cItem & a_HeldItem) { // This is for creative Inventory changes - if (m_Player->GetGameMode() != eGameMode_Creative) + if (!m_Player->IsGameModeCreative()) { LOGWARNING("Got a CreativeInventoryAction packet from user \"%s\" while not in creative mode. Ignoring.", m_Username.c_str()); return; } - if (m_Player->GetWindow()->GetWindowType() != cWindow::Inventory) + if (m_Player->GetWindow()->GetWindowType() != cWindow::wtInventory) { LOGWARNING("Got a CreativeInventoryAction packet from user \"%s\" while not in the inventory window. Ignoring.", m_Username.c_str()); return; @@ -650,7 +650,7 @@ void cClientHandle::HandleBlockDigStarted(int a_BlockX, int a_BlockY, int a_Bloc m_LastDigBlockZ = a_BlockZ; if ( - (m_Player->GetGameMode() == eGameMode_Creative) || // In creative mode, digging is done immediately + (m_Player->IsGameModeCreative()) || // In creative mode, digging is done immediately g_BlockOneHitDig[a_OldBlock] // One-hit blocks get destroyed immediately, too ) { diff --git a/source/Entities/Pickup.cpp b/source/Entities/Pickup.cpp index 075f93449..bc8abd204 100644 --- a/source/Entities/Pickup.cpp +++ b/source/Entities/Pickup.cpp @@ -24,11 +24,12 @@ -cPickup::cPickup(double a_X, double a_Y, double a_Z, const cItem & a_Item, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */) - : cEntity(etPickup, a_X, a_Y, a_Z, 0.2, 0.2) +cPickup::cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX /* = 0.f */, float a_SpeedY /* = 0.f */, float a_SpeedZ /* = 0.f */) + : cEntity(etPickup, a_PosX, a_PosY, a_PosZ, 0.2, 0.2) , m_Timer( 0.f ) , m_Item(a_Item) , m_bCollected( false ) + , m_bIsPlayerCreated( IsPlayerCreated ) { m_MaxHealth = 5; m_Health = 5; @@ -126,8 +127,8 @@ bool cPickup::CollectedBy(cPlayer * a_Dest) return false; // It's already collected! } - // 800 is to long - if (m_Timer < 500.f) + // Two seconds if player created the pickup (vomiting), half a second if anything else + if (m_Timer < (m_bIsPlayerCreated ? 2000.f : 500.f)) { // LOG("Pickup %d cannot be collected by \"%s\", because it is not old enough.", m_UniqueID, a_Dest->GetName().c_str()); return false; // Not old enough diff --git a/source/Entities/Pickup.h b/source/Entities/Pickup.h index 488f91fb2..d39eda298 100644 --- a/source/Entities/Pickup.h +++ b/source/Entities/Pickup.h @@ -24,14 +24,14 @@ class cPickup : public: CLASS_PROTODEF(cPickup); - cPickup(double a_X, double a_Y, double a_Z, const cItem & a_Item, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export + cPickup(double a_PosX, double a_PosY, double a_PosZ, const cItem & a_Item, bool IsPlayerCreated, float a_SpeedX = 0.f, float a_SpeedY = 0.f, float a_SpeedZ = 0.f); // tolua_export cItem & GetItem(void) {return m_Item; } // tolua_export const cItem & GetItem(void) const {return m_Item; } virtual void SpawnOn(cClientHandle & a_ClientHandle) override; - virtual bool CollectedBy(cPlayer * a_Dest); // tolua_export + bool CollectedBy(cPlayer * a_Dest); // tolua_export virtual void Tick(float a_Dt, cChunk & a_Chunk) override; @@ -40,6 +40,9 @@ public: /// Returns true if the pickup has already been collected bool IsCollected(void) const { return m_bCollected; } // tolua_export + + /// Returns true if created by player (i.e. vomiting), used for determining picking-up delay time + bool IsPlayerCreated(void) const { return m_bIsPlayerCreated; } // tolua_export private: Vector3d m_ResultingSpeed; //Can be used to modify the resulting speed for the current tick ;) @@ -52,6 +55,8 @@ private: cItem m_Item; bool m_bCollected; + + bool m_bIsPlayerCreated; }; // tolua_export diff --git a/source/Entities/Player.cpp b/source/Entities/Player.cpp index d93b45614..d94bc944c 100644 --- a/source/Entities/Player.cpp +++ b/source/Entities/Player.cpp @@ -349,11 +349,8 @@ void cPlayer::SetTouchGround(bool a_bTouchGround) void cPlayer::Heal(int a_Health) { - if (m_Health < GetMaxHealth()) - { - m_Health = (short)std::min((int)a_Health + m_Health, (int)GetMaxHealth()); - SendHealth(); - } + super::Heal(a_Health); + SendHealth(); } @@ -1183,7 +1180,7 @@ void cPlayer::TossItem( double vX = 0, vY = 0, vZ = 0; EulerToVector(-GetRotation(), GetPitch(), vZ, vX, vY); vY = -vY * 2 + 1.f; - m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY() + 1.6f, GetPosZ(), vX * 3, vY * 3, vZ * 3); + m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY() + 1.6f, GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because created by player } @@ -1227,11 +1224,11 @@ void cPlayer::LoadPermissionsFromDisk() m_Groups.clear(); m_Permissions.clear(); - cIniFile IniFile("users.ini"); - if( IniFile.ReadFile() ) + cIniFile IniFile; + if (IniFile.ReadFile("users.ini")) { std::string Groups = IniFile.GetValue(m_PlayerName, "Groups", ""); - if( Groups.size() > 0 ) + if (!Groups.empty()) { AStringVector Split = StringSplit( Groups, "," ); for( unsigned int i = 0; i < Split.size(); i++ ) @@ -1248,7 +1245,7 @@ void cPlayer::LoadPermissionsFromDisk() } else { - LOGWARN("WARNING: Failed to read ini file users.ini"); + LOGWARN("Failed to read the users.ini file. The player will be added only to the Default group."); AddToGroup("Default"); } ResolvePermissions(); diff --git a/source/Entities/Player.h b/source/Entities/Player.h index 82ff48954..449a63231 100644 --- a/source/Entities/Player.h +++ b/source/Entities/Player.h @@ -128,8 +128,8 @@ public: // Sets the current gamemode, doesn't check validity, doesn't send update packets to client void LoginSetGameMode(eGameMode a_GameMode); - /// Tries to move to a new position, with collision checks and stuff - virtual void MoveTo( const Vector3d & a_NewPos ); // tolua_export + /// Tries to move to a new position, with attachment-related checks (y == -999) + void MoveTo(const Vector3d & a_NewPos); // tolua_export cWindow * GetWindow(void) { return m_CurrentWindow; } // tolua_export const cWindow * GetWindow(void) const { return m_CurrentWindow; } @@ -159,21 +159,25 @@ public: /// Adds a player to existing group or creates a new group when it doesn't exist void AddToGroup( const AString & a_GroupName ); // tolua_export + /// Removes a player from the group, resolves permissions and group inheritance (case sensitive) void RemoveFromGroup( const AString & a_GroupName ); // tolua_export + bool CanUseCommand( const AString & a_Command ); // tolua_export bool HasPermission( const AString & a_Permission ); // tolua_export const GroupList & GetGroups() { return m_Groups; } // >> EXPORTED IN MANUALBINDINGS << StringList GetResolvedPermissions(); // >> EXPORTED IN MANUALBINDINGS << bool IsInGroup( const AString & a_Group ); // tolua_export - AString GetColor(void) const; // tolua_export + // tolua_begin + + /// Returns the full color code to use for this player, based on their primary group or set in m_Color + AString GetColor(void) const; - void TossItem(bool a_bDraggingItem, char a_Amount = 1, short a_CreateType = 0, short a_CreateHealth = 0); // tolua_export + void TossItem(bool a_bDraggingItem, char a_Amount = 1, short a_CreateType = 0, short a_CreateHealth = 0); - void Heal( int a_Health ); // tolua_export - - // tolua_begin + /// Heals the player by the specified amount of HPs (positive only); sends health update + void Heal(int a_Health); int GetFoodLevel (void) const { return m_FoodLevel; } double GetFoodSaturationLevel (void) const { return m_FoodSaturationLevel; } @@ -181,7 +185,7 @@ public: double GetFoodExhaustionLevel (void) const { return m_FoodExhaustionLevel; } int GetFoodPoisonedTicksRemaining(void) const { return m_FoodPoisonedTicksRemaining; } - int GetAirLevel (void) const { return m_AirLevel; } + int GetAirLevel (void) const { return m_AirLevel; } /// Returns true if the player is satiated, i. e. their foodlevel is at the max and they cannot eat anymore bool IsSatiated(void) const { return (m_FoodLevel >= MAX_FOOD_LEVEL); } @@ -302,6 +306,7 @@ protected: /// Player's air level (for swimming) int m_AirLevel; + /// used to time ticks between damage taken via drowning/suffocation int m_AirTickTimer; diff --git a/source/Entities/ProjectileEntity.cpp b/source/Entities/ProjectileEntity.cpp index 4c8e680d0..1d5532718 100644 --- a/source/Entities/ProjectileEntity.cpp +++ b/source/Entities/ProjectileEntity.cpp @@ -474,8 +474,17 @@ cThrownEggEntity::cThrownEggEntity(cEntity * a_Creator, double a_X, double a_Y, void cThrownEggEntity::OnHitSolidBlock(const Vector3d & a_HitPos, char a_HitFace) { - // TODO: Random-spawn a chicken or four - + if (m_World->GetTickRandomNumber(7) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } + else if (m_World->GetTickRandomNumber(32) == 1) + { + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + m_World->SpawnMob(a_HitPos.x, a_HitPos.y, a_HitPos.z, cMonster::mtChicken); + } Destroy(); } diff --git a/source/Generating/ChunkGenerator.cpp b/source/Generating/ChunkGenerator.cpp index d35b30460..59a00b540 100644 --- a/source/Generating/ChunkGenerator.cpp +++ b/source/Generating/ChunkGenerator.cpp @@ -75,8 +75,6 @@ bool cChunkGenerator::Start(cWorld * a_World, cIniFile & a_IniFile) m_Generator->Initialize(a_World, a_IniFile); - a_IniFile.WriteFile(); - return super::Start(); } diff --git a/source/Globals.h b/source/Globals.h index 1e531f7f3..ef79e4cf1 100644 --- a/source/Globals.h +++ b/source/Globals.h @@ -12,24 +12,24 @@ #if defined(_MSC_VER) // MSVC produces warning C4481 on the override keyword usage, so disable the warning altogether #pragma warning(disable:4481) - + // Disable some warnings that we don't care about: #pragma warning(disable:4100) #define OBSOLETE __declspec(deprecated) - + // No alignment needed in MSVC #define ALIGN_8 #define ALIGN_16 - + #elif defined(__GNUC__) // TODO: Can GCC explicitly mark classes as abstract (no instances can be created)? #define abstract - + // TODO: Can GCC mark virtual methods as overriding (forcing them to have a virtual function of the same signature in the base class) #define override - + #define OBSOLETE __attribute__((deprecated)) #define ALIGN_8 __attribute__((aligned(8))) @@ -41,13 +41,13 @@ #else #error "You are using an unsupported compiler, you might need to #define some stuff here for your compiler" - + /* // Copy and uncomment this into another #elif section based on your compiler identification - + // Explicitly mark classes as abstract (no instances can be created) #define abstract - + // Mark virtual methods as overriding (forcing them to have a virtual function of the same signature in the base class) #define override @@ -92,17 +92,17 @@ typedef unsigned short UInt16; // OS-dependent stuff: #ifdef _WIN32 #define WIN32_LEAN_AND_MEAN - + #define _WIN32_WINNT 0x501 // We want to target WinXP and higher - + #include <Windows.h> #include <winsock2.h> #include <Ws2tcpip.h> // IPv6 stuff - + // Windows SDK defines min and max macros, messing up with our std::min and std::max usage #undef min #undef max - + // Windows SDK defines GetFreeSpace as a constant, probably a Win16 API remnant #ifdef GetFreeSpace #undef GetFreeSpace diff --git a/source/GroupManager.cpp b/source/GroupManager.cpp index b79fde9dc..d7332fd0a 100644 --- a/source/GroupManager.cpp +++ b/source/GroupManager.cpp @@ -44,8 +44,8 @@ cGroupManager::cGroupManager() : m_pState( new sGroupManagerState ) { LOGD("-- Loading Groups --"); - cIniFile IniFile("groups.ini"); - if (!IniFile.ReadFile()) + cIniFile IniFile; + if (!IniFile.ReadFile("groups.ini")) { LOGWARNING("groups.ini inaccessible, no groups are defined"); return; diff --git a/source/Inventory.cpp b/source/Inventory.cpp index c104db4c7..d5fc7f0d8 100644 --- a/source/Inventory.cpp +++ b/source/Inventory.cpp @@ -374,7 +374,7 @@ bool cInventory::DamageItem(int a_SlotNum, short a_Amount) } // The item has broken, remove it: - Grid->EmptySlot(a_SlotNum); + Grid->EmptySlot(GridSlotNum); return true; } diff --git a/source/LuaWindow.cpp b/source/LuaWindow.cpp index a0609f746..9011d668c 100644 --- a/source/LuaWindow.cpp +++ b/source/LuaWindow.cpp @@ -31,8 +31,8 @@ cLuaWindow::cLuaWindow(cWindow::WindowType a_WindowType, int a_SlotsX, int a_Slo // If appropriate, add an Armor slot area: switch (a_WindowType) { - case cWindow::Inventory: - case cWindow::Workbench: + case cWindow::wtInventory: + case cWindow::wtWorkbench: { m_SlotAreas.push_back(new cSlotAreaArmor(*this)); break; diff --git a/source/LuaWindow.h b/source/LuaWindow.h index 5a0685ebb..4c32c263e 100644 --- a/source/LuaWindow.h +++ b/source/LuaWindow.h @@ -23,8 +23,6 @@ class cPluginLua; -// tolua_begin - /** A window that has been created by a Lua plugin and is handled entirely by that plugin This object needs extra care with its lifetime management: - It is created by Lua, so Lua expects to garbage-collect it later @@ -35,9 +33,10 @@ Additionally, to forbid Lua from deleting this object while it is used by player cPlayer:OpenWindow check if the window is of this class, and if so, make a global Lua reference for this object. This reference needs to be unreferenced in the Destroy() function. */ -class cLuaWindow : - public cWindow, - public cItemGrid::cListener +class cLuaWindow : // tolua_export + public cItemGrid::cListener, + // tolua_begin + public cWindow { typedef cWindow super; diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index e6605ddb0..466701bf8 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -17,6 +17,7 @@ #include "BlockEntities/DispenserEntity.h" #include "BlockEntities/DropperEntity.h" #include "BlockEntities/FurnaceEntity.h" +#include "BlockEntities/HopperEntity.h" #include "md5/md5.h" #include "LuaWindow.h" #include "LineBlockTracer.h" @@ -2059,6 +2060,45 @@ static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) +static int tolua_cHopperEntity_GetOutputBlockPos(lua_State * tolua_S) +{ + // function cHopperEntity::GetOutputBlockPos() + // Exported manually because tolua would require meaningless params + + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cHopperEntity") || + !L.CheckParamNumber (2) || + !L.CheckParamEnd (3) + ) + { + return 0; + } + cHopperEntity * self = (cHopperEntity *)tolua_tousertype(tolua_S, 1, 0); + if (self == NULL) + { + tolua_error(tolua_S, "invalid 'self' in function 'cHopperEntity::GetOutputBlockPos()'", NULL); + return 0; + } + + NIBBLETYPE a_BlockMeta = ((NIBBLETYPE)tolua_tonumber(tolua_S, 2, 0)); + int a_OutputX, a_OutputY, a_OutputZ; + bool res = self->GetOutputBlockPos(a_BlockMeta, a_OutputX, a_OutputY, a_OutputZ); + tolua_pushboolean(tolua_S, res); + if (res) + { + tolua_pushnumber(tolua_S, (lua_Number)a_OutputX); + tolua_pushnumber(tolua_S, (lua_Number)a_OutputY); + tolua_pushnumber(tolua_S, (lua_Number)a_OutputZ); + return 4; + } + return 1; +} + + + + + void ManualBindings::Bind(lua_State * tolua_S) { tolua_beginmodule(tolua_S, NULL); @@ -2070,6 +2110,10 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_function(tolua_S, "LOGWARNING", tolua_LOGWARN); tolua_function(tolua_S, "LOGERROR", tolua_LOGERROR); + tolua_beginmodule(tolua_S, "cHopperEntity"); + tolua_function(tolua_S, "GetOutputBlockPos", tolua_cHopperEntity_GetOutputBlockPos); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cLineBlockTracer"); tolua_function(tolua_S, "Trace", tolua_cLineBlockTracer_Trace); tolua_endmodule(tolua_S); diff --git a/source/MobCensus.cpp b/source/MobCensus.cpp new file mode 100644 index 000000000..66b5932bc --- /dev/null +++ b/source/MobCensus.cpp @@ -0,0 +1,92 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "MobCensus.h" + + + + + +void cMobCensus::CollectMob(cMonster & a_Monster, cChunk & a_Chunk, double a_Distance) +{ + m_ProximityCounter.CollectMob(a_Monster, a_Chunk, a_Distance); + m_MobFamilyCollecter.CollectMob(a_Monster); +} + + + + + +bool cMobCensus::IsCapped(cMonster::eFamily a_MobFamily) +{ + bool toReturn = true; + const int ratio = 319; // this should be 256 as we are only supposed to take account from chunks that are in 17x17 from a player + // but for now, we use all chunks loaded by players. that means 19 x 19 chunks. That's why we use 256 * (19*19) / (17*17) = 319 + // MG TODO : code the correct count + if ((GetCapMultiplier(a_MobFamily) * GetNumChunks()) / ratio >= m_MobFamilyCollecter.GetNumberOfCollectedMobs(a_MobFamily)) + { + return false; + } + return true; +} + + + + + +int cMobCensus::GetCapMultiplier(cMonster::eFamily a_MobFamily) +{ + switch (a_MobFamily) + { + case cMonster::mfHostile: return 79; + case cMonster::mfPassive: return 11; + case cMonster::mfAmbient: return 16; + case cMonster::mfWater: return 5; + } + ASSERT(!"Unhandled mob family"); + return -1; +} + + + + + +void cMobCensus::CollectSpawnableChunk(cChunk & a_Chunk) +{ + m_EligibleForSpawnChunks.insert(&a_Chunk); +} + + + + + +int cMobCensus::GetNumChunks(void) +{ + return m_EligibleForSpawnChunks.size(); +} + + + + + +cMobProximityCounter & cMobCensus::GetProximityCounter(void) +{ + return m_ProximityCounter; +} + + + + + +void cMobCensus::Logd() +{ + LOGD("Hostile mobs : %d %s", m_MobFamilyCollecter.GetNumberOfCollectedMobs(cMonster::mfHostile), IsCapped(cMonster::mfHostile) ? "(capped)" : ""); + LOGD("Ambient mobs : %d %s", m_MobFamilyCollecter.GetNumberOfCollectedMobs(cMonster::mfAmbient), IsCapped(cMonster::mfAmbient) ? "(capped)" : ""); + LOGD("Water mobs : %d %s", m_MobFamilyCollecter.GetNumberOfCollectedMobs(cMonster::mfWater), IsCapped(cMonster::mfWater) ? "(capped)" : ""); + LOGD("Passive mobs : %d %s", m_MobFamilyCollecter.GetNumberOfCollectedMobs(cMonster::mfPassive), IsCapped(cMonster::mfPassive) ? "(capped)" : ""); +} + + + + + diff --git a/source/MobCensus.h b/source/MobCensus.h new file mode 100644 index 000000000..e3892bec6 --- /dev/null +++ b/source/MobCensus.h @@ -0,0 +1,59 @@ + +#pragma once + +#include "MobProximityCounter.h" +#include "MobFamilyCollecter.h" + + + + +// fwd: +class cChunk; +class cMonster; + + + + + +/** This class is used to collect information, for each Mob, what is the distance of the closest player +it was first being designed in order to make mobs spawn / despawn / act +as the behaviour and even life of mobs depends on the distance to closest player + +as side effect : it also collect the chunks that are elligible for spawning +as side effect 2 : it also know the caps for mobs number and can compare census to this numbers +*/ +class cMobCensus +{ +public: + /// Returns the nested proximity counter + cMobProximityCounter & GetProximityCounter(void); + + // collect an elligible Chunk for Mob Spawning + // MG TODO : code the correct rule (not loaded chunk but short distant from players) + void CollectSpawnableChunk(cChunk & a_Chunk); + + /// Collect a mob - it's distance to player, it's family ... + void CollectMob(cMonster& a_Monster, cChunk& a_Chunk, double a_Distance); + + /// Returns true if the family is capped (i.e. there are more mobs of this family than max) + bool IsCapped(cMonster::eFamily a_MobFamily); + + /// log the results of census to server console + void Logd(void); + +protected : + cMobProximityCounter m_ProximityCounter; + cMobFamilyCollecter m_MobFamilyCollecter; + + std::set<cChunk *> m_EligibleForSpawnChunks; + + /// Returns the number of chunks that are elligible for spawning (for now, the loaded, valid chunks) + int GetNumChunks(); + + /// Returns the cap multiplier value of the given monster family + static int GetCapMultiplier(cMonster::eFamily a_MobFamily); +} ; + + + + diff --git a/source/MobFamilyCollecter.cpp b/source/MobFamilyCollecter.cpp new file mode 100644 index 000000000..e9c69e078 --- /dev/null +++ b/source/MobFamilyCollecter.cpp @@ -0,0 +1,26 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "MobFamilyCollecter.h" +#include "Mobs/Monster.h" + + + +void cMobFamilyCollecter::CollectMob(cMonster & a_Monster) +{ + cMonster::eFamily MobFamily = a_Monster.GetMobFamily(); + m_Mobs[MobFamily].insert(&a_Monster); +} + + + + + +int cMobFamilyCollecter::GetNumberOfCollectedMobs(cMonster::eFamily a_Family) +{ + return m_Mobs[a_Family].size(); +} + + + + diff --git a/source/MobFamilyCollecter.h b/source/MobFamilyCollecter.h new file mode 100644 index 000000000..6cef133b5 --- /dev/null +++ b/source/MobFamilyCollecter.h @@ -0,0 +1,39 @@ + +#pragma once + +#include <map> +#include <set> +#include "BlockID.h" +#include "Mobs/Monster.h" //this is a side-effect of keeping Mobfamily inside Monster class. I'd prefer to keep both (Mobfamily and Monster) inside a "Monster" namespace MG TODO : do it + + + + +// fwd: +class cChunk; + + + + + +/** This class is used to collect the list of mobs for each family +*/ +class cMobFamilyCollecter +{ +public : + typedef const std::set<cMonster::eFamily> tMobFamilyList; + + // collect a mob + void CollectMob(cMonster & a_Monster); + + // return the number of mobs for this family + int GetNumberOfCollectedMobs(cMonster::eFamily a_Family); + +protected : + std::map<cMonster::eFamily, std::set<cMonster *> > m_Mobs; + +} ; + + + + diff --git a/source/MobProximityCounter.cpp b/source/MobProximityCounter.cpp new file mode 100644 index 000000000..583a71579 --- /dev/null +++ b/source/MobProximityCounter.cpp @@ -0,0 +1,83 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "MobProximityCounter.h" + +#include "Entities/Entity.h" +#include "Chunk.h" + +void cMobProximityCounter::CollectMob(cEntity& a_Monster, cChunk& a_Chunk, double a_Distance) +{ +// LOGD("Collecting monster %s, with distance %f",a_Monster->GetClass(),a_Distance); + tMonsterToDistance::iterator it = m_MonsterToDistance.find(&a_Monster); + if (it == m_MonsterToDistance.end()) + { + sDistanceAndChunk newDistanceAndChunk(a_Distance,a_Chunk); + std::pair<tMonsterToDistance::iterator,bool> result = m_MonsterToDistance.insert(tMonsterToDistance::value_type(&a_Monster,newDistanceAndChunk)); + if (!result.second) + { + ASSERT(!"A collected Monster was not found inside distance map using find(), but insert() said there already is a key for it"); + } + } + else + { + if (a_Distance < it->second.m_Distance) + { + it->second.m_Distance = a_Distance; + it->second.m_Chunk = a_Chunk; + } + } + + m_EligibleForSpawnChunks.insert(&a_Chunk); + +} + +void cMobProximityCounter::convertMaps() +{ + for(tMonsterToDistance::const_iterator itr = m_MonsterToDistance.begin(); itr != m_MonsterToDistance.end(); itr++) + { + m_DistanceToMonster.insert(tDistanceToMonster::value_type(itr->second.m_Distance,sMonsterAndChunk(*itr->first,itr->second.m_Chunk))); + } +} + +cMobProximityCounter::sIterablePair cMobProximityCounter::getMobWithinThosesDistances(double a_DistanceMin, double a_DistanceMax) +{ + sIterablePair toReturn; + toReturn.m_Count = 0; + toReturn.m_Begin = m_DistanceToMonster.end(); + toReturn.m_End = m_DistanceToMonster.end(); + + a_DistanceMin *= a_DistanceMin;// this is because is use square distance + a_DistanceMax *= a_DistanceMax; + + if (m_DistanceToMonster.size() <= 0) + { + convertMaps(); + } + + for(tDistanceToMonster::const_iterator itr = m_DistanceToMonster.begin(); itr != m_DistanceToMonster.end(); itr++) + { + if (toReturn.m_Begin == m_DistanceToMonster.end()) + { + if (a_DistanceMin == -1 || itr->first > a_DistanceMin) + { + toReturn.m_Begin = itr; // this is the first one with distance > a_DistanceMin; + } + } + + if (toReturn.m_Begin != m_DistanceToMonster.end()) + { + if (a_DistanceMax != -1 && itr->first > a_DistanceMax) + { + toReturn.m_End = itr; // this is just after the last one with distance < a_DistanceMax + // Note : if we are not going through this, it's ok, toReturn.m_End will be end(); + break; + } + else + { + toReturn.m_Count ++; + } + } + } + return toReturn; +} diff --git a/source/MobProximityCounter.h b/source/MobProximityCounter.h new file mode 100644 index 000000000..8a67139aa --- /dev/null +++ b/source/MobProximityCounter.h @@ -0,0 +1,65 @@ + +#pragma once + +#include <set> + +class cChunk; +class cEntity; + + +// This class is used to collect, for each Mob, what is the distance of the closest player +// it was first being designed in order to make mobs spawn / despawn / act +// as the behaviour and even life of mobs depends on the distance to closest player +class cMobProximityCounter +{ +protected : + // structs used for later maps (see m_MonsterToDistance and m_DistanceToMonster) + struct sDistanceAndChunk + { + sDistanceAndChunk(double a_Distance, cChunk& a_Chunk) : m_Distance(a_Distance), m_Chunk(a_Chunk) {} + double m_Distance; + cChunk& m_Chunk; + }; + struct sMonsterAndChunk + { + sMonsterAndChunk(cEntity& a_Monster, cChunk& a_Chunk) : m_Monster(a_Monster), m_Chunk(a_Chunk) {} + cEntity& m_Monster; + cChunk& m_Chunk; + }; + +public : + typedef std::map<cEntity*,sDistanceAndChunk> tMonsterToDistance; + typedef std::multimap<double,sMonsterAndChunk> tDistanceToMonster; + +protected : + // this map is filled during collection phase, it will be later transformed into DistanceToMonster + tMonsterToDistance m_MonsterToDistance; + + // this map is generated after collection phase, in order to access monster by distance to player + tDistanceToMonster m_DistanceToMonster; + + // this are the collected chunks. Used to determinate the number of elligible chunk for spawning. + std::set<cChunk*> m_EligibleForSpawnChunks; + +protected : + // transform monsterToDistance map (that was usefull for collecting) into distanceToMonster + // that will be usefull for picking up. + void convertMaps(); + +public : + // count a mob on a specified chunk with specified distance to an unkown player + // if the distance is shortest than the one collected, this become the new closest + // distance and the chunk become the "hosting" chunk (that is the one that will perform the action) + void CollectMob(cEntity& a_Monster, cChunk& a_Chunk, double a_Distance); + + // return the mobs that are within the range of distance of the closest player they are + // that means that if a mob is 30 m from a player and 150 m from another one. It will be + // in the range [0..50] but not in [100..200] + struct sIterablePair{ + tDistanceToMonster::const_iterator m_Begin; + tDistanceToMonster::const_iterator m_End; + int m_Count; + }; + sIterablePair getMobWithinThosesDistances(double a_DistanceMin, double a_DistanceMax); + +}; diff --git a/source/MobSpawner.cpp b/source/MobSpawner.cpp new file mode 100644 index 000000000..d4926bbe5 --- /dev/null +++ b/source/MobSpawner.cpp @@ -0,0 +1,289 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "MobSpawner.h" +#include "Mobs/IncludeAllMonsters.h" + + + + + +cMobSpawner::cMobSpawner(cMonster::eFamily a_MonsterFamily,const std::set<cMonster::eType>& a_AllowedTypes) : + m_MonsterFamily(a_MonsterFamily), + m_NewPack(true), + m_MobType(cMonster::mtInvalidType) +{ + for (std::set<cMonster::eType>::const_iterator itr = a_AllowedTypes.begin(); itr != a_AllowedTypes.end(); itr++) + { + if (cMonster::FamilyFromType(*itr) == a_MonsterFamily) + { + m_AllowedTypes.insert(*itr); + } + } +} + + + + + +bool cMobSpawner::CheckPackCenter(BLOCKTYPE a_BlockType) +{ + // Packs of non-water mobs can only be centered on an air block + // Packs of water mobs can only be centered on a water block + if (m_MonsterFamily == cMonster::mfWater) + { + return IsBlockWater(a_BlockType); + } + else + { + return a_BlockType == E_BLOCK_AIR; + } +} + + + + + +void cMobSpawner::addIfAllowed(cMonster::eType toAdd, std::set<cMonster::eType>& toAddIn) +{ + std::set<cMonster::eType>::iterator itr = m_AllowedTypes.find(toAdd); + if (itr != m_AllowedTypes.end()) + { + toAddIn.insert(toAdd); + } +} + + + + + +cMonster::eType cMobSpawner::ChooseMobType(EMCSBiome a_Biome) +{ + std::set<cMonster::eType> allowedMobs; + + if (a_Biome == biMushroomIsland || a_Biome == biMushroomShore) + { + addIfAllowed(cMonster::mtMooshroom, allowedMobs); + } + else if (a_Biome == biNether) + { + addIfAllowed(cMonster::mtGhast, allowedMobs); + addIfAllowed(cMonster::mtZombiePigman, allowedMobs); + addIfAllowed(cMonster::mtMagmaCube, allowedMobs); + } + /*else if (a_Biome == biEnder) MG TODO : figure out what are the biomes of the ender + { + addIfAllowed(cMonster::mtEnderman, allowedMobs); + }*/ + else + { + addIfAllowed(cMonster::mtBat, allowedMobs); + addIfAllowed(cMonster::mtSpider, allowedMobs); + addIfAllowed(cMonster::mtZombie, allowedMobs); + addIfAllowed(cMonster::mtSkeleton, allowedMobs); + addIfAllowed(cMonster::mtCreeper, allowedMobs); + addIfAllowed(cMonster::mtSquid, allowedMobs); + + if (a_Biome != biDesert && a_Biome != biBeach && a_Biome != biOcean) + { + addIfAllowed(cMonster::mtSheep, allowedMobs); + addIfAllowed(cMonster::mtPig, allowedMobs); + addIfAllowed(cMonster::mtCow, allowedMobs); + addIfAllowed(cMonster::mtChicken, allowedMobs); + addIfAllowed(cMonster::mtEnderman, allowedMobs); + addIfAllowed(cMonster::mtSlime, allowedMobs); // MG TODO : much more complicated rule + + if (a_Biome == biForest || a_Biome == biForestHills || a_Biome == biTaiga || a_Biome == biTaigaHills) + { + addIfAllowed(cMonster::mtWolf, allowedMobs); + } + else if (a_Biome == biJungle || a_Biome == biJungleHills) + { + addIfAllowed(cMonster::mtOcelot, allowedMobs); + } + } + } + + int allowedMobsSize = allowedMobs.size(); + if (allowedMobsSize > 0) + { + std::set<cMonster::eType>::iterator itr = allowedMobs.begin(); + int iRandom = m_Random.NextInt(allowedMobsSize,a_Biome); + + for(int i = 0; i < iRandom; i++) + { + itr++; + } + + return *itr; + } + return cMonster::mtInvalidType; +} + + + + + +bool cMobSpawner::CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome) +{ + BLOCKTYPE TargetBlock; + if (m_AllowedTypes.find(a_MobType) != m_AllowedTypes.end() && a_Chunk->UnboundedRelGetBlockType(a_RelX, a_RelY, a_RelZ, TargetBlock)) + { + NIBBLETYPE BlockLight = a_Chunk->GetBlockLight(a_RelX, a_RelY, a_RelZ); + NIBBLETYPE SkyLight = a_Chunk->GetSkyLight(a_RelX, a_RelY, a_RelZ); + BLOCKTYPE BlockAbove = a_Chunk->GetBlock(a_RelX, a_RelY + 1, a_RelZ); + BLOCKTYPE BlockBelow = a_Chunk->GetBlock(a_RelX, a_RelY - 1, a_RelZ); + + SkyLight = a_Chunk->GetTimeAlteredLight(SkyLight); + + switch(a_MobType) + { + case cMonster::mtSquid: + return IsBlockWater(TargetBlock) && (a_RelY >= 45) && (a_RelY <= 62); + + case cMonster::mtBat: + return (a_RelY <= 63) && (BlockLight <= 4) && (SkyLight <= 4) && (TargetBlock == E_BLOCK_AIR) && (!g_BlockTransparent[BlockAbove]); + + case cMonster::mtChicken: + case cMonster::mtCow: + case cMonster::mtPig: + case cMonster::mtHorse: + case cMonster::mtSheep: + { + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + (BlockBelow == E_BLOCK_GRASS) && (SkyLight >= 9); + } + + case cMonster::mtOcelot: + { + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && + ((BlockBelow == E_BLOCK_GRASS) || (BlockBelow == E_BLOCK_LEAVES)) && (a_RelY >= 62) && (m_Random.NextInt(3,a_Biome) != 0); + } + case cMonster::mtEnderman: + { + if (a_RelY < 250) + { + BLOCKTYPE BlockTop = a_Chunk->GetBlock(a_RelX, a_RelY + 2, a_RelZ); + if (BlockTop == E_BLOCK_AIR) + { + BlockTop = a_Chunk->GetBlock(a_RelX, a_RelY + 3, a_RelZ); + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (BlockTop == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + (SkyLight <= 7) && (BlockLight <= 7); + } + } + break; + } + case cMonster::mtSpider: + { + bool CanSpawn = true; + bool HaveFloor = false; + for (int x = 0; x < 2; ++x) + { + for(int z = 0; z < 2; ++z) + { + CanSpawn = a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY, a_RelZ + z, TargetBlock); + CanSpawn = CanSpawn && (TargetBlock == E_BLOCK_AIR); + if (!CanSpawn) + { + return false; + } + if (!HaveFloor) + { + a_Chunk->UnboundedRelGetBlockType(a_RelX + x, a_RelY - 1, a_RelZ + z, TargetBlock); + HaveFloor = HaveFloor || !g_BlockTransparent[TargetBlock]; + } + } + } + return CanSpawn && HaveFloor && (SkyLight <= 7) && (BlockLight <= 7); + + } + case cMonster::mtCreeper: + case cMonster::mtZombie: + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + (SkyLight <= 7) && (BlockLight <= 7) && (m_Random.NextInt(2,a_Biome) == 0); + + case cMonster::mtSlime: + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + ((a_RelY <= 40) || a_Biome == biSwampland); + case cMonster::mtGhast: + case cMonster::mtZombiePigman: + return (TargetBlock == E_BLOCK_AIR) && (BlockAbove == E_BLOCK_AIR) && (!g_BlockTransparent[BlockBelow]) && + (m_Random.NextInt(20,a_Biome) == 0); + default: + LOGD("MG TODO : check I've got a Rule to write for type %d",a_MobType); + return false; + } + } + return false; +} + + + + + +cMonster* cMobSpawner::TryToSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int& a_MaxPackSize) +{ + cMonster* toReturn = NULL; + if (m_NewPack) + { + m_MobType = ChooseMobType(a_Biome); + if (m_MobType == cMonster::mtInvalidType) + { + return toReturn; + } + if (m_MobType == cMonster::mtWolf) + { + a_MaxPackSize = 8; + } + else if (m_MobType == cMonster::mtGhast) + { + a_MaxPackSize = 1; + } + m_NewPack = false; + } + + // Make sure we are looking at the right chunk to spawn in + a_Chunk = a_Chunk->GetRelNeighborChunkAdjustCoords(a_RelX, a_RelZ); + + if (CanSpawnHere(a_Chunk, a_RelX, a_RelY, a_RelZ, m_MobType, a_Biome)) + { + cMonster * newMob = cMonster::NewMonsterFromType(m_MobType); + if (newMob) + { + m_Spawned.insert(newMob); + } + toReturn = newMob; + } + return toReturn; +} + + + + + +void cMobSpawner::NewPack() +{ + m_NewPack = true; +} + + + + + +cMobSpawner::tSpawnedContainer & cMobSpawner::getSpawned(void) +{ + return m_Spawned; +} + + + + + +bool cMobSpawner::CanSpawnAnything(void) +{ + return !m_AllowedTypes.empty(); +} + + + + diff --git a/source/MobSpawner.h b/source/MobSpawner.h new file mode 100644 index 000000000..ea6636310 --- /dev/null +++ b/source/MobSpawner.h @@ -0,0 +1,76 @@ + +#pragma once + +#include <set> +#include "BlockID.h" +#include "ChunkDef.h" +#include "Chunk.h" +#include "FastRandom.h" +#include "Mobs/Monster.h" //this is a side-effect of keeping Mobfamily inside Monster class. I'd prefer to keep both (Mobfamily and Monster) inside a "Monster" namespace MG TODO : do it + + + + +// fwd: +class cChunk; + + + + + +/** This class is used to determine which monster can be spawned in which place +it is essentially static (eg. Squids spawn in water, Zombies spawn in dark places) +but it also has dynamic part depending on the world.ini settings. +*/ +class cMobSpawner +{ +public : + // constructor + // a_MobFamily is the Family of mobs that this spawner will spawn + // a_AllowedTypes is the set of types allowed for mobs it will spawn. Empty set + // would result in no spawn at all + // Allowed mobs thah are not of the right Family will not be include (no warning) + cMobSpawner(cMonster::eFamily MobFamily, const std::set<cMonster::eType> & a_AllowedTypes); + + /// Check if specified block can be a Pack center for this spawner + bool CheckPackCenter(BLOCKTYPE a_BlockType); + + // Try to create a monster here + // if this is the first of a Pack : determine the type of monster + // BlockType & BlockMeta are used to decide what kind of Mob can Spawn here + // MaxPackSize is set to the maximal size for a pack this type of mob + cMonster * TryToSpawnHere(cChunk * a_Chunk, int A_RelX, int a_RelY, int a_RelZ, EMCSBiome a_Biome, int& a_MaxPackSize); + + // mark the beginning of a new Pack + // all mobs of the same Pack are the same type + void NewPack(void); + + // return true if there is at least one allowed type + bool CanSpawnAnything(void); + + typedef const std::set<cMonster *> tSpawnedContainer; + tSpawnedContainer & getSpawned(void); + +protected : + // return true if specified type of mob can spawn on specified block + bool CanSpawnHere(cChunk * a_Chunk, int a_RelX, int a_RelY, int a_RelZ, cMonster::eType a_MobType, EMCSBiome a_Biome); + + // return a random type that can spawn on specified biome. + // returns E_ENTITY_TYPE_DONOTUSE if none is possible + cMonster::eType ChooseMobType(EMCSBiome a_Biome); + + // add toAdd inside toAddIn, if toAdd is in m_AllowedTypes + void addIfAllowed(cMonster::eType toAdd, std::set<cMonster::eType> & toAddIn); + +protected : + cMonster::eFamily m_MonsterFamily; + std::set<cMonster::eType> m_AllowedTypes; + bool m_NewPack; + cMonster::eType m_MobType; + std::set<cMonster*> m_Spawned; + cFastRandom m_Random; +} ; + + + + diff --git a/source/Mobs/AggressiveMonster.cpp b/source/Mobs/AggressiveMonster.cpp index 2eae772d7..88bd2743a 100644 --- a/source/Mobs/AggressiveMonster.cpp +++ b/source/Mobs/AggressiveMonster.cpp @@ -12,8 +12,8 @@ -cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : - super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height), +cAggressiveMonster::cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : + super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height), m_ChaseTime(999999) { m_EMPersonality = AGGRESSIVE; @@ -33,7 +33,7 @@ void cAggressiveMonster::InStateChasing(float a_Dt) if (m_Target->IsPlayer()) { cPlayer * Player = (cPlayer *) m_Target; - if (Player->GetGameMode() == 1) + if (Player->IsGameModeCreative()) { m_EMState = IDLE; return; @@ -95,5 +95,3 @@ void cAggressiveMonster::Tick(float a_Dt, cChunk & a_Chunk) } - - diff --git a/source/Mobs/AggressiveMonster.h b/source/Mobs/AggressiveMonster.h index 1eff1831e..5a0d93f3d 100644 --- a/source/Mobs/AggressiveMonster.h +++ b/source/Mobs/AggressiveMonster.h @@ -13,12 +13,13 @@ class cAggressiveMonster : typedef cMonster super; public: - cAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); + cAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); virtual void Tick (float a_Dt, cChunk & a_Chunk) override; virtual void InStateChasing(float a_Dt) override; virtual void EventSeePlayer(cEntity *) override; + protected: float m_ChaseTime; diff --git a/source/Mobs/Bat.cpp b/source/Mobs/Bat.cpp new file mode 100644 index 000000000..b9c82996b --- /dev/null +++ b/source/Mobs/Bat.cpp @@ -0,0 +1,15 @@ + +#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules + +#include "Bat.h" +#include "../Vector3d.h" +#include "../Chunk.h" + + +cBat::cBat(void) : + // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here + super("Bat", mtBat, "mob.bat.hurt", "mob.bat.death", 0.7, 0.7) +{ +} + + diff --git a/source/Mobs/Bat.h b/source/Mobs/Bat.h index 0b50e06cd..e878d0ee8 100644 --- a/source/Mobs/Bat.h +++ b/source/Mobs/Bat.h @@ -13,13 +13,10 @@ class cBat : typedef cPassiveMonster super; public: - cBat(void) : - super("Bat", 65, "mob.bat.hurt", "mob.bat.death", 0.5, 0.9) - { - } + cBat(void); CLASS_PROTODEF(cBat); - + bool IsHanging(void) const {return false; } } ; diff --git a/source/Mobs/Blaze.cpp b/source/Mobs/Blaze.cpp index dbbccf417..74c82c081 100644 --- a/source/Mobs/Blaze.cpp +++ b/source/Mobs/Blaze.cpp @@ -9,7 +9,7 @@ cBlaze::cBlaze(void) : // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here - super("Blaze", 61, "mob.blaze.hit", "mob.blaze.death", 0.7, 1.8) + super("Blaze", mtBlaze, "mob.blaze.hit", "mob.blaze.death", 0.7, 1.8) { } diff --git a/source/Mobs/Cavespider.cpp b/source/Mobs/Cavespider.cpp index 2d50b391a..aba1ff9f5 100644 --- a/source/Mobs/Cavespider.cpp +++ b/source/Mobs/Cavespider.cpp @@ -9,7 +9,7 @@ cCavespider::cCavespider(void) : - super("Cavespider", 59, "mob.spider.say", "mob.spider.death", 0.7, 0.5) + super("Cavespider", mtCaveSpider, "mob.spider.say", "mob.spider.death", 0.7, 0.5) { } diff --git a/source/Mobs/Chicken.cpp b/source/Mobs/Chicken.cpp index 3da9781d3..434a32f94 100644 --- a/source/Mobs/Chicken.cpp +++ b/source/Mobs/Chicken.cpp @@ -14,7 +14,7 @@ cChicken::cChicken(void) : - super("Chicken", 93, "mob.chicken.hurt", "mob.chicken.hurt", 0.3, 0.4) + super("Chicken", mtChicken, "mob.chicken.hurt", "mob.chicken.hurt", 0.3, 0.4) { } diff --git a/source/Mobs/Cow.cpp b/source/Mobs/Cow.cpp index 431a6916d..9eb74dac2 100644 --- a/source/Mobs/Cow.cpp +++ b/source/Mobs/Cow.cpp @@ -2,6 +2,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Cow.h" +#include "../Entities/Player.h" @@ -10,7 +11,7 @@ cCow::cCow(void) : - super("Cow", 92, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3) + super("Cow", mtCow, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3) { } @@ -24,6 +25,10 @@ void cCow::GetDrops(cItems & a_Drops, cEntity * a_Killer) AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_STEAK : E_ITEM_RAW_BEEF); } + + + + void cCow::OnRightClicked(cPlayer & a_Player) { if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_BUCKET)) @@ -31,9 +36,8 @@ void cCow::OnRightClicked(cPlayer & a_Player) if (!a_Player.IsGameModeCreative()) { a_Player.GetInventory().RemoveOneEquippedItem(); - a_Player.GetInventory().AddItem(E_ITEM_MILK) + a_Player.GetInventory().AddItem(E_ITEM_MILK); } - } } diff --git a/source/Mobs/Creeper.cpp b/source/Mobs/Creeper.cpp index b41b05f42..4e11ae13e 100644 --- a/source/Mobs/Creeper.cpp +++ b/source/Mobs/Creeper.cpp @@ -9,7 +9,7 @@ cCreeper::cCreeper(void) : - super("Creeper", 50, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8), + super("Creeper", mtCreeper, "mob.creeper.say", "mob.creeper.say", 0.6, 1.8), m_bIsBlowing(false), m_bIsCharged(false) { diff --git a/source/Mobs/EnderDragon.cpp b/source/Mobs/EnderDragon.cpp index 64f2bedfa..acd81cde1 100644 --- a/source/Mobs/EnderDragon.cpp +++ b/source/Mobs/EnderDragon.cpp @@ -9,7 +9,7 @@ cEnderDragon::cEnderDragon(void) : // TODO: Vanilla source says this, but is it right? Dragons fly, they don't stand - super("EnderDragon", 63, "mob.enderdragon.hit", "mob.enderdragon.end", 16.0, 8.0) + super("EnderDragon", mtEnderDragon, "mob.enderdragon.hit", "mob.enderdragon.end", 16.0, 8.0) { } diff --git a/source/Mobs/Enderman.cpp b/source/Mobs/Enderman.cpp index c0ea3d6aa..a784131e4 100644 --- a/source/Mobs/Enderman.cpp +++ b/source/Mobs/Enderman.cpp @@ -8,7 +8,7 @@ cEnderman::cEnderman(void) : - super("Enderman", 58, "mob.endermen.hit", "mob.endermen.death", 0.5, 2.9), + super("Enderman", mtEnderman, "mob.endermen.hit", "mob.endermen.death", 0.5, 2.9), m_bIsScreaming(false), CarriedBlock(E_BLOCK_AIR), CarriedMeta(0) diff --git a/source/Mobs/Ghast.cpp b/source/Mobs/Ghast.cpp index 288d0c28a..419c8474d 100644 --- a/source/Mobs/Ghast.cpp +++ b/source/Mobs/Ghast.cpp @@ -8,7 +8,7 @@ cGhast::cGhast(void) : - super("Ghast", 56, "mob.ghast.scream", "mob.ghast.death", 4, 4) + super("Ghast", mtGhast, "mob.ghast.scream", "mob.ghast.death", 4, 4) { } diff --git a/source/Mobs/Giant.cpp b/source/Mobs/Giant.cpp index a02758a43..f41977535 100644 --- a/source/Mobs/Giant.cpp +++ b/source/Mobs/Giant.cpp @@ -9,7 +9,7 @@ cGiant::cGiant(void) : // TODO: The size is only a guesstimate, measure in vanilla and fix the size values here - super("Giant", 53, "mob.zombie.hurt", "mob.zombie.death", 2.0, 13.5) + super("Giant", mtGiant, "mob.zombie.hurt", "mob.zombie.death", 2.0, 13.5) { } diff --git a/source/Mobs/Horse.cpp b/source/Mobs/Horse.cpp index c2a8f6ed0..d18887ea4 100644 --- a/source/Mobs/Horse.cpp +++ b/source/Mobs/Horse.cpp @@ -1,4 +1,3 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "Horse.h" @@ -10,7 +9,7 @@ cHorse::cHorse(int Type, int Color, int Style, int TameTimes) : - super("Horse", 100, "mob.horse.hit", "mob.horse.death", 1.4, 1.6), + super("Horse", mtHorse, "mob.horse.hit", "mob.horse.death", 1.4, 1.6), m_bHasChest(false), m_bIsEating(false), m_bIsRearing(false), @@ -76,8 +75,12 @@ void cHorse::Tick(float a_Dt, cChunk & a_Chunk) if (m_RearTickCount == 20) { m_bIsRearing = false; + m_RearTickCount = 0; + } + else + { + m_RearTickCount++; } - else { m_RearTickCount++;} } m_World->BroadcastEntityMetadata(*this); @@ -89,35 +92,45 @@ void cHorse::Tick(float a_Dt, cChunk & a_Chunk) void cHorse::OnRightClicked(cPlayer & a_Player) { - if (m_Attachee != NULL) + if (!m_bIsSaddled && m_bIsTame) { - if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) + if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SADDLE) { - a_Player.Detach(); - return; + // Saddle the horse: + if (!a_Player.IsGameModeCreative()) + { + a_Player.GetInventory().RemoveOneEquippedItem(); + } + m_bIsSaddled = true; + m_World->BroadcastEntityMetadata(*this); } - - if (m_Attachee->IsPlayer()) + else if (!a_Player.GetEquippedItem().IsEmpty()) { - return; + // The horse doesn't like being hit, make it rear: + m_bIsRearing = true; + m_RearTickCount = 0; } - - m_Attachee->Detach(); } - - m_TameAttemptTimes++; - a_Player.AttachTo(this); - - if (a_Player.GetEquippedItem().m_ItemType == E_ITEM_SADDLE) + else { - if (!a_Player.IsGameModeCreative()) + if (m_Attachee != NULL) { - a_Player.GetInventory().RemoveOneEquippedItem(); + if (m_Attachee->GetUniqueID() == a_Player.GetUniqueID()) + { + a_Player.Detach(); + return; + } + + if (m_Attachee->IsPlayer()) + { + return; + } + + m_Attachee->Detach(); } - // Set saddle state & broadcast metadata - m_bIsSaddled = true; - m_World->BroadcastEntityMetadata(*this); + m_TameAttemptTimes++; + a_Player.AttachTo(this); } } @@ -128,6 +141,10 @@ void cHorse::OnRightClicked(cPlayer & a_Player) void cHorse::GetDrops(cItems & a_Drops, cEntity * a_Killer) { AddRandomDropItem(a_Drops, 0, 2, E_ITEM_LEATHER); + if (m_bIsSaddled) + { + a_Drops.push_back(cItem(E_ITEM_SADDLE, 1)); + } } diff --git a/source/Mobs/IncludeAllMonsters.h b/source/Mobs/IncludeAllMonsters.h new file mode 100644 index 000000000..1b436a11f --- /dev/null +++ b/source/Mobs/IncludeAllMonsters.h @@ -0,0 +1,29 @@ +#include "Bat.h" +#include "Blaze.h" +#include "Cavespider.h" +#include "Chicken.h" +#include "Cow.h" +#include "Creeper.h" +#include "Enderman.h" +#include "EnderDragon.h" +#include "Ghast.h" +#include "Giant.h" +#include "Horse.h" +#include "IronGolem.h" +#include "Magmacube.h" +#include "Mooshroom.h" +#include "Ocelot.h" +#include "Pig.h" +#include "Sheep.h" +#include "Silverfish.h" +#include "Skeleton.h" +#include "Slime.h" +#include "SnowGolem.h" +#include "Spider.h" +#include "Squid.h" +#include "Villager.h" +#include "Witch.h" +#include "Wither.h" +#include "Wolf.h" +#include "Zombie.h" +#include "Zombiepigman.h" diff --git a/source/Mobs/IronGolem.cpp b/source/Mobs/IronGolem.cpp index 42d312c23..47c961098 100644 --- a/source/Mobs/IronGolem.cpp +++ b/source/Mobs/IronGolem.cpp @@ -8,7 +8,7 @@ cIronGolem::cIronGolem(void) : - super("IronGolem", 99, "mob.IronGolem.hit", "mob.IronGolem.death", 1.4, 2.9) + super("IronGolem", mtIronGolem, "mob.IronGolem.hit", "mob.IronGolem.death", 1.4, 2.9) { } diff --git a/source/Mobs/Magmacube.cpp b/source/Mobs/Magmacube.cpp index c72b4831b..86447ff6b 100644 --- a/source/Mobs/Magmacube.cpp +++ b/source/Mobs/Magmacube.cpp @@ -8,7 +8,7 @@ cMagmaCube::cMagmaCube(int a_Size) : - super("MagmaCube", 62, "mob.MagmaCube.big", "mob.MagmaCube.big", 0.6 * a_Size, 0.6 * a_Size), + super("MagmaCube", mtMagmaCube, "mob.MagmaCube.big", "mob.MagmaCube.big", 0.6 * a_Size, 0.6 * a_Size), m_Size(a_Size) { } diff --git a/source/Mobs/Monster.cpp b/source/Mobs/Monster.cpp index 334229a42..72dfb2583 100644 --- a/source/Mobs/Monster.cpp +++ b/source/Mobs/Monster.cpp @@ -1,7 +1,7 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules -#include "Monster.h" +#include "IncludeAllMonsters.h" #include "../Root.h" #include "../Server.h" #include "../ClientHandle.h" @@ -16,14 +16,56 @@ #include "../Vector3d.h" #include "../Tracer.h" #include "../Chunk.h" +#include "../FastRandom.h" -// #include "../../iniFile/iniFile.h" - -cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) +/** Map for eType <-> string +Needs to be alpha-sorted by the strings, because binary search is used in StringToMobType() +The strings need to be lowercase (for more efficient comparisons in StringToMobType()) +*/ +static const struct +{ + cMonster::eType m_Type; + const char * m_lcName; +} g_MobTypeNames[] = +{ + {cMonster::mtBat, "bat"}, + {cMonster::mtBlaze, "blaze"}, + {cMonster::mtCaveSpider, "cavespider"}, + {cMonster::mtChicken, "chicken"}, + {cMonster::mtCow, "cow"}, + {cMonster::mtCreeper, "creeper"}, + {cMonster::mtEnderman, "enderman"}, + {cMonster::mtGhast, "ghast"}, + {cMonster::mtHorse, "horse"}, + {cMonster::mtMagmaCube, "magmacube"}, + {cMonster::mtMooshroom, "mooshroom"}, + {cMonster::mtOcelot, "ocelot"}, + {cMonster::mtPig, "pig"}, + {cMonster::mtSheep, "sheep"}, + {cMonster::mtSilverfish, "silverfish"}, + {cMonster::mtSkeleton, "skeleton"}, + {cMonster::mtSlime, "slime"}, + {cMonster::mtSpider, "spider"}, + {cMonster::mtSquid, "squid"}, + {cMonster::mtVillager, "villager"}, + {cMonster::mtWitch, "witch"}, + {cMonster::mtWolf, "wolf"}, + {cMonster::mtZombie, "zombie"}, + {cMonster::mtZombiePigman, "zombiepigman"}, +} ; + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cMonster: + +cMonster::cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : super(etMonster, a_Width, a_Height) , m_Target(NULL) , m_AttackRate(3) @@ -32,7 +74,7 @@ cMonster::cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const A , m_DestinationTime( 0 ) , m_DestroyTimer( 0 ) , m_Jump(0) - , m_MobType(a_ProtocolMobType) + , m_MobType(a_MobType) , m_SoundHurt(a_SoundHurt) , m_SoundDeath(a_SoundDeath) , m_EMState(IDLE) @@ -465,6 +507,189 @@ void cMonster::SetSightDistance(float sd) +AString cMonster::MobTypeToString(cMonster::eType a_MobType) +{ + // Mob types aren't sorted, so we need to search linearly: + for (int i = 0; i < ARRAYCOUNT(g_MobTypeNames); i++) + { + if (g_MobTypeNames[i].m_Type == a_MobType) + { + return g_MobTypeNames[i].m_lcName; + } + } + + // Not found: + return ""; +} + + + + + +cMonster::eType cMonster::StringToMobType(const AString & a_Name) +{ + AString lcName(a_Name); + StrToLower(lcName); + + // Binary-search for the lowercase name: + int lo = 0, hi = ARRAYCOUNT(g_MobTypeNames) - 1; + while (hi - lo > 1) + { + int mid = (lo + hi) / 2; + int res = strcmp(g_MobTypeNames[mid].m_lcName, lcName.c_str()); + if (res == 0) + { + return g_MobTypeNames[mid].m_Type; + } + if (res < 0) + { + lo = mid; + } + else + { + hi = mid; + } + } + // Range has collapsed to at most two elements, compare each: + if (strcmp(g_MobTypeNames[lo].m_lcName, lcName.c_str()) == 0) + { + return g_MobTypeNames[lo].m_Type; + } + if ((lo != hi) && (strcmp(g_MobTypeNames[hi].m_lcName, lcName.c_str()) == 0)) + { + return g_MobTypeNames[hi].m_Type; + } + + // Not found: + return mtInvalidType; +} + + + + + +cMonster::eFamily cMonster::FamilyFromType(eType a_Type) +{ + switch (a_Type) + { + case mtBat: return mfAmbient; + case mtBlaze: return mfHostile; + case mtCaveSpider: return mfHostile; + case mtChicken: return mfPassive; + case mtCow: return mfPassive; + case mtCreeper: return mfHostile; + case mtEnderman: return mfHostile; + case mtGhast: return mfHostile; + case mtHorse: return mfPassive; + case mtMagmaCube: return mfHostile; + case mtMooshroom: return mfHostile; + case mtOcelot: return mfHostile; + case mtPig: return mfPassive; + case mtSheep: return mfPassive; + case mtSilverfish: return mfHostile; + case mtSkeleton: return mfHostile; + case mtSlime: return mfHostile; + case mtSpider: return mfHostile; + case mtSquid: return mfWater; + case mtVillager: return mfPassive; + case mtWitch: return mfHostile; + case mtWolf: return mfHostile; + case mtZombie: return mfHostile; + case mtZombiePigman: return mfHostile; + } ; + ASSERT(!"Unhandled mob type"); + return mfMaxplusone; +} + + + + + +int cMonster::GetSpawnDelay(cMonster::eFamily a_MobFamily) +{ + switch (a_MobFamily) + { + case mfHostile: return 40; + case mfPassive: return 40; + case mfAmbient: return 40; + case mfWater: return 400; + } + ASSERT(!"Unhandled mob family"); + return -1; +} + + + + + +cMonster * cMonster::NewMonsterFromType(cMonster::eType a_MobType, int a_Size) +{ + cFastRandom Random; + + cMonster * toReturn = NULL; + + // unspecified size get rand[1,3] for Monsters that need size + switch (a_MobType) + { + case mtMagmaCube: + case mtSlime: + { + if (a_Size == -1) + { + a_Size = Random.NextInt(2, a_MobType) + 1; + } + if ((a_Size <= 0) || (a_Size >= 4)) + { + ASSERT(!"Random for size was supposed to pick in [1..3] and picked outside"); + a_Size = 1; + } + break; + } + default: break; + } // switch (a_MobType) + + // Create the mob entity + switch (a_MobType) + { + case mtMagmaCube: toReturn = new cMagmaCube(a_Size); break; + case mtSlime: toReturn = new cSlime(a_Size); break; + case mtBat: toReturn = new cBat(); break; + case mtBlaze: toReturn = new cBlaze(); break; + case mtCaveSpider: toReturn = new cCavespider(); break; + case mtChicken: toReturn = new cChicken(); break; + case mtCow: toReturn = new cCow(); break; + case mtCreeper: toReturn = new cCreeper(); break; + case mtEnderman: toReturn = new cEnderman(); break; + case mtGhast: toReturn = new cGhast(); break; + // TODO: + // case cMonster::mtHorse: toReturn = new cHorse(); break; + case mtMooshroom: toReturn = new cMooshroom(); break; + case mtOcelot: toReturn = new cOcelot(); break; + case mtPig: toReturn = new cPig(); break; + // TODO: Implement sheep color + case mtSheep: toReturn = new cSheep(0); break; + case mtSilverfish: toReturn = new cSilverfish(); break; + // TODO: Implement wither skeleton geration + case mtSkeleton: toReturn = new cSkeleton(false); break; + case mtSpider: toReturn = new cSpider(); break; + case mtSquid: toReturn = new cSquid(); break; + case mtVillager: toReturn = new cVillager(cVillager::vtFarmer); break; + case mtWitch: toReturn = new cWitch(); break; + case mtWolf: toReturn = new cWolf(); break; + case mtZombie: toReturn = new cZombie(false); break; + case mtZombiePigman: toReturn = new cZombiePigman(); break; + default: + { + ASSERT(!"Unhandled Mob type"); + } + } + return toReturn; +} + + + + + void cMonster::AddRandomDropItem(cItems & a_Drops, unsigned int a_Min, unsigned int a_Max, short a_Item, short a_ItemHealth) { MTRand r1; @@ -493,8 +718,8 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) return; } - int RelX = (int)floor(GetPosX()) - a_Chunk.GetPosX() * cChunkDef::Width; - int RelZ = (int)floor(GetPosZ()) - a_Chunk.GetPosZ() * cChunkDef::Width; + int RelX = (int)floor(GetPosX()) - GetChunkX() * cChunkDef::Width; + int RelZ = (int)floor(GetPosZ()) - GetChunkZ() * cChunkDef::Width; if ( (a_Chunk.GetSkyLight(RelX, RelY, RelZ) == 15) && // In the daylight (a_Chunk.GetBlock(RelX, RelY, RelZ) != E_BLOCK_SOULSAND) && // Not on soulsand @@ -510,3 +735,11 @@ void cMonster::HandleDaylightBurning(cChunk & a_Chunk) +cMonster::eFamily cMonster::GetMobFamily(void) const +{ + return FamilyFromType(m_MobType); +} + + + + diff --git a/source/Mobs/Monster.h b/source/Mobs/Monster.h index d784f2eec..a0002bf4f 100644 --- a/source/Mobs/Monster.h +++ b/source/Mobs/Monster.h @@ -26,6 +26,8 @@ public: /// This identifies individual monster type, as well as their network type-ID enum eType { + mtInvalidType = -1, + mtBat = E_META_SPAWN_EGG_BAT, mtBlaze = E_META_SPAWN_EGG_BLAZE, mtCaveSpider = E_META_SPAWN_EGG_CAVE_SPIDER, @@ -55,19 +57,31 @@ public: mtWolf = E_META_SPAWN_EGG_WOLF, mtZombie = E_META_SPAWN_EGG_ZOMBIE, mtZombiePigman = E_META_SPAWN_EGG_ZOMBIE_PIGMAN, + } ; + + enum eFamily + { + mfHostile = 0, // Spider, Zombies ... + mfPassive = 1, // Cows, Pigs + mfAmbient = 2, // Bats + mfWater = 3, // Squid + mfMaxplusone, // Nothing. Be sure this is the last and the others are in order } ; // tolua_end + enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState; + enum MPersonality{PASSIVE,AGGRESSIVE,COWARDLY} m_EMPersonality; + float m_SightDistance; /** Creates the mob object. * If a_ConfigName is not empty, the configuration is loaded using GetMonsterConfig() - * a_ProtocolMobType is the ID of the mob used in the protocol ( http://wiki.vg/Entities#Mobs , 2012_12_22) + * a_MobType is the type of the mob (also used in the protocol ( http://wiki.vg/Entities#Mobs , 2012_12_22)) * a_SoundHurt and a_SoundDeath are assigned into m_SoundHurt and m_SoundDeath, respectively */ - cMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); + cMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); CLASS_PROTODEF(cMonster); @@ -82,7 +96,11 @@ public: virtual void MoveToPosition(const Vector3f & a_Position); virtual bool ReachedDestination(void); - char GetMobType(void) const {return m_MobType; } + // tolua_begin + eType GetMobType(void) const {return m_MobType; } + eFamily GetMobFamily(void) const; + // tolua_end + const char * GetState(); void SetState(const AString & str); @@ -103,8 +121,6 @@ public: virtual void Attack(float a_Dt); - int GetMobType() { return m_MobType; } // tolua_export - int GetAttackRate(){return (int)m_AttackRate;} void SetAttackRate(int ar); void SetAttackRange(float ar); @@ -119,9 +135,31 @@ public: virtual bool IsTame (void) const { return false; } virtual bool IsSitting (void) const { return false; } - enum MState{ATTACKING, IDLE, CHASING, ESCAPING} m_EMState; - enum MPersonality{PASSIVE,AGGRESSIVE,COWARDLY} m_EMPersonality; + // tolua_begin + + /// Translates MobType enum to a string, empty string if unknown + static AString MobTypeToString(eType a_MobType); + + /// Translates MobType string to the enum, mtInvalidType if not recognized + static eType StringToMobType(const AString & a_MobTypeName); + /// Returns the mob family based on the type + static eFamily FamilyFromType(eType a_MobType); + + /// Returns the spawn delay (number of game ticks between spawn attempts) for the given mob family + static int GetSpawnDelay(cMonster::eFamily a_MobFamily); + + // tolua_end + + /** Creates a new object of the specified mob. + a_MobType is the type of the mob to be created + a_Size is the size (for mobs with size) + if a_Size is let to -1 for entities that need size, size will be random + asserts and returns null if mob type is not specified + asserts if invalid size for mobs that need size + */ + static cMonster * NewMonsterFromType(eType a_MobType, int a_Size = -1); + protected: cEntity * m_Target; @@ -137,7 +175,7 @@ protected: float m_DestroyTimer; float m_Jump; - char m_MobType; + eType m_MobType; AString m_SoundHurt; AString m_SoundDeath; diff --git a/source/Mobs/Mooshroom.cpp b/source/Mobs/Mooshroom.cpp index 5d2c901ba..940e2db44 100644 --- a/source/Mobs/Mooshroom.cpp +++ b/source/Mobs/Mooshroom.cpp @@ -14,7 +14,7 @@ cMooshroom::cMooshroom(void) : - super("Mooshroom", 96, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3) + super("Mooshroom", mtMooshroom, "mob.cow.hurt", "mob.cow.hurt", 0.9, 1.3) { } diff --git a/source/Mobs/Ocelot.h b/source/Mobs/Ocelot.h index 6d24c5672..adb7a1f75 100644 --- a/source/Mobs/Ocelot.h +++ b/source/Mobs/Ocelot.h @@ -14,7 +14,7 @@ class cOcelot : public: cOcelot(void) : - super("Ocelot", 98, "mob.cat.hitt", "mob.cat.hitt", 0.6, 0.8) + super("Ocelot", mtOcelot, "mob.cat.hitt", "mob.cat.hitt", 0.6, 0.8) { } diff --git a/source/Mobs/PassiveAggressiveMonster.cpp b/source/Mobs/PassiveAggressiveMonster.cpp index e473137a9..28de65905 100644 --- a/source/Mobs/PassiveAggressiveMonster.cpp +++ b/source/Mobs/PassiveAggressiveMonster.cpp @@ -9,8 +9,8 @@ -cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : - super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height) +cPassiveAggressiveMonster::cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : + super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height) { m_EMPersonality = PASSIVE; } diff --git a/source/Mobs/PassiveAggressiveMonster.h b/source/Mobs/PassiveAggressiveMonster.h index 243dfff38..2c5ef30b1 100644 --- a/source/Mobs/PassiveAggressiveMonster.h +++ b/source/Mobs/PassiveAggressiveMonster.h @@ -13,7 +13,7 @@ class cPassiveAggressiveMonster : typedef cAggressiveMonster super; public: - cPassiveAggressiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); + cPassiveAggressiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; } ; diff --git a/source/Mobs/PassiveMonster.cpp b/source/Mobs/PassiveMonster.cpp index 7a6140c04..91ceb5a53 100644 --- a/source/Mobs/PassiveMonster.cpp +++ b/source/Mobs/PassiveMonster.cpp @@ -9,8 +9,8 @@ -cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : - super(a_ConfigName, a_ProtocolMobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height) +cPassiveMonster::cPassiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height) : + super(a_ConfigName, a_MobType, a_SoundHurt, a_SoundDeath, a_Width, a_Height) { m_EMPersonality = PASSIVE; } @@ -56,3 +56,4 @@ void cPassiveMonster::Tick(float a_Dt, cChunk & a_Chunk) + diff --git a/source/Mobs/PassiveMonster.h b/source/Mobs/PassiveMonster.h index ae0bea3fb..14a6be6b1 100644 --- a/source/Mobs/PassiveMonster.h +++ b/source/Mobs/PassiveMonster.h @@ -13,12 +13,13 @@ class cPassiveMonster : typedef cMonster super; public: - cPassiveMonster(const AString & a_ConfigName, char a_ProtocolMobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); + cPassiveMonster(const AString & a_ConfigName, eType a_MobType, const AString & a_SoundHurt, const AString & a_SoundDeath, double a_Width, double a_Height); virtual void Tick(float a_Dt, cChunk & a_Chunk) override; /// When hit by someone, run away virtual void DoTakeDamage(TakeDamageInfo & a_TDI) override; + } ; diff --git a/source/Mobs/Pig.cpp b/source/Mobs/Pig.cpp index cd18c087f..0871a38a9 100644 --- a/source/Mobs/Pig.cpp +++ b/source/Mobs/Pig.cpp @@ -10,7 +10,7 @@ cPig::cPig(void) : - super("Pig", 90, "mob.pig.say", "mob.pig.death", 0.9, 0.9), + super("Pig", mtPig, "mob.pig.say", "mob.pig.death", 0.9, 0.9), m_bIsSaddled(false) { } @@ -22,6 +22,10 @@ cPig::cPig(void) : void cPig::GetDrops(cItems & a_Drops, cEntity * a_Killer) { AddRandomDropItem(a_Drops, 1, 3, IsOnFire() ? E_ITEM_COOKED_PORKCHOP : E_ITEM_RAW_PORKCHOP); + if (m_bIsSaddled) + { + a_Drops.push_back(cItem(E_ITEM_SADDLE, 1)); + } } diff --git a/source/Mobs/Sheep.cpp b/source/Mobs/Sheep.cpp index 440c5c2b9..703482ddb 100644 --- a/source/Mobs/Sheep.cpp +++ b/source/Mobs/Sheep.cpp @@ -11,7 +11,7 @@ cSheep::cSheep(int a_Color) : - super("Sheep", 91, "mob.sheep.say", "mob.sheep.say", 0.6, 1.3), + super("Sheep", mtSheep, "mob.sheep.say", "mob.sheep.say", 0.6, 1.3), m_IsSheared(false), m_WoolColor(a_Color) { @@ -33,6 +33,7 @@ void cSheep::GetDrops(cItems & a_Drops, cEntity * a_Killer) + void cSheep::OnRightClicked(cPlayer & a_Player) { if ((a_Player.GetEquippedItem().m_ItemType == E_ITEM_SHEARS) && (!m_IsSheared)) @@ -46,7 +47,8 @@ void cSheep::OnRightClicked(cPlayer & a_Player) } cItems Drops; - Drops.push_back(cItem(E_BLOCK_WOOL, 4, m_WoolColor)); + int NumDrops = m_World->GetTickRandomNumber(2) + 1; + Drops.push_back(cItem(E_BLOCK_WOOL, NumDrops, m_WoolColor)); m_World->SpawnItemPickups(Drops, GetPosX(), GetPosY(), GetPosZ(), 10); } } @@ -54,3 +56,4 @@ void cSheep::OnRightClicked(cPlayer & a_Player) + diff --git a/source/Mobs/Silverfish.h b/source/Mobs/Silverfish.h index d632ac169..a6e11c49d 100644 --- a/source/Mobs/Silverfish.h +++ b/source/Mobs/Silverfish.h @@ -14,7 +14,7 @@ class cSilverfish : public: cSilverfish(void) : - super("Silverfish", 60, "mob.silverfish.hit", "mob.silverfish.kill", 0.3, 0.7) + super("Silverfish", mtSilverfish, "mob.silverfish.hit", "mob.silverfish.kill", 0.3, 0.7) { } diff --git a/source/Mobs/Skeleton.cpp b/source/Mobs/Skeleton.cpp index 6297b867c..37a724848 100644 --- a/source/Mobs/Skeleton.cpp +++ b/source/Mobs/Skeleton.cpp @@ -9,7 +9,7 @@ cSkeleton::cSkeleton(bool IsWither) : - super("Skeleton", 51, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8), + super("Skeleton", mtSkeleton, "mob.skeleton.hurt", "mob.skeleton.death", 0.6, 1.8), m_bIsWither(IsWither) { SetBurnsInDaylight(true); diff --git a/source/Mobs/Slime.cpp b/source/Mobs/Slime.cpp index 7a9487a06..19f376c21 100644 --- a/source/Mobs/Slime.cpp +++ b/source/Mobs/Slime.cpp @@ -9,7 +9,7 @@ /// Creates a slime of the specified size; size is 1 .. 3, with 1 being the smallest cSlime::cSlime(int a_Size) : - super("Slime", 55, "mob.slime.attack", "mob.slime.attack", 0.6 * a_Size, 0.6 * a_Size), + super("Slime", mtSlime, "mob.slime.attack", "mob.slime.attack", 0.6 * a_Size, 0.6 * a_Size), m_Size(a_Size) { } diff --git a/source/Mobs/SnowGolem.cpp b/source/Mobs/SnowGolem.cpp index 51125542d..9e199f87e 100644 --- a/source/Mobs/SnowGolem.cpp +++ b/source/Mobs/SnowGolem.cpp @@ -8,7 +8,7 @@ cSnowGolem::cSnowGolem(void) : - super("SnowGolem", 97, "", "", 0.4, 1.8) + super("SnowGolem", mtSnowGolem, "", "", 0.4, 1.8) { } diff --git a/source/Mobs/Spider.cpp b/source/Mobs/Spider.cpp index 2f244cdbc..b19a5dcef 100644 --- a/source/Mobs/Spider.cpp +++ b/source/Mobs/Spider.cpp @@ -8,7 +8,7 @@ cSpider::cSpider(void) : - super("Spider", 52, "mob.spider.say", "mob.spider.death", 1.4, 0.9) + super("Spider", mtSpider, "mob.spider.say", "mob.spider.death", 1.4, 0.9) { } diff --git a/source/Mobs/Squid.cpp b/source/Mobs/Squid.cpp index cb796f5ec..a311108ae 100644 --- a/source/Mobs/Squid.cpp +++ b/source/Mobs/Squid.cpp @@ -10,7 +10,7 @@ cSquid::cSquid(void) : - super("Squid", 94, "", "", 0.95, 0.95) + super("Squid", mtSquid, "", "", 0.95, 0.95) { } @@ -54,4 +54,3 @@ void cSquid::Tick(float a_Dt, cChunk & a_Chunk) - diff --git a/source/Mobs/Squid.h b/source/Mobs/Squid.h index 35d7295b3..ad299b95c 100644 --- a/source/Mobs/Squid.h +++ b/source/Mobs/Squid.h @@ -20,6 +20,7 @@ public: CLASS_PROTODEF(cSquid); virtual void GetDrops(cItems & a_Drops, cEntity * a_Killer = NULL) override; + } ; diff --git a/source/Mobs/Villager.cpp b/source/Mobs/Villager.cpp index 97d6dc3ca..7f89fb6cc 100644 --- a/source/Mobs/Villager.cpp +++ b/source/Mobs/Villager.cpp @@ -9,7 +9,7 @@ cVillager::cVillager(eVillagerType VillagerType) : - super("Villager", 120, "", "", 0.6, 1.8), + super("Villager", mtVillager, "", "", 0.6, 1.8), m_Type(VillagerType) { } diff --git a/source/Mobs/Witch.cpp b/source/Mobs/Witch.cpp index b29783853..25d27041f 100644 --- a/source/Mobs/Witch.cpp +++ b/source/Mobs/Witch.cpp @@ -8,7 +8,7 @@ cWitch::cWitch(void) : - super("Witch", 66, "", "", 0.6, 1.8) + super("Witch", mtWitch, "", "", 0.6, 1.8) { } diff --git a/source/Mobs/Wither.cpp b/source/Mobs/Wither.cpp index 8b77284c8..c46e0beab 100644 --- a/source/Mobs/Wither.cpp +++ b/source/Mobs/Wither.cpp @@ -8,7 +8,7 @@ cWither::cWither(void) : - super("Wither", 64, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0) + super("Wither", mtWither, "mob.wither.hurt", "mob.wither.death", 0.9, 4.0) { } diff --git a/source/Mobs/Wolf.cpp b/source/Mobs/Wolf.cpp index e76f991dc..2baeb4b7b 100644 --- a/source/Mobs/Wolf.cpp +++ b/source/Mobs/Wolf.cpp @@ -10,7 +10,7 @@ cWolf::cWolf(void) : - super("Wolf", 95, "mob.wolf.hurt", "mob.wolf.death", 0.6, 0.8), + super("Wolf", mtWolf, "mob.wolf.hurt", "mob.wolf.death", 0.6, 0.8), m_bIsAngry(false), m_bIsTame(false), m_bIsSitting(false), diff --git a/source/Mobs/Zombie.cpp b/source/Mobs/Zombie.cpp index f495fe5ee..1752ec390 100644 --- a/source/Mobs/Zombie.cpp +++ b/source/Mobs/Zombie.cpp @@ -9,7 +9,7 @@ cZombie::cZombie(bool IsVillagerZombie) : - super("Zombie", 54, "mob.zombie.hurt", "mob.zombie.death", 0.6, 1.8), + super("Zombie", mtZombie, "mob.zombie.hurt", "mob.zombie.death", 0.6, 1.8), m_bIsConverting(false), m_bIsVillagerZombie(IsVillagerZombie) { diff --git a/source/Mobs/Zombiepigman.cpp b/source/Mobs/Zombiepigman.cpp index 1e31a72d9..6ac89ed4c 100644 --- a/source/Mobs/Zombiepigman.cpp +++ b/source/Mobs/Zombiepigman.cpp @@ -9,7 +9,7 @@ cZombiePigman::cZombiePigman(void) : - super("ZombiePigman", 57, "mob.zombiepig.zpighurt", "mob.zombiepig.zpigdeath", 0.6, 1.8) + super("ZombiePigman", mtZombiePigman, "mob.zombiepig.zpighurt", "mob.zombiepig.zpigdeath", 0.6, 1.8) { } diff --git a/source/MonsterConfig.cpp b/source/MonsterConfig.cpp index 37c7431b0..a5a1ebd49 100644 --- a/source/MonsterConfig.cpp +++ b/source/MonsterConfig.cpp @@ -55,18 +55,18 @@ cMonsterConfig::~cMonsterConfig() void cMonsterConfig::Initialize() { - cIniFile MonstersIniFile("monsters.ini"); + cIniFile MonstersIniFile; - if (!MonstersIniFile.ReadFile()) + if (!MonstersIniFile.ReadFile("monsters.ini")) { LOGWARNING("%s: Cannot read monsters.ini file, monster attributes not available", __FUNCTION__); return; } - for (int i = (int)MonstersIniFile.NumKeys(); i >= 0; i--) + for (int i = (int)MonstersIniFile.GetNumKeys(); i >= 0; i--) { sAttributesStruct Attributes; - AString Name = MonstersIniFile.KeyName(i); + AString Name = MonstersIniFile.GetKeyName(i); Attributes.m_Name = Name; Attributes.m_AttackDamage = MonstersIniFile.GetValueF(Name, "AttackDamage", 0); Attributes.m_AttackRange = MonstersIniFile.GetValueF(Name, "AttackRange", 0); diff --git a/source/PluginManager.cpp b/source/PluginManager.cpp index a557bdc03..5ae70d48d 100644 --- a/source/PluginManager.cpp +++ b/source/PluginManager.cpp @@ -103,8 +103,8 @@ void cPluginManager::ReloadPluginsNow(void) cServer::BindBuiltInConsoleCommands(); - cIniFile IniFile("settings.ini"); - if (!IniFile.ReadFile()) + cIniFile IniFile; + if (!IniFile.ReadFile("settings.ini")) { LOGWARNING("cPluginManager: Can't find settings.ini, so can't load any plugins."); } diff --git a/source/Protocol/Protocol.h b/source/Protocol/Protocol.h index 5071f5961..466cf874b 100644 --- a/source/Protocol/Protocol.h +++ b/source/Protocol/Protocol.h @@ -186,6 +186,27 @@ protected: WriteInt(a_Vector.y); WriteInt(a_Vector.z); } + + void WriteVarInt(UInt32 a_Value) + { + // A 32-bit integer can be encoded by at most 5 bytes: + unsigned char b[5]; + int idx = 0; + do + { + b[idx] = (a_Value & 0x7f) | ((a_Value > 0x7f) ? 0x80 : 0x00); + a_Value = a_Value >> 7; + idx++; + } while (a_Value > 0); + + SendData((const char *)b, idx); + } + + void WriteVarUTF8String(const AString & a_String) + { + WriteVarInt(a_String.size()); + SendData(a_String.data(), a_String.size()); + } } ; diff --git a/source/Protocol/Protocol125.cpp b/source/Protocol/Protocol125.cpp index fb7315468..ef40f265a 100644 --- a/source/Protocol/Protocol125.cpp +++ b/source/Protocol/Protocol125.cpp @@ -963,7 +963,7 @@ void cProtocol125::SendWholeInventory(const cWindow & a_Window) void cProtocol125::SendWindowClose(const cWindow & a_Window) { - if (a_Window.GetWindowType() == cWindow::Inventory) + if (a_Window.GetWindowType() == cWindow::wtInventory) { // Do not send inventory-window-close return; diff --git a/source/Protocol/Protocol125.h b/source/Protocol/Protocol125.h index ae198780c..da3f81444 100644 --- a/source/Protocol/Protocol125.h +++ b/source/Protocol/Protocol125.h @@ -92,9 +92,9 @@ protected: PARSE_INCOMPLETE = -3, } ; - cByteBuffer m_ReceivedData; //< Buffer for the received data + cByteBuffer m_ReceivedData; ///< Buffer for the received data - AString m_Username; //< Stored in ParseHandshake(), compared to Login username + AString m_Username; ///< Stored in ParseHandshake(), compared to Login username virtual void SendData(const char * a_Data, int a_Size) override; diff --git a/source/Protocol/Protocol17x.cpp b/source/Protocol/Protocol17x.cpp new file mode 100644 index 000000000..b3e4540c7 --- /dev/null +++ b/source/Protocol/Protocol17x.cpp @@ -0,0 +1,541 @@ + +// Protocol17x.cpp + +/* +Implements the 1.7.x protocol classes: + - cProtocol172 + - release 1.7.2 protocol (#4) +(others may be added later in the future for the 1.7 release series) +*/ + +#include "Globals.h" +#include "Protocol17x.h" +#include "../ClientHandle.h" +#include "../Root.h" +#include "../Server.h" +#include "../Entities/Player.h" + + + + + +#define HANDLE_PACKET_READ(Proc, Type, Var) \ + Type Var; \ + m_ReceivedData.Proc(Var); + + + + + +cProtocol172::cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State) : + super(a_Client), + m_ServerAddress(a_ServerAddress), + m_ServerPort(a_ServerPort), + m_State(a_State), + m_ReceivedData(32 KiB), + m_IsEncrypted(false) +{ +} + + + + + +void cProtocol172::DataReceived(const char * a_Data, int a_Size) +{ + if (m_IsEncrypted) + { + byte Decrypted[512]; + while (a_Size > 0) + { + int NumBytes = (a_Size > sizeof(Decrypted)) ? sizeof(Decrypted) : a_Size; + m_Decryptor.ProcessData(Decrypted, (byte *)a_Data, NumBytes); + AddReceivedData((const char *)Decrypted, NumBytes); + a_Size -= NumBytes; + a_Data += NumBytes; + } + } + else + { + AddReceivedData(a_Data, a_Size); + } +} + + + + +void cProtocol172::AddReceivedData(const char * a_Data, int a_Size) +{ + if (!m_ReceivedData.Write(a_Data, a_Size)) + { + // Too much data in the incoming queue, report to caller: + m_Client->PacketBufferFull(); + return; + } + + // Handle all complete packets: + while (true) + { + UInt32 PacketLen; + if (!m_ReceivedData.ReadVarInt(PacketLen)) + { + // Not enough data + return; + } + if (!m_ReceivedData.CanReadBytes(PacketLen)) + { + // The full packet hasn't been received yet + return; + } + UInt32 PacketType; + UInt32 Mark1 = m_ReceivedData.GetReadableSpace(); + if (!m_ReceivedData.ReadVarInt(PacketType)) + { + // Not enough data + return; + } + UInt32 NumBytesRead = Mark1 - m_ReceivedData.GetReadableSpace(); + HandlePacket(PacketType, PacketLen - NumBytesRead); + + if (Mark1 - m_ReceivedData.GetReadableSpace() > PacketLen) + { + // Read more than packet length, report as error + m_Client->PacketError(PacketType); + } + + // Go to packet end in any case: + m_ReceivedData.ResetRead(); + m_ReceivedData.SkipRead(PacketLen); + m_ReceivedData.CommitRead(); + } // while (true) +} + + + + +void cProtocol172::HandlePacket(UInt32 a_PacketType, UInt32 a_RemainingBytes) +{ + switch (m_State) + { + case 1: + { + // Status + switch (a_PacketType) + { + case 0x00: HandlePacketStatusRequest(a_RemainingBytes); return; + case 0x01: HandlePacketStatusPing (a_RemainingBytes); return; + } + break; + } + + case 2: + { + // Login + switch (a_PacketType) + { + case 0x00: HandlePacketLoginStart(a_RemainingBytes); return; + case 0x01: HandlePacketLoginEncryptionResponse(a_RemainingBytes); return; + } + break; + } + + case 3: + { + // Game + switch (a_PacketType) + { + case 0x00: HandlePacketKeepAlive (a_RemainingBytes); break; + case 0x01: HandlePacketChatMessage (a_RemainingBytes); break; + case 0x02: HandlePacketUseEntity (a_RemainingBytes); break; + case 0x03: HandlePacketPlayer (a_RemainingBytes); break; + case 0x04: HandlePacketPlayerPos (a_RemainingBytes); break; + case 0x05: HandlePacketPlayerLook (a_RemainingBytes); break; + case 0x06: HandlePacketPlayerPosLook (a_RemainingBytes); break; + case 0x07: HandlePacketBlockDig (a_RemainingBytes); break; + case 0x08: HandlePacketBlockPlace (a_RemainingBytes); break; + case 0x09: HandlePacketSlotSelect (a_RemainingBytes); break; + case 0x0a: HandlePacketAnimation (a_RemainingBytes); break; + case 0x0b: HandlePacketEntityAction (a_RemainingBytes); break; + case 0x0c: HandlePacketSteerVehicle (a_RemainingBytes); break; + case 0x0d: HandlePacketWindowClose (a_RemainingBytes); break; + case 0x0e: HandlePacketWindowClick (a_RemainingBytes); break; + case 0x0f: // Confirm transaction - not used in MCS + case 0x10: HandlePacketCreativeInventoryAction(a_RemainingBytes); break; + case 0x12: HandlePacketUpdateSign (a_RemainingBytes); break; + case 0x13: HandlePacketPlayerAbilities (a_RemainingBytes); break; + case 0x14: HandlePacketTabComplete (a_RemainingBytes); break; + case 0x15: HandlePacketClientSettings (a_RemainingBytes); break; + case 0x16: HandlePacketClientStatus (a_RemainingBytes); break; + case 0x17: HandlePacketPluginMessage (a_RemainingBytes); break; + } + break; + } + } // switch (m_State) + + // Unknown packet type, report to the client: + m_Client->PacketUnknown(a_PacketType); + m_ReceivedData.SkipRead(a_RemainingBytes); + m_ReceivedData.CommitRead(); +} + + + + + +void cProtocol172::HandlePacketStatusPing(UInt32 a_RemainingBytes) +{ + ASSERT(a_RemainingBytes == 8); + if (a_RemainingBytes != 8) + { + m_Client->PacketError(0x01); + m_ReceivedData.SkipRead(a_RemainingBytes); + m_ReceivedData.CommitRead(); + return; + } + Int64 Timestamp; + m_ReceivedData.ReadBEInt64(Timestamp); + m_ReceivedData.CommitRead(); + + cByteBuffer Packet(18); + Packet.WriteVarInt(0x01); + Packet.WriteBEInt64(Timestamp); + WritePacket(Packet); +} + + + + + +void cProtocol172::HandlePacketStatusRequest(UInt32 a_RemainingBytes) +{ + // No more bytes in this packet + ASSERT(a_RemainingBytes == 0); + m_ReceivedData.CommitRead(); + + // Send the response: + AString Response = "{\"version\":{\"name\":\"1.7.2\",\"protocol\":4},\"players\":{"; + AppendPrintf(Response, "\"max\":%u,\"online\":%u,\"sample\":[]},", + cRoot::Get()->GetServer()->GetMaxPlayers(), + cRoot::Get()->GetServer()->GetNumPlayers() + ); + AppendPrintf(Response, "\"description\":{\"text\":\"%s\"}", + cRoot::Get()->GetServer()->GetDescription().c_str() + ); + Response.append("}"); + + cByteBuffer Packet(Response.size() + 10); + Packet.WriteVarInt(0x00); // Response packet + Packet.WriteVarUTF8String(Response); + WritePacket(Packet); +} + + + + + +void cProtocol172::HandlePacketLoginEncryptionResponse(UInt32 a_RemainingBytes) +{ + // TODO: Add protocol encryption +} + + + + + +void cProtocol172::HandlePacketLoginStart(UInt32 a_RemainingBytes) +{ + AString Username; + m_ReceivedData.ReadVarUTF8String(Username); + + // TODO: Protocol encryption should be set up here if not localhost / auth + + // Send login success: + cByteBuffer Packet(Username.size() + 30); + Packet.WriteVarInt(0x02); // Login success packet + Packet.WriteVarUTF8String(Printf("%d", m_Client->GetUniqueID())); // TODO: UUID + Packet.WriteVarUTF8String(Username); + WritePacket(Packet); + + m_Client->HandleLogin(4, Username); +} + + + + + +void cProtocol172::HandlePacketAnimation(UInt32 a_RemainingBytes) +{ + HANDLE_PACKET_READ(ReadBEInt, int, EntityID); + HANDLE_PACKET_READ(ReadByte, Byte, Animation); + m_Client->HandleAnimation(Animation); +} + + + + + +void cProtocol172::HandlePacketBlockDig(UInt32 a_RemainingBytes) +{ + HANDLE_PACKET_READ(ReadByte, Byte, Status); + HANDLE_PACKET_READ(ReadBEInt, int, BlockX); + HANDLE_PACKET_READ(ReadByte, Byte, BlockY); + HANDLE_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_PACKET_READ(ReadByte, Byte, Face); + m_Client->HandleLeftClick(BlockX, BlockY, BlockZ, Face, Status); +} + + + + + +void cProtocol172::HandlePacketBlockPlace(UInt32 a_RemainingBytes) +{ + HANDLE_PACKET_READ(ReadBEInt, int, BlockX); + HANDLE_PACKET_READ(ReadByte, Byte, BlockY); + HANDLE_PACKET_READ(ReadBEInt, int, BlockZ); + HANDLE_PACKET_READ(ReadByte, Byte, Face); + HANDLE_PACKET_READ(ReadByte, Byte, CursorX); + HANDLE_PACKET_READ(ReadByte, Byte, CursorY); + HANDLE_PACKET_READ(ReadByte, Byte, CursorZ); + m_Client->HandleRightClick(BlockX, BlockY, BlockZ, Face, CursorX, CursorY, CursorZ, m_Client->GetPlayer()->GetEquippedItem()); +} + + + + + +void cProtocol172::HandlePacketChatMessage(UInt32 a_RemainingBytes) +{ + HANDLE_PACKET_READ(ReadVarUTF8String, AString, Message); + m_Client->HandleChat(Message); +} + + + + + +void cProtocol172::HandlePacketClientSettings(UInt32 a_RemainingBytes) +{ + HANDLE_PACKET_READ(ReadVarUTF8String, AString, Locale); + HANDLE_PACKET_READ(ReadByte, Byte, ViewDistance); + HANDLE_PACKET_READ(ReadByte, Byte, ChatFlags); + HANDLE_PACKET_READ(ReadByte, Byte, Unused); + HANDLE_PACKET_READ(ReadByte, Byte, Difficulty); + HANDLE_PACKET_READ(ReadByte, Byte, ShowCape); + // TODO +} + + + + + +void cProtocol172::HandlePacketClientStatus(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketCreativeInventoryAction(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketEntityAction(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketKeepAlive(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketPlayer(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketPlayerAbilities(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketPlayerLook(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketPlayerPos(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketPlayerPosLook(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketPluginMessage(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketSlotSelect(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketSteerVehicle(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketTabComplete(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketUpdateSign(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketUseEntity(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketWindowClick(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::HandlePacketWindowClose(UInt32 a_RemainingBytes) +{ + // TODO +} + + + + + +void cProtocol172::WritePacket(cByteBuffer & a_Packet) +{ + cCSLock Lock(m_CSPacket); + AString Pkt; + a_Packet.ReadAll(Pkt); + WriteVarInt(Pkt.size()); + SendData(Pkt.data(), Pkt.size()); + Flush(); +} + + + + + +void cProtocol172::SendData(const char * a_Data, int a_Size) +{ + m_DataToSend.append(a_Data, a_Size); +} + + + + + +void cProtocol172::Flush(void) +{ + ASSERT(m_CSPacket.IsLockedByCurrentThread()); // Did all packets lock the CS properly? + + if (m_DataToSend.empty()) + { + LOGD("Flushing empty"); + return; + } + const char * a_Data = m_DataToSend.data(); + int a_Size = m_DataToSend.size(); + if (m_IsEncrypted) + { + byte Encrypted[8192]; // Larger buffer, we may be sending lots of data (chunks) + while (a_Size > 0) + { + int NumBytes = (a_Size > sizeof(Encrypted)) ? sizeof(Encrypted) : a_Size; + m_Encryptor.ProcessData(Encrypted, (byte *)a_Data, NumBytes); + m_Client->SendData((const char *)Encrypted, NumBytes); + a_Size -= NumBytes; + a_Data += NumBytes; + } + } + else + { + m_Client->SendData(a_Data, a_Size); + } + m_DataToSend.clear(); +} + + + + + diff --git a/source/Protocol/Protocol17x.h b/source/Protocol/Protocol17x.h new file mode 100644 index 000000000..bc197235b --- /dev/null +++ b/source/Protocol/Protocol17x.h @@ -0,0 +1,106 @@ + +// Protocol17x.h + +/* +Declares the 1.7.x protocol classes: + - cProtocol172 + - release 1.7.2 protocol (#4) +(others may be added later in the future for the 1.7 release series) +*/ + + + + + +#pragma once + +#include "Protocol16x.h" + + + + + +class cProtocol172 : + public cProtocol162 // TODO +{ + typedef cProtocol162 super; // TODO + +public: + + cProtocol172(cClientHandle * a_Client, const AString & a_ServerAddress, UInt16 a_ServerPort, UInt32 a_State); + + /// Called when client sends some data: + virtual void DataReceived(const char * a_Data, int a_Size) override; + +protected: + + AString m_ServerAddress; + + UInt16 m_ServerPort; + + /// State of the protocol. 1 = status, 2 = login, 3 = game + UInt32 m_State; + + /// Buffer for the received data + cByteBuffer m_ReceivedData; + + bool m_IsEncrypted; + CryptoPP::CFB_Mode<CryptoPP::AES>::Decryption m_Decryptor; + CryptoPP::CFB_Mode<CryptoPP::AES>::Encryption m_Encryptor; + + /// (Unencrypted) data to be sent to the client. Written by SendData, cleared by Flush() + AString m_DataToSend; + + + /// Adds the received (unencrypted) data to m_ReceivedData, parses complete packets + void AddReceivedData(const char * a_Data, int a_Size); + + /// Reads and handles the packet. The packet length and type have already been read. + void HandlePacket(UInt32 a_PacketType, UInt32 a_RemainingBytes); + + // Packet handlers while in the Status state (m_State == 1): + void HandlePacketStatusPing (UInt32 a_RemainingBytes); + void HandlePacketStatusRequest(UInt32 a_RemainingBytes); + + // Packet handlers while in the Login state (m_State == 2): + void HandlePacketLoginEncryptionResponse(UInt32 a_RemainingBytes); + void HandlePacketLoginStart (UInt32 a_RemainingBytes); + + // Packet handlers while in the Game state (m_State == 3): + void HandlePacketAnimation (UInt32 a_RemainingBytes); + void HandlePacketBlockDig (UInt32 a_RemainingBytes); + void HandlePacketBlockPlace (UInt32 a_RemainingBytes); + void HandlePacketChatMessage (UInt32 a_RemainingBytes); + void HandlePacketClientSettings (UInt32 a_RemainingBytes); + void HandlePacketClientStatus (UInt32 a_RemainingBytes); + void HandlePacketCreativeInventoryAction(UInt32 a_RemainingBytes); + void HandlePacketEntityAction (UInt32 a_RemainingBytes); + void HandlePacketKeepAlive (UInt32 a_RemainingBytes); + void HandlePacketPlayer (UInt32 a_RemainingBytes); + void HandlePacketPlayerAbilities (UInt32 a_RemainingBytes); + void HandlePacketPlayerLook (UInt32 a_RemainingBytes); + void HandlePacketPlayerPos (UInt32 a_RemainingBytes); + void HandlePacketPlayerPosLook (UInt32 a_RemainingBytes); + void HandlePacketPluginMessage (UInt32 a_RemainingBytes); + void HandlePacketSlotSelect (UInt32 a_RemainingBytes); + void HandlePacketSteerVehicle (UInt32 a_RemainingBytes); + void HandlePacketTabComplete (UInt32 a_RemainingBytes); + void HandlePacketUpdateSign (UInt32 a_RemainingBytes); + void HandlePacketUseEntity (UInt32 a_RemainingBytes); + void HandlePacketWindowClick (UInt32 a_RemainingBytes); + void HandlePacketWindowClose (UInt32 a_RemainingBytes); + + + /// Writes an entire packet into the output stream. a_Packet is expected to start with the packet type; data length is prepended here. + void WritePacket(cByteBuffer & a_Packet); + + /// Adds unencrypted data to the outgoing data buffer + virtual void SendData(const char * a_Data, int a_Size) override; + + /// Flushes m_DataToSend through the optional encryption into the outgoing socket data + virtual void Flush(void) override; +} ; + + + + diff --git a/source/Protocol/ProtocolRecognizer.cpp b/source/Protocol/ProtocolRecognizer.cpp index fe99b22e1..18e9186b2 100644 --- a/source/Protocol/ProtocolRecognizer.cpp +++ b/source/Protocol/ProtocolRecognizer.cpp @@ -12,6 +12,7 @@ #include "Protocol14x.h" #include "Protocol15x.h" #include "Protocol16x.h" +#include "Protocol17x.h" #include "../ClientHandle.h" #include "../Root.h" #include "../Server.h" @@ -667,11 +668,65 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) } switch (PacketType) { - case 0x02: break; // Handshake, continue recognizing - case 0xfe: HandleServerPing(); return false; - default: return false; + case 0x02: return TryRecognizeLengthlessProtocol(); // Handshake, continue recognizing + case 0xfe: + { + // This may be either a packet length or the length-less Ping packet + Byte NextByte; + if (!m_Buffer.ReadByte(NextByte)) + { + // Not enough data for either protocol + // This could actually happen with the 1.2 / 1.3 client, but their support is fading out anyway + return false; + } + if (NextByte != 0x01) + { + // This is definitely NOT a length-less Ping packet, handle as lengthed protocol: + break; + } + if (!m_Buffer.ReadByte(NextByte)) + { + // There is no more data. Although this *could* mean TCP fragmentation, it is highly unlikely + // and rather this is a 1.4 client sending a regular Ping packet (without the following Plugin message) + SendLengthlessServerPing(); + return false; + } + if (NextByte == 0xfa) + { + // Definitely a length-less Ping followed by a Plugin message + SendLengthlessServerPing(); + return false; + } + // Definitely a lengthed Initial handshake, handle below: + break; + } + } // switch (PacketType) + + // This must be a lengthed protocol, try if it has the entire initial handshake packet: + m_Buffer.ResetRead(); + UInt32 PacketLen; + UInt32 ReadSoFar = m_Buffer.GetReadableSpace(); + if (!m_Buffer.ReadVarInt(PacketLen)) + { + // Not enough bytes for the packet length, keep waiting + return false; } - + ReadSoFar -= m_Buffer.GetReadableSpace(); + if (!m_Buffer.CanReadBytes(PacketLen)) + { + // Not enough bytes for the packet, keep waiting + return false; + } + return TryRecognizeLengthedProtocol(PacketLen - ReadSoFar); +} + + + + + +bool cProtocolRecognizer::TryRecognizeLengthlessProtocol(void) +{ + // The comm started with 0x02, which is a Handshake packet in the length-less protocol family // 1.3.2 starts with 0x02 0x39 <name-length-short> // 1.2.5 starts with 0x02 <name-length-short> and name is expected to less than 0x3900 long :) char ch; @@ -724,10 +779,59 @@ bool cProtocolRecognizer::TryRecognizeProtocol(void) -void cProtocolRecognizer::HandleServerPing(void) +bool cProtocolRecognizer::TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining) +{ + UInt32 PacketType; + UInt32 NumBytesRead = m_Buffer.GetReadableSpace(); + if (!m_Buffer.ReadVarInt(PacketType)) + { + return false; + } + if (PacketType != 0x00) + { + // Not an initial handshake packet, we don't know how to talk to them + LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, initial packet %u)", + m_Client->GetIPString().c_str(), PacketType + ); + m_Client->Kick("Unsupported protocol version"); + return false; + } + UInt32 ProtocolVersion; + if (!m_Buffer.ReadVarInt(ProtocolVersion)) + { + return false; + } + NumBytesRead -= m_Buffer.GetReadableSpace(); + switch (ProtocolVersion) + { + case PROTO_VERSION_1_7_2: + { + AString ServerAddress; + short ServerPort; + UInt32 NextState; + m_Buffer.ReadVarUTF8String(ServerAddress); + m_Buffer.ReadBEShort(ServerPort); + m_Buffer.ReadVarInt(NextState); + m_Buffer.CommitRead(); + m_Protocol = new cProtocol172(m_Client, ServerAddress, ServerPort, NextState); + return true; + } + } + LOGINFO("Client \"%s\" uses an unsupported protocol (lengthed, version %u)", + m_Client->GetIPString().c_str(), ProtocolVersion + ); + m_Client->Kick("Unsupported protocol version"); + return false; +} + + + + + +void cProtocolRecognizer::SendLengthlessServerPing(void) { AString Reply; - switch (cRoot::Get()->m_PrimaryServerVersion) + switch (cRoot::Get()->GetPrimaryServerVersion()) { case PROTO_VERSION_1_2_5: case PROTO_VERSION_1_3_2: @@ -757,10 +861,12 @@ void cProtocolRecognizer::HandleServerPing(void) // http://wiki.vg/wiki/index.php?title=Protocol&oldid=3101#Server_List_Ping_.280xFE.29 // _X 2012_10_31: I know that this needn't eat the byte, since it still may be in transit. // Who cares? We're disconnecting anyway. - if (m_Buffer.CanReadBytes(1)) + m_Buffer.ResetRead(); + if (m_Buffer.CanReadBytes(2)) { byte val; - m_Buffer.ReadByte(val); + m_Buffer.ReadByte(val); // Packet type - Serverlist ping + m_Buffer.ReadByte(val); // 0x01 magic value ASSERT(val == 0x01); } @@ -771,8 +877,8 @@ void cProtocolRecognizer::HandleServerPing(void) Printf(MaxPlayers, "%d", cRoot::Get()->GetServer()->GetMaxPlayers()); AString ProtocolVersionNum; - Printf(ProtocolVersionNum, "%d", cRoot::Get()->m_PrimaryServerVersion); - AString ProtocolVersionTxt(GetVersionTextFromInt(cRoot::Get()->m_PrimaryServerVersion)); + Printf(ProtocolVersionNum, "%d", cRoot::Get()->GetPrimaryServerVersion()); + AString ProtocolVersionTxt(GetVersionTextFromInt(cRoot::Get()->GetPrimaryServerVersion())); // Cannot use Printf() because of in-string NUL bytes. Reply = cChatColor::Delimiter; diff --git a/source/Protocol/ProtocolRecognizer.h b/source/Protocol/ProtocolRecognizer.h index c53288230..4c473a269 100644 --- a/source/Protocol/ProtocolRecognizer.h +++ b/source/Protocol/ProtocolRecognizer.h @@ -47,6 +47,9 @@ public: PROTO_VERSION_NEXT, PROTO_VERSION_LATEST = PROTO_VERSION_NEXT - 1, ///< Automatically assigned to the last protocol version, this serves as the default for PrimaryServerVersion + + // These will be kept "under" the next / latest, because the next and latest are only needed for previous protocols + PROTO_VERSION_1_7_2 = 4, } ; cProtocolRecognizer(cClientHandle * a_Client); @@ -124,8 +127,23 @@ protected: /// Tries to recognize protocol based on m_Buffer contents; returns true if recognized bool TryRecognizeProtocol(void); - /// Called when the recognizer gets a server ping packet; responds with server stats and destroys the client - void HandleServerPing(void); + /** Tries to recognize a protocol in the length-less family, based on m_Buffer; returns true if recognized. + Handles protocols before release 1.7, that didn't include packet lengths, and started with a 0x02 handshake packet + Note that length-less server ping is handled directly in TryRecognizeProtocol(), this function is called only + when the 0x02 Handshake packet has been received + */ + bool TryRecognizeLengthlessProtocol(void); + + /** Tries to recognize a protocol in the leghted family (1.7+), based on m_Buffer; returns true if recognized. + The packet length and type have already been read, type is 0 + The number of bytes remaining in the packet is passed as a_PacketLengthRemaining + **/ + bool TryRecognizeLengthedProtocol(UInt32 a_PacketLengthRemaining); + + /** Called when the recognizer gets a length-less protocol's server ping packet + Responds with server stats and destroys the client. + */ + void SendLengthlessServerPing(void); } ; diff --git a/source/Root.cpp b/source/Root.cpp index 290a5269a..e992ff614 100644 --- a/source/Root.cpp +++ b/source/Root.cpp @@ -116,8 +116,8 @@ void cRoot::Start(void) m_Server = new cServer(); LOG("Reading server config..."); - cIniFile IniFile("settings.ini"); - if (!IniFile.ReadFile()) + cIniFile IniFile; + if (!IniFile.ReadFile("settings.ini")) { LOGWARNING("settings.ini inaccessible, all settings are reset to default values"); } @@ -138,9 +138,7 @@ void cRoot::Start(void) LOGERROR("Failure starting server, aborting..."); return; } - IniFile.WriteFile(); - LOG("Initialising WebAdmin..."); m_WebAdmin = new cWebAdmin(); m_WebAdmin->Init(); @@ -150,7 +148,7 @@ void cRoot::Start(void) m_FurnaceRecipe = new cFurnaceRecipe(); LOGD("Loading worlds..."); - LoadWorlds(); + LoadWorlds(IniFile); LOGD("Loading plugin manager..."); m_PluginManager = new cPluginManager(); @@ -161,8 +159,10 @@ void cRoot::Start(void) // This sets stuff in motion LOGD("Starting Authenticator..."); - m_Authenticator.Start(); + m_Authenticator.Start(IniFile); + IniFile.WriteFile("settings.ini"); + LOGD("Starting worlds..."); StartWorlds(); @@ -172,7 +172,6 @@ void cRoot::Start(void) LOGD("Finalising startup..."); m_Server->Start(); - LOG("Starting WebAdmin..."); m_WebAdmin->Start(); #if !defined(ANDROID_NDK) @@ -210,7 +209,6 @@ void cRoot::Start(void) LOGD("Freeing MonsterConfig..."); delete m_MonsterConfig; m_MonsterConfig = NULL; - LOGD("Stopping WebAdmin..."); delete m_WebAdmin; m_WebAdmin = NULL; LOGD("Unloading recipes..."); delete m_FurnaceRecipe; m_FurnaceRecipe = NULL; @@ -248,10 +246,8 @@ void cRoot::LoadGlobalSettings() -void cRoot::LoadWorlds(void) +void cRoot::LoadWorlds(cIniFile & IniFile) { - cIniFile IniFile("settings.ini"); IniFile.ReadFile(); - // First get the default world AString DefaultWorldName = IniFile.GetValueSet("Worlds", "DefaultWorld", "world"); m_pDefaultWorld = new cWorld( DefaultWorldName.c_str() ); diff --git a/source/Root.h b/source/Root.h index 2b15d3461..175084c53 100644 --- a/source/Root.h +++ b/source/Root.h @@ -32,10 +32,7 @@ typedef cItemCallback<cWorld> cWorldListCallback; class cRoot // tolua_export { // tolua_export public: - /// The version of the protocol that is primary for the server (reported in the server list). All versions are still supported. - int m_PrimaryServerVersion; // tolua_export - - static cRoot* Get() { return s_Root; } // tolua_export + static cRoot * Get() { return s_Root; } // tolua_export cRoot(void); ~cRoot(); @@ -55,7 +52,7 @@ public: int GetPrimaryServerVersion(void) const { return m_PrimaryServerVersion; } // tolua_export void SetPrimaryServerVersion(int a_Version) { m_PrimaryServerVersion = a_Version; } // tolua_export - cMonsterConfig * GetMonsterConfig() { return m_MonsterConfig; } + cMonsterConfig * GetMonsterConfig(void) { return m_MonsterConfig; } cGroupManager * GetGroupManager (void) { return m_GroupManager; } // tolua_export cCraftingRecipes * GetCraftingRecipes(void) { return m_CraftingRecipes; } // tolua_export @@ -135,6 +132,9 @@ private: typedef std::map<AString, cWorld *> WorldMap; typedef std::vector<cCommand> cCommandQueue; + /// The version of the protocol that is primary for the server (reported in the server list). All versions are still supported. + int m_PrimaryServerVersion; + cWorld * m_pDefaultWorld; WorldMap m_WorldsByName; @@ -162,7 +162,7 @@ private: void LoadGlobalSettings(); /// Loads the worlds from settings.ini, creates the worldmap - void LoadWorlds(void); + void LoadWorlds(cIniFile & IniFile); /// Starts each world's life void StartWorlds(void); diff --git a/source/UI/SlotArea.cpp b/source/UI/SlotArea.cpp index 0a37e82b0..82e87e126 100644 --- a/source/UI/SlotArea.cpp +++ b/source/UI/SlotArea.cpp @@ -559,7 +559,7 @@ cSlotAreaInventoryBase::cSlotAreaInventoryBase(int a_NumSlots, int a_SlotOffset, void cSlotAreaInventoryBase::Clicked(cPlayer & a_Player, int a_SlotNum, eClickAction a_ClickAction, const cItem & a_ClickedItem) { - if ((a_Player.GetGameMode() == eGameMode_Creative) && (m_ParentWindow.GetWindowType() == cWindow::Inventory)) + if (a_Player.IsGameModeCreative() && (m_ParentWindow.GetWindowType() == cWindow::wtInventory)) { // Creative inventory must treat a_ClickedItem as a DraggedItem instead, replacing the inventory slot with it SetSlot(a_SlotNum, a_Player, a_ClickedItem); @@ -793,7 +793,7 @@ void cSlotAreaTemporary::TossItems(cPlayer & a_Player, int a_Begin, int a_End) double vX = 0, vY = 0, vZ = 0; EulerToVector(-a_Player.GetRotation(), a_Player.GetPitch(), vZ, vX, vY); vY = -vY * 2 + 1.f; - a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 3, vY * 3, vZ * 3); + a_Player.GetWorld()->SpawnItemPickups(Drops, a_Player.GetPosX(), a_Player.GetPosY() + 1.6f, a_Player.GetPosZ(), vX * 3, vY * 3, vZ * 3, true); // 'true' because player created } diff --git a/source/UI/Window.cpp b/source/UI/Window.cpp index 2794abe22..1318cbca8 100644 --- a/source/UI/Window.cpp +++ b/source/UI/Window.cpp @@ -23,7 +23,7 @@ char cWindow::m_WindowIDCounter = 1; -cWindow::cWindow(cWindow::WindowType a_WindowType, const AString & a_WindowTitle) : +cWindow::cWindow(WindowType a_WindowType, const AString & a_WindowTitle) : m_WindowID((++m_WindowIDCounter) % 127), m_WindowType(a_WindowType), m_WindowTitle(a_WindowTitle), @@ -31,7 +31,7 @@ cWindow::cWindow(cWindow::WindowType a_WindowType, const AString & a_WindowTitle m_IsDestroyed(false), m_ShouldDistributeToHotbarFirst(true) { - if (a_WindowType == Inventory) + if (a_WindowType == wtInventory) { m_WindowID = 0; } @@ -277,7 +277,7 @@ bool cWindow::ClosedByPlayer(cPlayer & a_Player, bool a_CanRefuse) m_OpenedBy.remove(&a_Player); - if ((m_WindowType != Inventory) && m_OpenedBy.empty()) + if ((m_WindowType != wtInventory) && m_OpenedBy.empty()) { Destroy(); } @@ -703,7 +703,7 @@ void cWindow::SetProperty(int a_Property, int a_Value, cPlayer & a_Player) // cInventoryWindow: cInventoryWindow::cInventoryWindow(cPlayer & a_Player) : - cWindow(cWindow::Inventory, "Inventory"), + cWindow(wtInventory, "Inventory"), m_Player(a_Player) { m_SlotAreas.push_back(new cSlotAreaCrafting(2, *this)); // The creative inventory doesn't display it, but it's still counted into slot numbers @@ -720,7 +720,7 @@ cInventoryWindow::cInventoryWindow(cPlayer & a_Player) : // cCraftingWindow: cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : - cWindow(cWindow::Workbench, "Crafting Table") + cWindow(wtWorkbench, "Crafting Table") { m_SlotAreas.push_back(new cSlotAreaCrafting(3, *this)); m_SlotAreas.push_back(new cSlotAreaInventory(*this)); @@ -735,7 +735,7 @@ cCraftingWindow::cCraftingWindow(int a_BlockX, int a_BlockY, int a_BlockZ) : // cChestWindow: cChestWindow::cChestWindow(cChestEntity * a_Chest) : - cWindow(cWindow::Chest, "Chest"), + cWindow(wtChest, "Chest"), m_World(a_Chest->GetWorld()), m_BlockX(a_Chest->GetPosX()), m_BlockY(a_Chest->GetPosY()), @@ -757,7 +757,7 @@ cChestWindow::cChestWindow(cChestEntity * a_Chest) : cChestWindow::cChestWindow(cChestEntity * a_PrimaryChest, cChestEntity * a_SecondaryChest) : - cWindow(cWindow::Chest, "Double Chest"), + cWindow(wtChest, "Double Chest"), m_World(a_PrimaryChest->GetWorld()), m_BlockX(a_PrimaryChest->GetPosX()), m_BlockY(a_PrimaryChest->GetPosY()), @@ -796,7 +796,7 @@ cChestWindow::~cChestWindow() // cDropSpenserWindow: cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cDropSpenserEntity * a_DropSpenser) : - cWindow(cWindow::DropSpenser, "Dropspenser") + cWindow(wtDropSpenser, "Dropspenser") { m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaItemGrid(a_DropSpenser->GetContents(), *this)); @@ -812,7 +812,7 @@ cDropSpenserWindow::cDropSpenserWindow(int a_BlockX, int a_BlockY, int a_BlockZ, // cHopperWindow: cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEntity * a_Hopper) : - super(cWindow::Hopper, "Hopper") + super(wtHopper, "Hopper") { m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaItemGrid(a_Hopper->GetContents(), *this)); @@ -828,7 +828,7 @@ cHopperWindow::cHopperWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cHopperEn // cFurnaceWindow: cFurnaceWindow::cFurnaceWindow(int a_BlockX, int a_BlockY, int a_BlockZ, cFurnaceEntity * a_Furnace) : - cWindow(cWindow::Furnace, "Furnace") + cWindow(wtFurnace, "Furnace") { m_ShouldDistributeToHotbarFirst = false; m_SlotAreas.push_back(new cSlotAreaFurnace(a_Furnace, *this)); diff --git a/source/UI/Window.h b/source/UI/Window.h index aa7e9d0d0..2d5e81e9e 100644 --- a/source/UI/Window.h +++ b/source/UI/Window.h @@ -49,17 +49,17 @@ class cWindow public: enum WindowType { - Inventory = -1, // This value is never actually sent to a client - Chest = 0, - Workbench = 1, - Furnace = 2, - DropSpenser = 3, // Dropper or Dispenser - Enchantment = 4, - Brewery = 5, - NPCTrade = 6, - Beacon = 7, - Anvil = 8, - Hopper = 9, + wtInventory = -1, // This value is never actually sent to a client + wtChest = 0, + wtWorkbench = 1, + wtFurnace = 2, + wtDropSpenser = 3, // Dropper or Dispenser + wtEnchantment = 4, + wtBrewery = 5, + wtNPCTrade = 6, + wtBeacon = 7, + wtAnvil = 8, + wtHopper = 9, }; // tolua_end diff --git a/source/WebAdmin.cpp b/source/WebAdmin.cpp index 316513f11..8c95e4e21 100644 --- a/source/WebAdmin.cpp +++ b/source/WebAdmin.cpp @@ -32,7 +32,7 @@ class cPlayerAccum : m_Contents.append("</li>"); return false; } - + public: AString m_Contents; @@ -44,9 +44,20 @@ public: cWebAdmin::cWebAdmin(void) : m_IsInitialized(false), - m_TemplateScript("<webadmin_template>"), - m_IniFile("webadmin.ini") + m_TemplateScript("<webadmin_template>") +{ +} + + + + + +cWebAdmin::~cWebAdmin() { + if (m_IsInitialized) + { + LOG("Stopping WebAdmin..."); + } } @@ -74,20 +85,22 @@ void cWebAdmin::RemovePlugin( cWebPlugin * a_Plugin ) bool cWebAdmin::Init(void) { - if (!m_IniFile.ReadFile()) + if (!m_IniFile.ReadFile("webadmin.ini")) { return false; } - + if (!m_IniFile.GetValueSetB("WebAdmin", "Enabled", true)) { // WebAdmin is disabled, bail out faking a success return true; } - + + LOG("Initialising WebAdmin..."); + AString PortsIPv4 = m_IniFile.GetValueSet("WebAdmin", "Port", "8080"); AString PortsIPv6 = m_IniFile.GetValueSet("WebAdmin", "PortsIPv6", ""); - + if (!m_HTTPServer.Initialize(PortsIPv4, PortsIPv6)) { return false; @@ -107,7 +120,9 @@ bool cWebAdmin::Start(void) // Not initialized return false; } - + + LOG("Starting WebAdmin..."); + // Initialize the WebAdmin template script and load the file m_TemplateScript.Create(); if (!m_TemplateScript.LoadFile(FILE_IO_PREFIX "webadmin/template.lua")) @@ -160,12 +175,12 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque a_Connection.SendNeedAuth("MCServer WebAdmin - bad username or password"); return; } - + // Check if the contents should be wrapped in the template: AString URL = a_Request.GetBareURL(); ASSERT(URL.length() > 0); bool ShouldWrapInTemplate = ((URL.length() > 1) && (URL[1] != '~')); - + // Retrieve the request data: cWebadminRequestData * Data = (cWebadminRequestData *)(a_Request.GetUserData()); if (Data == NULL) @@ -173,14 +188,14 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque a_Connection.SendStatusAndReason(500, "Bad UserData"); return; } - + // Wrap it all up for the Lua call: AString Template; HTTPTemplateRequest TemplateRequest; TemplateRequest.Request.Username = a_Request.GetAuthUsername(); TemplateRequest.Request.Method = a_Request.GetMethod(); TemplateRequest.Request.Path = URL.substr(1); - + if (Data->m_Form.Finish()) { for (cHTTPFormParser::const_iterator itr = Data->m_Form.begin(), end = Data->m_Form.end(); itr != end; ++itr) @@ -192,7 +207,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque TemplateRequest.Request.FormData[itr->first] = HTTPfd; TemplateRequest.Request.PostParams[itr->first] = itr->second; } // for itr - Data->m_Form[] - + // Parse the URL into individual params: size_t idxQM = a_Request.GetURL().find('?'); if (idxQM != AString::npos) @@ -205,7 +220,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque } // for itr - URLParams[] } } - + // Try to get the template from the Lua template script if (ShouldWrapInTemplate) { @@ -220,7 +235,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque a_Connection.SendStatusAndReason(500, "m_TemplateScript failed"); return; } - + AString BaseURL = GetBaseURL(URL); AString Menu; Template = "{CONTENT}"; @@ -254,7 +269,7 @@ void cWebAdmin::HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPReque Content += "\n<p><a href='" + BaseURL + "'>Go back</a></p>"; } - int MemUsageKiB = GetMemoryUsage(); + int MemUsageKiB = cRoot::GetPhysicalRAMUsage(); if (MemUsageKiB > 0) { ReplaceString(Template, "{MEM}", Printf("%.02f", (double)MemUsageKiB / 1024)); @@ -381,7 +396,38 @@ AString cWebAdmin::GetBaseURL( const AString& a_URL ) -AString cWebAdmin::GetBaseURL( const AStringVector& a_URLSplit ) +AString cWebAdmin::GetHTMLEscapedString(const AString & a_Input) +{ + AString dst; + dst.reserve(a_Input.length()); + + // Loop over input and substitute HTML characters for their alternatives: + size_t len = a_Input.length(); + for (size_t i = 0; i < len; i++) + { + switch (a_Input[i]) + { + case '&': dst.append("&"); break; + case '\'': dst.append("'"); break; + case '"': dst.append("""); break; + case '<': dst.append("<"); break; + case '>': dst.append(">"); break; + default: + { + dst.push_back(a_Input[i]); + break; + } + } // switch (a_Input[i]) + } // for i - a_Input[] + + return dst; +} + + + + + +AString cWebAdmin::GetBaseURL(const AStringVector & a_URLSplit) { AString BaseURL = "./"; if (a_URLSplit.size() > 1) @@ -399,16 +445,6 @@ AString cWebAdmin::GetBaseURL( const AStringVector& a_URLSplit ) -int cWebAdmin::GetMemoryUsage(void) -{ - LOGWARNING("%s: This function is obsolete, use cRoot::GetPhysicalRAMUsage() or cRoot::GetVirtualRAMUsage() instead", __FUNCTION__); - return cRoot::GetPhysicalRAMUsage(); -} - - - - - void cWebAdmin::OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) { const AString & URL = a_Request.GetURL(); @@ -465,7 +501,7 @@ void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & { // TODO: Handle other requests } - + // Delete any request data assigned to the request: cRequestData * Data = (cRequestData *)(a_Request.GetUserData()); delete Data; diff --git a/source/WebAdmin.h b/source/WebAdmin.h index 72c77ddfb..acd81ebfa 100644 --- a/source/WebAdmin.h +++ b/source/WebAdmin.h @@ -51,18 +51,18 @@ struct HTTPRequest { typedef std::map< std::string, std::string > StringStringMap; typedef std::map< std::string, HTTPFormData > FormDataMap; - + AString Method; AString Path; AString Username; // tolua_end - + /// Parameters given in the URL, after the questionmark StringStringMap Params; // >> EXPORTED IN MANUALBINDINGS << - + /// Parameters posted as a part of a form - either in the URL (GET method) or in the body (POST method) StringStringMap PostParams; // >> EXPORTED IN MANUALBINDINGS << - + /// Same as PostParams FormDataMap FormData; // >> EXPORTED IN MANUALBINDINGS << } ; // tolua_export @@ -101,15 +101,16 @@ class cWebAdmin : { public: // tolua_end - + typedef std::list< cWebPlugin* > PluginList; cWebAdmin(void); + ~cWebAdmin(); /// Initializes the object. Returns true if successfully initialized and ready to start bool Init(void); - + /// Starts the HTTP server taking care of the admin. Returns true if successful bool Start(void); @@ -117,35 +118,37 @@ public: void RemovePlugin( cWebPlugin* a_Plugin ); // TODO: Convert this to the auto-locking callback mechanism used for looping players in worlds and such - PluginList GetPlugins() const { return m_Plugins; } // >> EXPORTED IN MANUALBINDINGS << + PluginList GetPlugins() const { return m_Plugins; } // >> EXPORTED IN MANUALBINDINGS << // tolua_begin - - /// Returns the amount of currently used memory, in KiB, or -1 if it cannot be queried - static int GetMemoryUsage(void); - sWebAdminPage GetPage(const HTTPRequest& a_Request); - + sWebAdminPage GetPage(const HTTPRequest & a_Request); + /// Returns the contents of the default page - the list of plugins and players AString GetDefaultPage(void); - - AString GetBaseURL(const AString& a_URL); - + + /// Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) + AString GetBaseURL(const AString & a_URL); + + /// Escapes text passed into it, so it can be embedded into html. + static AString GetHTMLEscapedString(const AString & a_Input); + // tolua_end - AString GetBaseURL(const AStringVector& a_URLSplit); - + /// Returns the prefix needed for making a link point to the webadmin root from the given URL ("../../../webadmin"-style) + AString GetBaseURL(const AStringVector& a_URLSplit); + protected: /// Common base class for request body data handlers class cRequestData { public: virtual ~cRequestData() {} // Force a virtual destructor in all descendants - + /// Called when a new chunk of body data is received virtual void OnBody(const char * a_Data, int a_Size) = 0; } ; - + /// The body handler for requests in the "/webadmin" and "/~webadmin" paths class cWebadminRequestData : public cRequestData, @@ -153,13 +156,13 @@ protected: { public: cHTTPFormParser m_Form; - - + + cWebadminRequestData(cHTTPRequest & a_Request) : m_Form(a_Request, *this) { } - + // cRequestData overrides: virtual void OnBody(const char * a_Data, int a_Size) override; @@ -168,31 +171,31 @@ protected: virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) override {} virtual void OnFileEnd(cHTTPFormParser & a_Parser) override {} } ; - - + + /// Set to true if Init() succeeds and the webadmin isn't to be disabled bool m_IsInitialized; /// The webadmin.ini file, used for the settings and allowed logins cIniFile m_IniFile; - + PluginList m_Plugins; /// The Lua template script to provide templates: cLuaState m_TemplateScript; - + /// The HTTP server which provides the underlying HTTP parsing, serialization and events cHTTPServer m_HTTPServer; AString GetTemplate(void); - + /// Handles requests coming to the "/webadmin" or "/~webadmin" URLs void HandleWebadminRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request); - + /// Handles requests for the root page void HandleRootRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request); - + // cHTTPServer::cCallbacks overrides: virtual void OnRequestBegun (cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override; virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override; diff --git a/source/World.cpp b/source/World.cpp index ef56e7fe9..dd3965e3d 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -28,35 +28,9 @@ #include "Simulator/VaporizeFluidSimulator.h" // Mobs: -#include "Mobs/Bat.h" -#include "Mobs/Blaze.h" -#include "Mobs/Cavespider.h" -#include "Mobs/Chicken.h" -#include "Mobs/Cow.h" -#include "Mobs/Creeper.h" -#include "Mobs/Enderman.h" -#include "Mobs/EnderDragon.h" -#include "Mobs/Ghast.h" -#include "Mobs/Giant.h" -#include "Mobs/Horse.h" -#include "Mobs/IronGolem.h" -#include "Mobs/Magmacube.h" -#include "Mobs/Mooshroom.h" -#include "Mobs/Ocelot.h" -#include "Mobs/Pig.h" -#include "Mobs/Sheep.h" -#include "Mobs/Silverfish.h" -#include "Mobs/Skeleton.h" -#include "Mobs/Slime.h" -#include "Mobs/SnowGolem.h" -#include "Mobs/Spider.h" -#include "Mobs/Squid.h" -#include "Mobs/Villager.h" -#include "Mobs/Witch.h" -#include "Mobs/Wither.h" -#include "Mobs/Wolf.h" -#include "Mobs/Zombie.h" -#include "Mobs/Zombiepigman.h" +#include "Mobs/IncludeAllMonsters.h" +#include "MobCensus.h" +#include "MobSpawner.h" #include "MersenneTwister.h" #include "Generating/Trees.h" @@ -81,6 +55,12 @@ /// Up to this many m_SpreadQueue elements are handled each world tick const int MAX_LIGHTING_SPREAD_PER_TICK = 10; +const int TIME_SUNSET = 12000; +const int TIME_NIGHT_START = 13187; +const int TIME_NIGHT_END = 22812; +const int TIME_SUNRISE = 23999; +const int TIME_SPAWN_DIVISOR = 148; + @@ -252,11 +232,11 @@ cWorld::cWorld(const AString & a_WorldName) : m_WorldAge(0), m_TimeOfDay(0), m_LastTimeUpdate(0), - m_LastSpawnMonster(0), m_RSList(0), m_Weather(eWeather_Sunny), m_WeatherInterval(24000), // Guaranteed 1 day of sunshine at server start :) - m_TickThread(*this) + m_TickThread(*this), + m_SkyDarkness(0) { LOGD("cWorld::cWorld(\"%s\")", a_WorldName.c_str()); @@ -471,8 +451,8 @@ void cWorld::Start(void) m_SpawnZ = (double)((m_TickRand.randInt() % 1000) - 500); m_GameMode = eGameMode_Creative; - cIniFile IniFile(m_IniFileName); - if (!IniFile.ReadFile()) + cIniFile IniFile; + if (!IniFile.ReadFile(m_IniFileName)) { LOGWARNING("Cannot read world settings from \"%s\", defaults will be used.", m_IniFileName.c_str()); } @@ -515,14 +495,35 @@ void cWorld::Start(void) m_GameMode = (eGameMode)IniFile.GetValueSetI("GameMode", "GameMode", m_GameMode); - m_bAnimals = true; - m_SpawnMonsterRate = 200; // 1 mob each 10 seconds - cIniFile IniFile2("settings.ini"); - if (IniFile2.ReadFile()) + // Load allowed mobs: + const char * DefaultMonsters = ""; + switch (m_Dimension) { - m_bAnimals = IniFile2.GetValueB("Monsters", "AnimalsOn", true); - m_SpawnMonsterRate = (Int64)(IniFile2.GetValueF("Monsters", "AnimalSpawnInterval", 10) * 20); // Convert from secs to ticks - + case dimOverworld: DefaultMonsters = "bat, cavespider, chicken, cow, creeper, enderman, horse, mooshroom, ocelot, pig, sheep, silverfish, skeleton, slime, spider, squid, wolf, zombie"; break; + case dimNether: DefaultMonsters = "blaze, ghast, magmacube, skeleton, zombie, zombiepigman"; break; + case dimEnd: DefaultMonsters = "enderman"; break; + default: + { + ASSERT(!"Unhandled world dimension"); + DefaultMonsters = "wither"; + break; + } + } + m_bAnimals = IniFile.GetValueB("Monsters", "AnimalsOn", true); + AString AllMonsters = IniFile.GetValueSet("Monsters", "Types", DefaultMonsters); + AStringVector SplitList = StringSplitAndTrim(AllMonsters, ","); + for (AStringVector::const_iterator itr = SplitList.begin(), end = SplitList.end(); itr != end; ++itr) + { + cMonster::eType ToAdd = cMonster::StringToMobType(*itr); + if (ToAdd != cMonster::mtInvalidType) + { + m_AllowedMobs.insert(ToAdd); + LOGD("Allowed mob: %s", itr->c_str()); + } + else + { + LOG("World \"%s\": Unknown mob type: %s", m_WorldName.c_str(), itr->c_str()); + } } m_ChunkMap = new cChunkMap(this); @@ -553,8 +554,15 @@ void cWorld::Start(void) m_ChunkSender.Start(this); m_TickThread.Start(); + // Init of the spawn monster time (as they are supposed to have different spawn rate) + m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfHostile, 0)); + m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfPassive, 0)); + m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfAmbient, 0)); + m_LastSpawnMonster.insert(std::map<cMonster::eFamily, Int64>::value_type(cMonster::mfWater, 0)); + + // Save any changes that the defaults may have done to the ini file: - if (!IniFile.WriteFile()) + if (!IniFile.WriteFile(m_IniFileName)) { LOGWARNING("Could not write world config to %s", m_IniFileName.c_str()); } @@ -607,6 +615,9 @@ void cWorld::Tick(float a_Dt) m_WorldAge = (Int64)(m_WorldAgeSecs * 20.0); m_TimeOfDay = (Int64)(m_TimeOfDaySecs * 20.0); + // Updates the sky darkness based on current time of day + UpdateSkyDarkness(); + // Broadcast time update every 40 ticks (2 seconds) if (m_LastTimeUpdate < m_WorldAge - 40) { @@ -648,7 +659,7 @@ void cWorld::Tick(float a_Dt) UnloadUnusedChunks(); } - TickSpawnMobs(a_Dt); + TickMobs(a_Dt); std::vector<int> m_RSList_copy(m_RSList); @@ -733,125 +744,61 @@ void cWorld::TickWeather(float a_Dt) -void cWorld::TickSpawnMobs(float a_Dt) +void cWorld::TickMobs(float a_Dt) { - if (!m_bAnimals || (m_WorldAge - m_LastSpawnMonster <= m_SpawnMonsterRate)) - { - return; - } - - m_LastSpawnMonster = m_WorldAge; - Vector3d SpawnPos; - { - cCSLock Lock(m_CSPlayers); - if (m_Players.size() <= 0) - { - return; - } - int RandomPlayerIdx = m_TickRand.randInt() & m_Players.size(); - cPlayerList::iterator itr = m_Players.begin(); - for (int i = 1; i < RandomPlayerIdx; i++) - { - itr++; - } - SpawnPos = (*itr)->GetPosition(); - } + // _X 2013_10_22: This is a quick fix for #283 - the world needs to be locked while ticking mobs + cWorld::cLock Lock(*this); - int dayRand = (m_TickRand.randInt() / 7) % 6; - int nightRand = (m_TickRand.randInt() / 11) % 10; - - SpawnPos += Vector3d((double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32, (double)(m_TickRand.randInt() % 64) - 32); - int Height = GetHeight((int)SpawnPos.x, (int)SpawnPos.z); - - int MobType = -1; - int Biome = GetBiomeAt((int)SpawnPos.x, (int)SpawnPos.z); - switch (Biome) + // before every Mob action, we have to count them depending on the distance to players, on their family ... + cMobCensus MobCensus; + m_ChunkMap->CollectMobCensus(MobCensus); + if (m_bAnimals) { - case biNether: + // Spawning is enabled, spawn now: + static const cMonster::eFamily AllFamilies[] = { - // Spawn nether mobs - switch (nightRand) - { - case 0: MobType = cMonster::mtBlaze; break; - case 1: MobType = cMonster::mtGhast; break; - case 2: MobType = cMonster::mtGhast; break; - case 3: MobType = cMonster::mtGhast; break; - case 4: MobType = cMonster::mtZombiePigman; break; - case 5: MobType = cMonster::mtZombiePigman; break; - case 6: MobType = cMonster::mtZombiePigman; break; - case 7: MobType = cMonster::mtZombiePigman; break; - case 8: MobType = cMonster::mtZombiePigman; break; - case 9: MobType = cMonster::mtZombiePigman; break; - } - break; - } - - case biEnd: + cMonster::mfHostile, + cMonster::mfPassive, + cMonster::mfAmbient, + cMonster::mfWater, + } ; + for (int i = 0; i < ARRAYCOUNT(AllFamilies); i++) { - // Spawn only The End mobs - switch (nightRand) + cMonster::eFamily Family = AllFamilies[i]; + int SpawnDelay = cMonster::GetSpawnDelay(Family); + if ( + (m_LastSpawnMonster[Family] > m_WorldAge - SpawnDelay) || // Not reached the needed ticks before the next round + MobCensus.IsCapped(Family) + ) { - case 0: MobType = cMonster::mtEnderDragon; break; - case 1: MobType = cMonster::mtEnderman; break; - case 2: MobType = cMonster::mtEnderman; break; - case 3: MobType = cMonster::mtEnderman; break; - case 4: MobType = cMonster::mtEnderman; break; - case 5: MobType = cMonster::mtEnderman; break; - case 6: MobType = cMonster::mtEnderman; break; - case 7: MobType = cMonster::mtEnderman; break; - case 8: MobType = cMonster::mtEnderman; break; - case 9: MobType = cMonster::mtEnderman; break; + continue; } - break; - } - - case biMushroomIsland: - case biMushroomShore: - { - // Mushroom land gets only mooshrooms - MobType = cMonster::mtMooshroom; - break; - } - - default: - { - // Overworld biomes depend on whether it's night or day: - if (m_TimeOfDay >= 12000 + 1000) - { - // Night mobs: - switch (nightRand) - { - case 0: MobType = cMonster::mtSpider; break; - case 1: MobType = cMonster::mtZombie; break; - case 2: MobType = cMonster::mtEnderman; break; - case 3: MobType = cMonster::mtCreeper; break; - case 4: MobType = cMonster::mtCaveSpider; break; - case 7: MobType = cMonster::mtSlime; break; - case 8: MobType = cMonster::mtSilverfish; break; - case 9: MobType = cMonster::mtSkeleton; break; - } - } // if (night) - else + m_LastSpawnMonster[Family] = m_WorldAge; + cMobSpawner Spawner(Family, m_AllowedMobs); + if (Spawner.CanSpawnAnything()) { - // During the day: - switch (dayRand) + m_ChunkMap->SpawnMobs(Spawner); + // do the spawn + for (cMobSpawner::tSpawnedContainer::const_iterator itr2 = Spawner.getSpawned().begin(); itr2 != Spawner.getSpawned().end(); itr2++) { - case 0: MobType = cMonster::mtChicken; break; - case 1: MobType = cMonster::mtCow; break; - case 2: MobType = cMonster::mtPig; break; - case 3: MobType = cMonster::mtSheep; break; - case 4: MobType = cMonster::mtSquid; break; - case 5: MobType = cMonster::mtWolf; break; - case 6: MobType = cMonster::mtHorse; break; + SpawnMobFinalize(*itr2); } - } // else (night) - } // case overworld biomes - } // switch (biome) + } + } // for i - AllFamilies[] + } // if (Spawning enabled) - if (MobType >= 0) + // move close mobs + cMobProximityCounter::sIterablePair allCloseEnoughToMoveMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(-1, 64 * 16);// MG TODO : deal with this magic number (the 16 is the size of a block) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allCloseEnoughToMoveMobs.m_Begin; itr != allCloseEnoughToMoveMobs.m_End; itr++) { - // A proper mob type was selected, now spawn the mob: - SpawnMob(SpawnPos.x, SpawnPos.y, SpawnPos.z, (cMonster::eType)MobType); + itr->second.m_Monster.Tick(a_Dt, itr->second.m_Chunk); + } + + // remove too far mobs + cMobProximityCounter::sIterablePair allTooFarMobs = MobCensus.GetProximityCounter().getMobWithinThosesDistances(128 * 16, -1);// MG TODO : deal with this magic number (the 16 is the size of a block) + for(cMobProximityCounter::tDistanceToMonster::const_iterator itr = allTooFarMobs.m_Begin; itr != allTooFarMobs.m_End; itr++) + { + itr->second.m_Monster.Destroy(true); } } @@ -931,6 +878,31 @@ void cWorld::TickClients(float a_Dt) +void cWorld::UpdateSkyDarkness(void) +{ + int TempTime = (int)m_TimeOfDay; + if (TempTime <= TIME_SUNSET) + { + m_SkyDarkness = 0; + } + else if (TempTime <= TIME_NIGHT_START) + { + m_SkyDarkness = (TIME_NIGHT_START - TempTime) / TIME_SPAWN_DIVISOR; + } + else if (TempTime <= TIME_NIGHT_END) + { + m_SkyDarkness = 8; + } + else + { + m_SkyDarkness = (TIME_SUNRISE - TempTime) / TIME_SPAWN_DIVISOR; + } +} + + + + + void cWorld::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) { return m_ChunkMap->WakeUpSimulators(a_BlockX, a_BlockY, a_BlockZ); @@ -1533,7 +1505,7 @@ bool cWorld::WriteBlockArea(cBlockArea & a_Area, int a_MinBlockX, int a_MinBlock -void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed) +void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed, bool IsPlayerCreated) { MTRand r1; a_FlyAwaySpeed /= 1000; // Pre-divide, so that we don't have to divide each time inside the loop @@ -1545,7 +1517,7 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double cPickup * Pickup = new cPickup( a_BlockX, a_BlockY, a_BlockZ, - *itr, SpeedX, SpeedY, SpeedZ + *itr, IsPlayerCreated, SpeedX, SpeedY, SpeedZ ); Pickup->Initialize(this); } @@ -1555,13 +1527,13 @@ void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double -void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ) +void cWorld::SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated) { for (cItems::const_iterator itr = a_Pickups.begin(); itr != a_Pickups.end(); ++itr) { cPickup * Pickup = new cPickup( a_BlockX, a_BlockY, a_BlockZ, - *itr, (float)a_SpeedX, (float)a_SpeedY, (float)a_SpeedZ + *itr, IsPlayerCreated, (float)a_SpeedX, (float)a_SpeedY, (float)a_SpeedZ ); Pickup->Initialize(this); } @@ -2592,82 +2564,39 @@ int cWorld::SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eTyp { cMonster * Monster = NULL; - int SlSize = GetTickRandomNumber(2) + 1; // 1 .. 3 - Slime int ShColor = GetTickRandomNumber(15); // 0 .. 15 - Sheep - bool SkType = GetDimension() == biNether; // Skeleton - - int VilType = GetTickRandomNumber(cVillager::vtMax); // 0 .. 6 - Villager - if (VilType == 6) { VilType = 0; } // Give farmers a better chance of spawning + bool SkType = GetDimension() == dimNether ; // Skeleton - int HseType = GetTickRandomNumber(7); // 0 .. 7 - Horse Type (donkey, zombie, etc.) - int HseColor = GetTickRandomNumber(6); // 0 .. 6 - Horse - int HseStyle = GetTickRandomNumber(4); // 0 .. 4 - Horse - int HseTameTimes = GetTickRandomNumber(6) + 1; // 1 .. 7 - Horse tame amount - if ((HseType == 5) || (HseType == 6) || (HseType == 7)) { HseType = 0; } // 5,6,7 = 0 because little chance of getting 0 with TickRand - - switch (a_MonsterType) - { - case cMonster::mtBat: Monster = new cBat(); break; - case cMonster::mtBlaze: Monster = new cBlaze(); break; - case cMonster::mtCaveSpider: Monster = new cCavespider(); break; - case cMonster::mtChicken: Monster = new cChicken(); break; - case cMonster::mtCow: Monster = new cCow(); break; - case cMonster::mtCreeper: Monster = new cCreeper(); break; - case cMonster::mtEnderman: Monster = new cEnderman(); break; - case cMonster::mtEnderDragon: Monster = new cEnderDragon(); break; - case cMonster::mtGhast: Monster = new cGhast(); break; - case cMonster::mtGiant: Monster = new cGiant(); break; - case cMonster::mtHorse: - { - Monster = new cHorse(HseType, HseColor, HseStyle, HseTameTimes); break; - } - case cMonster::mtIronGolem: Monster = new cIronGolem(); break; - case cMonster::mtMagmaCube: Monster = new cMagmaCube(SlSize); break; - case cMonster::mtMooshroom: Monster = new cMooshroom(); break; - case cMonster::mtOcelot: Monster = new cOcelot(); break; - case cMonster::mtPig: Monster = new cPig(); break; - case cMonster::mtSheep: Monster = new cSheep(ShColor); break; - case cMonster::mtSilverfish: Monster = new cSilverfish(); break; - case cMonster::mtSkeleton: Monster = new cSkeleton(SkType); break; - case cMonster::mtSlime: Monster = new cSlime(SlSize); break; - case cMonster::mtSnowGolem: Monster = new cSnowGolem(); break; - case cMonster::mtSpider: Monster = new cSpider(); break; - case cMonster::mtSquid: Monster = new cSquid(); break; - case cMonster::mtVillager: - { - Monster = new cVillager((cVillager::eVillagerType)VilType); break; - } - case cMonster::mtWitch: Monster = new cWitch(); break; - case cMonster::mtWither: Monster = new cWither(); break; - case cMonster::mtWolf: Monster = new cWolf(); break; - case cMonster::mtZombie: Monster = new cZombie(false); break; // TODO: Villager infection - case cMonster::mtZombiePigman: Monster = new cZombiePigman(); break; - - default: - { - LOGWARNING("%s: Unhandled monster type: %d. Not spawning.", __FUNCTION__, a_MonsterType); - return -1; - } + Monster = cMonster::NewMonsterFromType(a_MonsterType); + if (Monster != NULL) + { + Monster->SetPosition(a_PosX, a_PosY, a_PosZ); } - Monster->SetPosition(a_PosX, a_PosY, a_PosZ); - Monster->SetHealth(Monster->GetMaxHealth()); - if (cPluginManager::Get()->CallHookSpawningMonster(*this, *Monster)) + return SpawnMobFinalize(Monster); +} + + + + +int cWorld::SpawnMobFinalize(cMonster * a_Monster) +{ + if (!a_Monster) + return -1; + a_Monster->SetHealth(a_Monster->GetMaxHealth()); + if (cPluginManager::Get()->CallHookSpawningMonster(*this, *a_Monster)) { - delete Monster; + delete a_Monster; return -1; } - if (!Monster->Initialize(this)) + if (!a_Monster->Initialize(this)) { - delete Monster; + delete a_Monster; return -1; } + BroadcastSpawnEntity(*a_Monster); + cPluginManager::Get()->CallHookSpawnedMonster(*this, *a_Monster); - BroadcastSpawnEntity(*Monster); - // Because it's logical that ALL mob spawns need spawn effects, not just spawners - BroadcastSoundParticleEffect(2004, (int)(floor(a_PosX) * 8), (int)(floor(a_PosY) * 8), (int)(floor(a_PosZ) * 8), 0); - - cPluginManager::Get()->CallHookSpawnedMonster(*this, *Monster); - return Monster->GetUniqueID(); + return a_Monster->GetUniqueID(); } @@ -2782,3 +2711,4 @@ void cWorld::cTaskSaveAllChunks::Run(cWorld & a_World) + diff --git a/source/World.h b/source/World.h index 25bc0b338..c4fd06d0b 100644 --- a/source/World.h +++ b/source/World.h @@ -42,6 +42,7 @@ class cChunkGenerator; // The thread responsible for generating chunks class cChestEntity;
class cDispenserEntity;
class cFurnaceEntity;
+class cMobCensus;
typedef std::list< cPlayer * > cPlayerList;
@@ -347,10 +348,10 @@ public: // tolua_begin
/// Spawns item pickups for each item in the list. May compress pickups if too many entities:
- void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0);
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_FlyAwaySpeed = 1.0, bool IsPlayerCreated = false);
/// Spawns item pickups for each item in the list. May compress pickups if too many entities. All pickups get the speed specified:
- void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ);
+ void SpawnItemPickups(const cItems & a_Pickups, double a_BlockX, double a_BlockY, double a_BlockZ, double a_SpeedX, double a_SpeedY, double a_SpeedZ, bool IsPlayerCreated = false);
/// Spawns a new primed TNT entity at the specified block coords and specified fuse duration. Initial velocity is given based on the relative coefficient provided
void SpawnPrimedTNT(double a_X, double a_Y, double a_Z, double a_FuseTimeInSec, double a_InitialVelocityCoeff = 1);
@@ -580,6 +581,7 @@ public: /// Spawns a mob of the specified type. Returns the mob's EntityID if recognized and spawned, <0 otherwise
int SpawnMob(double a_PosX, double a_PosY, double a_PosZ, cMonster::eType a_MonsterType); // tolua_export
+ int SpawnMobFinalize(cMonster* a_Monster);
/// Creates a projectile of the specified type. Returns the projectile's EntityID if successful, <0 otherwise
int CreateProjectile(double a_PosX, double a_PosY, double a_PosZ, cProjectileEntity::eKind a_Kind, cEntity * a_Creator, const Vector3d * a_Speed = NULL); // tolua_export
@@ -590,6 +592,9 @@ public: /// Appends all usernames starting with a_Text (case-insensitive) into Results
void TabCompleteUserName(const AString & a_Text, AStringVector & a_Results);
+ /// Get the current darkness level based on the time
+ NIBBLETYPE GetSkyDarkness() { return m_SkyDarkness; }
+
private:
friend class cRoot;
@@ -632,7 +637,9 @@ private: Int64 m_LastTimeUpdate; // The tick in which the last time update has been sent.
Int64 m_LastUnload; // The last WorldAge (in ticks) in which unloading was triggerred
Int64 m_LastSave; // The last WorldAge (in ticks) in which save-all was triggerred
- Int64 m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned
+ std::map<cMonster::eFamily,Int64> m_LastSpawnMonster; // The last WorldAge (in ticks) in which a monster was spawned (for each megatype of monster) // MG TODO : find a way to optimize without creating unmaintenability (if mob IDs are becoming unrowed)
+
+ NIBBLETYPE m_SkyDarkness;
eGameMode m_GameMode;
bool m_bEnabledPVP;
@@ -662,7 +669,7 @@ private: cChunkMap * m_ChunkMap;
bool m_bAnimals;
- Int64 m_SpawnMonsterRate;
+ std::set<cMonster::eType> m_AllowedMobs;
eWeather m_Weather;
int m_WeatherInterval;
@@ -717,14 +724,16 @@ private: /// Handles the weather in each tick
void TickWeather(float a_Dt);
- /// Handles the mob spawning each tick
- void TickSpawnMobs(float a_Dt);
+ /// Handles the mob spawning/moving/destroying each tick
+ void TickMobs(float a_Dt);
/// Executes all tasks queued onto the tick thread
void TickQueuedTasks(void);
/// Ticks all clients that are in this world
void TickClients(float a_Dt);
+
+ void UpdateSkyDarkness();
/// Creates a new fluid simulator, loads its settings from the inifile (a_FluidName section)
cFluidSimulator * InitializeFluidSimulator(cIniFile & a_IniFile, const char * a_FluidName, BLOCKTYPE a_SimulateBlock, BLOCKTYPE a_StationaryBlock);
diff --git a/source/WorldStorage/WSSAnvil.cpp b/source/WorldStorage/WSSAnvil.cpp index 537e2f723..b2e104a78 100644 --- a/source/WorldStorage/WSSAnvil.cpp +++ b/source/WorldStorage/WSSAnvil.cpp @@ -1123,7 +1123,7 @@ void cWSSAnvil::LoadPickupFromNBT(cEntityList & a_Entities, const cParsedNBT & a { return; } - std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item)); + std::auto_ptr<cPickup> Pickup(new cPickup(0, 0, 0, Item, false)); // Pickup delay doesn't matter, just say false if (!LoadEntityBaseFromNBT(*Pickup.get(), a_NBT, a_TagIdx)) { return; |