You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UE4 Lua虚拟机循环调用Next引发栈溢出问题求助

UE4 Lua JSON对象合并的无限循环与栈溢出问题

开发UE4 Lua虚拟机的JSON对象系统时,JSON对象合并功能出现问题:使用while循环结合IterateTable函数遍历table时,调用Next或包含Next的函数会触发无限循环,进而引发栈溢出崩溃。

期望实现的逻辑:当Original和ToMerge拥有相同键,且该键对应的值为table时,递归合并这两个table,完成后回到原循环继续执行。


遍历用户数据对象的映射元素

void UJsonMergetFunctionLibrary::MergeLuaJsonObject(UMyDynamicObject* Origional, UMyDynamicObject* ToMerge, bool Override)
{
    //Get all user data object keys
    for (TPair<FString, FLuaValue>& P: ToMerge->GetTableContent())
    {
        //Holds the value of current key
        FLuaValue Hold;
        
        if (Origional->hasField(P.Key))
        {
            if ((P.Value.Type == ELuaValueType::Table) || (P.Value.Type == ELuaValueType::UObject))
            {
                Hold = Origional->LuaGetField(P.Key);
                MergeLuaJsonObject(Hold, P.Value, Override);
            } 
            else if (Override)
            {
                Origional->LuaSetField(P.Key, P.Value);
            }
            
        } 
        else
        {
            Origional->LuaSetField(P.Key, P.Value);
            
        }
    }
}

遍历Lua table或用户数据对象的元素

void UJsonMergetFunctionLibrary::MergeLuaJsonObject(FLuaValue& Origional, FLuaValue& ToMerge, bool Override)
{
    if (Origional.Type != ToMerge.Type) {
        if (Override)
        {
            Origional = ToMerge;
            return;
        } 
        else
        {
            return;
        }
    }

    //Table
    if ((Origional.Type == ELuaValueType::Table) || (ToMerge.Type == ELuaValueType::Table)) {
        TPair<FLuaValue, FLuaValue> Pair;
        int32 MaxDex = MaxTableIndex(Origional);
        
        while (IterateTable(ToMerge, Pair)) {

            if (Pair.Key.Type == ELuaValueType::Integer)
            {
                MaxDex += 1;
                Origional.SetFieldByIndex(MaxDex, Pair.Value);
            } 
            else if (HasTableField(Origional, Pair.Key.ToString()))
            {
                FLuaValue Hold = Origional.GetField(Pair.Key.ToString());

                if ((Pair.Value.Type == ELuaValueType::Table) && (Hold.Type == ELuaValueType::Table))
                {
                    //Hold = OrigionalObj->LuaGetField(P.Key);
                    MergeLuaJsonObject(Hold, Pair.Value, Override);
                }
                else if((Pair.Value.Type == ELuaValueType::UObject) && (Hold.Type == ELuaValueType::UObject))
                {
                    MergeLuaJsonObject(Hold, Pair.Value, Override);
                }
                else if (Override) {
                    Origional.SetField(Pair.Key.ToString(), Pair.Value);
                }
            }
            else
            {
                Origional.SetField(Pair.Key.ToString(), Pair.Value);
            }
        }
    }
    //Object
    else if ((Origional.Type == ELuaValueType::UObject) || (ToMerge.Type == ELuaValueType::UObject)) {
        UMyDynamicObject* ToMergeObj = Cast<UMyDynamicObject>(ULuaBlueprintFunctionLibrary::Conv_LuaValueToObject(ToMerge));
        UMyDynamicObject* OrigionalObj = Cast<UMyDynamicObject>(ULuaBlueprintFunctionLibrary::Conv_LuaValueToObject(Origional));
        TMap<FString, FLuaValue> Keys = ToMergeObj->GetTableContent();

        for (TPair<FString, FLuaValue>& P: Keys)
        {
            FLuaValue Hold;

            if (OrigionalObj->hasField(P.Key))
            {
                if ((P.Value.Type == ELuaValueType::Table) || (P.Value.Type == ELuaValueType::UObject))
                {
                    Hold = OrigionalObj->LuaGetField(P.Key);
                    MergeLuaJsonObject(Hold, P.Value, Override);
                }
                else if (Override)
                {
                    OrigionalObj->LuaSetField(P.Key, P.Value);
                }

            }
            else
            {
                OrigionalObj->LuaSetField(P.Key, P.Value);

            }
            //OrigionalObj->LuaSetField(P.Key, P)
        }

        Origional = FLuaValue(OrigionalObj);
    }
}

遍历并获取table中的下一个键

bool UJsonMergetFunctionLibrary::IterateTable(FLuaValue Table, TPair<FLuaValue, FLuaValue>& Pair)
{
    if (Table.Type != ELuaValueType::Table)
        return false;

    ULuaState* L = Table.LuaState;
    if (!L)
        return false;

    if (Pair.Key.IsNil())
    {
        L->FromLuaValue(Table);
        L->PushNil(); // first key
    }

    if (L->Next(-2))
    {
        Pair.Key = L->ToLuaValue(-2);
        Pair.Value = L->ToLuaValue(-1);

        if (GEngine)
            GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow, Pair.Key.ToString());

        L->Pop(); // pop the value
        
        return true;
    } 
    else
    {
        L->Pop(); // pop the table
        return false;
    }
}

检查table是否包含指定键

bool UJsonMergetFunctionLibrary::HasTableField(FLuaValue Table, FString FieldName)
{
    if (Table.Type != ELuaValueType::Table)
        return false;

    ULuaState* L = Table.LuaState;
    if (!L)
        return false;
    
    L->FromLuaValue(Table);
    L->PushNil(); // first key

    while (L->Next(-2))
    {
        FLuaValue Key = L->ToLuaValue(-2);

        if (Key.ToString() == FieldName)
        {
            L->Pop(); // pop the value
            L->Pop(); // pop the table
            return true;
        }
        else {
            L->Pop(); // pop the value
        }
    }

    L->Pop(); // pop the table

    return false;
}

已尝试的无效方法

  • 在循环内调用Next时弹出值和键,结束内部Next调用后重新赋值旧键;
  • 搜索相关解决方案但无结果;
  • 为循环执行次数添加限制,测试是否由无限循环导致崩溃;
  • 编写纯Lua函数遍历table并调用Next(未成功,本人Lua经验尚浅)。

内容的提问来源于stack exchange,提问作者The Darkest Edge Lord

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 06:35:20