Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 223 additions & 1 deletion Plugins/UnLua/Source/UnLua/Private/LuaEnv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@
#include "UnLuaLib.h"
#include "UnLuaSettings.h"
#include "lstate.h"
#include "Containers/Queue.h"
#include "Interfaces/IPluginManager.h"
#include "HAL/FileManager.h"
#include "Misc/Paths.h"

// 添加调试定义
#define UNLUA_DEBUG_PATH 1

namespace UnLua
{
Expand Down Expand Up @@ -599,12 +606,19 @@ namespace UnLua
FString FileName(UTF8_TO_TCHAR(lua_tostring(L, 1)));
FileName.ReplaceInline(TEXT("."), TEXT("/"));

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Trying to load module: %s"), *FileName);
#endif

auto& Env = *(FLuaEnv*)lua_touserdata(L, lua_upvalueindex(1));
TArray<uint8> Data;
FString FullPath;

auto LoadIt = [&]
{
#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Successfully loaded file: %s"), *FullPath);
#endif
if (Env.LoadString(L, Data, FullPath))
return 1;
const auto Msg = FString::Printf(TEXT("file loading from file system error.\nfull path:%s"), *FullPath);
Expand All @@ -615,13 +629,169 @@ namespace UnLua
if (PackagePath.IsEmpty())
return 0;

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Package path: %s"), *PackagePath);
#endif

TArray<FString> Patterns;
if (PackagePath.ParseIntoArray(Patterns, TEXT(";"), false) == 0)
return 0;

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Found %d patterns"), Patterns.Num());
#endif

// 特殊处理 GameFeature 插件路径
// 如果是PluginName.ModuleName这样的模块格式,尝试直接定位到对应插件
if (FileName.Contains(TEXT("/")))
{
TArray<FString> ModuleParts;
FileName.ParseIntoArray(ModuleParts, TEXT("/"));

if (ModuleParts.Num() >= 2)
{
FString PluginName = ModuleParts[0];
FString ModuleFile = ModuleParts[ModuleParts.Num() - 1];

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Searching for module in plugin - Plugin: %s, Module: %s"),
*PluginName, *ModuleFile);
#endif

// 尝试在GameFeature插件中查找
FString GameFeaturePath = FPaths::Combine(
FPaths::ProjectPluginsDir(),
TEXT("GameFeatures"),
PluginName,
TEXT("Content/Script"),
PluginName,
ModuleFile + TEXT(".lua")
);

FullPath = FPaths::ConvertRelativePathToFull(GameFeaturePath);

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Checking GameFeature plugin path: %s"), *FullPath);
#endif

if (FPaths::FileExists(FullPath) && FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
{
return LoadIt();
}

// 尝试在普通插件中查找
FString NormalPluginPath = FPaths::Combine(
FPaths::ProjectPluginsDir(),
PluginName,
TEXT("Content/Script"),
PluginName,
ModuleFile + TEXT(".lua")
);

FullPath = FPaths::ConvertRelativePathToFull(NormalPluginPath);

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Checking normal plugin path: %s"), *FullPath);
#endif

if (FPaths::FileExists(FullPath) && FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
{
return LoadIt();
}

// 尝试第二种常见结构 - 直接在Content/Script下
FString DirectPath = FPaths::Combine(
FPaths::ProjectPluginsDir(),
TEXT("GameFeatures"),
PluginName,
TEXT("Content/Script"),
ModuleFile + TEXT(".lua")
);

FullPath = FPaths::ConvertRelativePathToFull(DirectPath);

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Checking direct GameFeature path: %s"), *FullPath);
#endif

if (FPaths::FileExists(FullPath) && FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
{
return LoadIt();
}

// 尝试普通插件的直接路径
FString DirectNormalPath = FPaths::Combine(
FPaths::ProjectPluginsDir(),
PluginName,
TEXT("Content/Script"),
ModuleFile + TEXT(".lua")
);

FullPath = FPaths::ConvertRelativePathToFull(DirectNormalPath);

#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Display, TEXT("[UnLua] LoadFromFileSystem - Checking direct normal plugin path: %s"), *FullPath);
#endif

if (FPaths::FileExists(FullPath) && FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
{
return LoadIt();
}
}
}

// 优先加载下载目录下的单文件
for (auto& Pattern : Patterns)
{
// 处理通配符路径,例如Plugins/*/Content/Script
bool bHasWildcard = Pattern.Contains(TEXT("*"));
if (bHasWildcard)
{
// 找到通配符位置
int32 WildcardPos = Pattern.Find(TEXT("*"));
if (WildcardPos != INDEX_NONE)
{
FString PreWildcard = Pattern.Left(WildcardPos);
FString PostWildcard = Pattern.Mid(WildcardPos + 1);

// 替换问号为文件名
FString FilePartPattern = PostWildcard;
FilePartPattern.ReplaceInline(TEXT("?"), *FileName);

// 获取插件目录
IFileManager& FileManager = IFileManager::Get();
TArray<FString> Plugins;

// 判断是GameFeature插件还是普通插件
FString PluginsRoot;
if (PreWildcard.Contains(TEXT("GameFeatures")))
{
PluginsRoot = FPaths::ProjectPluginsDir() / TEXT("GameFeatures");
}
else
{
PluginsRoot = FPaths::ProjectPluginsDir();
}

// 获取所有插件目录
FileManager.FindFiles(Plugins, *PluginsRoot, false, true);

// 检查每个插件目录下的文件
for (const FString& Plugin : Plugins)
{
FString TestPath = FPaths::Combine(PluginsRoot, Plugin, FilePartPattern);
FullPath = FPaths::ConvertRelativePathToFull(TestPath);

if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
return LoadIt();
}

// 找不到文件时继续下一个模式
continue;
}
}

// 处理标准路径
Pattern.ReplaceInline(TEXT("?"), *FileName);
const auto PathWithPersistentDir = FPaths::Combine(FPaths::ProjectPersistentDownloadDir(), Pattern);
FullPath = FPaths::ConvertRelativePathToFull(PathWithPersistentDir);
Expand All @@ -632,12 +802,64 @@ namespace UnLua
// 其次是打包目录下的文件
for (auto& Pattern : Patterns)
{
// 同样处理通配符路径
bool bHasWildcard = Pattern.Contains(TEXT("*"));
if (bHasWildcard)
{
// 找到通配符位置
int32 WildcardPos = Pattern.Find(TEXT("*"));
if (WildcardPos != INDEX_NONE)
{
FString PreWildcard = Pattern.Left(WildcardPos);
FString PostWildcard = Pattern.Mid(WildcardPos + 1);

// 替换问号为文件名
FString FilePartPattern = PostWildcard;
FilePartPattern.ReplaceInline(TEXT("?"), *FileName);

// 获取插件目录
IFileManager& FileManager = IFileManager::Get();
TArray<FString> Plugins;

// 判断是GameFeature插件还是普通插件
FString PluginsRoot;
if (PreWildcard.Contains(TEXT("GameFeatures")))
{
PluginsRoot = FPaths::ProjectPluginsDir() / TEXT("GameFeatures");
}
else
{
PluginsRoot = FPaths::ProjectPluginsDir();
}

// 获取所有插件目录
FileManager.FindFiles(Plugins, *PluginsRoot, false, true);

// 检查每个插件目录下的文件
for (const FString& Plugin : Plugins)
{
FString TestPath = FPaths::Combine(FPaths::ProjectDir(), PreWildcard, Plugin, FilePartPattern);
FullPath = FPaths::ConvertRelativePathToFull(TestPath);

if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
return LoadIt();
}

// 找不到文件时继续下一个模式
continue;
}
}

// 处理标准路径
const auto PathWithProjectDir = FPaths::Combine(FPaths::ProjectDir(), Pattern);
FullPath = FPaths::ConvertRelativePathToFull(PathWithProjectDir);
if (FFileHelper::LoadFileToArray(Data, *FullPath, FILEREAD_Silent))
return LoadIt();
}


#if UNLUA_DEBUG_PATH
UE_LOG(LogUnLua, Warning, TEXT("[UnLua] LoadFromFileSystem - File not found: %s"), *FileName);
#endif
return 0;
}

Expand Down
94 changes: 91 additions & 3 deletions Plugins/UnLua/Source/UnLua/Private/LuaModuleLocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,98 @@ FString ULuaModuleLocator_ByPackage::Locate(const UObject* Object)
}
else
{
ModuleName = Object->GetOutermost()->GetName();
const auto ChopCount = ModuleName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, 1) + 1;
ModuleName = ModuleName.Replace(TEXT("/"), TEXT(".")).RightChop(ChopCount);
FString OuterName = Object->GetOutermost()->GetName();

// 检查是否来自GameFeature插件
const bool bFromGameFeature = OuterName.Contains(TEXT("/GameFeatures/"));
const bool bFromPlugin = OuterName.Contains(TEXT("/Plugins/"));

if (bFromGameFeature || bFromPlugin)
{
// 提取插件名称
FString PluginName;
int32 PluginPathPos = INDEX_NONE;

if (bFromGameFeature)
{
// 处理 GameFeature 插件
const int32 GameFeaturesPos = OuterName.Find(TEXT("/GameFeatures/"), ESearchCase::IgnoreCase);
if (GameFeaturesPos != INDEX_NONE)
{
const int32 StartPos = GameFeaturesPos + FString(TEXT("/GameFeatures/")).Len();
const int32 EndPos = OuterName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, StartPos);
if (EndPos != INDEX_NONE)
{
PluginName = OuterName.Mid(StartPos, EndPos - StartPos);
PluginPathPos = GameFeaturesPos;
}
}
}
else if (bFromPlugin)
{
// 处理普通插件
const int32 PluginsPos = OuterName.Find(TEXT("/Plugins/"), ESearchCase::IgnoreCase);
if (PluginsPos != INDEX_NONE)
{
const int32 StartPos = PluginsPos + FString(TEXT("/Plugins/")).Len();
const int32 EndPos = OuterName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, StartPos);
if (EndPos != INDEX_NONE)
{
PluginName = OuterName.Mid(StartPos, EndPos - StartPos);
PluginPathPos = PluginsPos;
}
}
}

// 处理插件中的蓝图
if (!PluginName.IsEmpty() && PluginPathPos != INDEX_NONE)
{
// 获取资源路径部分
FString ResourcePath;
const int32 ContentPos = OuterName.Find(TEXT("/Content/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, PluginPathPos);
if (ContentPos != INDEX_NONE)
{
const int32 ScriptPartStart = ContentPos + FString(TEXT("/Content/")).Len();
ResourcePath = OuterName.Mid(ScriptPartStart);

// 获取类名部分(最后一个斜杠后的部分)
FString ClassName;
const int32 LastSlashPos = ResourcePath.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromEnd);
if (LastSlashPos != INDEX_NONE)
{
ClassName = ResourcePath.Mid(LastSlashPos + 1);

// 构建最终的模块名
// 对于GameFeature插件,使用: 插件名.类名
// 例如: AstraAI.BP_TEST_C
ModuleName = PluginName + TEXT(".") + ClassName;
}
else
{
ModuleName = PluginName + TEXT(".") + ResourcePath;
}
}
else
{
// 如果找不到Content目录,使用类名
ModuleName = PluginName + TEXT(".") + Class->GetName();
}
}
else
{
// 使用默认处理
const auto ChopCount = OuterName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, 1) + 1;
ModuleName = OuterName.Replace(TEXT("/"), TEXT(".")).RightChop(ChopCount);
}
}
else
{
// 普通资产的处理方式(不变)
const auto ChopCount = OuterName.Find(TEXT("/"), ESearchCase::IgnoreCase, ESearchDir::FromStart, 1) + 1;
ModuleName = OuterName.Replace(TEXT("/"), TEXT(".")).RightChop(ChopCount);
}
}

Cache.Add(Key, ModuleName);
return ModuleName;
}
Loading