Lua emulating the require function
Asked Answered
C

2

6

In the embeded lua environment (World of Warcraft - WoW) is missing the require function.

I want port one existing lua source code (an great OO-library) for the use it in the WoW. The library itself is relatively small (approx 8 small files) but of course it heavily uses the require.

World of Warcraft loads files and libraries by defining it in an XML file, like:

<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
    <Script file="LibOne.lua"/>
    <Script file="LibTwo.lua"/>
</Ui>

but i don't know how the low level library manipulation is done in the WoW.

AFAIK in the WoW is missing even the package. table too. :(

So the question(s): For me, the streamlined way would be write an function which will emulate the require function using the interface available in WoW. The question is how. Could someone give me some directions?

Or as alternative, for the porting the mentioned existing source to WoW, I need replace the require Some.Other.Module lines in the lua sources to something what WoW will understand. What is the equivalent/replacement for such require Some.Module in the WoW?

How the WoW handles modules/libraries at low-level?

Campion answered 26/4, 2016 at 17:31 Comment(0)
C
6

You could merge all files into one using one of the various amalgamation scripts, e.g. amalg. Then you can load this file and a stub that implements the require function using the usual WoW way:

<Ui xsi:schemaLocation="http://www.blizzard.com/wow/ui/">
    <Script file="RequireStub.lua"/>
    <Script file="AllModules.lua"/><!-- amalgamated Lua modules -->
    <Script file="YourCode.lua"/>
</Ui>

The file RequireStub.lua could look like:

package = {}
local preload, loaded = {}, {
  string = string,
  debug = debug,
  package = package,
  _G = _G,
  io = io,
  os = os,
  table = table,
  math = math,
  coroutine = coroutine,
}
package.preload, package.loaded = preload, loaded


function require( mod )
  if not loaded[ mod ] then
    local f = preload[ mod ]
    if f == nil then
      error( "module '"..mod..[[' not found:
       no field package.preload[']]..mod.."']", 1 )
    end
    local v = f( mod )
    if v ~= nil then
      loaded[ mod ] = v
    elseif loaded[ mod ] == nil then
      loaded[ mod ] = true
    end
  end
  return loaded[ mod ]
end

This should emulate enough of the package library to get you a working require that loads modules in the amalgamated file. Different amalgamation scripts might need different bits from package, though, so you probably will have to take a look at the generated Lua source code.

And in the specific case of Coat you might need to implement stubs for other Lua functions as well. E.g. I've seen that Coat uses the debug library ...

Chagall answered 27/4, 2016 at 14:9 Comment(2)
This code is really hard for to me understand. What is the purpose of all those variables inside of loaded? Can you go more into detail?Tallowy
@Hatefiend: package.loaded caches all loaded/required modules. The ones listed above are the modules from Lua's standard library. In "normal" Lua they are available via require from package.loaded and as global variables. In WoW there are only the global variables, so we have to fill package.loaded ourselves.Chagall
T
2

WoW environment doesn't have dofile or any other means to read external files at all. You need to explicitly mention all files that must be loaded in .toc file or .xml referenced from .toc.

You can then write your own implementation of require to maintain compatibility with your library, which would be quite trivial as it would only need to parse module name and retrieve it's content from modules.loaded table, but you'd still need to alter original source to make files register in that table and you'll need to manually arrange all files into correct order of loading.

Alternatively you can rearrange files into separate WoW-addons and use its own built-in Dependencies/OptionalDeps facilities or popular LibStub framework to handle loading order automatically.

Thaddeus answered 26/4, 2016 at 18:5 Comment(5)
So, the modules.loaded table is available? Because the package.* tables are missing (AFAIK - it is used by the require in the "standard" lua).Campion
No, it is not. But it is just a regular table. It is just a convention of require framework to use it. You can make and fill it yourself.Thaddeus
Does WoW environment have loadstring ?Naturalism
@EgorSkriptunoff: It seems that way.Chagall
Yes, but it is patched to only allow plain source and not bytecode.Thaddeus

© 2022 - 2024 — McMap. All rights reserved.