diff options
36 files changed, 3217 insertions, 1491 deletions
diff --git a/MCServer/.gitignore b/MCServer/.gitignore index 62225e137..ca10d90e8 100644 --- a/MCServer/.gitignore +++ b/MCServer/.gitignore @@ -1,11 +1,8 @@ *.exe -ChunkWorx.ini -ChunkWorxSave.ini +*.ini MCServer -banned.ini logs players -whitelist.ini world* API.txt *.dat @@ -15,9 +12,6 @@ schematics *.pdb memdump.xml *.grab -ProtectionAreas.ini ProtectionAreas.sqlite helgrind.log -settings.ini -webadmin.ini motd.txt diff --git a/MCServer/Plugins/Debuggers/Debuggers.lua b/MCServer/Plugins/Debuggers/Debuggers.lua index f26b9a98d..e864cfe92 100644 --- a/MCServer/Plugins/Debuggers/Debuggers.lua +++ b/MCServer/Plugins/Debuggers/Debuggers.lua @@ -23,17 +23,18 @@ function Initialize(Plugin) PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHAT); PluginManager:AddHook(Plugin, cPluginManager.HOOK_PLAYER_RIGHT_CLICKING_ENTITY); - PluginManager:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "Shows a list of all the loaded entities"); - PluginManager:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "Kills all the loaded entities"); - PluginManager:BindCommand("/wool", "debuggers", HandleWoolCmd, "Sets all your armor to blue wool"); - PluginManager:BindCommand("/testwnd", "debuggers", HandleTestWndCmd, "Opens up a window using plugin API"); - PluginManager:BindCommand("/gc", "debuggers", HandleGCCmd, "Activates the Lua garbage collector"); - PluginManager:BindCommand("/fast", "debuggers", HandleFastCmd, "Switches between fast and normal movement speed"); - PluginManager:BindCommand("/dash", "debuggers", HandleDashCmd, "Switches between fast and normal sprinting speed"); - PluginManager:BindCommand("/hunger", "debuggers", HandleHungerCmd, "Lists the current hunger-related variables"); - PluginManager:BindCommand("/poison", "debuggers", HandlePoisonCmd, "Sets food-poisoning for 15 seconds"); - PluginManager:BindCommand("/starve", "debuggers", HandleStarveCmd, "Sets the food level to zero"); - PluginManager:BindCommand("/fl", "debuggers", HandleFoodLevelCmd, "Sets the food level to the given value"); + PluginManager:BindCommand("/le", "debuggers", HandleListEntitiesCmd, "- Shows a list of all the loaded entities"); + PluginManager:BindCommand("/ke", "debuggers", HandleKillEntitiesCmd, "- Kills all the loaded entities"); + PluginManager:BindCommand("/wool", "debuggers", HandleWoolCmd, "- Sets all your armor to blue wool"); + PluginManager:BindCommand("/testwnd", "debuggers", HandleTestWndCmd, "- Opens up a window using plugin API"); + PluginManager:BindCommand("/gc", "debuggers", HandleGCCmd, "- Activates the Lua garbage collector"); + PluginManager:BindCommand("/fast", "debuggers", HandleFastCmd, "- Switches between fast and normal movement speed"); + PluginManager:BindCommand("/dash", "debuggers", HandleDashCmd, "- Switches between fast and normal sprinting speed"); + PluginManager:BindCommand("/hunger", "debuggers", HandleHungerCmd, "- Lists the current hunger-related variables"); + PluginManager:BindCommand("/poison", "debuggers", HandlePoisonCmd, "- Sets food-poisoning for 15 seconds"); + PluginManager:BindCommand("/starve", "debuggers", HandleStarveCmd, "- Sets the food level to zero"); + PluginManager:BindCommand("/fl", "debuggers", HandleFoodLevelCmd, "- Sets the food level to the given value"); + PluginManager:BindCommand("/spidey", "debuggers", HandleSpideyCmd, "- Shoots a line of web blocks until it hits non-air"); -- Enable the following line for BlockArea / Generator interface testing: -- PluginManager:AddHook(Plugin, cPluginManager.HOOK_CHUNK_GENERATED); @@ -707,3 +708,34 @@ end + +function HandleSpideyCmd(a_Split, a_Player) + -- Place a line of cobwebs from the player's eyes until non-air block, in the line-of-sight of the player + local World = a_Player:GetWorld(); + + local Callbacks = { + OnNextBlock = function(a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta) + if (a_BlockType ~= E_BLOCK_AIR) then + -- abort the trace + return true; + end + World:SetBlock(a_BlockX, a_BlockY, a_BlockZ, E_BLOCK_COBWEB, 0); + end + }; + + local EyePos = a_Player:GetEyePosition(); + local LookVector = a_Player:GetLookVector(); + LookVector:Normalize(); + + -- Start cca 2 blocks away from the eyes + local Start = EyePos + LookVector + LookVector; + local End = EyePos + LookVector * 50; + + cLineBlockTracer.Trace(World, Callbacks, Start.x, Start.y, Start.z, End.x, End.y, End.z); + + return true; +end + + + + diff --git a/MCServer/monsters.ini b/MCServer/monsters.ini index 80a0c7dde..8289e0a0a 100644 --- a/MCServer/monsters.ini +++ b/MCServer/monsters.ini @@ -1,9 +1,9 @@ [Spider] AttackRange=5.0 AttackRate=1 -AttackDamage=1.0 +AttackDamage=2.0 SightDistance=25.0 -MaxHealth=10 +MaxHealth=16 [Chicken] AttackRange=5.0 @@ -50,7 +50,7 @@ MaxHealth=40 [Zombiepigman] AttackRange=5.0 AttackRate=1 -AttackDamage=5.0 +AttackDamage=7.0 SightDistance=25.0 MaxHealth=20 @@ -85,27 +85,70 @@ MaxHealth=8 [Skeleton] AttackRange=5.0 AttackRate=1 -AttackDamage=4.0 +AttackDamage=3.0 SightDistance=25.0 MaxHealth=20 [Slime] AttackRange=5.0 AttackRate=1 -AttackDamage=10.0 +AttackDamage=4.0 SightDistance=25.0 -MaxHealth=32 +MaxHealth=16 -[Spider] +[Zombie] AttackRange=5.0 AttackRate=1 -AttackDamage=2.0 +AttackDamage=4.0 SightDistance=25.0 -MaxHealth=16 +MaxHealth=20 -[Zombie] +[Wolf] AttackRange=5.0 AttackRate=1 AttackDamage=4.0 SightDistance=25.0 -MaxHealth=20
\ No newline at end of file +MaxHealth=20 + +[Blaze] +AttackRange=5.0 +AttackRate=1 +AttackDamage=6.0 +SightDistance=25.0 +MaxHealth=20 + +[Villager] +AttackRange=5.0 +AttackRate=1 +AttackDamage=0.0 +SightDistance=25.0 +MaxHealth=20 + +[Witch] +AttackRange=5.0 +AttackRate=1 +AttackDamage=0.0 +SightDistance=25.0 +MaxHealth=26 + + +[Ocelot] +AttackRange=5.0 +AttackRate=1 +AttackDamage=0.0 +SightDistance=25.0 +MaxHealth=10 + +[Mooshroom] +AttackRange=5.0 +AttackRate=1 +AttackDamage=0.0 +SightDistance=25.0 +MaxHealth=10 + +[Magmacube] +AttackRange=5.0 +AttackRate=1 +AttackDamage=6.0 +SightDistance=25.0 +MaxHealth=16 diff --git a/MCServer/webadmin/template.lua b/MCServer/webadmin/template.lua index f508ad5aa..1ab1aab88 100644 --- a/MCServer/webadmin/template.lua +++ b/MCServer/webadmin/template.lua @@ -4,6 +4,10 @@ function Output(String) table.insert(SiteContent, String) end + + + + function GetTableSize(Table) local Size = 0 for key,value in pairs(Table) do @@ -12,6 +16,10 @@ function GetTableSize(Table) return Size end + + + + function GetDefaultPage() local PM = cRoot:Get():GetPluginManager() @@ -42,11 +50,15 @@ function GetDefaultPage() return Content, SubTitle end + + + + function ShowPage(WebAdmin, TemplateRequest) SiteContent = {} local BaseURL = WebAdmin:GetBaseURL(TemplateRequest.Request.Path) local Title = "MCServer" - local MemoryUsage = WebAdmin:GetMemoryUsage() + local MemoryUsage = cWebAdmin:GetMemoryUsage() local NumChunks = cRoot:Get():GetTotalChunkCount() local PluginPage = WebAdmin:GetPage(TemplateRequest.Request) local PageContent = PluginPage.Content @@ -408,6 +420,7 @@ function ShowPage(WebAdmin, TemplateRequest) <div id="sidebar"> <ul class="sideNav"> ]]) + local AllPlugins = WebAdmin:GetPlugins() for key,value in pairs(AllPlugins) do @@ -421,6 +434,7 @@ function ShowPage(WebAdmin, TemplateRequest) end end end + Output([[ </ul> diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 6fcd55388..591ee678a 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="UTF-8"?> +<?xml version="1.0" encoding="UTF-8"?> <VisualStudioProject ProjectType="Visual C++" Version="9,00" @@ -307,6 +307,10 @@ > </File> <File + RelativePath="..\source\BlockTracer.h" + > + </File> + <File RelativePath="..\source\ByteBuffer.cpp" > </File> @@ -546,6 +550,14 @@ > </File> <File + RelativePath="..\source\LineBlockTracer.cpp" + > + </File> + <File + RelativePath="..\source\LineBlockTracer.h" + > + </File> + <File RelativePath="..\source\Log.cpp" > </File> @@ -1486,6 +1498,14 @@ > </File> <File + RelativePath="..\source\LuaState.cpp" + > + </File> + <File + RelativePath="..\source\LuaState.h" + > + </File> + <File RelativePath="..\source\LuaWindow.cpp" > </File> @@ -1833,6 +1853,10 @@ > </File> <File + RelativePath="..\source\Blocks\BlockCarpet.h" + > + </File> + <File RelativePath="..\source\Blocks\BlockCauldron.h" > </File> diff --git a/iniFile/iniFile.cpp b/iniFile/iniFile.cpp index 76f71284f..5ecbc5e06 100644 --- a/iniFile/iniFile.cpp +++ b/iniFile/iniFile.cpp @@ -12,17 +12,13 @@ ////////////////////////////////////////////////////////////////////// /* - !! MODIFIED BY FAKETRUTH !! +!! MODIFIED BY FAKETRUTH and xoft !! */ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules // C++ Includes -#include <iostream> #include <fstream> -#include <sstream> - -using namespace std; // C Includes #include <ctype.h> @@ -31,26 +27,32 @@ using namespace std; #include "iniFile.h" #if defined(WIN32) -#define iniEOL endl + #define iniEOL endl #else -#define iniEOL '\r' << endl + #define iniEOL '\r' << endl #endif #ifndef _WIN32 -#define sscanf_s(buffer, stringbuffer, ...) (sscanf(buffer, stringbuffer, __VA_ARGS__)) + #define sscanf_s(buffer, stringbuffer, ...) (sscanf(buffer, stringbuffer, __VA_ARGS__)) #endif +using namespace std; + -cIniFile::cIniFile( const string iniPath) +cIniFile::cIniFile(const string & a_Path) : + m_IsCaseInsensitive(true) { - Path( iniPath); - caseInsensitive = true; + Path(a_Path); } -bool cIniFile::ReadFile() + + + + +bool cIniFile::ReadFile(bool a_AllowExampleRedirect) { // Normally you would use ifstream, but the SGI CC compiler has // a few bugs with ifstream. So ... fstream used. @@ -58,12 +60,31 @@ bool cIniFile::ReadFile() string line; string keyname, valuename, value; string::size_type pLeft, pRight; + bool IsFromExampleRedirect = false; + + f.open((FILE_IO_PREFIX + m_Path).c_str(), ios::in); + if (f.fail()) + { + f.clear(); + if (a_AllowExampleRedirect) + { + // Retry with the .example.ini file instead of .ini: + string ExPath(m_Path.substr(0, m_Path.length() - 4)); + ExPath.append(".example.ini"); + f.open((FILE_IO_PREFIX + ExPath).c_str(), ios::in); + if (f.fail()) + { + return false; + } + IsFromExampleRedirect = true; + } + else + { + return false; + } + } - f.open( (FILE_IO_PREFIX + path).c_str(), ios::in); - if ( f.fail()) - return false; - - while (getline( f, line)) + while (getline(f, line)) { // To be compatible with Win32, check for existence of '\r'. // Win32 files have the '\r' and Unix files don't at the end of a line. @@ -75,49 +96,49 @@ bool cIniFile::ReadFile() { continue; } - if ( line[lineLength - 1] == '\r') + if (line[lineLength - 1] == '\r') { - line = line.substr( 0, lineLength - 1); + line = line.substr(0, lineLength - 1); } if (line.length() == 0) { continue; } - + // Check that the user hasn't opened a binary file by checking the first // character of each line! - if ( !isprint( line[0])) + if (!isprint(line[0])) { - printf( "Failing on char %d\n", line[0]); + printf("%s: Binary-check failed on char %d\n", __FUNCTION__, line[0]); f.close(); return false; } - if (( pLeft = line.find_first_of(";#[=")) == string::npos) + if ((pLeft = line.find_first_of(";#[=")) == string::npos) { continue; } - - switch ( line[pLeft]) + + switch (line[pLeft]) { case '[': { if ( ((pRight = line.find_last_of("]")) != string::npos) && (pRight > pLeft) - ) + ) { - keyname = line.substr( pLeft + 1, pRight - pLeft - 1); - AddKeyName( keyname); + keyname = line.substr(pLeft + 1, pRight - pLeft - 1); + AddKeyName(keyname); } break; } case '=': { - valuename = line.substr( 0, pLeft); - value = line.substr( pLeft + 1); - SetValue( keyname, valuename, value); + valuename = line.substr(0, pLeft); + value = line.substr(pLeft + 1); + SetValue(keyname, valuename, value); break; } @@ -126,11 +147,11 @@ bool cIniFile::ReadFile() { if (names.size() == 0) { - HeaderComment( line.substr( pLeft + 1)); + HeaderComment(line.substr(pLeft + 1)); } else { - KeyComment( keyname, line.substr( pLeft + 1)); + KeyComment(keyname, line.substr(pLeft + 1)); } break; } @@ -138,256 +159,315 @@ bool cIniFile::ReadFile() } // while (getline()) f.close(); - if (names.size() > 0) + if (names.size() == 0) { - return true; + return false; } - return false; + + if (IsFromExampleRedirect) + { + WriteFile(); + } + return true; } -bool cIniFile::WriteFile() +bool cIniFile::WriteFile(void) const { - unsigned commentID, keyID, valueID; - // Normally you would use ofstream, but the SGI CC compiler has - // a few bugs with ofstream. So ... fstream used. - fstream f; + unsigned commentID, keyID, valueID; + // Normally you would use ofstream, but the SGI CC compiler has + // a few bugs with ofstream. So ... fstream used. + fstream f; - f.open( (FILE_IO_PREFIX + path).c_str(), ios::out); - if ( f.fail()) - return false; + f.open((FILE_IO_PREFIX + m_Path).c_str(), ios::out); + if (f.fail()) + { + return false; + } - // Write header comments. - for ( commentID = 0; commentID < comments.size(); ++commentID) - f << ';' << comments[commentID] << iniEOL; - if ( comments.size()) - f << iniEOL; + // Write header comments. + for (commentID = 0; commentID < comments.size(); ++commentID) + { + f << ';' << comments[commentID] << iniEOL; + } + if (comments.size()) + { + f << iniEOL; + } - // Write keys and values. - for ( keyID = 0; keyID < keys.size(); ++keyID) { - f << '[' << names[keyID] << ']' << iniEOL; - // Comments. - for ( commentID = 0; commentID < keys[keyID].comments.size(); ++commentID) - f << ';' << keys[keyID].comments[commentID] << iniEOL; - // Values. - for ( valueID = 0; valueID < keys[keyID].names.size(); ++valueID) - f << keys[keyID].names[valueID] << '=' << keys[keyID].values[valueID] << iniEOL; - f << iniEOL; - } - f.close(); + // Write keys and values. + for (keyID = 0; keyID < keys.size(); ++keyID) + { + f << '[' << names[keyID] << ']' << iniEOL; + + // Comments. + for (commentID = 0; commentID < keys[keyID].comments.size(); ++commentID) + { + f << ';' << keys[keyID].comments[commentID] << iniEOL; + } + + // Values. + for (valueID = 0; valueID < keys[keyID].names.size(); ++valueID) + { + f << keys[keyID].names[valueID] << '=' << keys[keyID].values[valueID] << iniEOL; + } + f << iniEOL; + } + f.close(); - return true; + return true; } -long cIniFile::FindKey( const string & keyname) const +long cIniFile::FindKey(const string & a_KeyName) const { - for ( unsigned keyID = 0; keyID < names.size(); ++keyID) - if ( CheckCase( names[keyID]) == CheckCase( keyname)) - return long(keyID); - return noID; + string CaseKeyName = CheckCase(a_KeyName); + for (unsigned keyID = 0; keyID < names.size(); ++keyID) + { + if (CheckCase(names[keyID]) == CaseKeyName) + { + return long(keyID); + } + } + return noID; } -long cIniFile::FindValue( unsigned const keyID, const string & valuename) const +long cIniFile::FindValue(unsigned const keyID, const string & a_ValueName) const { - if ( !keys.size() || keyID >= keys.size()) - return noID; + if (!keys.size() || (keyID >= keys.size())) + { + return noID; + } - for ( unsigned valueID = 0; valueID < keys[keyID].names.size(); ++valueID) - if ( CheckCase( keys[keyID].names[valueID]) == CheckCase( valuename)) - return long(valueID); - return noID; + string CaseValueName = CheckCase(a_ValueName); + for (unsigned valueID = 0; valueID < keys[keyID].names.size(); ++valueID) + { + if (CheckCase(keys[keyID].names[valueID]) == CaseValueName) + { + return long(valueID); + } + } + return noID; } -unsigned cIniFile::AddKeyName( const string & keyname) +unsigned cIniFile::AddKeyName(const string & keyname) { - names.resize( names.size() + 1, keyname); - keys.resize( keys.size() + 1); - return names.size() - 1; + names.resize(names.size() + 1, keyname); + keys.resize(keys.size() + 1); + return names.size() - 1; } -string cIniFile::KeyName( unsigned const keyID) const +string cIniFile::KeyName(unsigned const keyID) const { - if ( keyID < names.size()) - return names[keyID]; - else - return ""; + if (keyID < names.size()) + { + return names[keyID]; + } + else + { + return ""; + } } -unsigned cIniFile::NumValues( unsigned const keyID) +unsigned cIniFile::NumValues(unsigned const keyID) { - if ( keyID < keys.size()) - return keys[keyID].names.size(); - return 0; + if (keyID < keys.size()) + { + return keys[keyID].names.size(); + } + return 0; } -unsigned cIniFile::NumValues( const string & keyname) +unsigned cIniFile::NumValues(const string & keyname) { - long keyID = FindKey( keyname); - if ( keyID == noID) - return 0; - return keys[keyID].names.size(); + long keyID = FindKey(keyname); + if (keyID == noID) + { + return 0; + } + return keys[keyID].names.size(); } -string cIniFile::ValueName( unsigned const keyID, unsigned const valueID) const +string cIniFile::ValueName(unsigned const keyID, unsigned const valueID) const { - if ( keyID < keys.size() && valueID < keys[keyID].names.size()) - return keys[keyID].names[valueID]; - return ""; + if (keyID < keys.size() && valueID < keys[keyID].names.size()) + { + return keys[keyID].names[valueID]; + } + return ""; } -string cIniFile::ValueName( const string & keyname, unsigned const valueID) const +string cIniFile::ValueName(const string & keyname, unsigned const valueID) const { - long keyID = FindKey( keyname); - if ( keyID == noID) - return ""; - return ValueName( keyID, valueID); + long keyID = FindKey(keyname); + if (keyID == noID) + { + return ""; + } + return ValueName(keyID, valueID); } -bool cIniFile::SetValue( unsigned const keyID, unsigned const valueID, const string & value) +bool cIniFile::SetValue(unsigned const keyID, unsigned const valueID, const string & value) { - if ( keyID < keys.size() && valueID < keys[keyID].names.size()) - keys[keyID].values[valueID] = value; - - return false; + if ((keyID < keys.size()) && (valueID < keys[keyID].names.size())) + { + keys[keyID].values[valueID] = value; + } + return false; } -bool cIniFile::SetValue( const string & keyname, const string & valuename, const string & value, bool const create) +bool cIniFile::SetValue(const string & keyname, const string & valuename, const string & value, bool const create) { - long keyID = FindKey( keyname); - if ( keyID == noID) { - if ( create) - keyID = long( AddKeyName( keyname)); - else - return false; - } + long keyID = FindKey(keyname); + if (keyID == noID) + { + if (create) + { + keyID = long(AddKeyName(keyname)); + } + else + { + return false; + } + } - long valueID = FindValue( unsigned(keyID), valuename); - if ( valueID == noID) { - if ( !create) - return false; - keys[keyID].names.resize( keys[keyID].names.size() + 1, valuename); - keys[keyID].values.resize( keys[keyID].values.size() + 1, value); - } else - { - if(!create) - keys[keyID].values[valueID] = value; - else - { - keys[keyID].names.resize( keys[keyID].names.size() + 1, valuename); - keys[keyID].values.resize( keys[keyID].values.size() + 1, value); - } - } + long valueID = FindValue(unsigned(keyID), valuename); + if (valueID == noID) + { + if (!create) + { + return false; + } + keys[keyID].names.resize(keys[keyID].names.size() + 1, valuename); + keys[keyID].values.resize(keys[keyID].values.size() + 1, value); + } + else + { + if (!create) + { + keys[keyID].values[valueID] = value; + } + else + { + keys[keyID].names.resize(keys[keyID].names.size() + 1, valuename); + keys[keyID].values.resize(keys[keyID].values.size() + 1, value); + } + } - return true; + return true; } -bool cIniFile::SetValueI( const string & keyname, const string & valuename, int const value, bool const create) +bool cIniFile::SetValueI(const string & keyname, const string & valuename, int const value, bool const create) { - AString Data; - Printf(Data, "%d", value); - return SetValue( keyname, valuename, Data, create); + AString Data; + Printf(Data, "%d", value); + return SetValue(keyname, valuename, Data, create); } -bool cIniFile::SetValueF( const string & keyname, const string & valuename, double const value, bool const create) +bool cIniFile::SetValueF(const string & keyname, const string & valuename, double const value, bool const create) { - AString Data; - Printf(Data, "%f", value); - return SetValue( keyname, valuename, Data, create); + AString Data; + Printf(Data, "%f", value); + return SetValue(keyname, valuename, Data, create); } -bool cIniFile::SetValueV( const string & keyname, const string & valuename, char *format, ...) +bool cIniFile::SetValueV(const string & keyname, const string & valuename, char * format, ...) { - va_list args; + va_list args; + va_start(args, format); - va_start( args, format); - - AString Data; - AppendVPrintf(Data, format, args); - va_end( args); - return SetValue( keyname, valuename, Data); + AString Data; + AppendVPrintf(Data, format, args); + va_end(args); + return SetValue(keyname, valuename, Data); } -string cIniFile::GetValue( unsigned const keyID, unsigned const valueID, const string & defValue) const +string cIniFile::GetValue(unsigned const keyID, unsigned const valueID, const string & defValue) const { - if ( keyID < keys.size() && valueID < keys[keyID].names.size()) - return keys[keyID].values[valueID]; - return defValue; + if ((keyID < keys.size()) && (valueID < keys[keyID].names.size())) + { + return keys[keyID].values[valueID]; + } + return defValue; } -string cIniFile::GetValue( const string & keyname, const string & valuename, const string & defValue) const +string cIniFile::GetValue(const string & keyname, const string & valuename, const string & defValue) const { - long keyID = FindKey( keyname); - if ( keyID == noID) - return defValue; + long keyID = FindKey(keyname); + if (keyID == noID) + { + return defValue; + } - long valueID = FindValue( unsigned(keyID), valuename); - if ( valueID == noID) - return defValue; + long valueID = FindValue(unsigned(keyID), valuename); + if (valueID == noID) + { + return defValue; + } - return keys[keyID].values[valueID]; + return keys[keyID].values[valueID]; } @@ -398,7 +478,7 @@ int cIniFile::GetValueI(const string & keyname, const string & valuename, int co { AString Data; Printf(Data, "%d", defValue); - return atoi( GetValue( keyname, valuename, Data).c_str()); + return atoi(GetValue(keyname, valuename, Data).c_str()); } @@ -407,9 +487,9 @@ int cIniFile::GetValueI(const string & keyname, const string & valuename, int co double cIniFile::GetValueF(const string & keyname, const string & valuename, double const defValue) const { - AString Data; - Printf(Data, "%f", defValue); - return atof( GetValue( keyname, valuename, Data).c_str()); + AString Data; + Printf(Data, "%f", defValue); + return atof(GetValue(keyname, valuename, Data).c_str()); } @@ -418,15 +498,15 @@ double cIniFile::GetValueF(const string & keyname, const string & valuename, dou AString cIniFile::GetValueSet(const AString & keyname, const AString & valuename, const AString & defValue) { - long keyID = FindKey( keyname); - if ( keyID == noID) + long keyID = FindKey(keyname); + if (keyID == noID) { SetValue(keyname, valuename, defValue); return defValue; } - long valueID = FindValue( unsigned(keyID), valuename); - if ( valueID == noID) + long valueID = FindValue(unsigned(keyID), valuename); + if (valueID == noID) { SetValue(keyname, valuename, defValue); return defValue; @@ -441,9 +521,9 @@ AString cIniFile::GetValueSet(const AString & keyname, const AString & valuename double cIniFile::GetValueSetF(const AString & keyname, const AString & valuename, const double defValue) { - AString Data; - Printf(Data, "%f", defValue); - return atof(GetValueSet(keyname, valuename, Data).c_str()); + AString Data; + Printf(Data, "%f", defValue); + return atof(GetValueSet(keyname, valuename, Data).c_str()); } @@ -454,182 +534,273 @@ int cIniFile::GetValueSetI(const AString & keyname, const AString & valuename, c { AString Data; Printf(Data, "%d", defValue); - return atoi(GetValueSet(keyname, valuename, Data).c_str()); + return atoi(GetValueSet(keyname, valuename, Data).c_str()); } -bool cIniFile::DeleteValueByID( const unsigned keyID, const unsigned valueID ) +bool cIniFile::DeleteValueByID(const unsigned keyID, const unsigned valueID) { - if ( keyID < keys.size() && valueID < keys[keyID].names.size()) + if (keyID < keys.size() && valueID < keys[keyID].names.size()) { // This looks strange, but is neccessary. vector<string>::iterator npos = keys[keyID].names.begin() + valueID; vector<string>::iterator vpos = keys[keyID].values.begin() + valueID; - keys[keyID].names.erase( npos, npos + 1); - keys[keyID].values.erase( vpos, vpos + 1); + keys[keyID].names.erase(npos, npos + 1); + keys[keyID].values.erase(vpos, vpos + 1); return true; } return false; } -bool cIniFile::DeleteValue( const string & keyname, const string & valuename) + + + + +bool cIniFile::DeleteValue(const string & keyname, const string & valuename) { - long keyID = FindKey( keyname); - if ( keyID == noID) - return false; + long keyID = FindKey(keyname); + if (keyID == noID) + { + return false; + } - long valueID = FindValue( unsigned(keyID), valuename); - if ( valueID == noID) - return false; + long valueID = FindValue(unsigned(keyID), valuename); + if (valueID == noID) + { + return false; + } - return DeleteValueByID( keyID, valueID ); + return DeleteValueByID(keyID, valueID); } -bool cIniFile::DeleteKey( const string & keyname) -{ - long keyID = FindKey( keyname); - if ( keyID == noID) - return false; - // Now hopefully this destroys the vector lists within keys. - // Looking at <vector> source, this should be the case using the destructor. - // If not, I may have to do it explicitly. Memory leak check should tell. - // memleak_test.cpp shows that the following not required. - //keys[keyID].names.clear(); - //keys[keyID].values.clear(); - vector<string>::iterator npos = names.begin() + keyID; - vector<key>::iterator kpos = keys.begin() + keyID; - names.erase( npos, npos + 1); - keys.erase( kpos, kpos + 1); - return true; + +bool cIniFile::DeleteKey(const string & keyname) +{ + long keyID = FindKey(keyname); + if (keyID == noID) + { + return false; + } + + vector<string>::iterator npos = names.begin() + keyID; + vector<key>::iterator kpos = keys.begin() + keyID; + names.erase(npos, npos + 1); + keys.erase(kpos, kpos + 1); + + return true; } -void cIniFile::Erase() + + + + +void cIniFile::Clear(void) { - // This loop not needed. The vector<> destructor seems to do - // all the work itself. memleak_test.cpp shows this. - //for ( unsigned i = 0; i < keys.size(); ++i) { - // keys[i].names.clear(); - // keys[i].values.clear(); - //} - names.clear(); - keys.clear(); - comments.clear(); + names.clear(); + keys.clear(); + comments.clear(); } -void cIniFile::HeaderComment( const string & comment) + + + + +void cIniFile::HeaderComment(const string & comment) { - comments.resize( comments.size() + 1, comment); + comments.push_back(comment); + // comments.resize(comments.size() + 1, comment); } -string cIniFile::HeaderComment( unsigned const commentID) const + + + + +string cIniFile::HeaderComment(unsigned const commentID) const { - if ( commentID < comments.size()) - return comments[commentID]; - return ""; + if (commentID < comments.size()) + { + return comments[commentID]; + } + return ""; } -bool cIniFile::DeleteHeaderComment( unsigned commentID) + + + + +bool cIniFile::DeleteHeaderComment(unsigned commentID) { - if ( commentID < comments.size()) { - vector<string>::iterator cpos = comments.begin() + commentID; - comments.erase( cpos, cpos + 1); - return true; - } - return false; + if (commentID < comments.size()) + { + vector<string>::iterator cpos = comments.begin() + commentID; + comments.erase(cpos, cpos + 1); + return true; + } + return false; } -unsigned cIniFile::NumKeyComments( unsigned const keyID) const + + + + +unsigned cIniFile::NumKeyComments(unsigned const keyID) const { - if ( keyID < keys.size()) - return keys[keyID].comments.size(); - return 0; + if (keyID < keys.size()) + { + return keys[keyID].comments.size(); + } + return 0; } -unsigned cIniFile::NumKeyComments( const string & keyname) const + + + + +unsigned cIniFile::NumKeyComments(const string & keyname) const { - long keyID = FindKey( keyname); - if ( keyID == noID) - return 0; - return keys[keyID].comments.size(); + long keyID = FindKey(keyname); + if (keyID == noID) + return 0; + return keys[keyID].comments.size(); } -bool cIniFile::KeyComment( unsigned const keyID, const string & comment) + + + + +bool cIniFile::KeyComment(unsigned const keyID, const string & comment) { - if ( keyID < keys.size()) { - keys[keyID].comments.resize( keys[keyID].comments.size() + 1, comment); - return true; - } - return false; + if (keyID < keys.size()) + { + keys[keyID].comments.resize(keys[keyID].comments.size() + 1, comment); + return true; + } + return false; } -bool cIniFile::KeyComment( const string & keyname, const string & comment) + + + + +bool cIniFile::KeyComment(const string & keyname, const string & comment) { - long keyID = FindKey( keyname); - if ( keyID == noID) - return false; - return KeyComment( unsigned(keyID), comment); + long keyID = FindKey(keyname); + if (keyID == noID) + { + return false; + } + return KeyComment(unsigned(keyID), comment); } -string cIniFile::KeyComment( unsigned const keyID, unsigned const commentID) const + + + + +string cIniFile::KeyComment(unsigned const keyID, unsigned const commentID) const { - if ( keyID < keys.size() && commentID < keys[keyID].comments.size()) - return keys[keyID].comments[commentID]; - return ""; + if ((keyID < keys.size()) && (commentID < keys[keyID].comments.size())) + { + return keys[keyID].comments[commentID]; + } + return ""; } -string cIniFile::KeyComment( const string & keyname, unsigned const commentID) const + + + + +string cIniFile::KeyComment(const string & keyname, unsigned const commentID) const { - long keyID = FindKey( keyname); - if ( keyID == noID) - return ""; - return KeyComment( unsigned(keyID), commentID); + long keyID = FindKey(keyname); + if (keyID == noID) + { + return ""; + } + return KeyComment(unsigned(keyID), commentID); } -bool cIniFile::DeleteKeyComment( unsigned const keyID, unsigned const commentID) + + + + +bool cIniFile::DeleteKeyComment(unsigned const keyID, unsigned const commentID) { - if ( keyID < keys.size() && commentID < keys[keyID].comments.size()) { - vector<string>::iterator cpos = keys[keyID].comments.begin() + commentID; - keys[keyID].comments.erase( cpos, cpos + 1); - return true; - } - return false; + if ((keyID < keys.size()) && (commentID < keys[keyID].comments.size())) + { + vector<string>::iterator cpos = keys[keyID].comments.begin() + commentID; + keys[keyID].comments.erase(cpos, cpos + 1); + return true; + } + return false; } -bool cIniFile::DeleteKeyComment( const string & keyname, unsigned const commentID) + + + + +bool cIniFile::DeleteKeyComment(const string & keyname, unsigned const commentID) { - long keyID = FindKey( keyname); - if ( keyID == noID) - return false; - return DeleteKeyComment( unsigned(keyID), commentID); + long keyID = FindKey(keyname); + if (keyID == noID) + { + return false; + } + return DeleteKeyComment(unsigned(keyID), commentID); } -bool cIniFile::DeleteKeyComments( unsigned const keyID) + + + + +bool cIniFile::DeleteKeyComments(unsigned const keyID) { - if ( keyID < keys.size()) { - keys[keyID].comments.clear(); - return true; - } - return false; + if (keyID < keys.size()) + { + keys[keyID].comments.clear(); + return true; + } + return false; } -bool cIniFile::DeleteKeyComments( const string & keyname) + + + + +bool cIniFile::DeleteKeyComments(const string & keyname) { - long keyID = FindKey( keyname); - if ( keyID == noID) - return false; - return DeleteKeyComments( unsigned(keyID)); + long keyID = FindKey(keyname); + if (keyID == noID) + { + return false; + } + return DeleteKeyComments(unsigned(keyID)); } -string cIniFile::CheckCase( string s) const + + + + +string cIniFile::CheckCase(const string & s) const { - if ( caseInsensitive) - for ( string::size_type i = 0; i < s.length(); ++i) - s[i] = (char)tolower(s[i]); - return s; + if (!m_IsCaseInsensitive) + { + return s; + } + string res(s); + size_t len = res.length(); + for (size_t i = 0; i < len; i++) + { + res[i] = tolower(res[i]); + } + return res; } + + + + diff --git a/iniFile/iniFile.h b/iniFile/iniFile.h index 1afc404e3..aef45c094 100644 --- a/iniFile/iniFile.h +++ b/iniFile/iniFile.h @@ -30,135 +30,160 @@ -class cIniFile // tolua_export -{ // tolua_export +// tolua_begin + +class cIniFile +{ private: - bool caseInsensitive; - std::string path; - struct key { + bool m_IsCaseInsensitive; + std::string m_Path; + + struct key + { std::vector<std::string> names; std::vector<std::string> values; std::vector<std::string> comments; - }; - std::vector<key> keys; - std::vector<std::string> names; + } ; + + std::vector<key> keys; + std::vector<std::string> names; std::vector<std::string> comments; - std::string CheckCase( std::string s) const; + + /// If the object is case-insensitive, returns s as lowercase; otherwise returns s as-is + std::string CheckCase(const std::string & s) const; public: - enum errors{ noID = -1}; // tolua_export - cIniFile( const std::string iniPath = ""); // tolua_export - virtual ~cIniFile() {} + enum errors + { + noID = -1, + }; + + /// Creates a new instance; sets m_Path to a_Path, but doesn't read the file + cIniFile(const std::string & a_Path = ""); // Sets whether or not keynames and valuenames should be case sensitive. // The default is case insensitive. - void CaseSensitive() {caseInsensitive = false;} // tolua_export - void CaseInsensitive() {caseInsensitive = true;} // tolua_export + void CaseSensitive (void) { m_IsCaseInsensitive = false; } + void CaseInsensitive(void) { m_IsCaseInsensitive = true; } // Sets path of ini file to read and write from. - void Path(const std::string & newPath) {path = newPath;} // tolua_export - std::string Path() const {return path;} // tolua_export - void SetPath(const std::string & newPath) {Path( newPath);} // tolua_export + void Path(const std::string & newPath) {m_Path = newPath;} + const std::string & Path(void) const {return m_Path;} + void SetPath(const std::string & newPath) {Path(newPath);} - // Reads ini file specified using path. - // Returns true if successful, false otherwise. - bool ReadFile(); // tolua_export + /** Reads the ini file specified in m_Path + If the file doesn't exist and a_AllowExampleRedirect is true, tries to read <basename>.example.ini, and + writes its contents as <basename>.ini, if successful. + Returns true if successful, false otherwise. + */ + bool ReadFile(bool a_AllowExampleRedirect = true); - // Writes data stored in class to ini file. - bool WriteFile(); // tolua_export + /// Writes data stored in class to ini file specified in m_Path + bool WriteFile(void) const; - // Deletes all stored ini data. - void Erase(); // tolua_export - void Clear() {Erase();} // tolua_export - void Reset() {Erase();} // tolua_export + /// Deletes all stored ini data (but doesn't touch the file) + void Clear(void); + void Reset(void) { Clear(); } + void Erase(void) { Clear(); } // OBSOLETE, this name is misguiding and will be removed from the interface - // Returns index of specified key, or noID if not found. - long FindKey( const std::string & keyname) const; // tolua_export + /// Returns index of specified key, or noID if not found + long FindKey(const std::string & keyname) const; - // Returns index of specified value, in the specified key, or noID if not found. - long FindValue( const unsigned keyID, const std::string & valuename) const; // tolua_export + /// Returns index of specified value, in the specified key, or noID if not found + long FindValue(const unsigned keyID, const std::string & valuename) const; - // Returns number of keys currently in the ini. - unsigned NumKeys() const {return names.size();} // tolua_export - unsigned GetNumKeys() const {return NumKeys();} // tolua_export + /// Returns number of keys currently in the ini + unsigned NumKeys (void) const {return names.size();} + unsigned GetNumKeys(void) const {return NumKeys();} - // Add a key name. - unsigned AddKeyName( const std::string & keyname); // tolua_export + /// Add a key name + unsigned AddKeyName(const std::string & keyname); // Returns key names by index. - std::string KeyName( const unsigned keyID) const; // tolua_export - std::string GetKeyName( const unsigned keyID) const {return KeyName(keyID);} // tolua_export + std::string KeyName(const unsigned keyID) const; + std::string GetKeyName(const unsigned keyID) const {return KeyName(keyID);} // Returns number of values stored for specified key. - unsigned NumValues( const std::string & keyname); // tolua_export - unsigned GetNumValues( const std::string & keyname) {return NumValues( keyname);} // tolua_export - unsigned NumValues( const unsigned keyID); // tolua_export - unsigned GetNumValues( const unsigned keyID) {return NumValues( keyID);} // tolua_export + unsigned NumValues (const std::string & keyname); + unsigned GetNumValues(const std::string & keyname) {return NumValues(keyname);} + unsigned NumValues (const unsigned keyID); + unsigned GetNumValues(const unsigned keyID) {return NumValues(keyID);} // Returns value name by index for a given keyname or keyID. - std::string ValueName( const std::string & keyname, const unsigned valueID) const; // tolua_export - std::string GetValueName( const std::string & keyname, const unsigned valueID) const { // tolua_export - return ValueName( keyname, valueID); - } // tolua_export - std::string ValueName( const unsigned keyID, const unsigned valueID) const; // tolua_export - std::string GetValueName( const unsigned keyID, const unsigned valueID) const { // tolua_export - return ValueName( keyID, valueID); - } // tolua_export + std::string ValueName( const std::string & keyname, const unsigned valueID) const; + std::string GetValueName( const std::string & keyname, const unsigned valueID) const + { + return ValueName(keyname, valueID); + } + std::string ValueName (const unsigned keyID, const unsigned valueID) const; + std::string GetValueName(const unsigned keyID, const unsigned valueID) const + { + return ValueName(keyID, valueID); + } // Gets value of [keyname] valuename =. // Overloaded to return string, int, and double. // Returns defValue if key/value not found. - AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const; // tolua_export - AString GetValue (const unsigned keyID, const unsigned valueID, const AString & defValue = "") const; // tolua_export - double GetValueF(const AString & keyname, const AString & valuename, const double defValue = 0) const; // tolua_export - int GetValueI(const AString & keyname, const AString & valuename, const int defValue = 0) const; // tolua_export - bool GetValueB(const AString & keyname, const AString & valuename, const bool defValue = false) const { // tolua_export - return ( GetValueI( keyname, valuename, int( defValue)) > 0); - } // tolua_export + AString GetValue (const AString & keyname, const AString & valuename, const AString & defValue = "") const; + AString GetValue (const unsigned keyID, const unsigned valueID, const AString & defValue = "") const; + double GetValueF(const AString & keyname, const AString & valuename, const double defValue = 0) const; + int GetValueI(const AString & keyname, const AString & valuename, const int defValue = 0) const; + bool GetValueB(const AString & keyname, const AString & valuename, const bool defValue = false) const + { + return (GetValueI(keyname, valuename, int(defValue)) > 0); + } // Gets the value; if not found, write the default to the INI file - AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = ""); // tolua_export - double GetValueSetF(const AString & keyname, const AString & valuename, const double defValue = 0.0); // tolua_export - int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0); // tolua_export - bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) { // tolua_export + AString GetValueSet (const AString & keyname, const AString & valuename, const AString & defValue = ""); + double GetValueSetF(const AString & keyname, const AString & valuename, const double defValue = 0.0); + int GetValueSetI(const AString & keyname, const AString & valuename, const int defValue = 0); + bool GetValueSetB(const AString & keyname, const AString & valuename, const bool defValue = false) + { return (GetValueSetI(keyname, valuename, defValue ? 1 : 0) > 0); - } // tolua_export + } // Sets value of [keyname] valuename =. // Specify the optional paramter as false (0) if you do not want it to create // the key if it doesn't exist. Returns true if data entered, false otherwise. // Overloaded to accept string, int, and double. - bool SetValue( const unsigned keyID, const unsigned valueID, const std::string & value); // tolua_export - bool SetValue( const std::string & keyname, const std::string & valuename, const std::string & value, const bool create = true); // tolua_export - bool SetValueI( const std::string & keyname, const std::string & valuename, const int value, const bool create = true); // tolua_export - bool SetValueB( const std::string & keyname, const std::string & valuename, const bool value, const bool create = true) { // tolua_export + bool SetValue( const unsigned keyID, const unsigned valueID, const std::string & value); + bool SetValue( const std::string & keyname, const std::string & valuename, const std::string & value, const bool create = true); + bool SetValueI( const std::string & keyname, const std::string & valuename, const int value, const bool create = true); + bool SetValueB( const std::string & keyname, const std::string & valuename, const bool value, const bool create = true) + { return SetValueI( keyname, valuename, int(value), create); - } // tolua_export - bool SetValueF( const std::string & keyname, const std::string & valuename, const double value, const bool create = true); // tolua_export + } + bool SetValueF( const std::string & keyname, const std::string & valuename, const double value, const bool create = true); + + // tolua_end + bool SetValueV( const std::string & keyname, const std::string & valuename, char *format, ...); + + // tolua_begin // Deletes specified value. // Returns true if value existed and deleted, false otherwise. - bool DeleteValueByID( const unsigned keyID, const unsigned valueID ); // tolua_export - bool DeleteValue( const std::string & keyname, const std::string & valuename); // tolua_export + bool DeleteValueByID( const unsigned keyID, const unsigned valueID ); + bool DeleteValue( const std::string & keyname, const std::string & valuename); // Deletes specified key and all values contained within. // Returns true if key existed and deleted, false otherwise. - bool DeleteKey(const std::string & keyname); // tolua_export + bool DeleteKey(const std::string & keyname); // Header comment functions. // Header comments are those comments before the first key. // // Number of header comments. - unsigned NumHeaderComments() {return comments.size();} // tolua_export + unsigned NumHeaderComments(void) {return comments.size();} // Add a header comment. - void HeaderComment( const std::string & comment); // tolua_export + void HeaderComment(const std::string & comment); // Return a header comment. - std::string HeaderComment( const unsigned commentID) const; // tolua_export + std::string HeaderComment(const unsigned commentID) const; // Delete a header comment. - bool DeleteHeaderComment( unsigned commentID); // tolua_export + bool DeleteHeaderComment(unsigned commentID); // Delete all header comments. - void DeleteHeaderComments() {comments.clear();} // tolua_export + void DeleteHeaderComments(void) {comments.clear();} + // Key comment functions. // Key comments are those comments within a key. Any comments @@ -167,20 +192,26 @@ public: // the CIniFile::WriteFile() is called. // // Number of key comments. - unsigned NumKeyComments( const unsigned keyID) const; // tolua_export - unsigned NumKeyComments( const std::string & keyname) const; // tolua_export + unsigned NumKeyComments( const unsigned keyID) const; + unsigned NumKeyComments( const std::string & keyname) const; + // Add a key comment. - bool KeyComment( const unsigned keyID, const std::string & comment); // tolua_export - bool KeyComment( const std::string & keyname, const std::string & comment); // tolua_export + bool KeyComment(const unsigned keyID, const std::string & comment); + bool KeyComment(const std::string & keyname, const std::string & comment); + // Return a key comment. - std::string KeyComment( const unsigned keyID, const unsigned commentID) const; // tolua_export - std::string KeyComment( const std::string & keyname, const unsigned commentID) const; // tolua_export + std::string KeyComment(const unsigned keyID, const unsigned commentID) const; + std::string KeyComment(const std::string & keyname, const unsigned commentID) const; + // Delete a key comment. - bool DeleteKeyComment( const unsigned keyID, const unsigned commentID); // tolua_export - bool DeleteKeyComment( const std::string & keyname, const unsigned commentID); // tolua_export + bool DeleteKeyComment(const unsigned keyID, const unsigned commentID); + bool DeleteKeyComment(const std::string & keyname, const unsigned commentID); + // Delete all comments for a key. - bool DeleteKeyComments( const unsigned keyID); // tolua_export - bool DeleteKeyComments( const std::string & keyname); // tolua_export -}; // tolua_export + bool DeleteKeyComments(const unsigned keyID); + bool DeleteKeyComments(const std::string & keyname); +}; + +// tolua_end #endif diff --git a/source/AllToLua.pkg b/source/AllToLua.pkg index 7041211b5..cd22aba0a 100644 --- a/source/AllToLua.pkg +++ b/source/AllToLua.pkg @@ -63,3 +63,11 @@ $cfile "LuaWindow.h" + +// Need to declare this class so that the usertype is properly registered in Bindings.cpp - +// it seems impossible to register a usertype in ManualBindings.cpp +class cLineBlockTracer; + + + + diff --git a/source/Bindings.cpp b/source/Bindings.cpp index df45cb1b3..fd953e29d 100644 --- a/source/Bindings.cpp +++ b/source/Bindings.cpp @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/02/13 08:41:18. +** Generated automatically by tolua++-1.0.92 on 08/07/13 12:06:03. */ #ifndef __cplusplus @@ -202,8 +202,11 @@ static int tolua_collect_Vector3d (lua_State* tolua_S) static void tolua_reg_types (lua_State* tolua_S) { tolua_usertype(tolua_S,"TakeDamageInfo"); - tolua_usertype(tolua_S,"cCraftingRecipe"); tolua_usertype(tolua_S,"cPlugin_NewLua"); + tolua_usertype(tolua_S,"cCraftingGrid"); + tolua_usertype(tolua_S,"cCraftingRecipe"); + tolua_usertype(tolua_S,"cPlugin"); + tolua_usertype(tolua_S,"cWindow"); tolua_usertype(tolua_S,"cStringMap"); tolua_usertype(tolua_S,"cItemGrid"); tolua_usertype(tolua_S,"cBlockArea"); @@ -211,42 +214,42 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cLuaWindow"); tolua_usertype(tolua_S,"cInventory"); tolua_usertype(tolua_S,"cRoot"); - tolua_usertype(tolua_S,"cWindow"); - tolua_usertype(tolua_S,"cCraftingGrid"); - tolua_usertype(tolua_S,"cTracer"); - tolua_usertype(tolua_S,"cPickup"); - tolua_usertype(tolua_S,"cItems"); + tolua_usertype(tolua_S,"cCuboid"); + tolua_usertype(tolua_S,"std::vector<cIniFile::key>"); tolua_usertype(tolua_S,"cGroup"); + tolua_usertype(tolua_S,"cPickup"); + tolua_usertype(tolua_S,"std::vector<std::string>"); + tolua_usertype(tolua_S,"cTracer"); tolua_usertype(tolua_S,"cClientHandle"); tolua_usertype(tolua_S,"cChunkDesc"); tolua_usertype(tolua_S,"cFurnaceRecipe"); - tolua_usertype(tolua_S,"cCuboid"); - tolua_usertype(tolua_S,"cChatColor"); tolua_usertype(tolua_S,"Vector3i"); - tolua_usertype(tolua_S,"cEntity"); + tolua_usertype(tolua_S,"cChatColor"); + tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"Lua__cPickup"); tolua_usertype(tolua_S,"Lua__cWebPlugin"); - tolua_usertype(tolua_S,"cPlugin"); tolua_usertype(tolua_S,"cCraftingRecipes"); + tolua_usertype(tolua_S,"cEntity"); tolua_usertype(tolua_S,"cItem"); tolua_usertype(tolua_S,"Vector3f"); - tolua_usertype(tolua_S,"Lua__cPickup"); + tolua_usertype(tolua_S,"cWebPlugin"); tolua_usertype(tolua_S,"cDropSpenserEntity"); tolua_usertype(tolua_S,"Lua__cPlayer"); - tolua_usertype(tolua_S,"cWebPlugin"); + tolua_usertype(tolua_S,"cWebAdmin"); tolua_usertype(tolua_S,"cChestEntity"); tolua_usertype(tolua_S,"cDispenserEntity"); - tolua_usertype(tolua_S,"cWebAdmin"); + tolua_usertype(tolua_S,"sWebAdminPage"); tolua_usertype(tolua_S,"cBlockEntity"); tolua_usertype(tolua_S,"cCriticalSection"); tolua_usertype(tolua_S,"HTTPTemplateRequest"); - tolua_usertype(tolua_S,"sWebAdminPage"); tolua_usertype(tolua_S,"HTTPRequest"); tolua_usertype(tolua_S,"HTTPFormData"); tolua_usertype(tolua_S,"cFurnaceEntity"); - tolua_usertype(tolua_S,"cPluginManager"); tolua_usertype(tolua_S,"cDropperEntity"); + tolua_usertype(tolua_S,"cLineBlockTracer"); + tolua_usertype(tolua_S,"cPluginManager"); tolua_usertype(tolua_S,"cIniFile"); - tolua_usertype(tolua_S,"cWorld"); + tolua_usertype(tolua_S,"cBlockEntityWithItems"); tolua_usertype(tolua_S,"cListeners"); tolua_usertype(tolua_S,"cPawn"); tolua_usertype(tolua_S,"cPlayer"); @@ -254,7 +257,7 @@ static void tolua_reg_types (lua_State* tolua_S) tolua_usertype(tolua_S,"cBlockEntityWindowOwner"); tolua_usertype(tolua_S,"cItemGrid::cListener"); tolua_usertype(tolua_S,"cServer"); - tolua_usertype(tolua_S,"cBlockEntityWithItems"); + tolua_usertype(tolua_S,"cItems"); tolua_usertype(tolua_S,"Lua__cEntity"); tolua_usertype(tolua_S,"Vector3d"); } @@ -267,16 +270,14 @@ static int tolua_AllToLua_cIniFile_new00(lua_State* tolua_S) tolua_Error tolua_err; if ( !tolua_isusertable(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,1,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) + !tolua_isnoobj(tolua_S,2,&tolua_err) ) goto tolua_lerror; else #endif { - const std::string iniPath = ((const std::string) tolua_tocppstring(tolua_S,2,"")); { - cIniFile* tolua_ret = (cIniFile*) Mtolua_new((cIniFile)(iniPath)); + cIniFile* tolua_ret = (cIniFile*) Mtolua_new((cIniFile)()); tolua_pushusertype(tolua_S,(void*)tolua_ret,"cIniFile"); } } @@ -297,16 +298,14 @@ static int tolua_AllToLua_cIniFile_new00_local(lua_State* tolua_S) tolua_Error tolua_err; if ( !tolua_isusertable(tolua_S,1,"cIniFile",0,&tolua_err) || - !tolua_iscppstring(tolua_S,2,1,&tolua_err) || - !tolua_isnoobj(tolua_S,3,&tolua_err) + !tolua_isnoobj(tolua_S,2,&tolua_err) ) goto tolua_lerror; else #endif { - const std::string iniPath = ((const std::string) tolua_tocppstring(tolua_S,2,"")); { - cIniFile* tolua_ret = (cIniFile*) Mtolua_new((cIniFile)(iniPath)); + cIniFile* tolua_ret = (cIniFile*) Mtolua_new((cIniFile)()); tolua_pushusertype(tolua_S,(void*)tolua_ret,"cIniFile"); tolua_register_gc(tolua_S,lua_gettop(tolua_S)); } @@ -320,6 +319,59 @@ 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) @@ -433,7 +485,7 @@ static int tolua_AllToLua_cIniFile_Path01(lua_State* tolua_S) if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Path'", NULL); #endif { - std::string tolua_ret = (std::string) self->Path(); + const std::string tolua_ret = (const std::string) self->Path(); tolua_pushcppstring(tolua_S,(const char*)tolua_ret); } } @@ -485,18 +537,20 @@ 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_isnoobj(tolua_S,2,&tolua_err) + !tolua_isboolean(tolua_S,2,1,&tolua_err) || + !tolua_isnoobj(tolua_S,3,&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)); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'ReadFile'", NULL); #endif { - bool tolua_ret = (bool) self->ReadFile(); + bool tolua_ret = (bool) self->ReadFile(a_AllowExampleRedirect); tolua_pushboolean(tolua_S,(bool)tolua_ret); } } @@ -516,14 +570,14 @@ static int tolua_AllToLua_cIniFile_WriteFile00(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_isnoobj(tolua_S,2,&tolua_err) ) goto tolua_lerror; else #endif { - cIniFile* self = (cIniFile*) tolua_tousertype(tolua_S,1,0); + const cIniFile* self = (const cIniFile*) tolua_tousertype(tolua_S,1,0); #ifndef TOLUA_RELEASE if (!self) tolua_error(tolua_S,"invalid 'self' in function 'WriteFile'", NULL); #endif @@ -541,9 +595,9 @@ static int tolua_AllToLua_cIniFile_WriteFile00(lua_State* tolua_S) } #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) +/* method: Clear of class cIniFile */ +#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_Clear00 +static int tolua_AllToLua_cIniFile_Clear00(lua_State* tolua_S) { #ifndef TOLUA_RELEASE tolua_Error tolua_err; @@ -557,24 +611,24 @@ static int tolua_AllToLua_cIniFile_Erase00(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 'Erase'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Clear'", NULL); #endif { - self->Erase(); + self->Clear(); } } return 0; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'Erase'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'Clear'.",&tolua_err); return 0; #endif } #endif //#ifndef TOLUA_DISABLE -/* method: Clear of class cIniFile */ -#ifndef TOLUA_DISABLE_tolua_AllToLua_cIniFile_Clear00 -static int tolua_AllToLua_cIniFile_Clear00(lua_State* tolua_S) +/* 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; @@ -588,24 +642,24 @@ static int tolua_AllToLua_cIniFile_Clear00(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 'Clear'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Reset'", NULL); #endif { - self->Clear(); + self->Reset(); } } return 0; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'Clear'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'Reset'.",&tolua_err); return 0; #endif } #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) +/* 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; @@ -619,16 +673,16 @@ static int tolua_AllToLua_cIniFile_Reset00(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 'Reset'", NULL); + if (!self) tolua_error(tolua_S,"invalid 'self' in function 'Erase'", NULL); #endif { - self->Reset(); + self->Erase(); } } return 0; #ifndef TOLUA_RELEASE tolua_lerror: - tolua_error(tolua_S,"#ferror in function 'Reset'.",&tolua_err); + tolua_error(tolua_S,"#ferror in function 'Erase'.",&tolua_err); return 0; #endif } @@ -28476,6 +28530,9 @@ 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); @@ -28483,9 +28540,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) 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,"Erase",tolua_AllToLua_cIniFile_Erase00); 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); @@ -28699,6 +28756,7 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) tolua_constant(tolua_S,"E_BLOCK_QUARTZ_BLOCK",E_BLOCK_QUARTZ_BLOCK); tolua_constant(tolua_S,"E_BLOCK_ACTIVATOR_RAIL",E_BLOCK_ACTIVATOR_RAIL); tolua_constant(tolua_S,"E_BLOCK_DROPPER",E_BLOCK_DROPPER); + tolua_constant(tolua_S,"E_BLOCK_CARPET",E_BLOCK_CARPET); tolua_constant(tolua_S,"E_BLOCK_NUMBER_OF_TYPES",E_BLOCK_NUMBER_OF_TYPES); tolua_constant(tolua_S,"E_BLOCK_MAX_TYPE_ID",E_BLOCK_MAX_TYPE_ID); tolua_constant(tolua_S,"E_ITEM_EMPTY",E_ITEM_EMPTY); @@ -30283,6 +30341,9 @@ TOLUA_API int tolua_AllToLua_open (lua_State* tolua_S) 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,"cLineBlockTracer","cLineBlockTracer","",NULL); + tolua_beginmodule(tolua_S,"cLineBlockTracer"); + tolua_endmodule(tolua_S); tolua_endmodule(tolua_S); return 1; } diff --git a/source/Bindings.h b/source/Bindings.h index 6dfe855d3..a5654c062 100644 --- a/source/Bindings.h +++ b/source/Bindings.h @@ -1,6 +1,6 @@ /* ** Lua binding: AllToLua -** Generated automatically by tolua++-1.0.92 on 08/02/13 08:41:19. +** Generated automatically by tolua++-1.0.92 on 08/07/13 12:06:04. */ /* Exported function */ diff --git a/source/BlockEntities/ChestEntity.cpp b/source/BlockEntities/ChestEntity.cpp index 24d2aef11..d5cd076be 100644 --- a/source/BlockEntities/ChestEntity.cpp +++ b/source/BlockEntities/ChestEntity.cpp @@ -123,7 +123,7 @@ void cChestEntity::UsedBy(cPlayer * a_Player) // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first. // The few false positives aren't much to worry about int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(m_PosX, m_PosY, m_PosZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ); m_World->MarkChunkDirty(ChunkX, ChunkZ); } diff --git a/source/BlockEntities/HopperEntity.cpp b/source/BlockEntities/HopperEntity.cpp index 23e4b8096..591db7b4d 100644 --- a/source/BlockEntities/HopperEntity.cpp +++ b/source/BlockEntities/HopperEntity.cpp @@ -125,7 +125,7 @@ void cHopperEntity::UsedBy(cPlayer * a_Player) // We cannot properly detect contents change, but such a change doesn't happen without a player opening the chest first. // The few false positives aren't much to worry about int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(m_PosX, m_PosY, m_PosZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(m_PosX, m_PosZ, ChunkX, ChunkZ); m_World->MarkChunkDirty(ChunkX, ChunkZ); } diff --git a/source/BlockID.h b/source/BlockID.h index bd2580ca9..ad8dab8bd 100644 --- a/source/BlockID.h +++ b/source/BlockID.h @@ -169,6 +169,8 @@ enum ENUM_BLOCK_ID E_BLOCK_DROPPER = 158, + E_BLOCK_CARPET = 171, + // Keep these two as the last values, without a number - they will get their correct number assigned automagically by C++ // IsValidBlock() depends on this E_BLOCK_NUMBER_OF_TYPES, ///< Number of individual (different) blocktypes diff --git a/source/BlockTracer.h b/source/BlockTracer.h new file mode 100644 index 000000000..6d67f1052 --- /dev/null +++ b/source/BlockTracer.h @@ -0,0 +1,104 @@ + +// BlockTracer.h + +// Declares the classes common for all blocktracers + + + + + +#pragma once + + + + + +// fwd: World.h +class cWorld; + + + + + +class cBlockTracer abstract +{ +public: + /** The callback class is used to notify the caller of individual events that are being traced. + */ + class cCallbacks abstract + { + public: + /** Called on each block encountered along the path, including the first block (path start) + When this callback returns true, the tracing is aborted. + */ + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) = 0; + + /** Called on each block encountered along the path, including the first block (path start), if chunk data is not loaded + When this callback returns true, the tracing is aborted. + */ + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) { return false; } + + /** Called when the path goes out of world, either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) + The coords specify the exact point at which the path exited the world. + If this callback returns true, the tracing is aborted. + Note that some paths can go out of the world and come back again (parabola), + in such a case this callback is followed by OnIntoWorld() and further OnNextBlock() calls + */ + virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) { return false; } + + /** Called when the path goes into the world, from either below (a_BlockY < 0) or above (a_BlockY >= cChunkDef::Height) + The coords specify the exact point at which the path entered the world. + If this callback returns true, the tracing is aborted. + Note that some paths can go out of the world and come back again (parabola), + in such a case this callback is followed by further OnNextBlock() calls + */ + virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) { return false; } + + /** Called when the path is sure not to hit any more blocks. + Note that for some shapes this might never happen (line with constant Y) + */ + virtual void OnNoMoreHits(void) {} + + /** Called when the block tracing walks into a chunk that is not allocated. + This usually means that the tracing is aborted. + */ + virtual void OnNoChunk(void) {} + } ; + + + /// Creates the BlockTracer parent with the specified callbacks + cBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) : + m_World(&a_World), + m_Callbacks(&a_Callbacks) + { + } + + + /// Sets new world, returns the old one. Note that both need to be valid + cWorld & SetWorld(cWorld & a_World) + { + cWorld & Old = *m_World; + m_World = &a_World; + return Old; + } + + + /// Sets new callbacks, returns the old ones. Note that both need to be valid + cCallbacks & SetCallbacks(cCallbacks & a_NewCallbacks) + { + cCallbacks & Old = *m_Callbacks; + m_Callbacks = &a_NewCallbacks; + return Old; + } + +protected: + /// The world upon which to operate + cWorld * m_World; + + /// The callback to use for reporting + cCallbacks * m_Callbacks; +} ; + + + + diff --git a/source/Blocks/BlockCarpet.h b/source/Blocks/BlockCarpet.h new file mode 100644 index 000000000..f70ff45b6 --- /dev/null +++ b/source/Blocks/BlockCarpet.h @@ -0,0 +1,54 @@ + +// BlockCarpet.h + +// Declares the cBlockCarpetHandler class representing the handler for the carpet block + + + + +#pragma once + + + + + +class cBlockCarpetHandler : + public cBlockHandler +{ +public: + cBlockCarpetHandler(BLOCKTYPE a_BlockType); + + virtual const char * GetStepSound(void) override + { + return "step.cloth"; + } + + + virtual bool GetPlacementBlockTypeMeta( + cWorld * a_World, cPlayer * a_Player, + int a_BlockX, int a_BlockY, int a_BlockZ, char a_BlockFace, + int a_CursorX, int a_CursorY, int a_CursorZ, + BLOCKTYPE & a_BlockType, NIBBLETYPE & a_BlockMeta + ) override + { + a_BlockType = m_BlockType; + a_BlockMeta = a_Player->GetEquippedItem().m_ItemDamage & 0x0f; + return true; + } + + + virtual void ConvertToPickups(cItems & a_Pickups, NIBBLETYPE a_BlockMeta) override + { + a_Pickups.push_back(cItem(E_BLOCK_CARPET, a_BlockMeta)); + } + + + virtual bool CanBeAt(int a_RelX, int a_RelY, int a_RelZ, const cChunk & a_Chunk) override + { + return ((a_RelY > 0) && (a_Chunk.GetBlock(a_RelX, a_RelY - 1, a_RelZ) != E_BLOCK_AIR)); + } +} ; + + + + diff --git a/source/Blocks/BlockChest.h b/source/Blocks/BlockChest.h index 1975e11b2..8164942a3 100644 --- a/source/Blocks/BlockChest.h +++ b/source/Blocks/BlockChest.h @@ -3,6 +3,7 @@ #include "BlockEntity.h" #include "../World.h" +#include "../BlockArea.h" #include "../Player.h" diff --git a/source/Blocks/BlockDropSpenser.h b/source/Blocks/BlockDropSpenser.h index cfb607a7b..e5572da8a 100644 --- a/source/Blocks/BlockDropSpenser.h +++ b/source/Blocks/BlockDropSpenser.h @@ -5,6 +5,8 @@ #pragma once +#include "../Piston.h" + diff --git a/source/Blocks/BlockHandler.cpp b/source/Blocks/BlockHandler.cpp index 550a6795c..8978f4d46 100644 --- a/source/Blocks/BlockHandler.cpp +++ b/source/Blocks/BlockHandler.cpp @@ -5,59 +5,60 @@ #include "../World.h" #include "../Root.h" #include "../PluginManager.h" -#include "BlockSand.h" -#include "BlockGravel.h" -#include "BlockDoor.h" -#include "BlockFire.h" -#include "BlockRedstone.h" -#include "BlockRedstoneTorch.h" -#include "BlockRedstoneRepeater.h" -#include "BlockPiston.h" -#include "BlockWorkbench.h" -#include "BlockEntity.h" -#include "BlockVine.h" -#include "BlockTallGrass.h" -#include "BlockSnow.h" +#include "BlockBed.h" +#include "BlockBrewingStand.h" +#include "BlockCactus.h" +#include "BlockCarpet.h" +#include "BlockCauldron.h" +#include "BlockChest.h" #include "BlockCloth.h" -#include "BlockSlab.h" +#include "BlockCobWeb.h" +#include "BlockCrops.h" +#include "BlockDeadBush.h" #include "BlockDirt.h" -#include "BlockTorch.h" -#include "BlockWood.h" -#include "BlockLeaves.h" -#include "BlockSapling.h" +#include "BlockDoor.h" +#include "BlockDropSpenser.h" +#include "BlockEnderchest.h" +#include "BlockEntity.h" +#include "BlockFarmland.h" +#include "BlockFenceGate.h" +#include "BlockFire.h" +#include "BlockFlower.h" +#include "BlockFlowerPot.h" #include "BlockFluid.h" -#include "BlockChest.h" #include "BlockFurnace.h" -#include "BlockDropSpenser.h" -#include "BlockStairs.h" +#include "BlockGlass.h" +#include "BlockGlowstone.h" +#include "BlockGravel.h" +#include "BlockHopper.h" +#include "BlockIce.h" #include "BlockLadder.h" +#include "BlockLeaves.h" #include "BlockLever.h" -#include "BlockSign.h" -#include "BlockCrops.h" -#include "BlockSugarcane.h" -#include "BlockFlower.h" -#include "BlockMushroom.h" -#include "BlockCactus.h" -#include "BlockStems.h" -#include "BlockGlowstone.h" -#include "BlockStone.h" #include "BlockMelon.h" -#include "BlockIce.h" -#include "BlockOre.h" -#include "BlockNote.h" -#include "BlockBed.h" -#include "BlockFarmland.h" +#include "BlockMushroom.h" #include "BlockMycelium.h" +#include "BlockNote.h" +#include "BlockOre.h" +#include "BlockPiston.h" #include "BlockRail.h" -#include "BlockGlass.h" -#include "BlockEnderchest.h" -#include "BlockFenceGate.h" -#include "BlockFlowerPot.h" -#include "BlockCauldron.h" -#include "BlockBrewingStand.h" -#include "BlockCobWeb.h" -#include "BlockDeadBush.h" -#include "BlockHopper.h" +#include "BlockRedstone.h" +#include "BlockRedstoneRepeater.h" +#include "BlockRedstoneTorch.h" +#include "BlockSand.h" +#include "BlockSapling.h" +#include "BlockSign.h" +#include "BlockSlab.h" +#include "BlockSnow.h" +#include "BlockStairs.h" +#include "BlockStems.h" +#include "BlockStone.h" +#include "BlockSugarcane.h" +#include "BlockTallGrass.h" +#include "BlockTorch.h" +#include "BlockVine.h" +#include "BlockWood.h" +#include "BlockWorkbench.h" diff --git a/source/ChunkDef.h b/source/ChunkDef.h index 7f9c0ca98..3e78b59b1 100644 --- a/source/ChunkDef.h +++ b/source/ChunkDef.h @@ -137,7 +137,7 @@ public: /// Converts absolute block coords into relative (chunk + block) coords: inline static void AbsoluteToRelative(/* in-out */ int & a_X, int & a_Y, int & a_Z, /* out */ int & a_ChunkX, int & a_ChunkZ ) { - BlockToChunk(a_X, a_Y, a_Z, a_ChunkX, a_ChunkZ); + BlockToChunk(a_X, a_Z, a_ChunkX, a_ChunkZ); a_X = a_X - a_ChunkX * Width; a_Z = a_Z - a_ChunkZ * Width; @@ -145,9 +145,8 @@ public: /// Converts absolute block coords to chunk coords: - inline static void BlockToChunk( int a_X, int a_Y, int a_Z, int & a_ChunkX, int & a_ChunkZ ) + inline static void BlockToChunk(int a_X, int a_Z, int & a_ChunkX, int & a_ChunkZ) { - (void)a_Y; a_ChunkX = a_X / Width; if ((a_X < 0) && (a_X % Width != 0)) { diff --git a/source/ChunkMap.cpp b/source/ChunkMap.cpp index 0db4b898a..0d49ce9c4 100644 --- a/source/ChunkMap.cpp +++ b/source/ChunkMap.cpp @@ -345,7 +345,7 @@ void cChunkMap::BroadcastBlockAction(int a_BlockX, int a_BlockY, int a_BlockZ, c x = a_BlockX; y = a_BlockY; z = a_BlockZ; - cChunkDef::BlockToChunk(x, y, z, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(x, z, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); if (Chunk == NULL) { @@ -364,7 +364,7 @@ void cChunkMap::BroadcastBlockBreakAnimation(int a_entityID, int a_blockX, int a cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_blockX, a_blockY, a_blockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_blockX, a_blockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if (Chunk == NULL) { @@ -382,7 +382,7 @@ void cChunkMap::BroadcastBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, c { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { @@ -592,7 +592,7 @@ void cChunkMap::BroadcastSoundEffect(const AString & a_SoundName, int a_SrcX, in cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcY / 8, a_SrcZ / 8, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcZ / 8, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if (Chunk == NULL) { @@ -611,7 +611,7 @@ void cChunkMap::BroadcastSoundParticleEffect(int a_EffectID, int a_SrcX, int a_S cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcY / 8, a_SrcZ / 8, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_SrcX / 8, a_SrcZ / 8, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if (Chunk == NULL) { @@ -645,7 +645,7 @@ void cChunkMap::BroadcastThunderbolt(int a_BlockX, int a_BlockY, int a_BlockZ, c { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if (Chunk == NULL) { @@ -664,7 +664,7 @@ void cChunkMap::BroadcastUseBed(const cEntity & a_Entity, int a_BlockX, int a_Bl cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if (Chunk == NULL) { @@ -682,7 +682,7 @@ void cChunkMap::SendBlockEntity(int a_BlockX, int a_BlockY, int a_BlockZ, cClien { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { @@ -700,7 +700,7 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i // a_Player rclked block entity at the coords specified, handle it cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { @@ -713,11 +713,26 @@ void cChunkMap::UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, i +bool cChunkMap::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback) +{ + cCSLock Lock(m_CSLayers); + cChunkPtr Chunk = GetChunkNoLoad(a_ChunkX, ZERO_CHUNK_Y, a_ChunkZ); + if (Chunk == NULL) + { + return false; + } + return a_Callback.Item(Chunk); +} + + + + + void cChunkMap::WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ) { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, 0, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { @@ -735,8 +750,8 @@ void cChunkMap::WakeUpSimulatorsInArea(int a_MinBlockX, int a_MaxBlockX, int a_M { cSimulatorManager * SimMgr = m_World->GetSimulatorManager(); int MinChunkX, MinChunkZ, MaxChunkX, MaxChunkZ; - cChunkDef::BlockToChunk(a_MinBlockX, ZERO_CHUNK_Y, a_MinBlockZ, MinChunkX, MinChunkZ); - cChunkDef::BlockToChunk(a_MaxBlockX, ZERO_CHUNK_Y, a_MaxBlockZ, MaxChunkX, MaxChunkZ); + cChunkDef::BlockToChunk(a_MinBlockX, a_MinBlockZ, MinChunkX, MinChunkZ); + cChunkDef::BlockToChunk(a_MaxBlockX, a_MaxBlockZ, MaxChunkX, MaxChunkZ); for (int z = MinChunkZ; z <= MaxChunkZ; z++) { int MinZ = std::max(a_MinBlockZ, z * cChunkDef::Width); @@ -1903,7 +1918,7 @@ bool cChunkMap::SetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, const ASt { cCSLock Lock(m_CSLayers); int ChunkX, ChunkZ; - cChunkDef::BlockToChunk(a_BlockX, a_BlockY, a_BlockZ, ChunkX, ChunkZ); + cChunkDef::BlockToChunk(a_BlockX, a_BlockZ, ChunkX, ChunkZ); cChunkPtr Chunk = GetChunkNoGen(ChunkX, ZERO_CHUNK_Y, ChunkZ); if ((Chunk == NULL) || !Chunk->IsValid()) { diff --git a/source/ChunkMap.h b/source/ChunkMap.h index 899f290c5..183031808 100644 --- a/source/ChunkMap.h +++ b/source/ChunkMap.h @@ -35,6 +35,7 @@ typedef cItemCallback<cDispenserEntity> cDispenserCallback; typedef cItemCallback<cDropperEntity> cDropperCallback; typedef cItemCallback<cDropSpenserEntity> cDropSpenserCallback; typedef cItemCallback<cFurnaceEntity> cFurnaceCallback; +typedef cItemCallback<cChunk> cChunkCallback; @@ -79,6 +80,9 @@ public: /// a_Player rclked block entity at the coords specified, handle it void UseBlockEntity(cPlayer * a_Player, int a_X, int a_Y, int a_Z); + /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback + bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback); + /// Wakes up simulators for the specified block void WakeUpSimulators(int a_BlockX, int a_BlockY, int a_BlockZ); diff --git a/source/GroupManager.cpp b/source/GroupManager.cpp index 396ad2e2f..cef32dd58 100644 --- a/source/GroupManager.cpp +++ b/source/GroupManager.cpp @@ -47,11 +47,8 @@ cGroupManager::cGroupManager() cIniFile IniFile("groups.ini"); if (!IniFile.ReadFile()) { - LOGINFO("groups.ini inaccessible, using groups.example.ini for defaults!"); - IniFile.Path("groups.example.ini"); - IniFile.ReadFile(); - IniFile.Path("groups.ini"); - IniFile.WriteFile(); + LOGWARNING("groups.ini inaccessible, no groups are defined"); + return; } unsigned int NumKeys = IniFile.GetNumKeys(); diff --git a/source/Item.h b/source/Item.h index fc54da51d..fee861050 100644 --- a/source/Item.h +++ b/source/Item.h @@ -55,7 +55,10 @@ public: { if (!IsValidItem(m_ItemType)) { - LOGWARNING("%s: creating an invalid item type (%d), resetting to empty.", __FUNCTION__, a_ItemType); + if (m_ItemType != E_BLOCK_AIR) + { + LOGWARNING("%s: creating an invalid item type (%d), resetting to empty.", __FUNCTION__, a_ItemType); + } Empty(); } } diff --git a/source/LineBlockTracer.cpp b/source/LineBlockTracer.cpp new file mode 100644 index 000000000..03464314a --- /dev/null +++ b/source/LineBlockTracer.cpp @@ -0,0 +1,261 @@ + +// LineBlockTracer.cpp + +// Implements the cLineBlockTracer class representing a cBlockTracer that traces along a straight line between two points + +#include "Globals.h" +#include "LineBlockTracer.h" +#include "Vector3d.h" +#include "World.h" +#include "Chunk.h" + + + + + + +cLineBlockTracer::cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks) : + super(a_World, a_Callbacks) +{ +} + + + + + +bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks & a_Callbacks, const Vector3d & a_Start, const Vector3d & a_End) +{ + cLineBlockTracer Tracer(a_World, a_Callbacks); + return Tracer.Trace(a_Start.x, a_Start.y, a_Start.z, a_End.x, a_End.y, a_End.z); +} + + + + + +bool cLineBlockTracer::Trace(cWorld & a_World, cBlockTracer::cCallbacks &a_Callbacks, double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ) +{ + cLineBlockTracer Tracer(a_World, a_Callbacks); + return Tracer.Trace(a_StartX, a_StartY, a_StartZ, a_EndX, a_EndY, a_EndZ); +} + + + + + +bool cLineBlockTracer::Trace(double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ) +{ + // Initialize the member veriables: + m_StartX = a_StartX; + m_StartY = a_StartY; + m_StartZ = a_StartZ; + m_EndX = a_EndX; + m_EndY = a_EndY; + m_EndZ = a_EndZ; + m_DirX = (m_StartX < m_EndX) ? 1 : -1; + m_DirY = (m_StartY < m_EndY) ? 1 : -1; + m_DirZ = (m_StartZ < m_EndZ) ? 1 : -1; + + // Check the start coords, adjust into the world: + if (m_StartY < 0) + { + if (m_EndY < 0) + { + // Nothing to trace + m_Callbacks->OnNoMoreHits(); + return true; + } + FixStartBelowWorld(); + m_Callbacks->OnIntoWorld(m_StartX, m_StartY, m_StartZ); + } + else if (m_StartY >= cChunkDef::Height) + { + if (m_EndY >= cChunkDef::Height) + { + m_Callbacks->OnNoMoreHits(); + return true; + } + FixStartAboveWorld(); + m_Callbacks->OnIntoWorld(m_StartX, m_StartY, m_StartZ); + } + + m_CurrentX = (int)floor(m_StartX); + m_CurrentY = (int)floor(m_StartY); + m_CurrentZ = (int)floor(m_StartZ); + + m_DiffX = m_EndX - m_StartX; + m_DiffY = m_EndY - m_StartY; + m_DiffZ = m_EndZ - m_StartZ; + + // The actual trace is handled with ChunkMapCS locked by calling our Item() for the specified chunk + int BlockX = (int)floor(m_StartX); + int BlockZ = (int)floor(m_StartZ); + int ChunkX, ChunkZ; + cChunkDef::BlockToChunk(BlockX, BlockZ, ChunkX, ChunkZ); + return m_World->DoWithChunk(ChunkX, ChunkZ, *this); +} + + + + + +void cLineBlockTracer::FixStartAboveWorld(void) +{ + // We must set the start Y to less than cChunkDef::Height so that it is considered inside the world later on + // Therefore we use an EPS-offset from the height, as small as reasonably possible. + const double Height = (double)cChunkDef::Height - 0.00001; + CalcXZIntersection(Height, m_StartX, m_StartZ); + m_StartY = Height; +} + + + + + +void cLineBlockTracer::FixStartBelowWorld(void) +{ + CalcXZIntersection(0, m_StartX, m_StartZ); + m_StartY = 0; +} + + + + + +void cLineBlockTracer::CalcXZIntersection(double a_Y, double & a_IntersectX, double & a_IntersectZ) +{ + double Ratio = (m_StartY - a_Y) / (m_StartY - m_EndY); + a_IntersectX = m_StartX + (m_EndX - m_StartX) * Ratio; + a_IntersectZ = m_StartZ + (m_EndZ - m_StartZ) * Ratio; +} + + + + + +bool cLineBlockTracer::MoveToNextBlock(void) +{ + // Find out which of the current block's walls gets hit by the path: + static const double EPS = 0.00001; + double Coeff = 1; + enum eDirection + { + dirNONE, + dirX, + dirY, + dirZ, + } Direction = dirNONE; + if (abs(m_DiffX) > EPS) + { + double DestX = (m_DirX > 0) ? (m_CurrentX + 1) : m_CurrentX; + Coeff = (DestX - m_StartX) / m_DiffX; + if (Coeff <= 1) + { + Direction = dirX; + } + } + if (abs(m_DiffY) > EPS) + { + double DestY = (m_DirY > 0) ? (m_CurrentY + 1) : m_CurrentY; + double CoeffY = (DestY - m_StartY) / m_DiffY; + if (CoeffY < Coeff) + { + Coeff = CoeffY; + Direction = dirY; + } + } + if (abs(m_DiffZ) > EPS) + { + double DestZ = (m_DirZ > 0) ? (m_CurrentZ + 1) : m_CurrentZ; + double CoeffZ = (DestZ - m_StartZ) / m_DiffZ; + if (CoeffZ < Coeff) + { + Coeff = CoeffZ; + Direction = dirZ; + } + } + + // Based on the wall hit, adjust the current coords + switch (Direction) + { + case dirX: m_CurrentX += m_DirX; break; + case dirY: m_CurrentY += m_DirY; break; + case dirZ: m_CurrentZ += m_DirZ; break; + case dirNONE: return false; + } + return true; +} + + + + + +bool cLineBlockTracer::Item(cChunk * a_Chunk) +{ + ASSERT((m_CurrentY >= 0) && (m_CurrentY < cChunkDef::Height)); // This should be provided by FixStartAboveWorld() / FixStartBelowWorld() + + // This is the actual line tracing loop. + bool Finished = false; + while (true) + { + // Report the current block through the callbacks: + if (a_Chunk == NULL) + { + m_Callbacks->OnNoChunk(); + return false; + } + if (a_Chunk->IsValid()) + { + BLOCKTYPE BlockType; + NIBBLETYPE BlockMeta; + int RelX = m_CurrentX - a_Chunk->GetPosX() * cChunkDef::Width; + int RelZ = m_CurrentZ - a_Chunk->GetPosZ() * cChunkDef::Width; + a_Chunk->GetBlockTypeMeta(RelX, m_CurrentY, RelZ, BlockType, BlockMeta); + if (m_Callbacks->OnNextBlock(m_CurrentX, m_CurrentY, m_CurrentZ, BlockType, BlockMeta)) + { + // The callback terminated the trace + return false; + } + } + else + { + if (m_Callbacks->OnNextBlockNoData(m_CurrentX, m_CurrentY, m_CurrentZ)) + { + // The callback terminated the trace + return false; + } + } + + // Move to next block + if (!MoveToNextBlock()) + { + // We've reached the end + m_Callbacks->OnNoMoreHits(); + return true; + } + + // Update the current chunk + if (a_Chunk != NULL) + { + a_Chunk = a_Chunk->GetNeighborChunk(m_CurrentX, m_CurrentZ); + } + + if ((m_CurrentY < 0) || (m_CurrentY >= cChunkDef::Height)) + { + // We've gone out of the world, that's the end of this trace + double IntersectX, IntersectZ; + CalcXZIntersection(m_CurrentY, IntersectX, IntersectZ); + if (m_Callbacks->OnOutOfWorld(IntersectX, m_CurrentY, IntersectZ)) + { + // The callback terminated the trace + return false; + } + m_Callbacks->OnNoMoreHits(); + return true; + } + } +} + + + + diff --git a/source/LineBlockTracer.h b/source/LineBlockTracer.h new file mode 100644 index 000000000..4616cb191 --- /dev/null +++ b/source/LineBlockTracer.h @@ -0,0 +1,84 @@ + +// LineBlockTracer.h + +// Declares the cLineBlockTracer class representing a cBlockTracer that traces along a straight line between two points + + + + + +#pragma once + +#include "BlockTracer.h" + + + + + +// fwd: Chunk.h +class cChunk; + +// fwd: cChunkMap.h +typedef cItemCallback<cChunk> cChunkCallback; + + + + + + +class cLineBlockTracer : + public cBlockTracer, + public cChunkCallback +{ + typedef cBlockTracer super; + +public: + cLineBlockTracer(cWorld & a_World, cCallbacks & a_Callbacks); + + /// Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) + bool Trace(double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ); + + // Utility functions for simple one-line usage: + /// Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) + static bool Trace(cWorld & a_World, cCallbacks & a_Callbacks, double a_StartX, double a_StartY, double a_StartZ, double a_EndX, double a_EndY, double a_EndZ); + + /// Traces one line between Start and End; returns true if the entire line was traced (until OnNoMoreHits()) + static bool Trace(cWorld & a_World, cCallbacks & a_Callbacks, const Vector3d & a_Start, const Vector3d & a_End); + +protected: + // The start point of the trace + double m_StartX, m_StartY, m_StartZ; + + // The end point of the trace + double m_EndX, m_EndY, m_EndZ; + + // The difference in coords, End - Start + double m_DiffX, m_DiffY, m_DiffZ; + + // The increment at which the block coords are going from Start to End; either +1 or -1 + int m_DirX, m_DirY, m_DirZ; + + // The current block + int m_CurrentX, m_CurrentY, m_CurrentZ; + + + /// Adjusts the start point above the world to just at the world's top + void FixStartAboveWorld(void); + + /// Adjusts the start point below the world to just at the world's bottom + void FixStartBelowWorld(void); + + /// Calculates the XZ coords of an intersection with the specified Yconst plane; assumes that such an intersection exists + void CalcXZIntersection(double a_Y, double & a_IntersectX, double & a_IntersectZ); + + /// Moves m_Current to the next block on the line; returns false if no move is possible (reached the end) + bool MoveToNextBlock(void); + + // cChunkCallback overrides: + virtual bool Item(cChunk * a_Chunk) override; +} ; + + + + + diff --git a/source/LuaScript.cpp b/source/LuaScript.cpp index 8d92c238f..d406c2c02 100644 --- a/source/LuaScript.cpp +++ b/source/LuaScript.cpp @@ -6,34 +6,14 @@ #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "LuaScript.h" - -extern "C" -{ -#include "lualib.h" -} - #include "tolua++.h" -#include "Bindings.h" -#include "ManualBindings.h" - -// fwd: SQLite/lsqlite3.c -extern "C" -{ - LUALIB_API int luaopen_lsqlite3(lua_State * L); -} - -// fwd: LuaExpat/lxplib.c: -extern "C" -{ - int luaopen_lxp(lua_State * L); -} cLuaScript::cLuaScript() - : m_LuaState(NULL) + : m_LuaState("cLuaScript") { } @@ -42,197 +22,45 @@ cLuaScript::cLuaScript() -cLuaScript::~cLuaScript() -{ - if( m_LuaState ) - { - lua_close( m_LuaState ); - m_LuaState = 0; - } -} - - - - - void cLuaScript::Initialize() { // Check to see if this script has not been initialized before - ASSERT(!m_LuaState); + ASSERT(!m_LuaState.IsValid()); // Create a Lua state and bind all libraries to it - m_LuaState = lua_open(); - luaL_openlibs(m_LuaState); - tolua_AllToLua_open(m_LuaState); - ManualBindings::Bind(m_LuaState); - luaopen_lsqlite3(m_LuaState); - luaopen_lxp(m_LuaState); + m_LuaState.Create(); } -bool cLuaScript::LoadFile( const char* a_FilePath ) +bool cLuaScript::LoadFile(const char * a_FilePath) { // Make sure the plugin is initialized - ASSERT(m_LuaState); - - // Load the file into the Lua state - int s = luaL_loadfile(m_LuaState, a_FilePath ); - if (ReportErrors(s)) - { - return false; - } - return true; -} - - - - - -bool cLuaScript::Execute() -{ - // Make sure we got a Lua state - ASSERT(m_LuaState); - - // Execute the script as it is right now - int s = lua_pcall(m_LuaState, 0, LUA_MULTRET, 0); - if( ReportErrors( s ) ) - { - return false; - } - return true; -} - - - - - -bool cLuaScript::ReportErrors( int a_Status ) -{ - if (a_Status == 0) - { - // No error to report - return false; - } - - // Status was set to error so get the error from the Lua state and log it - LOGERROR("LUA: %s", lua_tostring(m_LuaState, -1)); - lua_pop(m_LuaState, 1); - - // Return true to indicate that an error was returned - return true; -} - - - - - -bool cLuaScript::LuaPushFunction( const char * a_FunctionName, bool a_bLogError /*= true*/ ) -{ - ASSERT(m_LuaState); - - // Find and push the function on the Lua stack - lua_getglobal(m_LuaState, a_FunctionName); - - // Make sure we found a function - if (!lua_isfunction(m_LuaState, -1)) - { - if (a_bLogError) - { - LOGWARN("LUA: Could not find function %s()", a_FunctionName); - } - - // Pop the pushed 'object' back - lua_pop(m_LuaState, 1); - return false; - } - - // Successfully pushed a function to the Lua stack - return true; -} + ASSERT(m_LuaState.IsValid()); - - - - -bool cLuaScript::LuaCallFunction( int a_NumArgs, int a_NumResults, const char * a_FunctionName ) -{ - ASSERT(m_LuaState); - - // Make sure there's a lua function on the stack - ASSERT(lua_isfunction(m_LuaState, -a_NumArgs - 1)); - - // Call the desired function - int s = lua_pcall(m_LuaState, a_NumArgs, a_NumResults, 0); - - // Check for errors - if (ReportErrors(s)) - { - LOGWARN("LUA: Error calling function %s()", a_FunctionName); - return false; - } - - // Successfully executed function - return true; -} - - - - - -bool cLuaScript::CallFunction( const char* a_Function, AString& ReturnedString ) -{ - // Make sure we have the required things to call a function - ASSERT(m_LuaState); - ASSERT(a_Function); - - // Push the desired function on the stack - if (!LuaPushFunction(a_Function)) - { - return false; - } - - if (!LuaCallFunction(0, 1, a_Function)) - { - return false; - } - - if (lua_isstring(m_LuaState, -1)) - { - ReturnedString = tolua_tostring(m_LuaState, -1, ""); - } - lua_pop(m_LuaState, 1); - return true; + return m_LuaState.LoadFile(a_FilePath); } -bool cLuaScript::CallFunction( const char* a_Function, const sLuaUsertype& a_UserType, AString& ReturnedString ) +bool cLuaScript::CallShowPage(cWebAdmin & a_WebAdmin, HTTPTemplateRequest & a_Request, AString & a_ReturnedString) { - // Make sure we have the required things to call a function - ASSERT(m_LuaState); - ASSERT(a_Function); - - // Push the desired function on the stack - if (!LuaPushFunction(a_Function)) + ASSERT(m_LuaState.IsValid()); + + m_LuaState.PushFunction("ShowPage"); + m_LuaState.PushUserType(&a_WebAdmin, "cWebAdmin"); + m_LuaState.PushUserType(&a_Request, "HTTPTemplateRequest"); + if (!m_LuaState.CallFunction(1)) { return false; } - - tolua_pushusertype(m_LuaState, a_UserType.Object, a_UserType.ClassName); - - if (!LuaCallFunction(1, 1, a_Function)) - { - return false; - } - if (lua_isstring(m_LuaState, -1)) { - ReturnedString = tolua_tostring(m_LuaState, -1, ""); + a_ReturnedString.assign(tolua_tostring(m_LuaState, -1, "")); } lua_pop(m_LuaState, 1); return true; @@ -241,38 +69,3 @@ bool cLuaScript::CallFunction( const char* a_Function, const sLuaUsertype& a_Use - -bool cLuaScript::CallFunction( const char* a_Function, const sLuaUsertype& a_UserType1, const sLuaUsertype& a_UserType2, AString& ReturnedString ) -{ - // Make sure we have the required things to call a function - ASSERT(m_LuaState); - ASSERT(a_Function); - - // Push the desired function on the stack - if (!LuaPushFunction(a_Function)) - { - return false; - } - - tolua_pushusertype(m_LuaState, a_UserType1.Object, a_UserType1.ClassName); - tolua_pushusertype(m_LuaState, a_UserType2.Object, a_UserType2.ClassName); - - if (!LuaCallFunction(2, 1, a_Function)) - { - return false; - } - - if (lua_isstring(m_LuaState, -1)) - { - ReturnedString = tolua_tostring(m_LuaState, -1, ""); - } - lua_pop(m_LuaState, 1); - return true; -} - - - - - - - diff --git a/source/LuaScript.h b/source/LuaScript.h index f98b2e65b..99ccb3d49 100644 --- a/source/LuaScript.h +++ b/source/LuaScript.h @@ -9,19 +9,15 @@ #pragma once -struct lua_State; +#include "LuaState.h" -struct sLuaUsertype -{ - sLuaUsertype(void* a_pObject, const char* a_pClassName) : Object(a_pObject), ClassName(a_pClassName) {} - // - void* Object; - const char* ClassName; -} ; +// fwd: +class cWebAdmin; +struct HTTPTemplateRequest; @@ -30,32 +26,18 @@ struct sLuaUsertype class cLuaScript { public: - cLuaScript(); - ~cLuaScript(); + cLuaScript(void); /// Prepares a Lua state - void Initialize(); + void Initialize(); /// Load a Lua script on the given path - bool LoadFile(const char* a_FilePath); - - /// Execute the loaded Lua script - bool Execute(); + bool LoadFile(const char * a_FilePath); - /// Call a function on the Lua script. Put all overloads here - bool CallFunction(const char* a_Function, AString& ReturnedString); - bool CallFunction(const char* a_Function, const sLuaUsertype& a_UserType, AString& ReturnedString); - bool CallFunction(const char* a_Function, const sLuaUsertype& a_UserType1, const sLuaUsertype& a_UserType2, AString& ReturnedString); + bool CallShowPage(cWebAdmin & a_WebAdmin, HTTPTemplateRequest & a_Request, AString & a_ReturnedString); protected: - /// Reports an error in the log if a_Status is flagged as an error. Returns true when a_Status is flagged as error, returns false when no error occured. - bool ReportErrors(int a_Status); - - /// Helper functions for calling functions in Lua - bool LuaPushFunction(const char * a_FunctionName, bool a_bLogError = true); - bool LuaCallFunction(int a_NumArgs, int a_NumResults, const char * a_FunctionName ); // a_FunctionName is only used for error messages, nothing else -private: - lua_State* m_LuaState; + cLuaState m_LuaState; } ; diff --git a/source/LuaState.cpp b/source/LuaState.cpp new file mode 100644 index 000000000..664ba8147 --- /dev/null +++ b/source/LuaState.cpp @@ -0,0 +1,646 @@ + +// LuaState.cpp + +// Implements the cLuaState class representing the wrapper over lua_State *, provides associated helper functions + +#include "Globals.h" +#include "LuaState.h" + +extern "C" +{ + #include "lualib.h" +} + +#include "tolua++.h" +#include "Bindings.h" +#include "ManualBindings.h" + +// fwd: SQLite/lsqlite3.c +extern "C" +{ + LUALIB_API int luaopen_lsqlite3(lua_State * L); +} + +// fwd: LuaExpat/lxplib.c: +extern "C" +{ + int luaopen_lxp(lua_State * L); +} + + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cLuaState: + +cLuaState::cLuaState(const AString & a_SubsystemName) : + m_LuaState(NULL), + m_IsOwned(false), + m_SubsystemName(a_SubsystemName), + m_NumCurrentFunctionArgs(-1) +{ +} + + + + + +cLuaState::cLuaState(lua_State * a_AttachState) : + m_LuaState(a_AttachState), + m_IsOwned(false), + m_SubsystemName("<attached>"), + m_NumCurrentFunctionArgs(-1) +{ +} + + + + + +cLuaState::~cLuaState() +{ + if (IsValid()) + { + if (m_IsOwned) + { + Close(); + } + else + { + Detach(); + } + } +} + + + + + +void cLuaState::Create(void) +{ + if (m_LuaState != NULL) + { + LOGWARNING("%s: Trying to create an already-existing LuaState, ignoring.", __FUNCTION__); + return; + } + m_LuaState = lua_open(); + luaL_openlibs(m_LuaState); + tolua_AllToLua_open(m_LuaState); + ManualBindings::Bind(m_LuaState); + luaopen_lsqlite3(m_LuaState); + luaopen_lxp(m_LuaState); + m_IsOwned = true; +} + + + + + +void cLuaState::Close(void) +{ + if (m_LuaState == NULL) + { + LOGWARNING("%s: Trying to close an invalid LuaState, ignoring.", __FUNCTION__); + return; + } + if (!m_IsOwned) + { + LOGWARNING( + "%s: Detected mis-use, calling Close() on an attached state (0x%p). Detaching instead.", + __FUNCTION__, m_LuaState + ); + Detach(); + return; + } + lua_close(m_LuaState); + m_LuaState = NULL; + m_IsOwned = false; +} + + + + + +void cLuaState::Attach(lua_State * a_State) +{ + if (m_LuaState != NULL) + { + LOGINFO("%s: Already contains a LuaState (0x%p), will be closed / detached.", __FUNCTION__, m_LuaState); + if (m_IsOwned) + { + Close(); + } + else + { + Detach(); + } + } + m_LuaState = a_State; + m_IsOwned = false; +} + + + + + +void cLuaState::Detach(void) +{ + if (m_LuaState == NULL) + { + return; + } + if (m_IsOwned) + { + LOGWARNING( + "%s: Detected a mis-use, calling Detach() when the state is owned. Closing the owned state (0x%p).", + __FUNCTION__, m_LuaState + ); + Close(); + return; + } + m_LuaState = NULL; +} + + + + + +bool cLuaState::LoadFile(const AString & a_FileName) +{ + ASSERT(IsValid()); + + // Load the file: + int s = luaL_loadfile(m_LuaState, a_FileName.c_str()); + if (ReportErrors(s)) + { + LOGWARNING("Can't load %s because of an error in file %s", m_SubsystemName.c_str(), a_FileName.c_str()); + return false; + } + + // Execute the globals: + s = lua_pcall(m_LuaState, 0, LUA_MULTRET, 0); + if (ReportErrors(s)) + { + LOGWARNING("Error in %s in file %s", m_SubsystemName.c_str(), a_FileName.c_str()); + return false; + } + + return true; +} + + + + + +bool cLuaState::PushFunction(const char * a_FunctionName, bool a_ShouldLogFailure /* = true */) +{ + ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack + + if (!IsValid()) + { + // This happens if cPlugin::Initialize() fails with an error + return false; + } + + lua_getglobal(m_LuaState, a_FunctionName); + if (!lua_isfunction(m_LuaState, -1)) + { + if (a_ShouldLogFailure) + { + LOGWARNING("Error in %s: Could not find function %s()", m_SubsystemName.c_str(), a_FunctionName); + } + lua_pop(m_LuaState, 1); + return false; + } + m_CurrentFunctionName.assign(a_FunctionName); + m_NumCurrentFunctionArgs = 0; + return true; +} + + + + + +bool cLuaState::PushFunctionFromRegistry(int a_FnRef) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack + + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // same as lua_getref() + if (!lua_isfunction(m_LuaState, -1)) + { + lua_pop(m_LuaState, 1); + return false; + } + m_CurrentFunctionName = "<callback>"; + m_NumCurrentFunctionArgs = 0; + return true; +} + + + + + +bool cLuaState::PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack + + lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef); // Get the table ref + if (!lua_istable(m_LuaState, -1)) + { + // Not a table, bail out + lua_pop(m_LuaState, 1); + return false; + } + lua_getfield(m_LuaState, -1, a_FnName); + if (lua_isnil(m_LuaState, -1) || !lua_isfunction(m_LuaState, -1)) + { + // Not a valid function, bail out + lua_pop(m_LuaState, 2); + return false; + } + lua_remove(m_LuaState, -2); // Remove the table ref from the stack + m_CurrentFunctionName = "<table_callback>"; + m_NumCurrentFunctionArgs = 0; + return true; +} + + + + + +void cLuaState::PushStringVector(const AStringVector & a_Vector) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + lua_createtable(m_LuaState, a_Vector.size(), 0); + int newTable = lua_gettop(m_LuaState); + int index = 1; + for (AStringVector::const_iterator itr = a_Vector.begin(), end = a_Vector.end(); itr != end; ++itr, ++index) + { + tolua_pushstring(m_LuaState, itr->c_str()); + lua_rawseti(m_LuaState, newTable, index); + } + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushUserType(void * a_Object, const char * a_Type) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Object, a_Type); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushNumber(int a_Value) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushnumber(m_LuaState, a_Value); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushNumber(double a_Value) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushnumber(m_LuaState, a_Value); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushString(const char * a_Value) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushstring(m_LuaState, a_Value); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushBool(bool a_Value) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushboolean(m_LuaState, a_Value ? 1 : 0); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushObject(cWorld * a_World) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_World, "cWorld"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushObject(cPlayer * a_Player) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushObject(cEntity * a_Entity) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Entity, "cEntity"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushObject(cItem * a_Item) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Item, "cItem"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushObject(cItems * a_Items) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Items, "cItems"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushObject(cClientHandle * a_Client) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Client, "cClientHandle"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +void cLuaState::PushObject(cPickup * a_Pickup) +{ + ASSERT(IsValid()); + ASSERT(m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + + tolua_pushusertype(m_LuaState, a_Pickup, "cPickup"); + m_NumCurrentFunctionArgs += 1; +} + + + + + +bool cLuaState::CallFunction(int a_NumResults) +{ + ASSERT (m_NumCurrentFunctionArgs >= 0); // A function must be pushed to stack first + ASSERT(lua_isfunction(m_LuaState, -m_NumCurrentFunctionArgs - 1)); + + int s = lua_pcall(m_LuaState, m_NumCurrentFunctionArgs, a_NumResults, 0); + if (ReportErrors(s)) + { + LOGWARNING("Error in %s calling function %s()", m_SubsystemName.c_str(), m_CurrentFunctionName.c_str()); + m_NumCurrentFunctionArgs = -1; + m_CurrentFunctionName.clear(); + return false; + } + m_NumCurrentFunctionArgs = -1; + m_CurrentFunctionName.clear(); + return true; +} + + + + + +bool cLuaState::CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_isusertype(m_LuaState, i, a_UserType, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + +bool cLuaState::CheckParamTable(int a_StartParam, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_istable(m_LuaState, i, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + +bool cLuaState::CheckParamNumber(int a_StartParam, int a_EndParam) +{ + ASSERT(IsValid()); + + if (a_EndParam < 0) + { + a_EndParam = a_StartParam; + } + + tolua_Error tolua_err; + for (int i = a_StartParam; i <= a_EndParam; i++) + { + if (tolua_isnumber(m_LuaState, i, 0, &tolua_err)) + { + continue; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; + } // for i - Param + + // All params checked ok + return true; +} + + + + + +bool cLuaState::CheckParamEnd(int a_Param) +{ + tolua_Error tolua_err; + if (tolua_isnoobj(m_LuaState, a_Param, &tolua_err)) + { + return true; + } + // Not the correct parameter + lua_Debug entry; + VERIFY(lua_getstack(m_LuaState, 0, &entry)); + VERIFY(lua_getinfo (m_LuaState, "n", &entry)); + AString ErrMsg = Printf("#ferror in function '%s': Too many arguments.", (entry.name != NULL) ? entry.name : "?"); + tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err); + return false; +} + + + + + +bool cLuaState::ReportErrors(int a_Status) +{ + return ReportErrors(m_LuaState, a_Status); +} + + + + + +bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status) +{ + if (a_Status == 0) + { + // No error to report + return false; + } + + LOGWARNING("LUA: %d - %s", a_Status, lua_tostring(a_LuaState, -1)); + lua_pop(a_LuaState, 1); + return true; +} + + + + + +/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// cLuaState::cRef: + +cLuaState::cRef::cRef(cLuaState & a_LuaState, int a_StackPos) : + m_LuaState(a_LuaState) +{ + ASSERT(m_LuaState.IsValid()); + + lua_pushvalue(m_LuaState, a_StackPos); // Push a copy of the value at a_StackPos onto the stack + m_Ref = luaL_ref(m_LuaState, LUA_REGISTRYINDEX); +} + + + + + +cLuaState::cRef::~cRef() +{ + ASSERT(m_LuaState.IsValid()); + + if (IsValid()) + { + luaL_unref(m_LuaState, LUA_REGISTRYINDEX, m_Ref); + } +} + + + + diff --git a/source/LuaState.h b/source/LuaState.h new file mode 100644 index 000000000..6820f1777 --- /dev/null +++ b/source/LuaState.h @@ -0,0 +1,198 @@ + +// LuaState.h + +// Declares the cLuaState class representing the wrapper over lua_State *, provides associated helper functions + +/* +The contained lua_State can be either owned or attached. +Owned lua_State is created by calling Create() and the cLuaState automatically closes the state +Or, lua_State can be attached by calling Attach(), the cLuaState doesn't close such a state +Attaching a state will automatically close an owned state. + +Calling a Lua function is done by pushing the function, either by PushFunction() or PushFunctionFromRegistry(), +then pushing the arguments (PushString(), PushNumber(), PushUserData() etc.) and finally +executing CallFunction(). cLuaState automatically keeps track of the number of arguments and the name of the +function (for logging purposes), which makes the call less error-prone. + +Reference management is provided by the cLuaState::cRef class. This is used when you need to hold a reference to +any Lua object across several function calls; usually this is used for callbacks. The class is RAII-like, with +automatic resource management. +*/ + + + + +#pragma once + +extern "C" +{ + #include "lauxlib.h" +} + + + + + +class cWorld; +class cPlayer; +class cEntity; +class cItem; +class cItems; +class cClientHandle; +class cPickup; + + + + + +/// Encapsulates a Lua state and provides some syntactic sugar for common operations +class cLuaState +{ +public: + + /// Used for storing references to object in the global registry + class cRef + { + public: + /// Creates a reference in the specified LuaState for object at the specified StackPos + cRef(cLuaState & a_LuaState, int a_StackPos); + ~cRef(); + + /// Returns true if the reference is valid + bool IsValid(void) const {return (m_Ref != LUA_REFNIL); } + + /// Allows to use this class wherever an int (i. e. ref) is to be used + operator int(void) { return m_Ref; } + + protected: + cLuaState & m_LuaState; + int m_Ref; + } ; + + + /** Creates a new instance. The LuaState is not initialized. + a_SubsystemName is used for reporting problems in the console, it is "plugin %s" for plugins, + or "LuaScript" for the cLuaScript template + */ + cLuaState(const AString & a_SubsystemName); + + /** Creates a new instance. The a_AttachState is attached. + Subsystem name is set to "<attached>". + */ + explicit cLuaState(lua_State * a_AttachState); + + ~cLuaState(); + + /// Allows this object to be used in the same way as a lua_State *, for example in the LuaLib functions + operator lua_State * (void) { return m_LuaState; } + + /// Creates the m_LuaState, if not closed already. This state will be automatically closed in the destructor + void Create(void); + + /// Closes the m_LuaState, if not closed already + void Close(void); + + /// Attaches the specified state. Operations will be carried out on this state, but it will not be closed in the destructor + void Attach(lua_State * a_State); + + /// Detaches a previously attached state. + void Detach(void); + + /// Returns true if the m_LuaState is valid + bool IsValid(void) const { return (m_LuaState != NULL); } + + /** Loads the specified file + Returns false and logs a warning to the console if not successful (but the LuaState is kept open). + m_SubsystemName is displayed in the warning log message. + */ + bool LoadFile(const AString & a_FileName); + + /** Pushes the function of the specified name onto the stack. + Returns true if successful. + If a_ShouldLogFail is true, logs a warning on failure (incl. m_SubsystemName) + */ + bool PushFunction(const char * a_FunctionName, bool a_ShouldLogFailure = true); + + /** Pushes a function that has been saved into the global registry, identified by a_FnRef. + Returns true if successful. Logs a warning on failure + */ + bool PushFunctionFromRegistry(int a_FnRef); + + /** Pushes a function that is stored in a table ref. + Returns true if successful, false on failure. Doesn't log failure. + */ + bool PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName); + + /// Pushes a string vector, as a table, onto the stack + void PushStringVector(const AStringVector & a_Vector); + + /// Pushes a usertype of the specified class type onto the stack + void PushUserType(void * a_Object, const char * a_Type); + + /// Pushes an integer onto the stack + void PushNumber(int a_Value); + + /// Pushes a double onto the stack + void PushNumber(double a_Value); + + /// Pushes a string onto the stack + void PushString(const char * a_Value); + + /// Pushes a bool onto the stack + void PushBool(bool a_Value); + + // Special family of functions that do PushUserType internally, but require one less parameter + void PushObject(cWorld * a_World); + void PushObject(cPlayer * a_Player); + void PushObject(cEntity * a_Entity); + void PushObject(cItem * a_Item); + void PushObject(cItems * a_Items); + void PushObject(cClientHandle * a_ClientHandle); + void PushObject(cPickup * a_Pickup); + + /** + Calls the function that has been pushed onto the stack by PushFunction(), + with arguments pushed by PushXXX(). + Returns true if successful, logs a warning on failure. + */ + bool CallFunction(int a_NumReturnValues); + + /// Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not + bool CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam = -1); + + /// Returns true if the specified parameters on the stack are a table; also logs warning if not + bool CheckParamTable(int a_StartParam, int a_EndParam = -1); + + /// Returns true if the specified parameters on the stack are a number; also logs warning if not + bool CheckParamNumber(int a_StartParam, int a_EndParam = -1); + + /// Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters) + bool CheckParamEnd(int a_Param); + + /// If the status is nonzero, prints the text on the top of Lua stack and returns true + bool ReportErrors(int status); + + /// If the status is nonzero, prints the text on the top of Lua stack and returns true + static bool ReportErrors(lua_State * a_LuaState, int status); + +protected: + lua_State * m_LuaState; + + /// If true, the state is owned by this object and will be auto-Closed. False => attached state + bool m_IsOwned; + + /** The subsystem name is used for reporting errors to the console, it is either "plugin %s" or "LuaScript" + whatever is given to the constructor + */ + AString m_SubsystemName; + + /// Name of the currently pushed function (for the Push / Call chain) + AString m_CurrentFunctionName; + + /// Number of arguments currently pushed (for the Push / Call chain) + int m_NumCurrentFunctionArgs; +} ; + + + + diff --git a/source/ManualBindings.cpp b/source/ManualBindings.cpp index 7a13d94c0..4041ccc94 100644 --- a/source/ManualBindings.cpp +++ b/source/ManualBindings.cpp @@ -19,13 +19,8 @@ #include "BlockEntities/FurnaceEntity.h" #include "md5/md5.h" #include "LuaWindow.h" - - - - - -// fwd: LuaCommandBinder.cpp -bool report_errors(lua_State* lua, int status); +#include "LuaState.h" +#include "LineBlockTracer.h" @@ -83,23 +78,14 @@ int lua_do_error(lua_State* L, const char * a_pFormat, ...) * Lua bound functions with special return types **/ -static int tolua_StringSplit(lua_State* tolua_S) +static int tolua_StringSplit(lua_State * tolua_S) { - std::string str = ((std::string) tolua_tocppstring(tolua_S,1,0)); - std::string delim = ((std::string) tolua_tocppstring(tolua_S,2,0)); - - AStringVector Split = StringSplit( str, delim ); + cLuaState LuaState(tolua_S); + std::string str = (std::string)tolua_tocppstring(LuaState, 1, 0); + std::string delim = (std::string)tolua_tocppstring(LuaState, 2, 0); - lua_createtable(tolua_S, Split.size(), 0); - int newTable = lua_gettop(tolua_S); - int index = 1; - std::vector<std::string>::const_iterator iter = Split.begin(); - while(iter != Split.end()) { - tolua_pushstring( tolua_S, (*iter).c_str() ); - lua_rawseti(tolua_S, newTable, index); - ++iter; - ++index; - } + AStringVector Split = StringSplit(str, delim); + LuaState.PushStringVector(Split); return 1; } @@ -157,7 +143,8 @@ cPlugin_NewLua * GetLuaPlugin(lua_State * L) lua_getglobal(L, LUA_PLUGIN_INSTANCE_VAR_NAME); if (!lua_islightuserdata(L, -1)) { - LOGERROR("%s: cannot get plugin instance, what have you done to my Lua state?", __FUNCTION__); + LOGWARNING("%s: cannot get plugin instance, what have you done to my Lua state?", __FUNCTION__); + lua_pop(L, 1); return NULL; } cPlugin_NewLua * Plugin = (cPlugin_NewLua *)lua_topointer(L, -1); @@ -169,7 +156,7 @@ cPlugin_NewLua * GetLuaPlugin(lua_State * L) - + template< class Ty1, class Ty2, @@ -177,181 +164,273 @@ template< > static int tolua_DoWith(lua_State* tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if ((NumArgs != 2) && (NumArgs != 3)) + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 2) && (NumArgs != 3)) { return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs); - } + } - Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); - const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); - if ((ItemName == NULL) || (ItemName[0] == 0)) - { + const char * ItemName = tolua_tocppstring(tolua_S, 2, ""); + if ((ItemName == NULL) || (ItemName[0] == 0)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a non-empty string for parameter #1", NumArgs); - } - if (!lua_isfunction( tolua_S, 3)) - { + } + if (!lua_isfunction( tolua_S, 3)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #2", NumArgs); - } - - /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ - int TableRef = LUA_REFNIL; - if (NumArgs == 3) - { - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (TableRef == LUA_REFNIL) - { + } + + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 3) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #3", NumArgs); - } - } + } + } - /* table value is popped, and now function is on top of the stack */ - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FuncRef == LUA_REFNIL) - { + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #2", NumArgs); - } + } - class cLuaCallback : public cItemCallback<Ty2> + class cLuaCallback : public cItemCallback<Ty2> { - public: - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) - : LuaState( a_LuaState ) - , FuncRef( a_FuncRef ) - , TableRef( a_TableRef ) - {} + public: + cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} - private: - virtual bool Item(Ty2 * a_Item) override - { - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); - if (TableRef != LUA_REFNIL) - { - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ - } + if (TableRef != LUA_REFNIL) + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ + } - int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); - if (report_errors(LuaState, s)) + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + if (cLuaState::ReportErrors(LuaState, s)) { return true; // Abort enumeration } - if (lua_isboolean(LuaState, -1)) - { - return (tolua_toboolean(LuaState, -1, 0) > 0); - } - return false; /* Continue enumeration */ - } - lua_State * LuaState; - int FuncRef; - int TableRef; - } Callback(tolua_S, FuncRef, TableRef); + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean(LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); bool bRetVal = (self->*Func1)(ItemName, Callback); - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal ); - return 1; + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; } -template< class Ty1, - class Ty2, - bool (Ty1::*Func1)(int, int, int, cItemCallback<Ty2> &) > +template< + class Ty1, + class Ty2, + bool (Ty1::*Func1)(int, cItemCallback<Ty2> &) +> +static int tolua_DoWithID(lua_State* tolua_S) +{ + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 2) && (NumArgs != 3)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 2 or 3 arguments, got %i", NumArgs); + } + + Ty1 * self = (Ty1 *)tolua_tousertype(tolua_S, 1, 0); + + int ItemID = (int)tolua_tonumber(tolua_S, 2, 0); + if (!lua_isfunction(tolua_S, 3)) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #2", NumArgs); + } + + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 3) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #3", NumArgs); + } + } + + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { + return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #2", NumArgs); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(lua_State * a_LuaState, int a_FuncRef, int a_TableRef) : + LuaState(a_LuaState), + FuncRef(a_FuncRef), + TableRef(a_TableRef) + {} + + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, FuncRef); // Push function to call + tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); // Push the item + if (TableRef != LUA_REFNIL) + { + lua_rawgeti(LuaState, LUA_REGISTRYINDEX, TableRef); // Push the optional callbackdata param + } + + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + if (cLuaState::ReportErrors(LuaState, s)) + { + return true; // Abort enumeration + } + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean(LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); + + + bool bRetVal = (self->*Func1)(ItemID, Callback); + + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; +} + + + + + +template< + class Ty1, + class Ty2, + bool (Ty1::*Func1)(int, int, int, cItemCallback<Ty2> &) +> static int tolua_DoWithXYZ(lua_State* tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if ((NumArgs != 4) && (NumArgs != 5)) - { + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 4) && (NumArgs != 5)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 4 or 5 arguments, got %i", NumArgs); - } + } - Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); - if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3) || !lua_isnumber(tolua_S, 4)) - { + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); + if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3) || !lua_isnumber(tolua_S, 4)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1, #2 and #3"); - } - - int ItemX = ((int)tolua_tonumber(tolua_S, 2, 0)); - int ItemY = ((int)tolua_tonumber(tolua_S, 3, 0)); - int ItemZ = ((int)tolua_tonumber(tolua_S, 4, 0)); - LOG("x %i y %i z %i", ItemX, ItemY, ItemZ ); - if (!lua_isfunction( tolua_S, 5)) - { + } + + int ItemX = ((int)tolua_tonumber(tolua_S, 2, 0)); + int ItemY = ((int)tolua_tonumber(tolua_S, 3, 0)); + int ItemZ = ((int)tolua_tonumber(tolua_S, 4, 0)); + LOG("x %i y %i z %i", ItemX, ItemY, ItemZ ); + if (!lua_isfunction( tolua_S, 5)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #4"); - } - - /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ - int TableRef = LUA_REFNIL; - if (NumArgs == 5) - { - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (TableRef == LUA_REFNIL) - { + } + + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 5) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #5"); - } - } + } + } - /* table value is popped, and now function is on top of the stack */ - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FuncRef == LUA_REFNIL) - { + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #4"); - } - - class cLuaCallback : public cItemCallback<Ty2> - { - public: - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) - : LuaState( a_LuaState ) - , FuncRef( a_FuncRef ) - , TableRef( a_TableRef ) - {} - - private: - virtual bool Item(Ty2 * a_Item) override - { - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ - tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); - if (TableRef != LUA_REFNIL) - { - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ - } - - int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); - if (report_errors(LuaState, s)) + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} + + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); + if (TableRef != LUA_REFNIL) + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ + } + + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + if (cLuaState::ReportErrors(LuaState, s)) { return true; // Abort enumeration } - if (lua_isboolean(LuaState, -1)) - { - return (tolua_toboolean(LuaState, -1, 0) > 0); - } - return false; /* Continue enumeration */ - } - lua_State * LuaState; - int FuncRef; - int TableRef; - } Callback(tolua_S, FuncRef, TableRef); + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean(LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); bool bRetVal = (self->*Func1)(ItemX, ItemY, ItemZ, Callback); - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal ); - return 1; + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; } @@ -363,89 +442,89 @@ template< class Ty1, bool (Ty1::*Func1)(int, int, cItemCallback<Ty2> &) > static int tolua_ForEachInChunk(lua_State* tolua_S) { - int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ - if ((NumArgs != 3) && (NumArgs != 4)) - { + int NumArgs = lua_gettop(tolua_S) - 1; /* This includes 'self' */ + if ((NumArgs != 3) && (NumArgs != 4)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Requires 3 or 4 arguments, got %i", NumArgs); - } + } - Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); - if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3)) - { + Ty1 * self = (Ty1 *) tolua_tousertype(tolua_S, 1, 0); + if (!lua_isnumber(tolua_S, 2) || !lua_isnumber(tolua_S, 3)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a number for parameters #1 and #2"); - } + } - int ChunkX = ((int)tolua_tonumber(tolua_S, 2, 0)); - int ChunkZ = ((int)tolua_tonumber(tolua_S, 3, 0)); + int ChunkX = ((int)tolua_tonumber(tolua_S, 2, 0)); + int ChunkZ = ((int)tolua_tonumber(tolua_S, 3, 0)); - if (!lua_isfunction( tolua_S, 4)) - { + if (!lua_isfunction( tolua_S, 4)) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Expected a function for parameter #3"); - } - - /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ - int TableRef = LUA_REFNIL; - if (NumArgs == 4) - { - TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (TableRef == LUA_REFNIL) - { + } + + /* luaL_ref gets reference to value on top of the stack, the table is the last argument and therefore on the top */ + int TableRef = LUA_REFNIL; + if (NumArgs == 4) + { + TableRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (TableRef == LUA_REFNIL) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get value reference of parameter #4"); - } - } + } + } - /* table value is popped, and now function is on top of the stack */ - int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); - if (FuncRef == LUA_REFNIL) - { + /* table value is popped, and now function is on top of the stack */ + int FuncRef = luaL_ref(tolua_S, LUA_REGISTRYINDEX); + if (FuncRef == LUA_REFNIL) + { return lua_do_error(tolua_S, "Error in function call '#funcname#': Could not get function reference of parameter #3"); - } - - class cLuaCallback : public cItemCallback<Ty2> - { - public: - cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) - : LuaState( a_LuaState ) - , FuncRef( a_FuncRef ) - , TableRef( a_TableRef ) - {} - - private: - virtual bool Item(Ty2 * a_Item) override - { - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ - tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); - if (TableRef != LUA_REFNIL) - { - lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ - } - - int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); - if (report_errors(LuaState, s)) - { - return true; /* Abort enumeration */ - } - - if (lua_isboolean(LuaState, -1)) - { - return (tolua_toboolean(LuaState, -1, 0) > 0); - } - return false; /* Continue enumeration */ - } - lua_State * LuaState; - int FuncRef; - int TableRef; - } Callback(tolua_S, FuncRef, TableRef); + } + + class cLuaCallback : public cItemCallback<Ty2> + { + public: + cLuaCallback(lua_State* a_LuaState, int a_FuncRef, int a_TableRef) + : LuaState( a_LuaState ) + , FuncRef( a_FuncRef ) + , TableRef( a_TableRef ) + {} + + private: + virtual bool Item(Ty2 * a_Item) override + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, FuncRef); /* Push function reference */ + tolua_pushusertype(LuaState, a_Item, Ty2::GetClassStatic()); + if (TableRef != LUA_REFNIL) + { + lua_rawgeti( LuaState, LUA_REGISTRYINDEX, TableRef); /* Push table reference */ + } + + int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); + if (cLuaState::ReportErrors(LuaState, s)) + { + return true; /* Abort enumeration */ + } + + if (lua_isboolean(LuaState, -1)) + { + return (tolua_toboolean(LuaState, -1, 0) > 0); + } + return false; /* Continue enumeration */ + } + lua_State * LuaState; + int FuncRef; + int TableRef; + } Callback(tolua_S, FuncRef, TableRef); bool bRetVal = (self->*Func1)(ChunkX, ChunkZ, Callback); - /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ - luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); - luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); + /* Unreference the values again, so the LUA_REGISTRYINDEX can make place for other references */ + luaL_unref(tolua_S, LUA_REGISTRYINDEX, TableRef); + luaL_unref(tolua_S, LUA_REGISTRYINDEX, FuncRef); - /* Push return value on stack */ - tolua_pushboolean(tolua_S, bRetVal ); - return 1; + /* Push return value on stack */ + tolua_pushboolean(tolua_S, bRetVal ); + return 1; } @@ -453,7 +532,7 @@ static int tolua_ForEachInChunk(lua_State* tolua_S) template< class Ty1, - class Ty2, + class Ty2, bool (Ty1::*Func1)(cItemCallback<Ty2> &) > static int tolua_ForEach(lua_State * tolua_S) { @@ -512,7 +591,7 @@ static int tolua_ForEach(lua_State * tolua_S) } int s = lua_pcall(LuaState, (TableRef == LUA_REFNIL ? 1 : 2), 1, 0); - if (report_errors(LuaState, s)) + if (cLuaState::ReportErrors(LuaState, s)) { return true; /* Abort enumeration */ } @@ -596,6 +675,52 @@ tolua_lerror: +static int tolua_cWorld_TryGetHeight(lua_State * tolua_S) +{ + // Exported manually, because tolua would require the out-only param a_Height to be used when calling + // Takes (a_World,) a_BlockX, a_BlockZ + // Returns Height, IsValid + #ifndef TOLUA_RELEASE + tolua_Error tolua_err; + if ( + !tolua_isusertype (tolua_S, 1, "cWorld", 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 + #endif + { + cWorld * self = (cWorld *) tolua_tousertype (tolua_S, 1, 0); + int BlockX = (int) tolua_tonumber (tolua_S, 2, 0); + int BlockZ = (int) tolua_tonumber (tolua_S, 3, 0); + #ifndef TOLUA_RELEASE + if (self == NULL) + { + tolua_error(tolua_S, "Invalid 'self' in function 'TryGetHeight'", NULL); + } + #endif + { + int Height = 0; + bool res = self->TryGetHeight(BlockX, BlockZ, Height); + tolua_pushnumber(tolua_S, Height); + tolua_pushboolean(tolua_S, res ? 1 : 0); + } + } + return 1; + + #ifndef TOLUA_RELEASE +tolua_lerror: + tolua_error(tolua_S, "#ferror in function 'TryGetHeight'.", &tolua_err); + return 0; + #endif +} + + + + + static int tolua_cPluginManager_GetAllPlugins(lua_State * tolua_S) { cPluginManager* self = (cPluginManager*) tolua_tousertype(tolua_S,1,0); @@ -677,7 +802,7 @@ static int tolua_cPluginManager_ForEachCommand(lua_State * tolua_S) tolua_pushcppstring(LuaState, a_HelpString); int s = lua_pcall(LuaState, 3, 1, 0); - if (report_errors(LuaState, s)) + if (cLuaState::ReportErrors(LuaState, s)) { return true; /* Abort enumeration */ } @@ -751,7 +876,7 @@ static int tolua_cPluginManager_ForEachConsoleCommand(lua_State * tolua_S) tolua_pushcppstring(LuaState, a_HelpString); int s = lua_pcall(LuaState, 2, 1, 0); - if (report_errors(LuaState, s)) + if (cLuaState::ReportErrors(LuaState, s)) { return true; /* Abort enumeration */ } @@ -1171,8 +1296,8 @@ static int tolua_cPlugin_Call(lua_State* tolua_S) return 0; } - int s = lua_pcall(targetState, top-2, LUA_MULTRET, 0); - if( report_errors( targetState, s ) ) + int s = lua_pcall(targetState, top - 2, LUA_MULTRET, 0); + if (cLuaState::ReportErrors(targetState, s)) { LOGWARN("Error while calling function '%s' in plugin '%s'", funcName.c_str(), self->GetName().c_str() ); return 0; @@ -1361,9 +1486,174 @@ tolua_lerror: +/// Provides interface between a Lua table of callbacks and the cBlockTracer::cCallbacks +class cLuaBlockTracerCallbacks : + public cBlockTracer::cCallbacks +{ +public: + cLuaBlockTracerCallbacks(cLuaState & a_LuaState, int a_ParamNum) : + m_LuaState(a_LuaState), + m_TableRef(a_LuaState, a_ParamNum) + { + } + + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + { + if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlock")) + { + // No such function in the table, skip the callback + return false; + } + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); + if (!m_LuaState.CallFunction(1)) + { + return false; + } + bool res = false; + if (lua_isboolean(m_LuaState, -1)) + { + res = (lua_toboolean(m_LuaState, -1) != 0); + } + lua_pop(m_LuaState, 1); + return res; + } + + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) override + { + if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNextBlockNoData")) + { + // No such function in the table, skip the callback + return false; + } + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + if (!m_LuaState.CallFunction(1)) + { + return false; + } + bool res = false; + if (lua_isboolean(m_LuaState, -1)) + { + res = (lua_toboolean(m_LuaState, -1) != 0); + } + lua_pop(m_LuaState, 1); + return res; + } + + virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override + { + if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnOutOfWorld")) + { + // No such function in the table, skip the callback + return false; + } + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + if (!m_LuaState.CallFunction(1)) + { + return false; + } + bool res = false; + if (lua_isboolean(m_LuaState, -1)) + { + res = (lua_toboolean(m_LuaState, -1) != 0); + } + lua_pop(m_LuaState, 1); + return res; + } + + virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override + { + if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnIntoWorld")) + { + // No such function in the table, skip the callback + return false; + } + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + if (!m_LuaState.CallFunction(1)) + { + return false; + } + bool res = false; + if (lua_isboolean(m_LuaState, -1)) + { + res = (lua_toboolean(m_LuaState, -1) != 0); + } + lua_pop(m_LuaState, 1); + return res; + } + + virtual void OnNoMoreHits(void) override + { + if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoMoreHits")) + { + // No such function in the table, skip the callback + return; + } + m_LuaState.CallFunction(0); + } + + virtual void OnNoChunk(void) override + { + if (!m_LuaState.PushFunctionFromRefTable(m_TableRef, "OnNoChunk")) + { + // No such function in the table, skip the callback + return; + } + m_LuaState.CallFunction(0); + } + +protected: + cLuaState & m_LuaState; + cLuaState::cRef m_TableRef; +} ; + + + + + +static int tolua_cLineBlockTracer_Trace(lua_State * tolua_S) +{ + // cLineBlockTracer.Trace(World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ) + cLuaState L(tolua_S); + if ( + !L.CheckParamUserType(1, "cWorld") || + !L.CheckParamTable (2) || + !L.CheckParamNumber (3, 8) || + !L.CheckParamEnd (9) + ) + { + return 0; + } + + cWorld * World = (cWorld *)tolua_tousertype(L, 1, NULL); + cLuaBlockTracerCallbacks Callbacks(L, 2); + double StartX = tolua_tonumber(L, 3, 0); + double StartY = tolua_tonumber(L, 4, 0); + double StartZ = tolua_tonumber(L, 5, 0); + double EndX = tolua_tonumber(L, 6, 0); + double EndY = tolua_tonumber(L, 7, 0); + double EndZ = tolua_tonumber(L, 8, 0); + bool res = cLineBlockTracer::Trace(*World, Callbacks, StartX, StartY, StartZ, EndX, EndY, EndZ); + tolua_pushboolean(L, res ? 1 : 0); + return 1; +} + + + + + void ManualBindings::Bind(lua_State * tolua_S) { - tolua_beginmodule(tolua_S,NULL); + tolua_beginmodule(tolua_S, NULL); tolua_function(tolua_S, "StringSplit", tolua_StringSplit); tolua_function(tolua_S, "LOG", tolua_LOG); tolua_function(tolua_S, "LOGINFO", tolua_LOGINFO); @@ -1371,26 +1661,32 @@ 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, "cLineBlockTracer"); + tolua_function(tolua_S, "Trace", tolua_cLineBlockTracer_Trace); + tolua_endmodule(tolua_S); + tolua_beginmodule(tolua_S, "cRoot"); - tolua_function(tolua_S, "ForEachWorld", tolua_ForEach<cRoot, cWorld, &cRoot::ForEachWorld>); tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith <cRoot, cPlayer, &cRoot::FindAndDoWithPlayer>); tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach<cRoot, cPlayer, &cRoot::ForEachPlayer>); + tolua_function(tolua_S, "ForEachWorld", tolua_ForEach<cRoot, cWorld, &cRoot::ForEachWorld>); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWorld"); - tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach<cWorld, cPlayer, &cWorld::ForEachPlayer>); - tolua_function(tolua_S, "ForEachEntity", tolua_ForEach<cWorld, cEntity, &cWorld::ForEachEntity>); - tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); - tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); - tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); - tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith<cWorld, cPlayer, &cWorld::DoWithPlayer>); - tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith<cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); tolua_function(tolua_S, "DoWithChestAt", tolua_DoWithXYZ<cWorld, cChestEntity, &cWorld::DoWithChestAt>); tolua_function(tolua_S, "DoWithDispenserAt", tolua_DoWithXYZ<cWorld, cDispenserEntity, &cWorld::DoWithDispenserAt>); - tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); tolua_function(tolua_S, "DoWithDropSpenserAt", tolua_DoWithXYZ<cWorld, cDropSpenserEntity, &cWorld::DoWithDropSpenserAt>); + tolua_function(tolua_S, "DoWithDropperAt", tolua_DoWithXYZ<cWorld, cDropperEntity, &cWorld::DoWithDropperAt>); + tolua_function(tolua_S, "DoWithEntityByID", tolua_DoWithID< cWorld, cEntity, &cWorld::DoWithEntityByID>); tolua_function(tolua_S, "DoWithFurnaceAt", tolua_DoWithXYZ<cWorld, cFurnaceEntity, &cWorld::DoWithFurnaceAt>); + tolua_function(tolua_S, "DoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::DoWithPlayer>); + tolua_function(tolua_S, "FindAndDoWithPlayer", tolua_DoWith< cWorld, cPlayer, &cWorld::FindAndDoWithPlayer>); + tolua_function(tolua_S, "ForEachChestInChunk", tolua_ForEachInChunk<cWorld, cChestEntity, &cWorld::ForEachChestInChunk>); + tolua_function(tolua_S, "ForEachEntity", tolua_ForEach< cWorld, cEntity, &cWorld::ForEachEntity>); + tolua_function(tolua_S, "ForEachEntityInChunk", tolua_ForEachInChunk<cWorld, cEntity, &cWorld::ForEachEntityInChunk>); + tolua_function(tolua_S, "ForEachFurnaceInChunk", tolua_ForEachInChunk<cWorld, cFurnaceEntity, &cWorld::ForEachFurnaceInChunk>); + tolua_function(tolua_S, "ForEachPlayer", tolua_ForEach< cWorld, cPlayer, &cWorld::ForEachPlayer>); tolua_function(tolua_S, "SetSignLines", tolua_cWorld_SetSignLines); + tolua_function(tolua_S, "TryGetHeight", tolua_cWorld_TryGetHeight); tolua_function(tolua_S, "UpdateSign", tolua_cWorld_SetSignLines); tolua_endmodule(tolua_S); @@ -1399,11 +1695,11 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPluginManager"); - tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins); tolua_function(tolua_S, "BindCommand", tolua_cPluginManager_BindCommand); tolua_function(tolua_S, "BindConsoleCommand", tolua_cPluginManager_BindConsoleCommand); tolua_function(tolua_S, "ForEachCommand", tolua_cPluginManager_ForEachCommand); tolua_function(tolua_S, "ForEachConsoleCommand", tolua_cPluginManager_ForEachConsoleCommand); + tolua_function(tolua_S, "GetAllPlugins", tolua_cPluginManager_GetAllPlugins); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlayer"); @@ -1418,17 +1714,17 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cPlugin_NewLua"); - tolua_function(tolua_S, "AddWebTab", tolua_cPlugin_NewLua_AddWebTab); tolua_function(tolua_S, "AddTab", tolua_cPlugin_NewLua_AddTab); + tolua_function(tolua_S, "AddWebTab", tolua_cPlugin_NewLua_AddWebTab); tolua_endmodule(tolua_S); tolua_cclass(tolua_S,"HTTPRequest","HTTPRequest","",NULL); tolua_beginmodule(tolua_S,"HTTPRequest"); // tolua_variable(tolua_S,"Method",tolua_get_HTTPRequest_Method,tolua_set_HTTPRequest_Method); // tolua_variable(tolua_S,"Path",tolua_get_HTTPRequest_Path,tolua_set_HTTPRequest_Path); + tolua_variable(tolua_S,"FormData",tolua_get_HTTPRequest_FormData,0); tolua_variable(tolua_S,"Params",tolua_get_HTTPRequest_Params,0); tolua_variable(tolua_S,"PostParams",tolua_get_HTTPRequest_PostParams,0); - tolua_variable(tolua_S,"FormData",tolua_get_HTTPRequest_FormData,0); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cWebAdmin"); @@ -1440,8 +1736,8 @@ void ManualBindings::Bind(lua_State * tolua_S) tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cClientHandle"); - tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); tolua_constant(tolua_S, "MAX_VIEW_DISTANCE", cClientHandle::MAX_VIEW_DISTANCE); + tolua_constant(tolua_S, "MIN_VIEW_DISTANCE", cClientHandle::MIN_VIEW_DISTANCE); tolua_endmodule(tolua_S); tolua_beginmodule(tolua_S, "cItemGrid"); diff --git a/source/Plugin_NewLua.cpp b/source/Plugin_NewLua.cpp index 8b0f047cd..704bb3a95 100644 --- a/source/Plugin_NewLua.cpp +++ b/source/Plugin_NewLua.cpp @@ -7,45 +7,10 @@ extern "C" { -#include "lualib.h" + #include "lualib.h" } #include "tolua++.h" -#include "Bindings.h" -#include "ManualBindings.h" - - - - - -// fwd: SQLite/lsqlite3.c -extern "C" -{ - LUALIB_API int luaopen_lsqlite3(lua_State * L); -} - -// fwd: LuaExpat/lxplib.c: -extern "C" -{ - int luaopen_lxp(lua_State * L); -} - - - - - -bool report_errors(lua_State * lua, int status) -{ - if (status == 0) - { - // No error to report - return false; - } - - LOGERROR("LUA: %s", lua_tostring(lua, -1)); - lua_pop(lua, 1); - return true; -} @@ -54,10 +19,9 @@ bool report_errors(lua_State * lua, int status) /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // cPlugin_NewLua: -cPlugin_NewLua::cPlugin_NewLua(const AString & a_PluginDirectory) - : m_LuaState( 0 ) - , cWebPlugin() - , cPlugin(a_PluginDirectory) +cPlugin_NewLua::cPlugin_NewLua(const AString & a_PluginDirectory) : + cPlugin(a_PluginDirectory), + m_LuaState(Printf("plugin %s", a_PluginDirectory.c_str())) { } @@ -68,12 +32,7 @@ cPlugin_NewLua::cPlugin_NewLua(const AString & a_PluginDirectory) cPlugin_NewLua::~cPlugin_NewLua() { cCSLock Lock(m_CriticalSection); - - if( m_LuaState ) - { - lua_close( m_LuaState ); - m_LuaState = 0; - } + m_LuaState.Close(); } @@ -83,14 +42,9 @@ cPlugin_NewLua::~cPlugin_NewLua() bool cPlugin_NewLua::Initialize(void) { cCSLock Lock(m_CriticalSection); - if (m_LuaState == NULL) + if (!m_LuaState.IsValid()) { - m_LuaState = lua_open(); - luaL_openlibs(m_LuaState); - tolua_AllToLua_open(m_LuaState); - ManualBindings::Bind(m_LuaState); - luaopen_lsqlite3(m_LuaState); - luaopen_lxp(m_LuaState); + m_LuaState.Create(); // Inject the identification global variables into the state: lua_pushlightuserdata(m_LuaState, this); @@ -110,47 +64,32 @@ bool cPlugin_NewLua::Initialize(void) continue; } AString Path = PluginPath + *itr; - int s = luaL_loadfile(m_LuaState, Path.c_str() ); - if( report_errors( m_LuaState, s ) ) + if (!m_LuaState.LoadFile(Path)) { - LOGERROR("Can't load plugin %s because of an error in file %s", GetLocalDirectory().c_str(), Path.c_str() ); - lua_close( m_LuaState ); - m_LuaState = 0; - return false; - } - - s = lua_pcall(m_LuaState, 0, LUA_MULTRET, 0); - if( report_errors( m_LuaState, s ) ) - { - LOGERROR("Error in plugin %s in file %s", GetLocalDirectory().c_str(), Path.c_str() ); - lua_close( m_LuaState ); - m_LuaState = 0; + m_LuaState.Close(); return false; } } // for itr - Files[] // Call intialize function - if (!PushFunction("Initialize")) + if (!m_LuaState.PushFunction("Initialize")) { - lua_close( m_LuaState ); - m_LuaState = 0; + m_LuaState.Close(); return false; } - tolua_pushusertype(m_LuaState, this, "cPlugin_NewLua"); + m_LuaState.PushUserType(this, "cPlugin_NewLua"); - if (!CallFunction(1, 1, "Initialize")) + if (!m_LuaState.CallFunction(1)) { - lua_close( m_LuaState ); - m_LuaState = 0; + m_LuaState.Close(); return false; } - if( !lua_isboolean( m_LuaState, -1 ) ) + if (!lua_isboolean(m_LuaState, -1)) { - LOGWARN("Error in plugin %s Initialize() must return a boolean value!", GetLocalDirectory().c_str() ); - lua_close( m_LuaState ); - m_LuaState = 0; + LOGWARNING("Error in plugin %s: Initialize() must return a boolean value!", GetName().c_str()); + m_LuaState.Close(); return false; } @@ -165,12 +104,12 @@ bool cPlugin_NewLua::Initialize(void) void cPlugin_NewLua::OnDisable() { cCSLock Lock(m_CriticalSection); - if (!PushFunction("OnDisable", false)) // false = don't log error if not found + if (!m_LuaState.PushFunction("OnDisable", false)) // false = don't log error if not found { return; } - CallFunction(0, 0, "OnDisable"); + m_LuaState.CallFunction(0); } @@ -181,14 +120,12 @@ void cPlugin_NewLua::Tick(float a_Dt) { cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_TICK); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return; } - - tolua_pushnumber( m_LuaState, a_Dt ); - - CallFunction(1, 0, FnName); + m_LuaState.PushNumber(a_Dt); + m_LuaState.CallFunction(0); } @@ -200,21 +137,21 @@ bool cPlugin_NewLua::OnBlockToPickups(cWorld * a_World, cEntity * a_Digger, int cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_BLOCK_TO_PICKUPS); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_World, "cWorld"); - tolua_pushusertype(m_LuaState, a_Digger, "cEntity"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockType); - tolua_pushnumber (m_LuaState, a_BlockMeta); - tolua_pushusertype(m_LuaState, &a_Pickups, "cItems"); + m_LuaState.PushObject(a_World); + m_LuaState.PushObject(a_Digger); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); + m_LuaState.PushObject(&a_Pickups); - if (!CallFunction(8, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -233,15 +170,15 @@ bool cPlugin_NewLua::OnChat(cPlayer * a_Player, AString & a_Message) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_CHAT); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); - tolua_pushstring (m_LuaState, a_Message.c_str()); + m_LuaState.PushObject(a_Player); + m_LuaState.PushString(a_Message.c_str()); - if (!CallFunction(2, 2, FnName)) + if (!m_LuaState.CallFunction(2)) { return false; } @@ -264,16 +201,16 @@ bool cPlugin_NewLua::OnChunkAvailable(cWorld * a_World, int a_ChunkX, int a_Chun cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_CHUNK_AVAILABLE); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_ChunkX); - tolua_pushnumber (m_LuaState, a_ChunkZ); + m_LuaState.PushObject(a_World); + m_LuaState.PushNumber(a_ChunkX); + m_LuaState.PushNumber(a_ChunkZ); - if (!CallFunction(3, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -292,17 +229,17 @@ bool cPlugin_NewLua::OnChunkGenerated(cWorld * a_World, int a_ChunkX, int a_Chun cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_CHUNK_GENERATED); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_ChunkX); - tolua_pushnumber (m_LuaState, a_ChunkZ); - tolua_pushusertype(m_LuaState, a_ChunkDesc, "cChunkDesc"); + m_LuaState.PushObject(a_World); + m_LuaState.PushNumber(a_ChunkX); + m_LuaState.PushNumber(a_ChunkZ); + m_LuaState.PushUserType(a_ChunkDesc, "cChunkDesc"); - if (!CallFunction(4, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -316,22 +253,22 @@ bool cPlugin_NewLua::OnChunkGenerated(cWorld * a_World, int a_ChunkX, int a_Chun -bool cPlugin_NewLua::OnChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_pLuaChunk) +bool cPlugin_NewLua::OnChunkGenerating(cWorld * a_World, int a_ChunkX, int a_ChunkZ, cChunkDesc * a_ChunkDesc) { cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_CHUNK_GENERATING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_ChunkX); - tolua_pushnumber (m_LuaState, a_ChunkZ); - tolua_pushusertype(m_LuaState, a_pLuaChunk, "cChunkDesc"); + m_LuaState.PushObject(a_World); + m_LuaState.PushNumber(a_ChunkX); + m_LuaState.PushNumber(a_ChunkZ); + m_LuaState.PushUserType(a_ChunkDesc, "cChunkDesc"); - if (!CallFunction(4, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -350,16 +287,16 @@ bool cPlugin_NewLua::OnChunkUnloaded(cWorld * a_World, int a_ChunkX, int a_Chunk cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_CHUNK_UNLOADED); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_ChunkX); - tolua_pushnumber (m_LuaState, a_ChunkZ); + m_LuaState.PushObject(a_World); + m_LuaState.PushNumber(a_ChunkX); + m_LuaState.PushNumber(a_ChunkZ); - if (!CallFunction(3, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -378,16 +315,16 @@ bool cPlugin_NewLua::OnChunkUnloading(cWorld * a_World, int a_ChunkX, int a_Chun cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_CHUNK_UNLOADING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_ChunkX); - tolua_pushnumber (m_LuaState, a_ChunkZ); + m_LuaState.PushObject(a_World); + m_LuaState.PushNumber(a_ChunkX); + m_LuaState.PushNumber(a_ChunkZ); - if (!CallFunction(3, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -406,15 +343,15 @@ bool cPlugin_NewLua::OnCollectingPickup(cPlayer * a_Player, cPickup * a_Pickup) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_COLLECTING_PICKUP); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); - tolua_pushusertype(m_LuaState, a_Pickup, "cPickup"); + m_LuaState.PushObject(a_Player); + m_LuaState.PushObject(a_Pickup); - if (!CallFunction(2, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -433,16 +370,16 @@ bool cPlugin_NewLua::OnCraftingNoRecipe(const cPlayer * a_Player, const cCraftin cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_CRAFTING_NO_RECIPE); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, (void *)a_Player, "cPlayer"); - tolua_pushusertype(m_LuaState, (void *)a_Grid, "cCraftingGrid"); - tolua_pushusertype(m_LuaState, (void *)a_Recipe, "cCraftingRecipe"); + m_LuaState.PushUserType((void *)a_Player, "cPlayer"); + m_LuaState.PushUserType((void *)a_Grid, "cCraftingGrid"); + m_LuaState.PushUserType((void *)a_Recipe, "cCraftingRecipe"); - if (!CallFunction(3, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -461,15 +398,15 @@ bool cPlugin_NewLua::OnDisconnect(cPlayer * a_Player, const AString & a_Reason) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_DISCONNECT); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); - tolua_pushstring (m_LuaState, a_Reason.c_str()); + m_LuaState.PushObject(a_Player); + m_LuaState.PushString(a_Reason.c_str()); - if (!CallFunction(2, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -488,27 +425,15 @@ bool cPlugin_NewLua::OnExecuteCommand(cPlayer * a_Player, const AStringVector & cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_EXECUTE_COMMAND); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); - - // Push the split: - lua_createtable(m_LuaState, a_Split.size(), 0); - int newTable = lua_gettop(m_LuaState); - int index = 1; - std::vector<std::string>::const_iterator iter = a_Split.begin(), end = a_Split.end(); - while(iter != end) - { - tolua_pushstring(m_LuaState, (*iter).c_str()); - lua_rawseti(m_LuaState, newTable, index); - ++iter; - ++index; - } + m_LuaState.PushObject(a_Player); + m_LuaState.PushStringVector(a_Split); - if (!CallFunction(2, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -527,15 +452,15 @@ bool cPlugin_NewLua::OnHandshake(cClientHandle * a_Client, const AString & a_Use cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_HANDSHAKE); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, a_Client, "cClientHandle"); - tolua_pushstring (m_LuaState, a_Username.c_str()); + m_LuaState.PushUserType(a_Client, "cClientHandle"); + m_LuaState.PushString (a_Username.c_str()); - if (!CallFunction(2, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -554,15 +479,15 @@ bool cPlugin_NewLua::OnKilling(cEntity & a_Victim, cEntity * a_Killer) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_KILLING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Victim, "cEntity"); - tolua_pushusertype(m_LuaState, a_Killer, "cEntity"); + m_LuaState.PushObject(&a_Victim); + m_LuaState.PushObject(a_Killer); - if (!CallFunction(2, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -581,16 +506,16 @@ bool cPlugin_NewLua::OnLogin(cClientHandle * a_Client, int a_ProtocolVersion, co cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_LOGIN); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype (m_LuaState, a_Client, "cClientHandle"); - tolua_pushnumber (m_LuaState, a_ProtocolVersion); - tolua_pushcppstring(m_LuaState, a_Username); + m_LuaState.PushObject(a_Client); + m_LuaState.PushNumber(a_ProtocolVersion); + m_LuaState.PushString(a_Username.c_str()); - if (!CallFunction(3, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -609,20 +534,20 @@ bool cPlugin_NewLua::OnPlayerBreakingBlock(cPlayer & a_Player, int a_BlockX, int cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_BREAKING_BLOCK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_BlockType); - tolua_pushnumber (m_LuaState, a_BlockMeta); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); - if (!CallFunction(7, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -641,20 +566,20 @@ bool cPlugin_NewLua::OnPlayerBrokenBlock(cPlayer & a_Player, int a_BlockX, int a cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_BROKEN_BLOCK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_BlockType); - tolua_pushnumber (m_LuaState, a_BlockMeta); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); - if (!CallFunction(7, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -673,14 +598,14 @@ bool cPlugin_NewLua::OnPlayerEating(cPlayer & a_Player) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_EATING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); + m_LuaState.PushObject(&a_Player); - if (!CallFunction(1, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -699,14 +624,14 @@ bool cPlugin_NewLua::OnPlayerJoined(cPlayer & a_Player) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_JOINED); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); + m_LuaState.PushObject(&a_Player); - if (!CallFunction(1, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -725,19 +650,19 @@ bool cPlugin_NewLua::OnPlayerLeftClick(cPlayer & a_Player, int a_BlockX, int a_B cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_LEFT_CLICK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_Status); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_Status); - if (!CallFunction(6, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -756,14 +681,14 @@ bool cPlugin_NewLua::OnPlayerMoved(cPlayer & a_Player) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_MOVING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); + m_LuaState.PushObject(&a_Player); - if (!CallFunction(1, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -782,23 +707,23 @@ bool cPlugin_NewLua::OnPlayerPlacedBlock(cPlayer & a_Player, int a_BlockX, int a cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_PLACED_BLOCK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_CursorX); - tolua_pushnumber (m_LuaState, a_CursorY); - tolua_pushnumber (m_LuaState, a_CursorZ); - tolua_pushnumber (m_LuaState, a_BlockType); - tolua_pushnumber (m_LuaState, a_BlockMeta); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_CursorX); + m_LuaState.PushNumber(a_CursorY); + m_LuaState.PushNumber(a_CursorZ); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); - if (!CallFunction(10, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -817,23 +742,23 @@ bool cPlugin_NewLua::OnPlayerPlacingBlock(cPlayer & a_Player, int a_BlockX, int cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_PLACING_BLOCK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_CursorX); - tolua_pushnumber (m_LuaState, a_CursorY); - tolua_pushnumber (m_LuaState, a_CursorZ); - tolua_pushnumber (m_LuaState, a_BlockType); - tolua_pushnumber (m_LuaState, a_BlockMeta); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_CursorX); + m_LuaState.PushNumber(a_CursorY); + m_LuaState.PushNumber(a_CursorZ); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); - if (!CallFunction(10, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -852,21 +777,21 @@ bool cPlugin_NewLua::OnPlayerRightClick(cPlayer & a_Player, int a_BlockX, int a_ cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_RIGHT_CLICK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_CursorX); - tolua_pushnumber (m_LuaState, a_CursorY); - tolua_pushnumber (m_LuaState, a_CursorZ); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_CursorX); + m_LuaState.PushNumber(a_CursorY); + m_LuaState.PushNumber(a_CursorZ); - if (!CallFunction(8, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -885,15 +810,15 @@ bool cPlugin_NewLua::OnPlayerRightClickingEntity(cPlayer & a_Player, cEntity & a cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_RIGHT_CLICKING_ENTITY); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushusertype(m_LuaState, &a_Entity, "cEntity"); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushObject(&a_Entity); - if (!CallFunction(2, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -912,14 +837,14 @@ bool cPlugin_NewLua::OnPlayerShooting(cPlayer & a_Player) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_SHOOTING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); + m_LuaState.PushObject(&a_Player); - if (!CallFunction(1, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -938,14 +863,14 @@ bool cPlugin_NewLua::OnPlayerSpawned(cPlayer & a_Player) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_SPAWNED); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); + m_LuaState.PushObject(&a_Player); - if (!CallFunction(1, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -964,14 +889,14 @@ bool cPlugin_NewLua::OnPlayerTossingItem(cPlayer & a_Player) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_TOSSING_ITEM); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); + m_LuaState.PushObject(&a_Player); - if (!CallFunction(1, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -990,23 +915,23 @@ bool cPlugin_NewLua::OnPlayerUsedBlock(cPlayer & a_Player, int a_BlockX, int a_B cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_USED_BLOCK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_CursorX); - tolua_pushnumber (m_LuaState, a_CursorY); - tolua_pushnumber (m_LuaState, a_CursorZ); - tolua_pushnumber (m_LuaState, a_BlockType); - tolua_pushnumber (m_LuaState, a_BlockMeta); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_CursorX); + m_LuaState.PushNumber(a_CursorY); + m_LuaState.PushNumber(a_CursorZ); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); - if (!CallFunction(10, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1025,21 +950,21 @@ bool cPlugin_NewLua::OnPlayerUsedItem(cPlayer & a_Player, int a_BlockX, int a_Bl cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_USED_ITEM); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_CursorX); - tolua_pushnumber (m_LuaState, a_CursorY); - tolua_pushnumber (m_LuaState, a_CursorZ); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_CursorX); + m_LuaState.PushNumber(a_CursorY); + m_LuaState.PushNumber(a_CursorZ); - if (!CallFunction(8, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1058,23 +983,23 @@ bool cPlugin_NewLua::OnPlayerUsingBlock(cPlayer & a_Player, int a_BlockX, int a_ cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_USING_BLOCK); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_CursorX); - tolua_pushnumber (m_LuaState, a_CursorY); - tolua_pushnumber (m_LuaState, a_CursorZ); - tolua_pushnumber (m_LuaState, a_BlockType); - tolua_pushnumber (m_LuaState, a_BlockMeta); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_CursorX); + m_LuaState.PushNumber(a_CursorY); + m_LuaState.PushNumber(a_CursorZ); + m_LuaState.PushNumber(a_BlockType); + m_LuaState.PushNumber(a_BlockMeta); - if (!CallFunction(10, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1093,21 +1018,21 @@ bool cPlugin_NewLua::OnPlayerUsingItem(cPlayer & a_Player, int a_BlockX, int a_B cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PLAYER_USING_ITEM); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushnumber (m_LuaState, a_BlockFace); - tolua_pushnumber (m_LuaState, a_CursorX); - tolua_pushnumber (m_LuaState, a_CursorY); - tolua_pushnumber (m_LuaState, a_CursorZ); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushNumber(a_BlockFace); + m_LuaState.PushNumber(a_CursorX); + m_LuaState.PushNumber(a_CursorY); + m_LuaState.PushNumber(a_CursorZ); - if (!CallFunction(8, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1126,16 +1051,16 @@ bool cPlugin_NewLua::OnPostCrafting(const cPlayer * a_Player, const cCraftingGri cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_POST_CRAFTING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, (void *)a_Player, "cPlayer"); - tolua_pushusertype(m_LuaState, (void *)a_Grid, "cCraftingGrid"); - tolua_pushusertype(m_LuaState, (void *)a_Recipe, "cCraftingRecipe"); + m_LuaState.PushUserType((void *)a_Player, "cPlayer"); + m_LuaState.PushUserType((void *)a_Grid, "cCraftingGrid"); + m_LuaState.PushUserType((void *)a_Recipe, "cCraftingRecipe"); - if (!CallFunction(3, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1154,16 +1079,16 @@ bool cPlugin_NewLua::OnPreCrafting(const cPlayer * a_Player, const cCraftingGrid cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_PRE_CRAFTING); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, (void *)a_Player, "cPlayer"); - tolua_pushusertype(m_LuaState, (void *)a_Grid, "cCraftingGrid"); - tolua_pushusertype(m_LuaState, (void *)a_Recipe, "cCraftingRecipe"); + m_LuaState.PushUserType((void *)a_Player, "cPlayer"); + m_LuaState.PushUserType((void *)a_Grid, "cCraftingGrid"); + m_LuaState.PushUserType((void *)a_Recipe, "cCraftingRecipe"); - if (!CallFunction(3, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1182,15 +1107,15 @@ bool cPlugin_NewLua::OnTakeDamage(cEntity & a_Receiver, TakeDamageInfo & a_TDI) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_TAKE_DAMAGE); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_Receiver, "cEntity"); - tolua_pushusertype(m_LuaState, &a_TDI, "TakeDamageInfo"); + m_LuaState.PushObject(&a_Receiver); + m_LuaState.PushUserType(&a_TDI, "TakeDamageInfo"); - if (!CallFunction(2, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1214,22 +1139,22 @@ bool cPlugin_NewLua::OnUpdatedSign( cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_UPDATED_SIGN); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, (void *)a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushstring (m_LuaState, a_Line1.c_str()); - tolua_pushstring (m_LuaState, a_Line2.c_str()); - tolua_pushstring (m_LuaState, a_Line3.c_str()); - tolua_pushstring (m_LuaState, a_Line4.c_str()); - tolua_pushusertype(m_LuaState, (void *)a_Player, "cPlayer"); + m_LuaState.PushObject(a_World); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushString(a_Line1.c_str()); + m_LuaState.PushString(a_Line2.c_str()); + m_LuaState.PushString(a_Line3.c_str()); + m_LuaState.PushString(a_Line4.c_str()); + m_LuaState.PushObject(a_Player); - if (!CallFunction(9, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1253,22 +1178,22 @@ bool cPlugin_NewLua::OnUpdatingSign( cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_UPDATING_SIGN); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, (void *)a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_BlockX); - tolua_pushnumber (m_LuaState, a_BlockY); - tolua_pushnumber (m_LuaState, a_BlockZ); - tolua_pushstring (m_LuaState, a_Line1.c_str()); - tolua_pushstring (m_LuaState, a_Line2.c_str()); - tolua_pushstring (m_LuaState, a_Line3.c_str()); - tolua_pushstring (m_LuaState, a_Line4.c_str()); - tolua_pushusertype(m_LuaState, (void *)a_Player, "cPlayer"); + m_LuaState.PushObject(a_World); + m_LuaState.PushNumber(a_BlockX); + m_LuaState.PushNumber(a_BlockY); + m_LuaState.PushNumber(a_BlockZ); + m_LuaState.PushString(a_Line1.c_str()); + m_LuaState.PushString(a_Line2.c_str()); + m_LuaState.PushString(a_Line3.c_str()); + m_LuaState.PushString(a_Line4.c_str()); + m_LuaState.PushObject(a_Player); - if (!CallFunction(9, 5, "OnUpdatingSign")) + if (!m_LuaState.CallFunction(5)) { return false; } @@ -1303,14 +1228,14 @@ bool cPlugin_NewLua::OnWeatherChanged(cWorld & a_World) cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_WEATHER_CHANGED); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_World, "cWorld"); + m_LuaState.PushObject(&a_World); - if (!CallFunction(1, 1, FnName)) + if (!m_LuaState.CallFunction(1)) { return false; } @@ -1329,15 +1254,15 @@ bool cPlugin_NewLua::OnWeatherChanging(cWorld & a_World, eWeather & a_NewWeather cCSLock Lock(m_CriticalSection); const char * FnName = GetHookFnName(cPluginManager::HOOK_WEATHER_CHANGED); ASSERT(FnName != NULL); - if (!PushFunction(FnName)) + if (!m_LuaState.PushFunction(FnName)) { return false; } - tolua_pushusertype(m_LuaState, &a_World, "cWorld"); - tolua_pushnumber (m_LuaState, a_NewWeather); + m_LuaState.PushObject(&a_World); + m_LuaState.PushNumber(a_NewWeather); - if (!CallFunction(2, 2, FnName)) + if (!m_LuaState.CallFunction(2)) { return false; } @@ -1368,29 +1293,19 @@ bool cPlugin_NewLua::HandleCommand(const AStringVector & a_Split, cPlayer * a_Pl cCSLock Lock(m_CriticalSection); // Push the function to be called: - lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, cmd->second); // same as lua_getref() - - // Push the split: - lua_createtable(m_LuaState, a_Split.size(), 0); - int newTable = lua_gettop(m_LuaState); - int index = 1; - std::vector<std::string>::const_iterator iter = a_Split.begin(), end = a_Split.end(); - while(iter != end) - { - tolua_pushstring(m_LuaState, (*iter).c_str()); - lua_rawseti(m_LuaState, newTable, index); - ++iter; - ++index; + if (!m_LuaState.PushFunctionFromRegistry(cmd->second)) + { + LOGWARNING("Command handler function for \"%s\" is invalid", cmd->first.c_str()); + return false; } - // Push player: - tolua_pushusertype(m_LuaState, a_Player, "cPlayer"); + m_LuaState.PushStringVector(a_Split); + m_LuaState.PushObject(a_Player); // Call function: - int s = lua_pcall(m_LuaState, 2, 1, 0); - if (report_errors(m_LuaState, s)) + if (!m_LuaState.CallFunction(1)) { - LOGERROR("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); + LOGWARNING("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); return false; } @@ -1420,26 +1335,14 @@ bool cPlugin_NewLua::HandleConsoleCommand(const AStringVector & a_Split, cComman cCSLock Lock(m_CriticalSection); // Push the function to be called: - lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, cmd->second); // same as lua_getref() + m_LuaState.PushFunctionFromRegistry(cmd->second); - // Push the split: - lua_createtable(m_LuaState, a_Split.size(), 0); - int newTable = lua_gettop(m_LuaState); - int index = 1; - std::vector<std::string>::const_iterator iter = a_Split.begin(), end = a_Split.end(); - while(iter != end) - { - tolua_pushstring(m_LuaState, (*iter).c_str()); - lua_rawseti(m_LuaState, newTable, index); - ++iter; - ++index; - } + m_LuaState.PushStringVector(a_Split); // Call function: - int s = lua_pcall(m_LuaState, 1, 2, 0); - if (report_errors(m_LuaState, s)) + if (!m_LuaState.CallFunction(2)) { - LOGERROR("Lua error. Stack size: %i", lua_gettop(m_LuaState)); + LOGWARNING("Lua error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); return false; } @@ -1604,9 +1507,9 @@ AString cPlugin_NewLua::HandleWebRequest(const HTTPRequest * a_Request ) return ""; sWebPluginTab* Tab = 0; - for( TabList::iterator itr = GetTabs().begin(); itr != GetTabs().end(); ++itr ) + for (TabList::iterator itr = GetTabs().begin(); itr != GetTabs().end(); ++itr) { - if( (*itr)->SafeTitle.compare( SafeTabName ) == 0 ) // This is the one! Rawr + if ((*itr)->SafeTitle.compare(SafeTabName) == 0) // This is the one! Rawr { Tab = *itr; break; @@ -1615,34 +1518,26 @@ AString cPlugin_NewLua::HandleWebRequest(const HTTPRequest * a_Request ) if( Tab ) { - //LOGINFO("1. Stack size: %i", lua_gettop(m_LuaState) ); - lua_rawgeti( m_LuaState, LUA_REGISTRYINDEX, Tab->UserData); // same as lua_getref() + m_LuaState.PushFunctionFromRegistry(Tab->UserData); - //LOGINFO("2. Stack size: %i", lua_gettop(m_LuaState) ); // Push HTTPRequest - tolua_pushusertype( m_LuaState, (void*)a_Request, "const HTTPRequest" ); - //LOGINFO("Calling bound function! :D"); - int s = lua_pcall( m_LuaState, 1, 1, 0); - - if ( s != 0 ) + m_LuaState.PushUserType((void*)a_Request, "const HTTPRequest"); + + if (!m_LuaState.CallFunction(1)) { - std::string err = lua_tostring(m_LuaState, -1); - LOGERROR("-- %s", err.c_str() ); - lua_pop(m_LuaState, 1); - LOGINFO("error. Stack size: %i", lua_gettop(m_LuaState) ); - return err; // Show the error message in the web page, looks cool + return "Lua encountered error while processing the page request"; } - if( !lua_isstring( m_LuaState, -1 ) ) + if (!lua_isstring(m_LuaState, -1)) { - LOGWARN("WARNING: WebPlugin tab '%s' did not return a string!", Tab->Title.c_str() ); - lua_pop(m_LuaState, 1); // Pop return value - return std::string("WARNING: WebPlugin tab '") + Tab->Title + std::string("' did not return a string!"); + LOGWARNING("WebPlugin tab '%s' did not return a string!", Tab->Title.c_str()); + lua_pop(m_LuaState, 1); // Pop return value + return Printf("WARNING: WebPlugin tab '%s' did not return a string!", Tab->Title.c_str()); } RetVal += tolua_tostring(m_LuaState, -1, 0); lua_pop(m_LuaState, 1); // Pop return value - //LOGINFO("ok. Stack size: %i", lua_gettop(m_LuaState) ); + // LOGINFO("ok. Stack size: %i", lua_gettop(m_LuaState) ); } return RetVal; @@ -1652,7 +1547,7 @@ AString cPlugin_NewLua::HandleWebRequest(const HTTPRequest * a_Request ) -bool cPlugin_NewLua::AddWebTab( const AString & a_Title, lua_State * a_LuaState, int a_FunctionReference ) +bool cPlugin_NewLua::AddWebTab(const AString & a_Title, lua_State * a_LuaState, int a_FunctionReference) { cCSLock Lock(m_CriticalSection); if (a_LuaState != m_LuaState) @@ -1666,7 +1561,7 @@ bool cPlugin_NewLua::AddWebTab( const AString & a_Title, lua_State * a_LuaState, Tab->UserData = a_FunctionReference; - GetTabs().push_back( Tab ); + GetTabs().push_back(Tab); return true; } @@ -1709,16 +1604,15 @@ bool cPlugin_NewLua::CallbackWindowClosing(int a_FnRef, cWindow & a_Window, cPla ASSERT(a_FnRef != LUA_REFNIL); cCSLock Lock(m_CriticalSection); - lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // Push the function to be called - tolua_pushusertype(m_LuaState, &a_Window, "cWindow"); - tolua_pushusertype(m_LuaState, &a_Player, "cPlayer"); - tolua_pushboolean (m_LuaState, a_CanRefuse ? 1 : 0); + m_LuaState.PushFunctionFromRegistry(a_FnRef); + m_LuaState.PushUserType(&a_Window, "cWindow"); + m_LuaState.PushObject(&a_Player); + m_LuaState.PushBool(a_CanRefuse); // Call function: - int s = lua_pcall(m_LuaState, 3, 1, 0); - if (report_errors(m_LuaState, s)) + if (!m_LuaState.CallFunction(1)) { - LOGERROR("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); + LOGWARNING("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); return false; } @@ -1736,59 +1630,15 @@ void cPlugin_NewLua::CallbackWindowSlotChanged(int a_FnRef, cWindow & a_Window, ASSERT(a_FnRef != LUA_REFNIL); cCSLock Lock(m_CriticalSection); - lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_FnRef); // Push the function to be called - tolua_pushusertype(m_LuaState, &a_Window, "cWindow"); - tolua_pushnumber (m_LuaState, a_SlotNum); + m_LuaState.PushFunctionFromRegistry(a_FnRef); + m_LuaState.PushUserType(&a_Window, "cWindow"); + m_LuaState.PushNumber(a_SlotNum); // Call function: - int s = lua_pcall(m_LuaState, 2, 0, 0); - if (report_errors(m_LuaState, s)) - { - LOGERROR("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); - } -} - - - - - -// Helper functions -bool cPlugin_NewLua::PushFunction(const char * a_FunctionName, bool a_bLogError /* = true */) -{ - if (m_LuaState == NULL) + if (!m_LuaState.CallFunction(0)) { - // This happens if Initialize() fails with an error - return false; + LOGWARNING("LUA error in %s. Stack size: %i", __FUNCTION__, lua_gettop(m_LuaState)); } - - lua_getglobal(m_LuaState, a_FunctionName); - if (!lua_isfunction(m_LuaState, -1)) - { - if (a_bLogError) - { - LOGWARN("Error in plugin %s: Could not find function %s()", GetName().c_str(), a_FunctionName); - } - lua_pop(m_LuaState, 1); - return false; - } - return true; -} - - - - - -bool cPlugin_NewLua::CallFunction( int a_NumArgs, int a_NumResults, const char * a_FunctionName) -{ - ASSERT(lua_isfunction(m_LuaState, -a_NumArgs - 1)); - - int s = lua_pcall(m_LuaState, a_NumArgs, a_NumResults, 0); - if (report_errors(m_LuaState, s)) - { - LOGWARN("Error in plugin %s calling function %s()", GetName().c_str(), a_FunctionName); - return false; - } - return true; } diff --git a/source/Plugin_NewLua.h b/source/Plugin_NewLua.h index a79affd5d..d31a62601 100644 --- a/source/Plugin_NewLua.h +++ b/source/Plugin_NewLua.h @@ -3,6 +3,7 @@ #include "Plugin.h" #include "WebPlugin.h" +#include "LuaState.h" // Names for the global variables through which the plugin is identified in its LuaState #define LUA_PLUGIN_NAME_VAR_NAME "_MCServerInternal_PluginName" @@ -11,9 +12,6 @@ -// fwd: Lua -typedef struct lua_State lua_State; - // fwd: UI/Window.h class cWindow; @@ -99,7 +97,7 @@ public: /// Binds the console command to call the function specified by a Lua function reference. Simply adds to CommandMap. void BindConsoleCommand(const AString & a_Command, int a_FnRef); - lua_State * GetLuaState(void) { return m_LuaState; } + cLuaState & GetLuaState(void) { return m_LuaState; } cCriticalSection & GetCriticalSection(void) { return m_CriticalSection; } @@ -114,7 +112,7 @@ public: protected: cCriticalSection m_CriticalSection; - lua_State * m_LuaState; + cLuaState m_LuaState; /// Maps command name into Lua function reference typedef std::map<AString, int> CommandMap; @@ -122,9 +120,6 @@ protected: CommandMap m_Commands; CommandMap m_ConsoleCommands; - bool PushFunction(const char * a_FunctionName, bool a_bLogError = true); - bool CallFunction(int a_NumArgs, int a_NumResults, const char * a_FunctionName ); // a_FunctionName is only used for error messages, nothing else - /// Returns the name of Lua function that should handle the specified hook const char * GetHookFnName(cPluginManager::PluginHook a_Hook); } ; // tolua_export diff --git a/source/Root.cpp b/source/Root.cpp index 59242c60d..f12ccc832 100644 --- a/source/Root.cpp +++ b/source/Root.cpp @@ -112,10 +112,7 @@ void cRoot::Start(void) cIniFile IniFile("settings.ini"); if (!IniFile.ReadFile()) { - LOGINFO("settings.ini inaccessible, using settings.example.ini for defaults!"); - IniFile.Path("settings.example.ini"); - IniFile.ReadFile(); - IniFile.Path("settings.ini"); + LOGWARNING("settings.ini inaccessible, all settings are reset to default values"); } m_PrimaryServerVersion = IniFile.GetValueI("Server", "PrimaryServerVersion", 0); if (m_PrimaryServerVersion == 0) @@ -139,23 +136,19 @@ void cRoot::Start(void) cIniFile WebIniFile("webadmin.ini"); if (!WebIniFile.ReadFile()) { - LOGINFO("webadmin.ini inaccessible, using webadmin.example.ini for defaults!"); - WebIniFile.Path("webadmin.example.ini"); - WebIniFile.ReadFile(); - WebIniFile.Path("webadmin.ini"); - WebIniFile.WriteFile(); + LOGWARNING("webadmin.ini inaccessible, wabadmin is disabled"); } - if (WebIniFile.GetValueB("WebAdmin", "Enabled", false )) + if (WebIniFile.GetValueB("WebAdmin", "Enabled", false)) { LOG("Creating WebAdmin..."); m_WebAdmin = new cWebAdmin(8080); } LOG("Loading settings..."); - m_GroupManager = new cGroupManager(); + m_GroupManager = new cGroupManager(); m_CraftingRecipes = new cCraftingRecipes; - m_FurnaceRecipe = new cFurnaceRecipe(); + m_FurnaceRecipe = new cFurnaceRecipe(); LOG("Loading worlds..."); LoadWorlds(); diff --git a/source/WebAdmin.cpp b/source/WebAdmin.cpp index 3d04ce8f3..be7efa18d 100644 --- a/source/WebAdmin.cpp +++ b/source/WebAdmin.cpp @@ -178,7 +178,7 @@ void cWebAdmin::Request_Handler(webserver::http_request* r) if (!bDontShowTemplate) { // New Lua web template - bLuaTemplateSuccessful = WebAdmin->m_pTemplate->CallFunction("ShowPage", sLuaUsertype(WebAdmin, "cWebAdmin"), sLuaUsertype(&TemplateRequest, "HTTPTemplateRequest"), Template); + bLuaTemplateSuccessful = WebAdmin->m_pTemplate->CallShowPage(*WebAdmin, TemplateRequest, Template); } if (!bLuaTemplateSuccessful) @@ -274,14 +274,14 @@ bool cWebAdmin::Init( int a_Port ) m_Port = a_Port; m_IniFile = new cIniFile("webadmin.ini"); - if( m_IniFile->ReadFile() ) + if (m_IniFile->ReadFile()) { - m_Port = m_IniFile->GetValueI("WebAdmin", "Port", 8080 ); + m_Port = m_IniFile->GetValueI("WebAdmin", "Port", 8080); } // Initialize the WebAdmin template script and load the file m_pTemplate->Initialize(); - if (!m_pTemplate->LoadFile( FILE_IO_PREFIX "webadmin/template.lua") || !m_pTemplate->Execute()) + if (!m_pTemplate->LoadFile(FILE_IO_PREFIX "webadmin/template.lua")) { LOGWARN("Could not load WebAdmin template."); } diff --git a/source/World.cpp b/source/World.cpp index 880f6e5b2..699767d5e 100644 --- a/source/World.cpp +++ b/source/World.cpp @@ -1,4 +1,3 @@ - #include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules #include "BlockID.h" @@ -59,6 +58,9 @@ #include "tolua++.h" +// DEBUG: Test out the cLineBlockTracer class by tracing a few lines: +#include "LineBlockTracer.h" + #ifndef _WIN32 #include <stdlib.h> #endif @@ -278,7 +280,7 @@ cWorld::cWorld(const AString & a_WorldName) : m_LastSave = 0; m_LastUnload = 0; - // preallocate some memory for ticking blocks so we don´t need to allocate that often + // preallocate some memory for ticking blocks so we don�t need to allocate that often m_BlockTickQueue.reserve(1000); m_BlockTickQueueCopy.reserve(1000); @@ -442,6 +444,60 @@ void cWorld::InitializeSpawn(void) // TODO: Better spawn detection - move spawn out of the water if it isn't set in the INI already m_SpawnY = (double)GetHeight((int)m_SpawnX, (int)m_SpawnZ) + 1.6f; // +1.6f eye height + + + #ifdef TEST_LINEBLOCKTRACER + // DEBUG: Test out the cLineBlockTracer class by tracing a few lines: + class cTracerCallbacks : + public cBlockTracer::cCallbacks + { + virtual bool OnNextBlock(int a_BlockX, int a_BlockY, int a_BlockZ, BLOCKTYPE a_BlockType, NIBBLETYPE a_BlockMeta) override + { + LOGD("Block {%d, %d, %d}: %d:%d (%s)", + a_BlockX, a_BlockY, a_BlockZ, a_BlockType, a_BlockMeta, + ItemToString(cItem(a_BlockType, 1, a_BlockMeta)).c_str() + ); + return false; + } + + virtual bool OnNextBlockNoData(int a_BlockX, int a_BlockY, int a_BlockZ) override + { + LOGD("Block {%d, %d, %d}: no data available", + a_BlockX, a_BlockY, a_BlockZ + ); + return false; + } + + virtual bool OnOutOfWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override + { + LOGD("Out of world at {%f, %f, %f}", a_BlockX, a_BlockY, a_BlockZ); + return false; + } + + virtual bool OnIntoWorld(double a_BlockX, double a_BlockY, double a_BlockZ) override + { + LOGD("Into world at {%f, %f, %f}", a_BlockX, a_BlockY, a_BlockZ); + return false; + } + + virtual void OnNoMoreHits(void) override + { + LOGD("No more hits"); + } + } Callbacks; + LOGD("Spawn is at {%f, %f, %f}", m_SpawnX, m_SpawnY, m_SpawnZ); + LOGD("Tracing a line along +X:"); + cLineBlockTracer::Trace(*this, Callbacks, m_SpawnX - 10, m_SpawnY, m_SpawnZ, m_SpawnX + 10, m_SpawnY, m_SpawnZ); + LOGD("Tracing a line along -Z:"); + cLineBlockTracer::Trace(*this, Callbacks, m_SpawnX, m_SpawnY, m_SpawnZ + 10, m_SpawnX, m_SpawnY, m_SpawnZ - 10); + LOGD("Tracing a line along -Y, out of world:"); + cLineBlockTracer::Trace(*this, Callbacks, m_SpawnX, 260, m_SpawnZ, m_SpawnX, -5, m_SpawnZ); + LOGD("Tracing a line along XY:"); + cLineBlockTracer::Trace(*this, Callbacks, m_SpawnX - 10, m_SpawnY - 10, m_SpawnZ, m_SpawnX + 10, m_SpawnY + 10, m_SpawnZ); + LOGD("Tracing a line in generic direction:"); + cLineBlockTracer::Trace(*this, Callbacks, m_SpawnX - 15, m_SpawnY - 5, m_SpawnZ + 7.5, m_SpawnX + 13, m_SpawnY - 10, m_SpawnZ + 8.5); + LOGD("Tracing tests done"); + #endif // TEST_LINEBLOCKTRACER } @@ -634,7 +690,6 @@ void cWorld::TickSpawnMobs(float a_Dt) { switch (nightRand) { - case 1: MobType = E_ENTITY_TYPE_ZOMBIE; break; // _X 2013_06_25: Really? Zombies in the Nether? case 5: MobType = E_ENTITY_TYPE_GHAST; break; case 6: MobType = E_ENTITY_TYPE_ZOMBIE_PIGMAN; break; } @@ -642,8 +697,9 @@ void cWorld::TickSpawnMobs(float a_Dt) else { switch (nightRand) - { + { case 0: MobType = E_ENTITY_TYPE_SPIDER; break; + case 1: MobType = E_ENTITY_TYPE_ZOMBIE; break; case 2: MobType = E_ENTITY_TYPE_ENDERMAN; break; case 3: MobType = E_ENTITY_TYPE_CREEPER; break; case 4: MobType = E_ENTITY_TYPE_CAVE_SPIDER; break; @@ -832,6 +888,15 @@ bool cWorld::GetSignLines(int a_BlockX, int a_BlockY, int a_BlockZ, AString & a_ +bool cWorld::DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback) +{ + return m_ChunkMap->DoWithChunk(a_ChunkX, a_ChunkZ, a_Callback); +} + + + + + void cWorld::GrowTree(int a_X, int a_Y, int a_Z) { if (GetBlock(a_X, a_Y, a_Z) == E_BLOCK_SAPLING) diff --git a/source/World.h b/source/World.h index 9de00ceec..712064af6 100644 --- a/source/World.h +++ b/source/World.h @@ -129,7 +129,7 @@ public: // tolua_end /// Retrieves the world height at the specified coords; returns false if chunk not loaded / generated - bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // TODO: Export in ManualBindings.cpp + bool TryGetHeight(int a_BlockX, int a_BlockZ, int & a_Height); // Exported in ManualBindings.cpp // Broadcast respective packets to all clients of the chunk where the event is taking place // (Please keep these alpha-sorted) @@ -174,7 +174,7 @@ public: If a_MarkDirty is set, the chunk is set as dirty (used after generating) */ void SetChunkData( - int a_ChunkX, int a_ChunkZ, + int a_ChunkX, int a_ChunkZ, const BLOCKTYPE * a_BlockTypes, const NIBBLETYPE * a_BlockMeta, const NIBBLETYPE * a_BlockLight, @@ -245,7 +245,7 @@ public: bool ForEachEntityInChunk(int a_ChunkX, int a_ChunkZ, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp /// Calls the callback if the entity with the specified ID is found, with the entity object as the callback param. Returns true if entity found and callback returned false. - bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // TODO: Exported in ManualBindings.cpp + bool DoWithEntityByID(int a_UniqueID, cEntityCallback & a_Callback); // Exported in ManualBindings.cpp /// Compares clients of two chunks, calls the callback accordingly void CompareChunkClients(int a_ChunkX1, int a_ChunkZ1, int a_ChunkX2, int a_ChunkZ2, cClientDiffCallback & a_Callback); @@ -319,8 +319,8 @@ public: void SetBlockMeta(const Vector3i & a_Pos, NIBBLETYPE a_MetaData ) { SetBlockMeta( a_Pos.x, a_Pos.y, a_Pos.z, a_MetaData ); } // tolua_end - /** Writes the block area into the specified coords. - Returns true if all chunks have been processed. + /** Writes the block area into the specified coords. + Returns true if all chunks have been processed. Prefer cBlockArea::Write() instead, this is the internal implementation; cBlockArea does error checking, too. a_DataTypes is a bitmask of cBlockArea::baXXX constants ORed together. */ @@ -404,6 +404,9 @@ public: /// a_Player is using block entity at [x, y, z], handle that: void UseBlockEntity(cPlayer * a_Player, int a_BlockX, int a_BlockY, int a_BlockZ) {m_ChunkMap->UseBlockEntity(a_Player, a_BlockX, a_BlockY, a_BlockZ); } + + /// Calls the callback for the chunk specified, with ChunkMapCS locked; returns false if the chunk doesn't exist, otherwise returns the same value as the callback + bool DoWithChunk(int a_ChunkX, int a_ChunkZ, cChunkCallback & a_Callback); void GrowTree (int a_BlockX, int a_BlockY, int a_BlockZ); // tolua_export void GrowTreeFromSapling(int a_BlockX, int a_BlockY, int a_BlockZ, char a_SaplingMeta); // tolua_export |