Skip to content

Commit 09319f3

Browse files
Added clientside support for require (only for pure lua modules)
1 parent 90dc2cd commit 09319f3

File tree

3 files changed

+161
-8
lines changed

3 files changed

+161
-8
lines changed

Client/mods/deathmatch/logic/lua/CLuaMain.cpp

Lines changed: 151 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ CLuaMain::CLuaMain ( CLuaManager* pLuaManager, CResource* pResourceOwner, bool b
4242

4343
m_pResource = pResourceOwner;
4444

45+
m_iPackageLoadedRef = -1;
46+
4547
m_bEnableOOP = bEnableOOP;
4648

4749
CClientPerfStatLuaMemory::GetSingleton ()->OnLuaMainCreate ( this );
@@ -150,6 +152,9 @@ void CLuaMain::InitVM ( void )
150152
luaopen_debug ( m_luaVM );
151153
luaopen_utf8 ( m_luaVM );
152154

155+
// Initialize packages system
156+
InitPackageStorage(m_luaVM);
157+
153158
// Initialize security restrictions. Very important to prevent lua trojans and viruses!
154159
InitSecurity();
155160

@@ -207,7 +212,7 @@ void CLuaMain::InstructionCountHook ( lua_State* luaVM, lua_Debug* pDebug )
207212
}
208213

209214

210-
bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInSize, const char* szFileName )
215+
bool CLuaMain::LoadScriptFromBuffer(const char* cpInBuffer, unsigned int uiInSize, const char* szFileName, bool bClearReturnValues)
211216
{
212217
SString strNiceFilename = ConformResourcePath( szFileName );
213218

@@ -272,7 +277,7 @@ bool CLuaMain::LoadScriptFromBuffer ( const char* cpInBuffer, unsigned int uiInS
272277
g_pClientGame->GetScriptDebugging()->LogPCallError( m_luaVM, strRes, true );
273278
}
274279
// Cleanup any return values
275-
if ( lua_gettop ( m_luaVM ) > luaSavedTop )
280+
if ( bClearReturnValues && lua_gettop ( m_luaVM ) > luaSavedTop )
276281
lua_settop( m_luaVM, luaSavedTop );
277282
return true;
278283
}
@@ -571,3 +576,147 @@ int CLuaMain::OnUndump( const char* p, size_t n )
571576
}
572577
return 1;
573578
}
579+
580+
581+
///////////////////////////////////////////////////////////////
582+
//
583+
// CLuaMain::InitPackageStorage
584+
//
585+
// Create a table for storage of Lua packages - stored in the Lua VM
586+
//
587+
///////////////////////////////////////////////////////////////
588+
void CLuaMain::InitPackageStorage(lua_State* L)
589+
{
590+
lua_newtable(L); // stack: [tbl_new]
591+
lua_pushstring(L, "loaded"); // stack: [tbl_new,"loaded"]
592+
lua_newtable(L); // stack: [tbl_new,"loaded",tbl_new2]
593+
594+
// We push our default Lua libs are loaded packages
595+
std::vector<const char*> szDefaultLibs = { "math", "string", "table", "debug", "utf8" };
596+
for (auto it : szDefaultLibs)
597+
{
598+
lua_pushstring(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math"]
599+
lua_getglobal(L, it); // stack: [tbl_new,"loaded",tbl_new2,"math",_G.math]
600+
lua_settable(L, -3); // stack: [tbl_new,"loaded",tbl_new2]
601+
}
602+
603+
// Keep our package.loaded table safely in registry
604+
m_iPackageLoadedRef = luaL_ref(L, LUA_REGISTRYINDEX); // stack: [tbl_new,"loaded"]
605+
lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_new,"loaded",tbl_new2]
606+
607+
// Finally, store our original table as global package.loaded
608+
lua_settable(L, -3); // stack: [tbl_new]
609+
lua_setglobal(L, "package"); // stack: []
610+
}
611+
612+
///////////////////////////////////////////////////////////////
613+
//
614+
// CLuaMain::SetPackage
615+
//
616+
// Set the top most value as a package (No pop)
617+
//
618+
///////////////////////////////////////////////////////////////
619+
void CLuaMain::SetPackage(lua_State* L, SString &strName)
620+
{
621+
if (m_iPackageLoadedRef < 0)
622+
return;
623+
// We set varPkg, which is already on the stack, into package.loaded.moduleName = varPkg.
624+
// stack: [varPkg]
625+
int iPkg = luaL_ref(L, LUA_REGISTRYINDEX); // stack: []
626+
lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // [tbl_loaded]
627+
628+
629+
lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"]
630+
lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [tbl_loaded,"moduleName",varPkg]
631+
lua_rawset(L, -3); // stack: [tbl_loaded]
632+
lua_pop(L, 2); // stack: []
633+
lua_rawgeti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg]
634+
635+
// Cleanup our used registry entry, i.e. REGISTRY[i] = nil.
636+
lua_pushnil(L); // stack: [varPkg,nil]
637+
lua_rawseti(L, LUA_REGISTRYINDEX, iPkg); // stack: [varPkg]
638+
}
639+
640+
///////////////////////////////////////////////////////////////
641+
//
642+
// CLuaMain::GetPackage
643+
//
644+
// Push the value of a package of name to the stack
645+
//
646+
///////////////////////////////////////////////////////////////
647+
void CLuaMain::GetPackage(lua_State* L, SString &strName)
648+
{
649+
if (m_iPackageLoadedRef < 0)
650+
return;
651+
652+
lua_rawgeti(L, LUA_REGISTRYINDEX, m_iPackageLoadedRef); // stack: [tbl_loaded]
653+
lua_pushstring(L, strName.c_str()); // stack: [tbl_loaded,"moduleName"]
654+
lua_rawget(L, -2); // stack: [tbl_loaded,varPkg]
655+
lua_remove(L, -2); // stack: [varPkg]
656+
}
657+
658+
///////////////////////////////////////////////////////////////
659+
//
660+
// CLuaMain::LoadLuaLib
661+
//
662+
// Load a Lua lib of a given name
663+
//
664+
///////////////////////////////////////////////////////////////
665+
bool CLuaMain::LoadLuaLib(lua_State *L, SString strName, SString &strError)
666+
{
667+
SString strPath = strName;
668+
// Name format shouldn't include slashes. Subdirs are dots.
669+
ReplaceOccurrencesInString(strPath, "\\", "");
670+
ReplaceOccurrencesInString(strPath, "/", "");
671+
ReplaceOccurrencesInString(strPath, ".", "/");
672+
673+
SString strResPath = m_pResource->GetResourceDirectoryPath(ACCESS_PUBLIC, "");
674+
675+
std::vector < char > buffer;
676+
// Try <resource>/?.lua
677+
SString strFilePath = PathJoin(strResPath, strPath + ".lua");
678+
if (FileExists(strFilePath))
679+
FileLoad(strFilePath, buffer);
680+
else
681+
{
682+
// Don't use a format string for safety, so we construct the error by hand
683+
strError += "error loading module " + strName + " from file " + strFilePath +
684+
":\n\t The specified module could not be found";
685+
686+
// Try <resource>/?/init.lua
687+
strFilePath = PathJoin(strResPath, strPath, "init.lua");
688+
if (FileExists(strFilePath))
689+
FileLoad(strFilePath, buffer);
690+
else
691+
{
692+
strError += "\n";
693+
strError += "error loading module " + strName + " from file " + strFilePath +
694+
":\n\t The specified module could not be found";
695+
return false;
696+
}
697+
}
698+
699+
if (buffer.size() > 0)
700+
{
701+
int luaSavedTop = lua_gettop(L);
702+
LoadScriptFromBuffer(&buffer.at(0), buffer.size(), strFilePath.c_str(), false);
703+
// Only keep the first return value
704+
if (lua_gettop(L) > luaSavedTop)
705+
lua_settop(L, luaSavedTop + 1);
706+
707+
if (lua_type(L, -1) == LUA_TNIL)
708+
{
709+
strError += "error loading module " + strName + " from file " + strFilePath +
710+
":\n\t Module didn't return a value";
711+
return false;
712+
}
713+
714+
SetPackage(L, strName); // Store our package into package.loaded
715+
return true;
716+
}
717+
else
718+
strError += "error loading module " + strName + " from file " + strFilePath +
719+
":\n\t Error loading script file";
720+
721+
return false;
722+
}

Client/mods/deathmatch/logic/lua/CLuaMain.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class CLuaMain //: public CClient
4444
CLuaMain ( class CLuaManager* pLuaManager, CResource* pResourceOwner, bool bEnableOOP );
4545
~CLuaMain ( void );
4646

47-
bool LoadScriptFromBuffer ( const char* cpBuffer, unsigned int uiSize, const char* szFileName );
47+
bool LoadScriptFromBuffer ( const char* cpBuffer, unsigned int uiSize, const char* szFileName, bool bClearReturnValues = true );
4848
bool LoadScript ( const char* szLUAScript );
4949
void UnloadScript ( void );
5050

@@ -80,6 +80,11 @@ class CLuaMain //: public CClient
8080
static int LuaLoadBuffer ( lua_State *L, const char *buff, size_t sz, const char *name );
8181
static int OnUndump ( const char* p, size_t n );
8282

83+
void InitPackageStorage(lua_State* L); // Create a psuedo package.loaded table
84+
void GetPackage(lua_State *L, SString &strName); // Push the package value to the top of the stack
85+
void SetPackage(lua_State *L, SString &strName); // Set the package to the value at the top of the stack
86+
bool LoadLuaLib(lua_State *L, SString strName, SString &strError); // Load a lua library of a given name
87+
8388
bool IsOOPEnabled ( void ) { return m_bEnableOOP; }
8489
private:
8590
void InitSecurity ( void );
@@ -90,6 +95,7 @@ class CLuaMain //: public CClient
9095

9196
lua_State* m_luaVM;
9297
CLuaTimerManager* m_pLuaTimerManager;
98+
int m_iPackageLoadedRef;
9399

94100
bool m_bBeingDeleted; // prevent it being deleted twice
95101

Shared/mods/deathmatch/logic/luadefs/CLuaUtilDefs.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,6 @@ int CLuaUtilDefs::PregMatch ( lua_State* luaVM )
565565

566566
int CLuaUtilDefs::Require(lua_State* luaVM)
567567
{
568-
#ifndef MTA_CLIENT
569568
// table require ( string name )
570569
SString strMod;
571570

@@ -587,17 +586,16 @@ int CLuaUtilDefs::Require(lua_State* luaVM)
587586
if (pLuaMain->LoadLuaLib(luaVM, strMod,strError)) // stack: ["moduleName",pkgLuaMod/nil]
588587
return 1;
589588
strError += "\n";
590-
589+
#ifndef MTA_CLIENT
591590
// Check if a C library exists
592591
if (pLuaMain->LoadClib(luaVM, strMod,strError)) // stack: ["moduleName",fncModule/nil]
593592
return 1;
593+
#endif
594594
m_pScriptDebugging->LogCustom(luaVM, strError);
595-
596-
lua_pop(luaVM,2); // stack: []
597595
}
598596
else
599597
m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage());
600-
#endif
598+
601599
lua_pushboolean(luaVM, false);
602600
return 1;
603601
}

0 commit comments

Comments
 (0)