Lua C API

发布于:2024-06-29 ⋅ 阅读:(13) ⋅ 点赞:(0)

Lua 5.4 Reference Manual - contents官方网站

void lua_call(lua_State *L, int nargs, int nresults);
void lua_callK(lua_State *L, int nargs, int nresults, lua_KContext ctx, lua_KFunction k);// allows the called function to yield


typedef int (*lua_CFunction)(lua_State *L);//自定义C函数,用于操作Lua中的变量或函数。

int lua_checkstack(lua_State *L, int n);//Ensures that the stack has space for at least n extra elements.

int lua_compare(lua_State *L, int index1, int index2, int op);


void lua_createtable(lua_State *L, int narr, int nrec);
//Parameter narr is a hint for how many elements the table will have as a sequence;
//Parameter nrec is a hint for how many other elements the table will have.


int lua_getfield(lua_State *L, int index, const char *k);
//Pushes onto the stack the value t[k], where t is the value at the given index;

int lua_getglobal(lua_State *L, const char *name);
//Pushes onto the stack the value of the global name.Returns the type of that value.

int lua_geti(lua_State *L, int index, lua_Integer i);
//Pushes onto the stack the value t[i], where t is the value at the given index.

int lua_getmetatable(lua_State *L, int index);
//If the value at the given index has a metatable, the function pushes that metatable onto the stack and returns 1.


int lua_gettable(lua_State *L, int index);
Pushes onto the stack the value t[k], where t is the value at the given index and k is the value on the top of the stack.

int lua_gettop(lua_State *L);
//Returns the index of the top element in the stack.

int lua_iscfunction(lua_State *L, int index)
int lua_isfunction(lua_State *L, int index)

int lua_isnumber(lua_State *L, int index)
Returns 1 if the value at the given index is a number or a string convertible to a number.
int lua_isstring(lua_State *L, int index)
Returns 1 if the value at the given index is a string or a number.


typedef ... lua_KContext;


lua_State *lua_newstate(lua_Alloc f, void *ud);
//Creates a new independent state and returns its main thread.

void lua_newtable(lua_State *L);
//Creates a new empty table and pushes it onto the stack. It is equivalent to lua_createtable(L, 0, 0).


int lua_next(lua_State *L, int index);
//Pops a key from the stack, and pushes a key-value pair from the table at the given index.


int lua_pcall(lua_State *L, int nargs, int nresults, int msgh);
//Calls a function(or a callable object) in protected mode.
//Like lua_call, lua_pcall always removes the function and its arguments from the stack.

int lua_pcallk(lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k);

void lua_pop(lua_State *L, int n);
void lua_pushcclosure(lua_State *L, lua_CFunction fn, int n);
//Pushes a new C closure onto the stack.The parameter n tells how many upvalues this function will have.
//When a C function in created, it is possible to associate some values with it, the so called upvalues; these upvalues are the accessible to the function whenever it is called. This association is called a C closure.
//When n is zero, this function creates a light C function, which is just a pointer to the C function.

void lua_pushcfunction(lua_State *L, lua_CFunction f);
//Pushes a C function onto the stack.This function is equivalent to lua_pushcclosure with no upvalues.

void lua_pushglobaltable(lua_State *L)
//Pushes the global environment onto the stack.

void lua_pushlightuserdata(lua_State *L, void *P);
//Pushes a light userdata onto the stack.
//Userdata represent C values in Lua. A light userdata represents a pointer.

void lua_pushvalue(lua_State *L, int index)
//Pushes a copy of the element at the given index onto the stack.

void lua_rawset(lua_State *L, int index)
//Similar to lua_settable, but does a raw access. the value at index must be a table.
void lua_rawget(lua_State *L, int index)
//Similar to lua_gettable, but does a raw access. The value at index must be a table.

int lua_rawgetp(lua_State *L, int index, const void *P);
//Pushes onto the stack the value t[k], where t is the table at the given index and k is the pointer p represented as a light userdata. Returns the type of the pushed value.

void lua_register(lua_State *L, const char *name, lua_CFunction f);
//Sets the C function f as the new value of global name.It is defined as a macro:
//#define lua_register(L, n, f) (lua_pushcfunction(L,f), lua_setglobal(L, n))

void lua_remove(lua_State *L, int index)
//Removes the element at the given valid index, shifting down the elements above this index to fill the gap.

void lua_setfield(lua_State *L, int index, const char *k)
//Does the equivalent to t[k] = v, where t is the value at the given index and v is the value on the top of the stack.

void lua_setglobal(lua_State *L, const char *name)
//Pops a value from the stack and sets it as the new value of global name.

int lua_setiuservalue(lua_State *L, int index, int n)
//Pops a value from the stack and sets it as the new n-th user value associated to the full userdata at the given index. Returns 0 if the userdata does not have that value.

int lua_setmetatable(lua_State *L, int index)
//Pops a table or nil from the stack and sets that value as the new metatable for the value at the given index.(nil means no metatable)

void lua_settable(lua_State *L, int index);
//Does the equivalent to t[k] = v, where t is the value at the given index, v is the value on the top of the stack, and k is the value just below the top.

void lua_settop(lua_State *L, int index);

//转换函数
int lua_toboolean(lua_State *L, int index);
//Converts the Lua value at the given index to a C boolean value (0 or 1)

lua_CFunction lua_tocfunction(lua_State *L, int index);
//Converts a value at the given index to a C function. That value must be a C function.

const void* lua_topointer(lua_State *L, int index)
//Converts the value at the given index to a generic C pointer(void*). The value can be a userdata, a table, a thread, a string, or a function; otherwise returns NULL.

void* lua_touserdata(lua_State *L, int index)
//If the value at the given index is a full userdata, returns its memory-block address. If the value is a light userdata, returns its value(a pointer). otherwise returns NULL.

int lua_upvalueindex(int i);
//Returns the pseudo-index that represents the i-th upvalue of the running function. i must be in the range [1,256]

void lua_toclose(lua_State *L, int index);

void

Unlua、Slua均是腾讯开源的UE lua框架。

// Tencent is pleased to support the open source community by making UnLua available.
// 
// Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the MIT License (the "License"); 
// you may not use this file except in compliance with the License. You may obtain a copy of the License at
//
// http://opensource.org/licenses/MIT
//
// Unless required by applicable law or agreed to in writing, 
// software distributed under the License is distributed on an "AS IS" BASIS, 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
// See the License for the specific language governing permissions and limitations under the License.

#include "UELib.h"
#include "Binding.h"
#include "Registries/ClassRegistry.h"
#include "LuaCore.h"
#include "LuaDynamicBinding.h"
#include "LuaEnv.h"
#include "Registries/EnumRegistry.h"

static const char* REGISTRY_KEY = "UnLua_UELib";
static const char* NAMESPACE_NAME = "UE";

static int UE_Index(lua_State* L)
{
    const int32 Type = lua_type(L, 2);
    if (Type != LUA_TSTRING)
        return 0;

    const char* Name = lua_tostring(L, 2);
    const auto Exported = UnLua::FindExportedNonReflectedClass(Name);
    if (Exported)
    {
        Exported->Register(L);
        lua_rawget(L, 1);
        return 1;
    }

    const char Prefix = Name[0];
    const auto& Env = UnLua::FLuaEnv::FindEnvChecked(L);
    if (Prefix == 'U' || Prefix == 'A' || Prefix == 'F')
    {
        const auto ReflectedType = UnLua::FClassRegistry::LoadReflectedType(Name + 1);
        if (!ReflectedType)
            return 0;

        if (ReflectedType->IsNative())
        {
            if (auto Struct = Cast<UStruct>(ReflectedType))
                Env.GetClassRegistry()->Register(Struct);
        }
        else
        {
            UE_LOG(LogUnLua, Warning, TEXT("attempt to load a blueprint type %s with UE namespace, use UE.UClass.Load or UE.UObject.Load instead."), UTF8_TO_TCHAR(Name));
            return 0;
        }
    }
    else if (Prefix == 'E')
    {
        const auto ReflectedType = UnLua::FClassRegistry::LoadReflectedType(Name);
        if (!ReflectedType)
            return 0;

        if (ReflectedType->IsNative())
        {
            if (auto Enum = Cast<UEnum>(ReflectedType))
                Env.GetEnumRegistry()->Register(Enum);
        }
        else
        {
            UE_LOG(LogUnLua, Warning, TEXT("attempt to load a blueprint enum %s with UE namespace, use UE.UObject.Load instead."), UTF8_TO_TCHAR(Name));
            return 0;
        }
    }

    lua_rawget(L, 1);
    return 1;
}

extern int32 UObject_Load(lua_State *L);
extern int32 UClass_Load(lua_State *L);
static int32 Global_NewObject(lua_State *L)
{
    int32 NumParams = lua_gettop(L);
    if (NumParams < 1)
    {
        UNLUA_LOGERROR(L, LogUnLua, Log, TEXT("%s: Invalid parameters!"), ANSI_TO_TCHAR(__FUNCTION__));
        return 0;
    }

    UClass *Class = Cast<UClass>(UnLua::GetUObject(L, 1));
    if (!Class)
    {
        UNLUA_LOGERROR(L, LogUnLua, Log, TEXT("%s: Invalid class!"), ANSI_TO_TCHAR(__FUNCTION__));
        return 0;
    }

    UObject* Outer = UnLua::GetUObject(L, 2);
    if (!Outer)
        Outer = GetTransientPackage();

    FName Name = NumParams > 2 ? FName(lua_tostring(L, 3)) : NAME_None;
    //EObjectFlags Flags = NumParams > 3 ? EObjectFlags(lua_tointeger(L, 4)) : RF_NoFlags;

    {
        const char *ModuleName = NumParams > 3 ? lua_tostring(L, 4) : nullptr;
        int32 TableRef = LUA_NOREF;
        if (NumParams > 4 && lua_type(L, 5) == LUA_TTABLE)
        {
            lua_pushvalue(L, 5);
            TableRef = luaL_ref(L, LUA_REGISTRYINDEX);
        }
        FScopedLuaDynamicBinding Binding(L, Class, UTF8_TO_TCHAR(ModuleName), TableRef);
#if ENGINE_MAJOR_VERSION <= 4 && ENGINE_MINOR_VERSION < 26
        UObject* Object = StaticConstructObject_Internal(Class, Outer, Name);
#else
        FStaticConstructObjectParameters ObjParams(Class);
        ObjParams.Outer = Outer;
        ObjParams.Name = Name;
        UObject* Object = StaticConstructObject_Internal(ObjParams);
#endif
        if (Object)
        {
            UnLua::PushUObject(L, Object);
        }
        else
        {
            UNLUA_LOGERROR(L, LogUnLua, Log, TEXT("%s: Failed to new object for class %s!"), ANSI_TO_TCHAR(__FUNCTION__), *Class->GetName());
            return 0;
        }
    }

    return 1;
}

static constexpr luaL_Reg UE_Functions[] = {
    {"LoadObject", UObject_Load},
    {"LoadClass", UClass_Load},
    {"NewObject", Global_NewObject},
    {NULL, NULL}
};

int UnLua::UELib::Open(lua_State* L)
{
    lua_newtable(L);
    lua_pushstring(L, "__index");
    lua_pushcfunction(L, UE_Index);
    lua_rawset(L, -3);

    lua_pushvalue(L, -1);
    lua_setmetatable(L, -2);

    lua_pushvalue(L, -1);
    lua_pushstring(L, REGISTRY_KEY);
    lua_rawset(L, LUA_REGISTRYINDEX);

    luaL_setfuncs(L, UE_Functions, 0);
    lua_setglobal(L, NAMESPACE_NAME);

    // global access for legacy support
    lua_getglobal(L, LUA_GNAME);
    luaL_setfuncs(L, UE_Functions, 0);
    lua_pop(L, 1);

#if WITH_UE4_NAMESPACE == 1
    // 兼容UE4访问
    lua_getglobal(L, NAMESPACE_NAME);
    lua_setglobal(L, "UE4");
#elif WITH_UE4_NAMESPACE == 0
    // 兼容无UE4全局访问
    lua_getglobal(L, LUA_GNAME);
    lua_newtable(L);
    lua_pushstring(L, "__index");
    lua_getglobal(L, NAMESPACE_NAME);
    lua_rawset(L, -3);
    lua_setmetatable(L, -2);
#endif

    return 1;
}

void UnLua::UELib::SetTableForClass(lua_State* L, const char* Name)
{
    lua_getglobal(L, NAMESPACE_NAME);
    lua_pushstring(L, Name);
    lua_pushvalue(L, -3);
    lua_rawset(L, -3);
    lua_pop(L, 1);
}