@@ -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+ }
0 commit comments