├── .editorconfig ├── .gitignore ├── .gitmodules ├── Benchmark.xlsx ├── Bluelua.uplugin ├── Doc └── Images │ └── cast.png ├── README-cn.md ├── README.md ├── Resources └── Icon128.png └── Source ├── Bluelua ├── Bluelua.Build.cs ├── Private │ ├── Bluelua.cpp │ ├── BlueluaLibrary.cpp │ ├── Delegates │ │ ├── LuaMulticastScriptDelegate.cpp │ │ ├── LuaScriptDelegate.cpp │ │ └── LuaSparseDelegate.cpp │ ├── LuaFunctionDelegate.cpp │ ├── LuaImplementableActor.cpp │ ├── LuaImplementableInterface.cpp │ ├── LuaImplementableWidget.cpp │ ├── LuaObjectBase.cpp │ ├── LuaStackGuard.cpp │ ├── LuaState.cpp │ ├── LuaUClass.cpp │ ├── LuaUDelegate.cpp │ ├── LuaUObject.cpp │ ├── LuaUScriptStruct.cpp │ └── LuaUStruct.cpp └── Public │ ├── Bluelua.h │ ├── BlueluaLibrary.h │ ├── Delegates │ ├── LuaMulticastScriptDelegate.h │ ├── LuaScriptDelegate.h │ └── LuaSparseDelegate.h │ ├── LuaFunctionDelegate.h │ ├── LuaImplementableActor.h │ ├── LuaImplementableInterface.h │ ├── LuaImplementableWidget.h │ ├── LuaObjectBase.h │ ├── LuaStackGuard.h │ ├── LuaState.h │ ├── LuaUClass.h │ ├── LuaUDelegate.h │ ├── LuaUObject.h │ ├── LuaUScriptStruct.h │ └── LuaUStruct.h ├── BlueluaEditor ├── BlueluaEditor.Build.cs ├── Private │ └── BlueluaEditor.cpp └── Public │ └── BlueluaEditor.h ├── LibLuasocket ├── LibLuasocket.Build.cs ├── LibLuasocket.cpp ├── LibLuasocket.h ├── auxiliar.c ├── auxiliar.h ├── buffer.c ├── buffer.h ├── except.c ├── except.h ├── ftp.lua.inc ├── headers.lua.inc ├── http.lua.inc ├── inet.c ├── inet.h ├── io.c ├── io.h ├── ltn12.lua.inc ├── luasocket.c ├── luasocket.h ├── mbox.lua.inc ├── mime.c ├── mime.h ├── mime.lua.inc ├── options.c ├── options.h ├── pierror.h ├── select.c ├── select.h ├── smtp.lua.inc ├── socket.h ├── socket.lua.inc ├── tcp.c ├── tcp.h ├── timeout.c ├── timeout.h ├── tp.lua.inc ├── udp.c ├── udp.h ├── url.lua.inc ├── usocket.c ├── usocket.h ├── wsocket.c └── wsocket.h └── LuaPanda ├── DebugTools.lua.inc ├── LuaPanda.1.lua.inc ├── LuaPanda.2.lua.inc ├── LuaPanda.3.lua.inc ├── LuaPanda.4.lua.inc ├── LuaPanda.5.lua.inc ├── LuaPanda.Build.cs ├── LuaPanda.cpp ├── LuaPanda.h ├── libpdebug.cpp └── libpdebug.h /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome:http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Baseline 7 | [*] 8 | charset = utf-8 9 | indent_style = tab 10 | indent_size = 4 11 | tab_width = 4 12 | trim_trailing_whitespace = true 13 | max_line_length = 120 14 | 15 | # MSBuild 16 | [*.{csproj,proj,projitems,shproj,fsproj,target,props}] 17 | indent_style = space 18 | indent_size = 2 19 | 20 | # XML config files 21 | [*.{config,nuspec,resx}] 22 | indent_style = space 23 | indent_size = 2 24 | 25 | # Python files 26 | [*.py] 27 | indent_style = space 28 | indent_size = 4 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | /*.sln 35 | bin/ 36 | obj/ 37 | 38 | .vs/ 39 | Binaries/ 40 | Intermediate/ 41 | 42 | /DerivedDataCache 43 | /Saved 44 | Build/**/ 45 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Source/Liblua"] 2 | path = Source/Liblua 3 | url = https://github.com/jashking/Liblua.git 4 | -------------------------------------------------------------------------------- /Benchmark.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashking/Bluelua/edcbd97f062637664ab2dd83c12b4311ab805c01/Benchmark.xlsx -------------------------------------------------------------------------------- /Bluelua.uplugin: -------------------------------------------------------------------------------- 1 | { 2 | "FileVersion": 3, 3 | "Version": 1, 4 | "VersionName": "1.0", 5 | "FriendlyName": "Bluelua", 6 | "Description": "Lua script for ue4", 7 | "Category": "Other", 8 | "CreatedBy": "jashwang", 9 | "CreatedByURL": "", 10 | "DocsURL": "", 11 | "MarketplaceURL": "", 12 | "SupportURL": "", 13 | "CanContainContent": true, 14 | "IsBetaVersion": false, 15 | "Installed": false, 16 | "EnabledByDefault": false, 17 | "Modules": [ 18 | { 19 | "Name": "Bluelua", 20 | "Type": "Runtime", 21 | "LoadingPhase": "Default" 22 | }, 23 | { 24 | "Name": "BlueluaEditor", 25 | "Type": "Editor", 26 | "LoadingPhase": "Default" 27 | }, 28 | { 29 | "Name": "Liblua", 30 | "Type": "Runtime", 31 | "LoadingPhase": "Default" 32 | }, 33 | { 34 | "Name": "LibLuasocket", 35 | "Type": "Runtime", 36 | "LoadingPhase": "Default" 37 | }, 38 | { 39 | "Name": "LuaPanda", 40 | "Type": "Runtime", 41 | "LoadingPhase": "Default" 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /Doc/Images/cast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashking/Bluelua/edcbd97f062637664ab2dd83c12b4311ab805c01/Doc/Images/cast.png -------------------------------------------------------------------------------- /README-cn.md: -------------------------------------------------------------------------------- 1 | # Bluelua for UE4 # 2 | 3 | 用 Lua 替换蓝图脚本,保持和蓝图一致的使用方式,无缝切换。Lua 中使用反射去访问虚幻对象的属性和方法,无需生成胶水代码,更加简洁易扩展,对于经常访问的方法可以在 lua 中进行 cache,减少反射访问成本。 4 | 5 | ## 第三方开源库列表 ## 6 | 7 | * [lua](https://www.lua.org/) : Lua is a powerful, efficient, lightweight, embeddable scripting language 8 | * [luasocket](https://github.com/diegonehab/luasocket) : Network support for the Lua language 9 | * [Tencent LuaPanda](https://github.com/Tencent/LuaPanda) : Pandora Lua Debugger for VS Code 10 | 11 | ## 特性 ## 12 | 13 | * 直接在 lua 中调用 UFunction 14 | * 直接在 lua 中访问 UClass/UStruct 的 UProperty 成员变量 15 | * 可在 lua 中重写 C++ 中的 BlueprintNativeEvent/BlueprintImplementable 事件 16 | * 可在 lua 中重写蓝图中的函数和事件 17 | * 可在 lua 中重写 C++ 中的网络事件(Server/Client/NetMulticast) 18 | * 可在 lua 中重写蓝图中的网络事件 19 | 20 | ## 使用 ## 21 | 22 | 复制到项目 *Plugins* 目录下即可 23 | 24 | ### 使用约定 ### 25 | 26 | * `ILuaImplementableInterface` 27 | 28 | 所有可用 lua 子类化的 C++ 类,都需要继承自该接口,并在对应的虚函数里调用相应的接口,主要几种类重载方式如下 29 | 30 | * 所有类(或蓝图)都需要重载两个重要的 `BlueprintNativeEvent`: `ShouldEnableLuaBinding` 和 `OnInitBindingLuaPath` 31 | * `ShouldEnableLuaBinding`: 返回是否开启 lua 绑定 32 | * `OnInitBindingLuaPath`: 返回绑定的 lua 文件路径 33 | 34 | * C++ 中可选择性重载 `OnInitLuaState`,返回自定义的 `FLuaState`,默认使用全局的 lua state 35 | 36 | * `AActor` 类,参见 [`LuaImplementableActor.h`](https://github.com/jashking/Bluelua/blob/master/Source/Bluelua/Public/LuaImplementableActor.h) 37 | * 在 `BeginPlay` 虚函数里调用 `OnInitLuaBinding` 38 | * 在 `EndPlay` 和 `BeginDestroy` 虚函数里调用 `OnReleaseLuaBinding` 39 | * 在 `ProcessEvent` 虚函数里调用 `LuaProcessEvent` 40 | 41 | * `UUserWidget` 类,参见 [`LuaImplementableWidget.h`](https://github.com/jashking/Bluelua/blob/master/Source/Bluelua/Public/LuaImplementableWidget.h) 42 | * 在 `NativeConstruct` 虚函数里调用 `OnInitLuaBinding` 43 | * 在 `NativeDestruct` 和 `BeginDestroy` 虚函数里调用 `OnReleaseLuaBinding` 44 | * 在 `ProcessEvent` 虚函数里调用 `LuaProcessEvent` 45 | 46 | Widget 类还有个特殊的地方,该类对象所拥有的 `LatentAction` 不受暂停影响,所以还需要重载 `NativeTick`,在该虚函数里调用 `LatentActionManager` 处理自己拥有的 `LatentAction` 对象 47 | 48 | * `UObject` 类,参见 [LuaActionRPG](https://github.com/jashking/LuaActionRPG) 例子中的 [`RPGAnimNotifyState.h`](https://github.com/jashking/LuaActionRPG/blob/master/Source/ActionRPG/Public/RPGAnimNotifyState.h) 49 | * 在 `BeginDestroy` 虚函数里调用 `OnReleaseLuaBinding` 50 | * 在 `ProcessEvent` 虚函数里调用 `LuaProcessEvent` 51 | * 因为 UObject 类没有一个初始化的虚函数可重载,所以可以在 `ProcessEvent` 第一次被调用时候进行初始化,详情见例子 52 | 53 | * `UGameInstance` 类,参见 [LuaActionRPG](https://github.com/jashking/LuaActionRPG) 例子中的 [`RPGGameInstanceBase.h`](https://github.com/jashking/LuaActionRPG/blob/master/Source/ActionRPG/Public/RPGGameInstanceBase.h) 54 | * 在 `Init` 虚函数里调用 `OnInitLuaBinding` 55 | * 在 `Shutdown` 和 `BeginDestroy` 虚函数里调用 `OnReleaseLuaBinding` 56 | * 在 `ProcessEvent` 虚函数里调用 `LuaProcessEvent` 57 | 58 | * `Super` 59 | 60 | 用 Lua 去子类化 Widget 或者 Actor 时候,会传入一个临时全局父类对象 Super,需要自己在 lua 里引用住 61 | 62 | * `CastToLua` 63 | 64 | 获取到一个虚幻对象后,判断该对象是否使用 lua 子类化,可以调用该对象的方法 `CastToLua`,如果使用了 lua 子类化则会返回一个 lua table,可以直接调用该 table 中的属性和方法,类似蓝图中将一个 C++ 对象转为蓝图对象,如图所示 65 | 66 | ![](Doc/Images/cast.png) 67 | 68 | * `Lua` 的模块化书写 69 | 70 | 编写 lua 代码去子类化 C++ 或蓝图类时,必须采用模块化的写法,并且所有方法都采用 **:** 的声明形式,如下所示 71 | ``` lua 72 | local m = {} 73 | 74 | function m:func() 75 | end 76 | 77 | return m 78 | ``` 79 | 80 | * `Lua` 实现蓝图中的继承逻辑 81 | 82 | 用蓝图编写逻辑时候,也可以类似 C++ 那样进行继承,在 Lua 中也可以利用元表实现 lua 对象间的继承,可以参见 [LuaActionRPG](https://github.com/jashking/LuaActionRPG) 中 [PlayerCharacter.lua](https://github.com/jashking/LuaActionRPG/blob/master/Content/Lua/Blueprints/PlayerCharacter.lua) 和 [Character.lua](https://github.com/jashking/LuaActionRPG/blob/master/Content/Lua/Blueprints/Character.lua) 83 | 84 | * `Lua` 中重载 `BlueprintImplementableEvent` 和 `BlueprintNativeEvent` 方法时要注意,方法名要完全一致,比如 `BeginPlay` 事件,可重载的方法名其实叫 `ReceiveBeginPlay`。Lua 调用成员方法时也需要注意方法的命名问题,因为有时候在蓝图中看到的方法名称其实是个别名 85 | 86 | ## Samples ## 87 | 88 | * [BlueluaDemo](https://github.com/jashking/BlueluaDemo): 性能对比测试和简单用法 89 | * [LuaActionRPG](https://github.com/jashking/LuaActionRPG): 官方的 ActionRPG 示例,将蓝图逻辑替换为 lua 逻辑,尚未完全替换完 90 | 91 | ## TODO ## 92 | 93 | * hot reload lua -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bluelua for UE4 # 2 | 3 | Replace the blueprint with Lua, keep it in a consistent way with the blueprint, and switch seamlessly. Accessing UObject's properties and methods with reflection and without the need to generate glue code, more simple and easy to expand. 4 | 5 | Android, iOS, Mac, Windows, Linux are supported now. 6 | 7 | ## Used Open Source Libraries ## 8 | 9 | * [lua](https://www.lua.org/) : Lua is a powerful, efficient, lightweight, embeddable scripting language 10 | * [luasocket](https://github.com/diegonehab/luasocket) : Network support for the Lua language 11 | * [Tencent LuaPanda](https://github.com/Tencent/LuaPanda) : Pandora Lua Debugger for VS Code 12 | 13 | ## Features ## 14 | 15 | * Call UFunction directly in lua 16 | * Access UProperty member of UClass/UStruct 17 | * Override BlueprintNativeEvent/BlueprintImplementable in lua 18 | * Override blueprint's function/event in lua 19 | * Override native net replicated event(Server/Client/NetMulticast) in lua 20 | * Override blueprint's net replicated event in lua 21 | 22 | ## How to use ## 23 | 24 | Clone Bluelua to your project's *Plugins* folder, regenerate project solution and build. 25 | 26 | ### How to inherit C++ with lua ### 27 | 28 | * `ILuaImplementableInterface` 29 | 30 | All C++ classes that can be used with LUA subclasses need to be inherited from this interface and the corresponding methods are called in the corresponding virtual functions, the main types of overrideing are as follows: 31 | 32 | All C++ classes (or blueprint classes) need to override two important `BlueprintNativeEvent`: `ShouldEnableLuaBinding`: should use lua subclass on this C++/Blueprint class. `OnInitBindingLuaPath`: return corresponding lua file path 33 | 34 | It's optional to override `OnInitLuaState`: return custom FLuaState wrapper, default use of global lua state 35 | 36 | * Class `AActor`, see [`LuaImplementableActor.h`](https://github.com/jashking/Bluelua/blob/master/Source/Bluelua/Public/LuaImplementableActor.h) 37 | * Call `OnInitLuaBinding` in `BeginPlay` 38 | * Call `OnReleaseLuaBinding` in `EndPlay` 39 | * Call `LuaProcessEvent` in `ProcessEvent` 40 | 41 | * Class `UUserWidget`, see [`LuaImplementableWidget.h`](https://github.com/jashking/Bluelua/blob/master/Source/Bluelua/Public/LuaImplementableWidget.h) 42 | * Call `OnInitLuaBinding` in `NativeConstruct` 43 | * Call `OnReleaseLuaBinding` in `NativeDestruct` 44 | * Call `LuaProcessEvent` in `ProcessEvent` 45 | 46 | The UUserWidget class also has a special place where the `LatentAction` owned by the class is not affected by the pause, so you also need to override `NativeTick` and call `LatentActionManager` in the virtual function to handle all `LatentAction` objects. See `TickActions` in [`LuaImplementableWidget.h`](https://github.com/jashking/Bluelua/blob/master/Source/Bluelua/Public/LuaImplementableWidget.h) 47 | 48 | * Class `UObject`, see [`RPGAnimNotifyState.h`](https://github.com/jashking/LuaActionRPG/blob/master/Source/ActionRPG/Public/RPGAnimNotifyState.h) in [Demo LuaActionRPG](https://github.com/jashking/LuaActionRPG) 49 | * Call `OnReleaseLuaBinding` in `BeginDestroy` 50 | * Call `LuaProcessEvent` in `ProcessEvent` 51 | * Because the Uobject class does not have an initialized virtual function that can be overrided, so it can call `OnInitLuaBinding` the first time the `ProcessEvent` is called, as shown in the demo 52 | 53 | * Class `UGameInstance`, see [`RPGGameInstanceBase.h`](https://github.com/jashking/LuaActionRPG/blob/master/Source/ActionRPG/Public/RPGGameInstanceBase.h) in [Demo LuaActionRPG](https://github.com/jashking/LuaActionRPG) 54 | * Call `OnInitLuaBinding` in `Init` 55 | * Call `OnReleaseLuaBinding` in `Shutdown` 56 | * Call `LuaProcessEvent` in `ProcessEvent` 57 | 58 | * keyword `Super` 59 | 60 | When you use Lua to subclass c++ classes or blueprints, there is a temporary global object called Super represent the parent UObject that you can access it's properties and methods. It's only avaliable when lua file is loaded(`luaL_loadbuffer`), so you need to cache it's reference in your lua file like `local MyParent = Super` and use `MyParent` in your lua 61 | 62 | * `CastToLua` 63 | 64 | When you have a UObject in lua and want to know if the object has a lua subclass, you can call `CastToLua` on that object like `local LuaObject = OtherObject:CastToLua()`, it returns a lua table represent the lua object if `OtherObject` has a lua subclass. `CastToLua` works like cast in blueprint: 65 | 66 | ![](Doc/Images/cast.png) 67 | 68 | * Modular lua subcalss 69 | 70 | All lua subclass should implement in modular table and methods should declare with **:** not **.**, see see [`GameInstance.lua`](https://github.com/jashking/LuaActionRPG/blob/master/Content/Lua/Blueprints/GameInstance.lua) in [Demo LuaActionRPG](https://github.com/jashking/LuaActionRPG) 71 | 72 | ``` lua 73 | local m = {} 74 | 75 | function m:func() 76 | end 77 | 78 | return m 79 | ``` 80 | 81 | * inheritance in lua 82 | 83 | You can use lua metatable to implement inheritance like you do in C++ or blueprint, see 84 | [PlayerCharacter.lua](https://github.com/jashking/LuaActionRPG/blob/master/Content/Lua/Blueprints/PlayerCharacter.lua) and [Character.lua](https://github.com/jashking/LuaActionRPG/blob/master/Content/Lua/Blueprints/Character.lua) in [Demo LuaActionRPG](https://github.com/jashking/LuaActionRPG) 85 | 86 | * When a UFUNCTION expose to blueprint, it can has a alias, like `BeginPlay` in blueprint, it actually called `ReceiveBeginPlay`. so when you override this function in lua you should use `ReceiveBeginPlay` not `BeginPlay`. 87 | 88 | ## Samples ## 89 | 90 | * [LuaActionRPG](https://github.com/jashking/LuaActionRPG): Epic's ActionRPG demo in lua implementation, still work in progress 91 | * [BlueluaDemo](https://github.com/jashking/BlueluaDemo): benchmark and test 92 | 93 | ## TODO ## 94 | 95 | * expose lua file reader to project, do not assume lua files under ProjectContent folder 96 | * hot reload lua 97 | * optimize OnProcessLuaOverrideEvent when find lua function 98 | 99 | ## 中文版使用介绍 ## 100 | 101 | [使用介绍](https://github.com/jashking/Bluelua/wiki/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8) -------------------------------------------------------------------------------- /Resources/Icon128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jashking/Bluelua/edcbd97f062637664ab2dd83c12b4311ab805c01/Resources/Icon128.png -------------------------------------------------------------------------------- /Source/Bluelua/Bluelua.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class Bluelua : ModuleRules 6 | { 7 | public Bluelua(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "Core", 29 | // ... add other public dependencies that you statically link with here ... 30 | } 31 | ); 32 | 33 | 34 | PrivateDependencyModuleNames.AddRange( 35 | new string[] 36 | { 37 | "CoreUObject", 38 | "Engine", 39 | "UMG", 40 | "Slate", 41 | // ... add private dependencies that you statically link with here ... 42 | "Liblua", 43 | "LibLuasocket", 44 | "LuaPanda", 45 | } 46 | ); 47 | 48 | 49 | DynamicallyLoadedModuleNames.AddRange( 50 | new string[] 51 | { 52 | // ... add any modules that your module loads dynamically here ... 53 | } 54 | ); 55 | 56 | PublicDefinitions.Add("WITH_BLUELUA=1"); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/Bluelua.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "Bluelua.h" 4 | 5 | #include "LuaState.h" 6 | #include "LuaObjectBase.h" 7 | 8 | #define LOCTEXT_NAMESPACE "FBlueluaModule" 9 | 10 | DEFINE_LOG_CATEGORY(LogBluelua); 11 | 12 | void FBlueluaModule::StartupModule() 13 | { 14 | FLuaObjectBase::Init(); 15 | } 16 | 17 | void FBlueluaModule::ShutdownModule() 18 | { 19 | ResetDefaultLuaState(); 20 | } 21 | 22 | TSharedPtr FBlueluaModule::GetDefaultLuaState() 23 | { 24 | if (!DefaultLuaState.IsValid()) 25 | { 26 | DefaultLuaState = MakeShared(); 27 | } 28 | 29 | return DefaultLuaState; 30 | } 31 | 32 | void FBlueluaModule::ResetDefaultLuaState() 33 | { 34 | DefaultLuaState.Reset(); 35 | } 36 | 37 | #undef LOCTEXT_NAMESPACE 38 | 39 | IMPLEMENT_MODULE(FBlueluaModule, Bluelua) -------------------------------------------------------------------------------- /Source/Bluelua/Private/BlueluaLibrary.cpp: -------------------------------------------------------------------------------- 1 | #include "BlueluaLibrary.h" 2 | 3 | #include "DelayAction.h" 4 | #include "Engine/Engine.h" 5 | #include "Engine/GameViewportClient.h" 6 | #include "Engine/LatentActionManager.h" 7 | #include "Engine/World.h" 8 | #include "Framework/Commands/InputChord.h" 9 | #include "LatentActions.h" 10 | #include "Misc/Guid.h" 11 | 12 | #include "LuaFunctionDelegate.h" 13 | 14 | UObject* UBlueluaLibrary::GetWorldContext() 15 | { 16 | if (GEngine && GEngine->GameViewport) 17 | { 18 | return Cast(GEngine->GameViewport->GetWorld()); 19 | } 20 | 21 | return nullptr; 22 | } 23 | 24 | int32 UBlueluaLibrary::Delay(UObject* WorldContextObject, float Duration, int32 InDelegateId, class ULuaFunctionDelegate* InDelegate) 25 | { 26 | if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)) 27 | { 28 | const int32 DelegateUUID = InDelegateId >= 0 ? InDelegateId : GetTypeHash(FGuid::NewGuid()); 29 | 30 | FLatentActionManager& LatentActionManager = World->GetLatentActionManager(); 31 | if (LatentActionManager.FindExistingAction(InDelegate, DelegateUUID) == NULL) 32 | { 33 | FDelayAction* DelayAction = new FDelayAction(Duration, FLatentActionInfo()); 34 | DelayAction->ExecutionFunction = ULuaFunctionDelegate::DelegateFunctionName; 35 | DelayAction->OutputLink = 0; 36 | DelayAction->CallbackTarget = InDelegate; 37 | 38 | LatentActionManager.AddNewAction(InDelegate, DelegateUUID, DelayAction); 39 | } 40 | 41 | return DelegateUUID; 42 | } 43 | 44 | return -1; 45 | } 46 | 47 | void UBlueluaLibrary::BindAction(AActor* TargetActor, FName ActionName, EInputEvent KeyEvent, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputActionHandlerDynamicSignature Action) 48 | { 49 | if (!TargetActor || !TargetActor->InputComponent) 50 | { 51 | return; 52 | } 53 | 54 | FInputActionBinding AB(ActionName, KeyEvent); 55 | AB.ActionDelegate.BindDelegate(Action.GetUObject(), Action.GetFunctionName()); 56 | AB.bConsumeInput = InbConsumeInput; 57 | AB.bExecuteWhenPaused = InbExecuteWhenPaused; 58 | TargetActor->InputComponent->AddActionBinding(AB); 59 | } 60 | 61 | void UBlueluaLibrary::BindAxisAction(AActor* TargetActor, FName AxisName, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputAxisHandlerDynamicSignature Action) 62 | { 63 | if (!TargetActor || !TargetActor->InputComponent) 64 | { 65 | return; 66 | } 67 | 68 | FInputAxisBinding AB(AxisName); 69 | AB.bConsumeInput = InbConsumeInput; 70 | AB.bExecuteWhenPaused = InbExecuteWhenPaused; 71 | AB.AxisDelegate.BindDelegate(Action.GetUObject(), Action.GetFunctionName()); 72 | 73 | TargetActor->InputComponent->AxisBindings.Emplace(AB); 74 | } 75 | 76 | void UBlueluaLibrary::BindTouchAction(AActor* TargetActor, EInputEvent InputEvent, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputTouchHandlerDynamicSignature Action) 77 | { 78 | if (!TargetActor || !TargetActor->InputComponent) 79 | { 80 | return; 81 | } 82 | 83 | FInputTouchBinding TB(InputEvent); 84 | TB.bConsumeInput = InbConsumeInput; 85 | TB.bExecuteWhenPaused = InbExecuteWhenPaused; 86 | TB.TouchDelegate.BindDelegate(Action.GetUObject(), Action.GetFunctionName()); 87 | 88 | TargetActor->InputComponent->TouchBindings.Emplace(TB); 89 | } 90 | 91 | void UBlueluaLibrary::BindKeyAction(AActor* TargetActor, FInputChord InInputChord, EInputEvent KeyEvent, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputActionHandlerDynamicSignature Action) 92 | { 93 | if (!TargetActor || !TargetActor->InputComponent) 94 | { 95 | return; 96 | } 97 | 98 | FInputKeyBinding KB(InInputChord, KeyEvent); 99 | KB.bConsumeInput = InbConsumeInput; 100 | KB.bExecuteWhenPaused = InbExecuteWhenPaused; 101 | KB.KeyDelegate.BindDelegate(Action.GetUObject(), Action.GetFunctionName()); 102 | 103 | TargetActor->InputComponent->KeyBindings.Emplace(KB); 104 | } 105 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/Delegates/LuaMulticastScriptDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaMulticastScriptDelegate.h" 2 | 3 | #include "UObject/Class.h" 4 | #include "UObject/UnrealType.h" 5 | 6 | #include "Bluelua.h" 7 | #include "lua.hpp" 8 | #include "LuaFunctionDelegate.h" 9 | #include "LuaState.h" 10 | 11 | FLuaMulticastScriptDelegate::FLuaMulticastScriptDelegate(void* InSource, UFunction* InFunction) 12 | : FLuaUDelegate(InSource, InFunction) 13 | { 14 | 15 | } 16 | 17 | FLuaMulticastScriptDelegate::~FLuaMulticastScriptDelegate() 18 | { 19 | 20 | } 21 | 22 | FLuaUDelegate* FLuaMulticastScriptDelegate::Create(lua_State* L, void* InSource, UFunction* InFunction) 23 | { 24 | uint8* UserData = (uint8*)lua_newuserdata(L, sizeof(FLuaMulticastScriptDelegate)); 25 | 26 | FLuaMulticastScriptDelegate* LuaMulticastScriptDelegate = new(UserData) FLuaMulticastScriptDelegate(InSource, InFunction); 27 | 28 | return LuaMulticastScriptDelegate; 29 | } 30 | 31 | void FLuaMulticastScriptDelegate::OnAdd(ULuaFunctionDelegate* LuaFunctionDelegate) 32 | { 33 | FScriptDelegate Delegate; 34 | Delegate.BindUFunction(LuaFunctionDelegate, ULuaFunctionDelegate::DelegateFunctionName); 35 | 36 | FMulticastScriptDelegate* MulticastScriptDelegate = reinterpret_cast(Source); 37 | if (MulticastScriptDelegate) 38 | { 39 | MulticastScriptDelegate->AddUnique(Delegate); 40 | } 41 | } 42 | 43 | void FLuaMulticastScriptDelegate::OnRemove(ULuaFunctionDelegate* LuaFunctionDelegate) 44 | { 45 | FScriptDelegate Delegate; 46 | Delegate.BindUFunction(LuaFunctionDelegate, ULuaFunctionDelegate::DelegateFunctionName); 47 | 48 | FMulticastScriptDelegate* MulticastScriptDelegate = reinterpret_cast(Source); 49 | if (MulticastScriptDelegate) 50 | { 51 | MulticastScriptDelegate->Remove(Delegate); 52 | } 53 | } 54 | 55 | void FLuaMulticastScriptDelegate::OnClear() 56 | { 57 | FMulticastScriptDelegate* MulticastScriptDelegate = reinterpret_cast(Source); 58 | if (MulticastScriptDelegate) 59 | { 60 | MulticastScriptDelegate->Clear(); 61 | } 62 | } 63 | 64 | TArray FLuaMulticastScriptDelegate::OnGetAllObjects() const 65 | { 66 | FMulticastScriptDelegate* MulticastScriptDelegate = reinterpret_cast(Source); 67 | if (MulticastScriptDelegate) 68 | { 69 | return MulticastScriptDelegate->GetAllObjects(); 70 | } 71 | else 72 | { 73 | return TArray(); 74 | } 75 | } 76 | 77 | FString FLuaMulticastScriptDelegate::OnGetName() 78 | { 79 | return TEXT("MulticastScriptDelegate"); 80 | } 81 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/Delegates/LuaScriptDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaScriptDelegate.h" 2 | 3 | #include "UObject/Class.h" 4 | #include "UObject/UnrealType.h" 5 | 6 | #include "Bluelua.h" 7 | #include "lua.hpp" 8 | #include "LuaFunctionDelegate.h" 9 | #include "LuaState.h" 10 | 11 | FLuaScriptDelegate::FLuaScriptDelegate(void* InSource, UFunction* InFunction) 12 | : FLuaUDelegate(InSource, InFunction) 13 | { 14 | 15 | } 16 | 17 | FLuaScriptDelegate::~FLuaScriptDelegate() 18 | { 19 | 20 | } 21 | 22 | FLuaUDelegate* FLuaScriptDelegate::Create(lua_State* L, void* InSource, UFunction* InFunction) 23 | { 24 | uint8* UserData = (uint8*)lua_newuserdata(L, sizeof(FLuaScriptDelegate)); 25 | 26 | FLuaScriptDelegate* LuaScriptDelegate = new(UserData) FLuaScriptDelegate(InSource, InFunction); 27 | 28 | return LuaScriptDelegate; 29 | } 30 | 31 | void FLuaScriptDelegate::OnAdd(ULuaFunctionDelegate* LuaFunctionDelegate) 32 | { 33 | FScriptDelegate* ScriptDelegate = reinterpret_cast(Source); 34 | if (ScriptDelegate) 35 | { 36 | ScriptDelegate->BindUFunction(LuaFunctionDelegate, ULuaFunctionDelegate::DelegateFunctionName); 37 | } 38 | } 39 | 40 | void FLuaScriptDelegate::OnRemove(ULuaFunctionDelegate* LuaFunctionDelegate) 41 | { 42 | FScriptDelegate* ScriptDelegate = reinterpret_cast(Source); 43 | if (ScriptDelegate) 44 | { 45 | ScriptDelegate->Clear(); 46 | } 47 | } 48 | 49 | void FLuaScriptDelegate::OnClear() 50 | { 51 | FScriptDelegate* ScriptDelegate = reinterpret_cast(Source); 52 | if (ScriptDelegate) 53 | { 54 | ScriptDelegate->Clear(); 55 | } 56 | } 57 | 58 | TArray FLuaScriptDelegate::OnGetAllObjects() const 59 | { 60 | TArray OutputList; 61 | 62 | FScriptDelegate* ScriptDelegate = reinterpret_cast(Source); 63 | if (ScriptDelegate) 64 | { 65 | OutputList.Add(ScriptDelegate->GetUObject()); 66 | } 67 | 68 | return OutputList; 69 | } 70 | 71 | FString FLuaScriptDelegate::OnGetName() 72 | { 73 | return TEXT("ScriptDelegate"); 74 | } 75 | 76 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/Delegates/LuaSparseDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaSparseDelegate.h" 2 | 3 | #include "Runtime/Launch/Resources/Version.h" 4 | #include "UObject/Class.h" 5 | #include "UObject/UnrealType.h" 6 | 7 | #if ENGINE_MINOR_VERSION >= 23 8 | #include "UObject/SparseDelegate.h" 9 | #endif // ENGINE_MINOR_VERSION >= 23 10 | 11 | #include "Bluelua.h" 12 | #include "lua.hpp" 13 | #include "LuaFunctionDelegate.h" 14 | #include "LuaState.h" 15 | 16 | FLuaSparseDelegate::FLuaSparseDelegate(void* InSource, UFunction* InFunction) 17 | : FLuaUDelegate(InSource, InFunction) 18 | { 19 | 20 | } 21 | 22 | FLuaSparseDelegate::~FLuaSparseDelegate() 23 | { 24 | 25 | } 26 | 27 | FLuaUDelegate* FLuaSparseDelegate::Create(lua_State* L, void* InSource, UFunction* InFunction) 28 | { 29 | uint8* UserData = (uint8*)lua_newuserdata(L, sizeof(FLuaSparseDelegate)); 30 | 31 | FLuaSparseDelegate* LuaSparseDelegate = new(UserData) FLuaSparseDelegate(InSource, InFunction); 32 | 33 | return LuaSparseDelegate; 34 | } 35 | 36 | void FLuaSparseDelegate::OnAdd(ULuaFunctionDelegate* LuaFunctionDelegate) 37 | { 38 | #if ENGINE_MINOR_VERSION >= 23 39 | FScriptDelegate Delegate; 40 | Delegate.BindUFunction(LuaFunctionDelegate, ULuaFunctionDelegate::DelegateFunctionName); 41 | 42 | FSparseDelegate* SparseDelegate = reinterpret_cast(Source); 43 | if (SparseDelegate) 44 | { 45 | USparseDelegateFunction* SparseDelegateFunc = CastChecked(Function); 46 | 47 | UObject* Parent = FSparseDelegateStorage::ResolveSparseOwner(*SparseDelegate, SparseDelegateFunc->OwningClassName, SparseDelegateFunc->DelegateName); 48 | 49 | SparseDelegate->__Internal_AddUnique(Parent, SparseDelegateFunc->DelegateName, MoveTemp(Delegate)); 50 | } 51 | #endif // ENGINE_MINOR_VERSION >= 23 52 | } 53 | 54 | void FLuaSparseDelegate::OnRemove(ULuaFunctionDelegate* LuaFunctionDelegate) 55 | { 56 | #if ENGINE_MINOR_VERSION >= 23 57 | FScriptDelegate Delegate; 58 | Delegate.BindUFunction(LuaFunctionDelegate, ULuaFunctionDelegate::DelegateFunctionName); 59 | 60 | FSparseDelegate* SparseDelegate = reinterpret_cast(Source); 61 | if (SparseDelegate) 62 | { 63 | USparseDelegateFunction* SparseDelegateFunc = CastChecked(Function); 64 | 65 | UObject* Parent = FSparseDelegateStorage::ResolveSparseOwner(*SparseDelegate, SparseDelegateFunc->OwningClassName, SparseDelegateFunc->DelegateName); 66 | 67 | SparseDelegate->__Internal_Remove(Parent, SparseDelegateFunc->DelegateName, MoveTemp(Delegate)); 68 | } 69 | #endif // ENGINE_MINOR_VERSION >= 23 70 | } 71 | 72 | void FLuaSparseDelegate::OnClear() 73 | { 74 | #if ENGINE_MINOR_VERSION >= 23 75 | FSparseDelegate* SparseDelegate = reinterpret_cast(Source); 76 | if (SparseDelegate) 77 | { 78 | USparseDelegateFunction* SparseDelegateFunc = CastChecked(Function); 79 | 80 | UObject* Parent = FSparseDelegateStorage::ResolveSparseOwner(*SparseDelegate, SparseDelegateFunc->OwningClassName, SparseDelegateFunc->DelegateName); 81 | 82 | SparseDelegate->__Internal_Clear(Parent, SparseDelegateFunc->DelegateName); 83 | } 84 | #endif // ENGINE_MINOR_VERSION >= 23 85 | } 86 | 87 | TArray FLuaSparseDelegate::OnGetAllObjects() const 88 | { 89 | TArray OutputList; 90 | 91 | #if ENGINE_MINOR_VERSION >= 23 92 | #else 93 | #endif // ENGINE_MINOR_VERSION >= 23 94 | 95 | return OutputList; 96 | } 97 | 98 | FString FLuaSparseDelegate::OnGetName() 99 | { 100 | return TEXT("SparseDelegate"); 101 | } 102 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaFunctionDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaFunctionDelegate.h" 2 | 3 | #include "UObject/Package.h" 4 | #include "UObject/UnrealType.h" 5 | #include "UObject/UObjectGlobals.h" 6 | 7 | #include "Bluelua.h" 8 | #include "lua.hpp" 9 | #include "LuaObjectBase.h" 10 | #include "LuaState.h" 11 | #include "LuaStackGuard.h" 12 | #include "LuaUObject.h" 13 | 14 | DECLARE_CYCLE_STAT(TEXT("HandleLuaDelegate"), STAT_HandleLuaDelegate, STATGROUP_Bluelua); 15 | 16 | const TCHAR* ULuaFunctionDelegate::DelegateFunctionName = TEXT("NeverUsed"); 17 | 18 | void ULuaFunctionDelegate::ProcessEvent(UFunction* Function, void* Parameters) 19 | { 20 | if (Function && Function->GetName().Equals(DelegateFunctionName)) 21 | { 22 | if (!IsBound()) 23 | { 24 | UE_LOG(LogBluelua, Warning, TEXT("Call lua delegate failed! Lua function is not bound! SignatureFunction[%s], FunctionDelegate[%s], Owner[%s]."), *LastSignatureFunctionName, *GetName(), *GetOuter()->GetName()); 25 | return; 26 | } 27 | 28 | SCOPE_CYCLE_COUNTER(STAT_HandleLuaDelegate); 29 | 30 | lua_State* L = LuaState.Pin()->GetState(); 31 | FLuaStackGuard Gurad(L); 32 | 33 | lua_rawgeti(L, LUA_REGISTRYINDEX, LuaFunctionIndex); 34 | if (lua_type(L, -1) != LUA_TFUNCTION) 35 | { 36 | return; 37 | } 38 | 39 | bool bWithSelf = false; 40 | if (LuaFunctionOwnerIndex != LUA_NOREF) 41 | { 42 | lua_rawgeti(L, LUA_REGISTRYINDEX, LuaFunctionOwnerIndex); 43 | bWithSelf = true; 44 | } 45 | 46 | // stack = [BindingFunction] 47 | LuaState.Pin()->CallLuaFunction(SignatureFunction, Parameters, bWithSelf); 48 | } 49 | else 50 | { 51 | Super::ProcessEvent(Function, Parameters); 52 | } 53 | } 54 | 55 | void ULuaFunctionDelegate::BeginDestroy() 56 | { 57 | Clear(); 58 | 59 | Super::BeginDestroy(); 60 | } 61 | 62 | ULuaFunctionDelegate* ULuaFunctionDelegate::Create(UObject* InDelegateOwner, TSharedPtr InLuaState, UFunction* InSignatureFunction, int InLuaFunctionIndex) 63 | { 64 | if (!InLuaState.IsValid()) 65 | { 66 | return nullptr; 67 | } 68 | 69 | ULuaFunctionDelegate* FunctionDelegate = NewObject(InDelegateOwner, ULuaFunctionDelegate::StaticClass(), NAME_None); 70 | if (!FunctionDelegate) 71 | { 72 | return nullptr; 73 | } 74 | 75 | FunctionDelegate->BindLuaState(InLuaState); 76 | 77 | lua_pushvalue(InLuaState->GetState(), InLuaFunctionIndex); 78 | FunctionDelegate->BindLuaFunction(InSignatureFunction, luaL_ref(InLuaState->GetState(), LUA_REGISTRYINDEX)); 79 | 80 | if (InLuaFunctionIndex != 2) 81 | { 82 | lua_pushvalue(InLuaState->GetState(), InLuaFunctionIndex - 1); 83 | FunctionDelegate->BindLuaFunctionOwner(luaL_ref(InLuaState->GetState(), LUA_REGISTRYINDEX)); 84 | } 85 | 86 | return FunctionDelegate; 87 | } 88 | 89 | ULuaFunctionDelegate* ULuaFunctionDelegate::Fetch(lua_State* L, int32 Index) 90 | { 91 | UObject* DelegateObject = FLuaUObject::Fetch(L, Index); 92 | ULuaFunctionDelegate* FunctionDelegate = Cast(DelegateObject); 93 | if (!FunctionDelegate) 94 | { 95 | luaL_error(L, "Param %d is not an ULuaFunctionDelegate! Use CreateFunctionDelegate to create one.", Index); 96 | } 97 | 98 | return FunctionDelegate; 99 | } 100 | 101 | int ULuaFunctionDelegate::CreateFunctionDelegate(lua_State* L) 102 | { 103 | UObject* DelegateOwner = FLuaUObject::Fetch(L, 1); 104 | if (!DelegateOwner) 105 | { 106 | luaL_error(L, "Create delegate failed! Param 1 must be a UObject as owner!"); 107 | return 0; 108 | } 109 | 110 | const int Param2Type = lua_type(L, 2); 111 | if (Param2Type != LUA_TFUNCTION && lua_type(L, 3) != LUA_TFUNCTION) 112 | { 113 | luaL_error(L, "Create delegate failed! Param 2 or Param 3 must be a function!"); 114 | } 115 | 116 | const int FunctionIndex = (Param2Type == LUA_TFUNCTION) ? 2 : 3; 117 | 118 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 119 | if (!LuaStateWrapper) 120 | { 121 | return 0; 122 | } 123 | 124 | ULuaFunctionDelegate* FunctionDelegate = ULuaFunctionDelegate::Create(DelegateOwner, LuaStateWrapper->AsShared(), nullptr, FunctionIndex); 125 | if (!FunctionDelegate) 126 | { 127 | return 0; 128 | } 129 | 130 | return FLuaUObject::Push(L, FunctionDelegate, DelegateOwner); 131 | } 132 | 133 | void ULuaFunctionDelegate::BindLuaState(TSharedPtr InLuaState) 134 | { 135 | LuaState = InLuaState; 136 | } 137 | 138 | void ULuaFunctionDelegate::BindLuaFunction(UFunction* InSignatureFunction, int InLuaFunctionIndex) 139 | { 140 | Clear(); 141 | 142 | LastSignatureFunctionName = InSignatureFunction ? InSignatureFunction->GetName() : TEXT(""); 143 | SignatureFunction = InSignatureFunction; 144 | LuaFunctionIndex = InLuaFunctionIndex; 145 | } 146 | 147 | void ULuaFunctionDelegate::BindLuaFunctionOwner(int InLuaFunctionOwerIndex) 148 | { 149 | LuaFunctionOwnerIndex = InLuaFunctionOwerIndex; 150 | } 151 | 152 | void ULuaFunctionDelegate::BindSignatureFunction(UFunction* InSignatureFunction) 153 | { 154 | LastSignatureFunctionName = InSignatureFunction ? InSignatureFunction->GetName() : TEXT(""); 155 | SignatureFunction = InSignatureFunction; 156 | } 157 | 158 | bool ULuaFunctionDelegate::IsBound() const 159 | { 160 | return (LuaState.IsValid() && LuaFunctionIndex != LUA_NOREF); 161 | } 162 | 163 | void ULuaFunctionDelegate::Clear() 164 | { 165 | SignatureFunction = nullptr; 166 | 167 | if (LuaState.IsValid()) 168 | { 169 | if (LuaFunctionIndex != LUA_NOREF) 170 | { 171 | luaL_unref(LuaState.Pin()->GetState(), LUA_REGISTRYINDEX, LuaFunctionIndex); 172 | } 173 | 174 | if (LuaFunctionOwnerIndex != LUA_NOREF) 175 | { 176 | luaL_unref(LuaState.Pin()->GetState(), LUA_REGISTRYINDEX, LuaFunctionOwnerIndex); 177 | } 178 | } 179 | 180 | LuaFunctionIndex = LUA_NOREF; 181 | LuaFunctionOwnerIndex = LUA_NOREF; 182 | } 183 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaImplementableActor.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "LuaImplementableActor.h" 4 | 5 | #include "Misc/Paths.h" 6 | 7 | // Sets default values 8 | ALuaImplementableActor::ALuaImplementableActor() 9 | { 10 | // Set this actor to call Tick() every frame. You can turn this off to improve performance if you don't need it. 11 | PrimaryActorTick.bCanEverTick = true; 12 | } 13 | 14 | // Called when the game starts or when spawned 15 | void ALuaImplementableActor::BeginPlay() 16 | { 17 | OnInitLuaBinding(); 18 | 19 | Super::BeginPlay(); 20 | } 21 | 22 | void ALuaImplementableActor::EndPlay(const EEndPlayReason::Type EndPlayReason) 23 | { 24 | Super::EndPlay(EndPlayReason); 25 | 26 | OnReleaseLuaBinding(); 27 | } 28 | 29 | void ALuaImplementableActor::BeginDestroy() 30 | { 31 | Super::BeginDestroy(); 32 | 33 | OnReleaseLuaBinding(); 34 | } 35 | 36 | void ALuaImplementableActor::ProcessEvent(UFunction* Function, void* Parameters) 37 | { 38 | LuaProcessEvent(Function, Parameters); 39 | } 40 | 41 | FString ALuaImplementableActor::OnInitBindingLuaPath_Implementation() 42 | { 43 | return FPaths::ProjectContentDir() / LuaFilePath; 44 | } 45 | 46 | bool ALuaImplementableActor::ShouldEnableLuaBinding_Implementation() 47 | { 48 | return !LuaFilePath.IsEmpty(); 49 | } 50 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaImplementableWidget.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "LuaImplementableWidget.h" 4 | 5 | #include "Misc/Paths.h" 6 | 7 | #include "Engine/LatentActionManager.h" 8 | #include "Engine/World.h" 9 | 10 | void ULuaImplementableWidget::ProcessEvent(UFunction* Function, void* Parameters) 11 | { 12 | LuaProcessEvent(Function, Parameters); 13 | } 14 | 15 | void ULuaImplementableWidget::NativeConstruct() 16 | { 17 | OnInitLuaBinding(); 18 | 19 | Super::NativeConstruct(); 20 | } 21 | 22 | void ULuaImplementableWidget::NativeDestruct() 23 | { 24 | Super::NativeDestruct(); 25 | 26 | OnReleaseLuaBinding(); 27 | } 28 | 29 | void ULuaImplementableWidget::NativeTick(const FGeometry& MyGeometry, float InDeltaTime) 30 | { 31 | Super::NativeTick(MyGeometry, InDeltaTime); 32 | 33 | if (ensureMsgf(GetDesiredTickFrequency() != EWidgetTickFrequency::Never, TEXT("SObjectWidget and UUserWidget have mismatching tick states or UUserWidget::NativeTick was called manually (Never do this)"))) 34 | { 35 | TickActions(InDeltaTime); 36 | } 37 | } 38 | 39 | void ULuaImplementableWidget::BeginDestroy() 40 | { 41 | Super::BeginDestroy(); 42 | 43 | OnReleaseLuaBinding(); 44 | } 45 | 46 | FString ULuaImplementableWidget::OnInitBindingLuaPath_Implementation() 47 | { 48 | return FPaths::ProjectContentDir() / LuaFilePath; 49 | } 50 | 51 | bool ULuaImplementableWidget::ShouldEnableLuaBinding_Implementation() 52 | { 53 | return !LuaFilePath.IsEmpty(); 54 | } 55 | 56 | void ULuaImplementableWidget::TickActions(float InDeltaTime) 57 | { 58 | if (LuaState.IsValid()) 59 | { 60 | TSet ChildObjects; 61 | LuaState->GetObjectsByOwner(this, ChildObjects); 62 | 63 | UWorld* World = GetWorld(); 64 | if (World) 65 | { 66 | for (const auto& Object : ChildObjects) 67 | { 68 | // UE4.21 and later, ProcessLatentActions only process actions with CLASS_CompiledFromBlueprint flag 69 | const EClassFlags ClassFlags = Object->GetClass()->ClassFlags; 70 | Object->GetClass()->ClassFlags |= CLASS_CompiledFromBlueprint; 71 | 72 | // Update any latent actions we have for this actor 73 | World->GetLatentActionManager().ProcessLatentActions(Object, InDeltaTime); 74 | 75 | Object->GetClass()->ClassFlags = ClassFlags; 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaStackGuard.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaStackGuard.h" 2 | 3 | #include "lua.hpp" 4 | 5 | FLuaStackGuard::FLuaStackGuard(lua_State* L) 6 | : GuardingStack(L) 7 | , StackTop(lua_gettop(L)) 8 | { 9 | 10 | } 11 | 12 | FLuaStackGuard::FLuaStackGuard(lua_State* L, int32 Top) 13 | : GuardingStack(L) 14 | , StackTop(Top) 15 | { 16 | 17 | } 18 | 19 | FLuaStackGuard::~FLuaStackGuard() 20 | { 21 | if (GuardingStack) 22 | { 23 | lua_settop(GuardingStack, StackTop); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaUClass.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaUClass.h" 2 | 3 | #include "UObject/Class.h" 4 | #include "UObject/StructOnScope.h" 5 | #include "UObject/UnrealType.h" 6 | 7 | #include "Bluelua.h" 8 | #include "lua.hpp" 9 | #include "LuaObjectBase.h" 10 | #include "LuaState.h" 11 | #include "LuaUObject.h" 12 | 13 | DECLARE_CYCLE_STAT(TEXT("ClassPush"), STAT_ClassPush, STATGROUP_Bluelua); 14 | DECLARE_CYCLE_STAT(TEXT("ClassConstruct"), STAT_ClassConstruct, STATGROUP_Bluelua); 15 | DECLARE_CYCLE_STAT(TEXT("ClassIndex"), STAT_ClassIndex, STATGROUP_Bluelua); 16 | DECLARE_CYCLE_STAT(TEXT("ClassNewIndex"), STAT_ClassNewIndex, STATGROUP_Bluelua); 17 | DECLARE_CYCLE_STAT(TEXT("ClassCallStaticUFunction"), STAT_ClassCallStaticUFunction, STATGROUP_Bluelua); 18 | 19 | const char* FLuaUClass::UCLASS_METATABLE = "UClass_Metatable"; 20 | 21 | FLuaUClass::FLuaUClass(UClass* InSource) 22 | : Source(InSource) 23 | { 24 | 25 | } 26 | 27 | FLuaUClass::~FLuaUClass() 28 | { 29 | 30 | } 31 | 32 | int FLuaUClass::Push(lua_State* L, UClass* InSource) 33 | { 34 | SCOPE_CYCLE_COUNTER(STAT_ClassPush); 35 | 36 | if (!InSource) 37 | { 38 | lua_pushnil(L); 39 | return 1; 40 | } 41 | 42 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 43 | if (LuaStateWrapper && LuaStateWrapper->GetFromCache(InSource)) 44 | { 45 | return 1; 46 | } 47 | 48 | void* Buffer = lua_newuserdata(L, sizeof(FLuaUClass)); 49 | FLuaUClass* LuaUClass = new(Buffer) FLuaUClass(InSource); 50 | 51 | if (luaL_newmetatable(L, UCLASS_METATABLE)) 52 | { 53 | static struct luaL_Reg Metamethods[] = 54 | { 55 | { "__call", Construct }, 56 | { "__index", Index }, 57 | { "__newindex", NewIndex }, 58 | { "__tostring", ToString }, 59 | { NULL, NULL }, 60 | }; 61 | 62 | luaL_setfuncs(L, Metamethods, 0); 63 | } 64 | 65 | lua_setmetatable(L, -2); 66 | 67 | if (LuaStateWrapper) 68 | { 69 | LuaStateWrapper->AddToCache(InSource); 70 | } 71 | 72 | return 1; 73 | } 74 | 75 | UClass* FLuaUClass::Fetch(lua_State* L, int32 Index) 76 | { 77 | if (lua_isnil(L, Index)) 78 | { 79 | return nullptr; 80 | } 81 | 82 | FLuaUClass* LuaUClass = (FLuaUClass*)luaL_checkudata(L, Index, UCLASS_METATABLE); 83 | 84 | return LuaUClass->Source.IsValid() ? LuaUClass->Source.Get() : nullptr; 85 | } 86 | 87 | int FLuaUClass::Construct(lua_State* L) 88 | { 89 | SCOPE_CYCLE_COUNTER(STAT_ClassConstruct); 90 | 91 | FLuaUClass* LuaUClass = (FLuaUClass*)luaL_checkudata(L, 1, UCLASS_METATABLE); 92 | if (!LuaUClass->Source.IsValid()) 93 | { 94 | return 0; 95 | } 96 | 97 | UObject* Owner = FLuaUObject::Fetch(L, 2); 98 | if (!Owner) 99 | { 100 | return 0; 101 | } 102 | 103 | FName ObjectName; 104 | if (lua_isstring(L, 3)) 105 | { 106 | FLuaObjectBase::Fetch(L, 3, ObjectName); 107 | } 108 | 109 | UObject* Object = NewObject(Owner, LuaUClass->Source.Get(), ObjectName); 110 | 111 | return FLuaUObject::Push(L, Object, Owner); 112 | } 113 | 114 | int FLuaUClass::Index(lua_State* L) 115 | { 116 | SCOPE_CYCLE_COUNTER(STAT_ClassIndex); 117 | 118 | FLuaUClass* LuaUClass = (FLuaUClass*)luaL_checkudata(L, 1, UCLASS_METATABLE); 119 | if (!LuaUClass->Source.IsValid()) 120 | { 121 | return 0; 122 | } 123 | 124 | const char* PropertyName = lua_tostring(L, 2); 125 | if (UFunction* Function = LuaUClass->Source->FindFunctionByName(PropertyName)) 126 | { 127 | if (!Function->HasAnyFunctionFlags(FUNC_BlueprintCallable | FUNC_BlueprintPure)) 128 | { 129 | luaL_error(L, "Function[%s] is not blueprint callable!", TCHAR_TO_UTF8(*Function->GetName())); 130 | } 131 | 132 | lua_pushlightuserdata(L, Function); 133 | lua_pushcclosure(L, CallStaticUFunction, 1); 134 | 135 | return 1; 136 | } 137 | else if (UProperty* Property = LuaUClass->Source->FindPropertyByName(PropertyName)) 138 | { 139 | UObject* ClassDefaultObject = LuaUClass->Source->GetDefaultObject(); 140 | return FLuaObjectBase::PushProperty(L, Property, Property->ContainerPtrToValuePtr(ClassDefaultObject), ClassDefaultObject, false); 141 | } 142 | 143 | return 0; 144 | } 145 | 146 | int FLuaUClass::NewIndex(lua_State* L) 147 | { 148 | SCOPE_CYCLE_COUNTER(STAT_ClassNewIndex); 149 | 150 | FLuaUClass* LuaUClass = (FLuaUClass*)luaL_checkudata(L, 1, UCLASS_METATABLE); 151 | if (!LuaUClass->Source.IsValid()) 152 | { 153 | return 0; 154 | } 155 | 156 | UObject* ClassDefaultObject = LuaUClass->Source->GetDefaultObject(); 157 | const char* PropertyName = lua_tostring(L, 2); 158 | 159 | UProperty* Property = LuaUClass->Source->FindPropertyByName(PropertyName); 160 | if (Property) 161 | { 162 | if (Property->PropertyFlags & CPF_BlueprintReadOnly) 163 | { 164 | luaL_error(L, "Can't write to a readonly property[%s] in class[%s]!", PropertyName, TCHAR_TO_UTF8(*(LuaUClass->Source->GetName()))); 165 | } 166 | 167 | FLuaObjectBase::FetchProperty(L, Property, Property->ContainerPtrToValuePtr(ClassDefaultObject), 3); 168 | } 169 | else 170 | { 171 | luaL_error(L, "Can't find property[%s] in class[%s]!", PropertyName, TCHAR_TO_UTF8(*(LuaUClass->Source->GetName()))); 172 | } 173 | 174 | return 0; 175 | } 176 | 177 | int FLuaUClass::ToString(lua_State* L) 178 | { 179 | FLuaUClass* LuaUClass = (FLuaUClass*)luaL_checkudata(L, 1, UCLASS_METATABLE); 180 | 181 | lua_pushstring(L, TCHAR_TO_UTF8(*FString::Printf(TEXT("UClass[%s][%x]"), LuaUClass->Source.IsValid() ? *(LuaUClass->Source->GetName()) : TEXT("null"), LuaUClass->Source.Get()))); 182 | 183 | return 1; 184 | } 185 | 186 | int FLuaUClass::CallStaticUFunction(lua_State* L) 187 | { 188 | SCOPE_CYCLE_COUNTER(STAT_ClassCallStaticUFunction); 189 | 190 | UFunction* Function = (UFunction*)lua_touserdata(L, lua_upvalueindex(1)); 191 | FLuaUClass* LuaUClass = (FLuaUClass*)luaL_checkudata(L, 1, UCLASS_METATABLE); 192 | if (!LuaUClass->Source.IsValid()) 193 | { 194 | return 0; 195 | } 196 | 197 | return FLuaObjectBase::CallFunction(L, LuaUClass->Source->GetDefaultObject(), Function); 198 | } 199 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaUDelegate.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaUDelegate.h" 2 | 3 | #include "Engine/LatentActionManager.h" 4 | #include "Misc/Guid.h" 5 | #include "UObject/Class.h" 6 | #include "UObject/UnrealType.h" 7 | 8 | #include "Bluelua.h" 9 | #include "lua.hpp" 10 | #include "LuaFunctionDelegate.h" 11 | #include "LuaState.h" 12 | 13 | DECLARE_CYCLE_STAT(TEXT("DelegatePush"), STAT_DelegatePush, STATGROUP_Bluelua); 14 | 15 | const char* FLuaUDelegate::UDELEGATE_METATABLE = "UDelegate_Metatable"; 16 | 17 | FLuaUDelegate::FLuaUDelegate(void* InSource, UFunction* InFunction) 18 | : Source(InSource) 19 | , Function(InFunction) 20 | { 21 | 22 | } 23 | 24 | FLuaUDelegate::~FLuaUDelegate() 25 | { 26 | 27 | } 28 | 29 | int FLuaUDelegate::Push(lua_State* L, void* InSource, UFunction* InFunction, FCreateDelegateFuncPtr CreateDelegateFuncPtr, void* InBuffer /*= nullptr*/) 30 | { 31 | SCOPE_CYCLE_COUNTER(STAT_DelegatePush); 32 | 33 | if (!InSource || !InFunction || !CreateDelegateFuncPtr) 34 | { 35 | lua_pushnil(L); 36 | return 1; 37 | } 38 | 39 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 40 | if (LuaStateWrapper && LuaStateWrapper->GetFromCache(InSource)) 41 | { 42 | return 1; 43 | } 44 | 45 | FLuaUDelegate* LuaUDelegate = CreateDelegateFuncPtr(L, InSource, InFunction); 46 | 47 | if (luaL_newmetatable(L, UDELEGATE_METATABLE)) 48 | { 49 | static struct luaL_Reg Metamethods[] = 50 | { 51 | { "__index", Index }, 52 | { "__tostring", ToString }, 53 | { NULL, NULL }, 54 | }; 55 | 56 | luaL_setfuncs(L, Metamethods, 0); 57 | } 58 | 59 | lua_setmetatable(L, -2); 60 | 61 | if (LuaStateWrapper) 62 | { 63 | LuaStateWrapper->AddToCache(InSource); 64 | } 65 | 66 | return 1; 67 | } 68 | 69 | bool FLuaUDelegate::Fetch(lua_State* L, int32 Index, UFunction* InFunction, FScriptDelegate* InScriptDelegate) 70 | { 71 | if (!InScriptDelegate || !InFunction || lua_isnil(L, Index)) 72 | { 73 | return false; 74 | } 75 | 76 | ULuaFunctionDelegate* FunctionDelegate = ULuaFunctionDelegate::Fetch(L, Index); 77 | 78 | FunctionDelegate->BindSignatureFunction(InFunction); 79 | InScriptDelegate->BindUFunction(FunctionDelegate, ULuaFunctionDelegate::DelegateFunctionName); 80 | 81 | return true; 82 | } 83 | 84 | int FLuaUDelegate::Index(lua_State* L) 85 | { 86 | FLuaUDelegate* LuaUDelegate = (FLuaUDelegate*)luaL_checkudata(L, 1, UDELEGATE_METATABLE); 87 | if (!LuaUDelegate->Source) 88 | { 89 | return 0; 90 | } 91 | 92 | const FString& PropertyName = UTF8_TO_TCHAR(lua_tostring(L, 2)); 93 | if (PropertyName.Equals(TEXT("Add"))) 94 | { 95 | lua_pushcfunction(L, &FLuaUDelegate::Add); 96 | return 1; 97 | } 98 | else if (PropertyName.Equals(TEXT("Remove"))) 99 | { 100 | lua_pushcfunction(L, &FLuaUDelegate::Remove); 101 | return 1; 102 | } 103 | else if (PropertyName.Equals(TEXT("Clear"))) 104 | { 105 | lua_pushcfunction(L, &FLuaUDelegate::Clear); 106 | return 1; 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | int FLuaUDelegate::Add(lua_State* L) 113 | { 114 | FLuaUDelegate* LuaUDelegate = (FLuaUDelegate*)luaL_checkudata(L, 1, UDELEGATE_METATABLE); 115 | if (!LuaUDelegate->Source || !LuaUDelegate->Function) 116 | { 117 | return 0; 118 | } 119 | 120 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 121 | if (!LuaStateWrapper) 122 | { 123 | return 0; 124 | } 125 | 126 | ULuaFunctionDelegate* FunctionDelegate = ULuaFunctionDelegate::Fetch(L, 2); 127 | FunctionDelegate->BindSignatureFunction(LuaUDelegate->Function); 128 | 129 | LuaUDelegate->OnAdd(FunctionDelegate); 130 | 131 | lua_pushboolean(L, 1); 132 | return 1; 133 | } 134 | 135 | int FLuaUDelegate::Remove(lua_State* L) 136 | { 137 | FLuaUDelegate* LuaUDelegate = (FLuaUDelegate*)luaL_checkudata(L, 1, UDELEGATE_METATABLE); 138 | ULuaFunctionDelegate* FunctionDelegate = ULuaFunctionDelegate::Fetch(L, 2); 139 | 140 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 141 | if (LuaStateWrapper) 142 | { 143 | LuaStateWrapper->RemoveReference(FunctionDelegate, FunctionDelegate->GetOuter()); 144 | } 145 | 146 | LuaUDelegate->OnRemove(FunctionDelegate); 147 | 148 | return 0; 149 | } 150 | 151 | int FLuaUDelegate::Clear(lua_State* L) 152 | { 153 | FLuaUDelegate* LuaUDelegate = (FLuaUDelegate*)luaL_checkudata(L, 1, UDELEGATE_METATABLE); 154 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 155 | 156 | TArray Objects = LuaUDelegate->OnGetAllObjects(); 157 | for (UObject* Object : Objects) 158 | { 159 | ULuaFunctionDelegate* FunctionDelegate = Cast(Object); 160 | if (FunctionDelegate && LuaStateWrapper) 161 | { 162 | LuaStateWrapper->RemoveReference(FunctionDelegate, FunctionDelegate->GetOuter()); 163 | } 164 | } 165 | 166 | LuaUDelegate->OnClear(); 167 | 168 | return 0; 169 | } 170 | 171 | int FLuaUDelegate::ToString(lua_State* L) 172 | { 173 | FLuaUDelegate* LuaUDelegate = (FLuaUDelegate*)luaL_checkudata(L, 1, UDELEGATE_METATABLE); 174 | 175 | lua_pushstring(L, TCHAR_TO_UTF8(*FString::Printf(TEXT("%s[%s][%x]"), *LuaUDelegate->OnGetName(), LuaUDelegate->Function ? *(LuaUDelegate->Function->GetName()) : TEXT("null"), LuaUDelegate))); 176 | 177 | return 1; 178 | } 179 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaUObject.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaUObject.h" 2 | 3 | #include "Blueprint/WidgetTree.h" 4 | #include "UObject/Class.h" 5 | #include "UObject/Package.h" 6 | #include "UObject/StructOnScope.h" 7 | #include "UObject/UnrealType.h" 8 | 9 | #include "Bluelua.h" 10 | #include "lua.hpp" 11 | #include "LuaState.h" 12 | #include "LuaImplementableInterface.h" 13 | 14 | DECLARE_CYCLE_STAT(TEXT("ObjectPush"), STAT_ObjectPush, STATGROUP_Bluelua); 15 | DECLARE_CYCLE_STAT(TEXT("ObjectIndex"), STAT_ObjectIndex, STATGROUP_Bluelua); 16 | DECLARE_CYCLE_STAT(TEXT("ObjectNewIndex"), STAT_ObjectNewIndex, STATGROUP_Bluelua); 17 | DECLARE_CYCLE_STAT(TEXT("ObjectCallUFunction"), STAT_ObjectCallUFunction, STATGROUP_Bluelua); 18 | 19 | const char* FLuaUObject::UOBJECT_METATABLE = "UObject_Metatable"; 20 | 21 | FLuaUObject::FLuaUObject(UObject* InSource, UObject* InParent) 22 | : Source(InSource) 23 | , Parent(InParent) 24 | { 25 | 26 | } 27 | 28 | FLuaUObject::~FLuaUObject() 29 | { 30 | 31 | } 32 | 33 | int FLuaUObject::Push(lua_State* L, UObject* InSource, UObject* InParent/* = nullptr*/) 34 | { 35 | SCOPE_CYCLE_COUNTER(STAT_ObjectPush); 36 | 37 | if (!InSource) 38 | { 39 | lua_pushnil(L); 40 | return 1; 41 | } 42 | 43 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 44 | if (LuaStateWrapper && LuaStateWrapper->GetFromCache(InSource)) 45 | { 46 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, -1, UOBJECT_METATABLE); 47 | if (LuaUObject && LuaUObject->Source.IsValid()) 48 | { 49 | return 1; 50 | } 51 | else 52 | { 53 | lua_pop(L, 1); 54 | } 55 | } 56 | 57 | void* Buffer = lua_newuserdata(L, sizeof(FLuaUObject)); 58 | FLuaUObject* LuaUObject = new(Buffer) FLuaUObject(InSource, InParent); 59 | 60 | if (luaL_newmetatable(L, UOBJECT_METATABLE)) 61 | { 62 | static struct luaL_Reg Metamethods[] = 63 | { 64 | { "__index", Index }, 65 | { "__newindex", NewIndex }, 66 | { "__tostring", ToString }, 67 | { NULL, NULL }, 68 | }; 69 | 70 | luaL_setfuncs(L, Metamethods, 0); 71 | } 72 | 73 | lua_setmetatable(L, -2); 74 | 75 | if (LuaStateWrapper) 76 | { 77 | LuaStateWrapper->AddToCache(InSource); 78 | 79 | if (InParent) 80 | { 81 | LuaStateWrapper->AddReference(InSource, InParent); 82 | } 83 | } 84 | 85 | return 1; 86 | } 87 | 88 | UObject* FLuaUObject::Fetch(lua_State* L, int32 Index) 89 | { 90 | if (lua_isnil(L, Index)) 91 | { 92 | return nullptr; 93 | } 94 | 95 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, Index, UOBJECT_METATABLE); 96 | 97 | return LuaUObject->Source.IsValid() ? LuaUObject->Source.Get() : nullptr; 98 | } 99 | 100 | int FLuaUObject::LuaLoadObject(lua_State* L) 101 | { 102 | UObject* Owner = FLuaUObject::Fetch(L, 1); 103 | 104 | const char* ObjectPath = lua_tostring(L, 2); 105 | if (!ObjectPath) 106 | { 107 | return 0; 108 | } 109 | 110 | UObject* Object = LoadObject(Owner ? Owner : Cast(GetTransientPackage()), UTF8_TO_TCHAR(ObjectPath)); 111 | 112 | return FLuaUObject::Push(L, Object, Owner); 113 | } 114 | 115 | int FLuaUObject::LuaDestroyObject(lua_State* L) 116 | { 117 | UObject* Object = FLuaUObject::Fetch(L, 1); 118 | if (!Object) 119 | { 120 | return 0; 121 | } 122 | 123 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 124 | if (LuaStateWrapper) 125 | { 126 | LuaStateWrapper->RemoveReference(Object, Object->GetOuter()); 127 | } 128 | 129 | return 0; 130 | } 131 | 132 | int FLuaUObject::Index(lua_State* L) 133 | { 134 | SCOPE_CYCLE_COUNTER(STAT_ObjectIndex); 135 | 136 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, 1, UOBJECT_METATABLE); 137 | if (!LuaUObject->Source.IsValid()) 138 | { 139 | UE_LOG(LogBluelua, Warning, TEXT("Try to index a property[%s] on a invalid object!"), UTF8_TO_TCHAR(lua_tostring(L, 2))); 140 | return 0; 141 | } 142 | 143 | FString PropertyName = UTF8_TO_TCHAR(lua_tostring(L, 2)); 144 | const bool bIsParentDefaultFunction = PropertyName.RemoveFromEnd(TEXT("_Default"), ESearchCase::CaseSensitive); 145 | 146 | UClass* Class = LuaUObject->Source->GetClass(); 147 | 148 | if (UFunction* Function = Class->FindFunctionByName(*PropertyName)) 149 | { 150 | lua_pushboolean(L, bIsParentDefaultFunction); 151 | lua_pushlightuserdata(L, Function); 152 | lua_pushcclosure(L, CallUFunction, 2); 153 | 154 | return 1; 155 | } 156 | else if (UProperty* Property = Class->FindPropertyByName(*PropertyName)) 157 | { 158 | return FLuaObjectBase::PushProperty(L, Property, Property->ContainerPtrToValuePtr(LuaUObject->Source.Get()), LuaUObject->Source.Get(), false); 159 | } 160 | else if (PropertyName.Equals(TEXT("CastToLua"))) 161 | { 162 | lua_pushcfunction(L, CastToLua); 163 | return 1; 164 | } 165 | else if (PropertyName.Equals(TEXT("IsValid"))) 166 | { 167 | lua_pushcfunction(L, IsValid); 168 | return 1; 169 | } 170 | 171 | return 0; 172 | } 173 | 174 | int FLuaUObject::NewIndex(lua_State* L) 175 | { 176 | SCOPE_CYCLE_COUNTER(STAT_ObjectNewIndex); 177 | 178 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, 1, UOBJECT_METATABLE); 179 | if (!LuaUObject->Source.IsValid()) 180 | { 181 | return 0; 182 | } 183 | 184 | const char* PropertyName = lua_tostring(L, 2); 185 | UClass* Class = LuaUObject->Source->GetClass(); 186 | UProperty* Property = Class->FindPropertyByName(PropertyName); 187 | if (Property) 188 | { 189 | if (Property->PropertyFlags & CPF_BlueprintReadOnly) 190 | { 191 | luaL_error(L, "Can't write to a readonly property[%s] in object[%s]!", PropertyName, TCHAR_TO_UTF8(*(LuaUObject->Source->GetName()))); 192 | } 193 | 194 | FLuaObjectBase::FetchProperty(L, Property, Property->ContainerPtrToValuePtr(LuaUObject->Source.Get()), 3); 195 | } 196 | else 197 | { 198 | luaL_error(L, "Can't find property[%s] in object[%s]!", PropertyName, TCHAR_TO_UTF8(*(LuaUObject->Source->GetName()))); 199 | } 200 | 201 | return 0; 202 | } 203 | 204 | int FLuaUObject::ToString(lua_State* L) 205 | { 206 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, 1, UOBJECT_METATABLE); 207 | 208 | lua_pushstring(L, TCHAR_TO_UTF8(*FString::Printf(TEXT("UObject[%s][%x]"), LuaUObject->Source.IsValid() ? *(LuaUObject->Source->GetName()) : TEXT("null"), LuaUObject->Source.Get()))); 209 | 210 | return 1; 211 | } 212 | 213 | int FLuaUObject::CallUFunction(lua_State* L) 214 | { 215 | SCOPE_CYCLE_COUNTER(STAT_ObjectCallUFunction); 216 | 217 | const bool bIsParentDefaultFunction = lua_toboolean(L, lua_upvalueindex(1)); 218 | UFunction* Function = (UFunction*)lua_touserdata(L, lua_upvalueindex(2)); 219 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, 1, UOBJECT_METATABLE); 220 | if (!LuaUObject->Source.IsValid()) 221 | { 222 | return 0; 223 | } 224 | 225 | return FLuaObjectBase::CallFunction(L, LuaUObject->Source.Get(), Function, bIsParentDefaultFunction); 226 | } 227 | 228 | int FLuaUObject::CastToLua(lua_State* L) 229 | { 230 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, 1, UOBJECT_METATABLE); 231 | if (!LuaUObject->Source.IsValid()) 232 | { 233 | return 0; 234 | } 235 | 236 | ILuaImplementableInterface* LuaImplementableInterface = Cast(LuaUObject->Source.Get()); 237 | if (!LuaImplementableInterface) 238 | { 239 | return 0; 240 | } 241 | 242 | return (LuaImplementableInterface->CastToLua() ? 1 : 0); 243 | } 244 | 245 | int FLuaUObject::IsValid(lua_State* L) 246 | { 247 | FLuaUObject* LuaUObject = (FLuaUObject*)luaL_checkudata(L, 1, UOBJECT_METATABLE); 248 | 249 | lua_pushboolean(L, LuaUObject->Source.IsValid()); 250 | 251 | return 1; 252 | } 253 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaUScriptStruct.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaUScriptStruct.h" 2 | 3 | #include "UObject/Class.h" 4 | #include "UObject/UnrealType.h" 5 | 6 | #include "Bluelua.h" 7 | #include "lua.hpp" 8 | #include "LuaState.h" 9 | #include "LuaUStruct.h" 10 | 11 | DECLARE_CYCLE_STAT(TEXT("ScriptStructPush"), STAT_ScriptStructPush, STATGROUP_Bluelua); 12 | DECLARE_CYCLE_STAT(TEXT("ScriptStructConstruct"), STAT_ScriptStructConstruct, STATGROUP_Bluelua); 13 | 14 | const char* FLuaUScriptStruct::USCRIPTSTRUCT_METATABLE = "UScriptStruct_Metatable"; 15 | 16 | FLuaUScriptStruct::FLuaUScriptStruct(UScriptStruct* InSource) 17 | : Source(InSource) 18 | { 19 | 20 | } 21 | 22 | FLuaUScriptStruct::~FLuaUScriptStruct() 23 | { 24 | 25 | } 26 | 27 | int FLuaUScriptStruct::Push(lua_State* L, UScriptStruct* InSource) 28 | { 29 | SCOPE_CYCLE_COUNTER(STAT_ScriptStructPush); 30 | 31 | if (!InSource) 32 | { 33 | lua_pushnil(L); 34 | return 1; 35 | } 36 | 37 | FLuaState* LuaStateWrapper = FLuaState::GetStateWrapper(L); 38 | if (LuaStateWrapper && LuaStateWrapper->GetFromCache(InSource)) 39 | { 40 | return 1; 41 | } 42 | 43 | void* Buffer = lua_newuserdata(L, sizeof(FLuaUScriptStruct)); 44 | FLuaUScriptStruct* LuaUScriptStruct = new(Buffer) FLuaUScriptStruct(InSource); 45 | 46 | if (luaL_newmetatable(L, USCRIPTSTRUCT_METATABLE)) 47 | { 48 | static struct luaL_Reg Metamethods[] = 49 | { 50 | { "__call", Construct }, 51 | { "__tostring", ToString }, 52 | { NULL, NULL }, 53 | }; 54 | 55 | luaL_setfuncs(L, Metamethods, 0); 56 | } 57 | 58 | lua_setmetatable(L, -2); 59 | 60 | if (LuaStateWrapper) 61 | { 62 | LuaStateWrapper->AddToCache(InSource); 63 | } 64 | 65 | return 1; 66 | } 67 | 68 | int FLuaUScriptStruct::Construct(lua_State* L) 69 | { 70 | SCOPE_CYCLE_COUNTER(STAT_ScriptStructConstruct); 71 | 72 | FLuaUScriptStruct* LuaUScriptStruct = (FLuaUScriptStruct*)luaL_checkudata(L, 1, USCRIPTSTRUCT_METATABLE); 73 | if (!LuaUScriptStruct->Source.IsValid()) 74 | { 75 | return 0; 76 | } 77 | 78 | return FLuaUStruct::Push(L, LuaUScriptStruct->Source.Get()); 79 | } 80 | 81 | int FLuaUScriptStruct::ToString(lua_State* L) 82 | { 83 | FLuaUScriptStruct* LuaUScriptStruct = (FLuaUScriptStruct*)luaL_checkudata(L, 1, USCRIPTSTRUCT_METATABLE); 84 | 85 | lua_pushstring(L, TCHAR_TO_UTF8(*FString::Printf(TEXT("UScriptStruct[%s][%x]"), LuaUScriptStruct->Source.IsValid() ? *(LuaUScriptStruct->Source->GetName()) : TEXT("null"), LuaUScriptStruct->Source.Get()))); 86 | 87 | return 1; 88 | } 89 | -------------------------------------------------------------------------------- /Source/Bluelua/Private/LuaUStruct.cpp: -------------------------------------------------------------------------------- 1 | #include "LuaUStruct.h" 2 | 3 | #include "HAL/UnrealMemory.h" 4 | #include "UObject/Class.h" 5 | #include "UObject/UnrealType.h" 6 | 7 | #include "Bluelua.h" 8 | #include "lua.hpp" 9 | 10 | DECLARE_CYCLE_STAT(TEXT("StructPush"), STAT_StructPush, STATGROUP_Bluelua); 11 | DECLARE_CYCLE_STAT(TEXT("StructIndex"), STAT_StructIndex, STATGROUP_Bluelua); 12 | DECLARE_CYCLE_STAT(TEXT("StructNewIndex"), STAT_StructNewIndex, STATGROUP_Bluelua); 13 | 14 | const char* FLuaUStruct::USTRUCT_METATABLE = "UStruct_Metatable"; 15 | 16 | FLuaUStruct::FLuaUStruct(UScriptStruct* InSource, uint8* InScriptBuffer, bool InbCopyValue) 17 | : Source(InSource) 18 | , ScriptBuffer(InScriptBuffer) 19 | , bCopyValue(InbCopyValue) 20 | { 21 | 22 | } 23 | 24 | FLuaUStruct::~FLuaUStruct() 25 | { 26 | 27 | } 28 | 29 | int32 FLuaUStruct::GetStructureSize() const 30 | { 31 | return Source.IsValid() ? Source->GetStructureSize() : 0; 32 | } 33 | 34 | int FLuaUStruct::Push(lua_State* L, UScriptStruct* InSource, void* InBuffer /*= nullptr*/, bool InbCopyValue/* = true*/) 35 | { 36 | SCOPE_CYCLE_COUNTER(STAT_StructPush); 37 | 38 | if (!InSource) 39 | { 40 | lua_pushnil(L); 41 | return 1; 42 | } 43 | 44 | uint8* UserData = (uint8*)lua_newuserdata(L, sizeof(FLuaUStruct)); 45 | 46 | uint8* ScriptBuffer = (uint8*)InBuffer; 47 | if (InbCopyValue) 48 | { 49 | ScriptBuffer = (uint8*)FMemory::Malloc(InSource->GetStructureSize()); 50 | InSource->InitializeStruct(ScriptBuffer); 51 | 52 | if (InBuffer) 53 | { 54 | InSource->CopyScriptStruct(ScriptBuffer, InBuffer); 55 | } 56 | } 57 | 58 | FLuaUStruct* LuaUStruct = new(UserData) FLuaUStruct(InSource, ScriptBuffer, InbCopyValue); 59 | 60 | if (luaL_newmetatable(L, USTRUCT_METATABLE)) 61 | { 62 | static struct luaL_Reg Metamethods[] = 63 | { 64 | { "__index", Index }, 65 | { "__newindex", NewIndex }, 66 | { "__gc", GC }, 67 | { "__tostring", ToString }, 68 | { NULL, NULL }, 69 | }; 70 | 71 | luaL_setfuncs(L, Metamethods, 0); 72 | } 73 | 74 | lua_setmetatable(L, -2); 75 | 76 | return 1; 77 | } 78 | 79 | bool FLuaUStruct::Fetch(lua_State* L, int32 Index, UScriptStruct* OutStruct, uint8* OutBuffer) 80 | { 81 | if (!OutStruct || lua_isnil(L, Index)) 82 | { 83 | return false; 84 | } 85 | 86 | if (lua_istable(L, Index)) 87 | { 88 | const int TableIndex = lua_absindex(L, Index); 89 | 90 | lua_pushnil(L); 91 | while (lua_next(L, TableIndex)) 92 | { 93 | if (lua_isstring(L, -2)) 94 | { 95 | const char* KeyName = lua_tostring(L, -2); 96 | UProperty* Property = FindStructPropertyByName(OutStruct, KeyName); 97 | if (Property && !(Property->PropertyFlags & CPF_BlueprintReadOnly)) 98 | { 99 | FLuaObjectBase::FetchProperty(L, Property, Property->ContainerPtrToValuePtr(OutBuffer), -1); 100 | } 101 | } 102 | 103 | lua_pop(L, 1); 104 | } 105 | 106 | return true; 107 | } 108 | 109 | FLuaUStruct* LuaUStruct = (FLuaUStruct*)luaL_checkudata(L, Index, FLuaUStruct::USTRUCT_METATABLE); 110 | 111 | //const int32 TargetSize = StructProperty->Struct->GetStructureSize(); 112 | //const int32 SourceSize = LuaUStruct->GetStructureSize(); 113 | 114 | //if (TargetSize <= SourceSize) 115 | { 116 | OutStruct->CopyScriptStruct(OutBuffer, LuaUStruct->ScriptBuffer); 117 | return true; 118 | } 119 | //else 120 | //{ 121 | // UE_LOG(LogBluelua, Warning, 122 | // TEXT("Fetch property[%s] struct at index[%d] failed! Structure size mismatch! TargetSize[%d], SourceSize[%d]."), 123 | // *Property->GetName(), Index, TargetSize, SourceSize); 124 | 125 | // return false; 126 | //} 127 | } 128 | 129 | int FLuaUStruct::Index(lua_State* L) 130 | { 131 | SCOPE_CYCLE_COUNTER(STAT_StructIndex); 132 | 133 | FLuaUStruct* LuaUStruct = (FLuaUStruct*)luaL_checkudata(L, 1, USTRUCT_METATABLE); 134 | if (!LuaUStruct->Source.IsValid()) 135 | { 136 | return 0; 137 | } 138 | 139 | const char* PropertyName = lua_tostring(L, 2); 140 | if (UProperty* Property = FindStructPropertyByName(LuaUStruct->Source.Get(), PropertyName)) 141 | { 142 | return FLuaObjectBase::PushProperty(L, Property, Property->ContainerPtrToValuePtr(LuaUStruct->ScriptBuffer), nullptr, false); 143 | } 144 | 145 | return 0; 146 | } 147 | 148 | int FLuaUStruct::NewIndex(lua_State* L) 149 | { 150 | SCOPE_CYCLE_COUNTER(STAT_StructNewIndex); 151 | 152 | FLuaUStruct* LuaUStruct = (FLuaUStruct*)luaL_checkudata(L, 1, USTRUCT_METATABLE); 153 | if (!LuaUStruct->Source.IsValid()) 154 | { 155 | return 0; 156 | } 157 | 158 | const char* PropertyName = lua_tostring(L, 2); 159 | UProperty* Property = FindStructPropertyByName(LuaUStruct->Source.Get(), PropertyName); 160 | if (Property) 161 | { 162 | if (Property->PropertyFlags & CPF_BlueprintReadOnly) 163 | { 164 | luaL_error(L, "Can't write to a readonly property[%s] in struct[%s]!", PropertyName, TCHAR_TO_UTF8(*(LuaUStruct->Source->GetName()))); 165 | } 166 | 167 | FLuaObjectBase::FetchProperty(L, Property, Property->ContainerPtrToValuePtr(LuaUStruct->ScriptBuffer), 3); 168 | } 169 | else 170 | { 171 | luaL_error(L, "Can't find property[%s] in struct[%s]!", PropertyName, TCHAR_TO_UTF8(*(LuaUStruct->Source->GetName()))); 172 | } 173 | 174 | return 0; 175 | } 176 | 177 | int FLuaUStruct::GC(lua_State* L) 178 | { 179 | FLuaUStruct* LuaUStruct = (FLuaUStruct*)luaL_checkudata(L, 1, USTRUCT_METATABLE); 180 | 181 | if (LuaUStruct->bCopyValue) 182 | { 183 | if (LuaUStruct->Source.IsValid() && LuaUStruct->ScriptBuffer) 184 | { 185 | LuaUStruct->Source->DestroyStruct(LuaUStruct->ScriptBuffer); 186 | } 187 | 188 | if (LuaUStruct->ScriptBuffer) 189 | { 190 | FMemory::Free(LuaUStruct->ScriptBuffer); 191 | LuaUStruct->ScriptBuffer = nullptr; 192 | } 193 | } 194 | 195 | return 0; 196 | } 197 | 198 | int FLuaUStruct::ToString(lua_State* L) 199 | { 200 | FLuaUStruct* LuaUStruct = (FLuaUStruct*)luaL_checkudata(L, 1, USTRUCT_METATABLE); 201 | 202 | lua_pushstring(L, TCHAR_TO_UTF8(*FString::Printf(TEXT("UStruct[%s][%x]"), LuaUStruct->Source.IsValid() ? *(LuaUStruct->Source->GetName()) : TEXT("null"), LuaUStruct->Source.Get()))); 203 | 204 | return 1; 205 | } 206 | 207 | class UProperty* FLuaUStruct::FindStructPropertyByName(UScriptStruct* Source, FName Name) 208 | { 209 | UProperty* Property = Source->FindPropertyByName(Name); 210 | if (Property) 211 | { 212 | return Property; 213 | } 214 | 215 | for (Property = Source->PropertyLink; Property != nullptr; Property = Property->PropertyLinkNext) 216 | { 217 | if (Property->GetFName().ToString().StartsWith(Name.ToString(), ESearchCase::CaseSensitive)) 218 | { 219 | return Property; 220 | } 221 | } 222 | 223 | return nullptr; 224 | } 225 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/Bluelua.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | #include "Stats/Stats.h" 8 | 9 | DECLARE_LOG_CATEGORY_EXTERN(LogBluelua, Log, All); 10 | 11 | DECLARE_STATS_GROUP(TEXT("Bluelua"), STATGROUP_Bluelua, STATCAT_Advanced); 12 | 13 | class FLuaState; 14 | 15 | class BLUELUA_API FBlueluaModule : public IModuleInterface 16 | { 17 | public: 18 | 19 | /** IModuleInterface implementation */ 20 | virtual void StartupModule() override; 21 | virtual void ShutdownModule() override; 22 | 23 | TSharedPtr GetDefaultLuaState(); 24 | 25 | void ResetDefaultLuaState(); 26 | 27 | static inline FBlueluaModule& Get() 28 | { 29 | return FModuleManager::LoadModuleChecked("Bluelua"); 30 | } 31 | 32 | static inline bool IsAvailable() 33 | { 34 | return FModuleManager::Get().IsModuleLoaded("Bluelua"); 35 | } 36 | 37 | protected: 38 | TSharedPtr DefaultLuaState; 39 | }; 40 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/BlueluaLibrary.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "Components/InputComponent.h" 5 | #include "Engine/EngineBaseTypes.h" 6 | #include "Kismet/BlueprintFunctionLibrary.h" 7 | #include "BlueluaLibrary.generated.h" 8 | 9 | UCLASS() 10 | class BLUELUA_API UBlueluaLibrary : public UBlueprintFunctionLibrary 11 | { 12 | GENERATED_BODY() 13 | 14 | public: 15 | UFUNCTION(BlueprintPure, Category = "Utilities|BlueluaLibrary") 16 | static UObject* GetWorldContext(); 17 | 18 | /** 19 | * Perform a lua function delegate with a delay (specified in seconds). Calling again while it is counting down will be ignored. 20 | * 21 | * @param WorldContext World context. 22 | * @param Duration length of delay (in seconds). 23 | * @param InDelegateId DelegateId. 24 | * @param InDelegate The lua function delegate. 25 | */ 26 | UFUNCTION(BlueprintCallable, Category = "Utilities|BlueluaLibrary", meta = (WorldContext = "WorldContextObject", Duration = "0.2")) 27 | static int32 Delay(UObject* WorldContextObject, float Duration, int32 InDelegateId, class ULuaFunctionDelegate* InDelegate); 28 | 29 | UFUNCTION(BlueprintCallable, Category = "Utilities|BlueluaLibrary") 30 | static void BindAction(AActor* TargetActor, FName ActionName, EInputEvent KeyEvent, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputActionHandlerDynamicSignature Action); 31 | 32 | UFUNCTION(BlueprintCallable, Category = "Utilities|BlueluaLibrary") 33 | static void BindAxisAction(AActor* TargetActor, FName AxisName, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputAxisHandlerDynamicSignature Action); 34 | 35 | UFUNCTION(BlueprintCallable, Category = "Utilities|BlueluaLibrary") 36 | static void BindTouchAction(AActor* TargetActor, EInputEvent InputEvent, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputTouchHandlerDynamicSignature Action); 37 | 38 | UFUNCTION(BlueprintCallable, Category = "Utilities|BlueluaLibrary") 39 | static void BindKeyAction(AActor* TargetActor, FInputChord InInputChord, EInputEvent KeyEvent, bool InbConsumeInput, bool InbExecuteWhenPaused, FInputActionHandlerDynamicSignature Action); 40 | }; 41 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/Delegates/LuaMulticastScriptDelegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaUDelegate.h" 6 | 7 | class BLUELUA_API FLuaMulticastScriptDelegate : public FLuaUDelegate 8 | { 9 | public: 10 | FLuaMulticastScriptDelegate(void* InSource, UFunction* InFunction); 11 | virtual ~FLuaMulticastScriptDelegate(); 12 | 13 | static FLuaUDelegate* Create(lua_State* L, void* InSource, UFunction* InFunction); 14 | 15 | protected: 16 | virtual void OnAdd(ULuaFunctionDelegate* LuaFunctionDelegate) override; 17 | virtual void OnRemove(ULuaFunctionDelegate* LuaFunctionDelegate) override; 18 | virtual void OnClear() override; 19 | virtual TArray OnGetAllObjects() const override; 20 | virtual FString OnGetName() override; 21 | }; 22 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/Delegates/LuaScriptDelegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaUDelegate.h" 6 | 7 | class BLUELUA_API FLuaScriptDelegate : public FLuaUDelegate 8 | { 9 | public: 10 | FLuaScriptDelegate(void* InSource, UFunction* InFunction); 11 | virtual ~FLuaScriptDelegate(); 12 | 13 | static FLuaUDelegate* Create(lua_State* L, void* InSource, UFunction* InFunction); 14 | 15 | protected: 16 | virtual void OnAdd(ULuaFunctionDelegate* LuaFunctionDelegate) override; 17 | virtual void OnRemove(ULuaFunctionDelegate* LuaFunctionDelegate) override; 18 | virtual void OnClear() override; 19 | virtual TArray OnGetAllObjects() const override; 20 | virtual FString OnGetName() override; 21 | }; 22 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/Delegates/LuaSparseDelegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaUDelegate.h" 6 | 7 | class BLUELUA_API FLuaSparseDelegate : public FLuaUDelegate 8 | { 9 | public: 10 | FLuaSparseDelegate(void* InSource, UFunction* InFunction); 11 | virtual ~FLuaSparseDelegate(); 12 | 13 | static FLuaUDelegate* Create(lua_State* L, void* InSource, UFunction* InFunction); 14 | 15 | protected: 16 | virtual void OnAdd(ULuaFunctionDelegate* LuaFunctionDelegate) override; 17 | virtual void OnRemove(ULuaFunctionDelegate* LuaFunctionDelegate) override; 18 | virtual void OnClear() override; 19 | virtual TArray OnGetAllObjects() const override; 20 | virtual FString OnGetName() override; 21 | }; 22 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaFunctionDelegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaFunctionDelegate.generated.h" 6 | 7 | class FLuaState; 8 | struct lua_State; 9 | 10 | UCLASS() 11 | class BLUELUA_API ULuaFunctionDelegate : public UObject 12 | { 13 | GENERATED_BODY() 14 | 15 | public: 16 | virtual void ProcessEvent(UFunction* Function, void* Parameters) override; 17 | virtual void BeginDestroy() override; 18 | 19 | static ULuaFunctionDelegate* Create(UObject* InDelegateOwner, TSharedPtr InLuaState, UFunction* InSignatureFunction, int InLuaFunctionIndex); 20 | static ULuaFunctionDelegate* Fetch(lua_State* L, int32 Index); 21 | static int CreateFunctionDelegate(lua_State* L); 22 | 23 | void BindLuaState(TSharedPtr InLuaState); 24 | void BindLuaFunction(UFunction* InSignatureFunction, int InLuaFunctionIndex); 25 | void BindLuaFunctionOwner(int InLuaFunctionOwerIndex); 26 | void BindSignatureFunction(UFunction* InSignatureFunction); 27 | bool IsBound() const; 28 | 29 | UFUNCTION(BlueprintCallable) 30 | void Clear(); 31 | 32 | UFUNCTION() 33 | void NeverUsed() {} 34 | 35 | static const TCHAR* DelegateFunctionName; 36 | 37 | protected: 38 | TWeakPtr LuaState; 39 | 40 | FString LastSignatureFunctionName; 41 | UFunction* SignatureFunction = nullptr; 42 | int LuaFunctionIndex = -2; 43 | int LuaFunctionOwnerIndex = -2; 44 | }; 45 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaImplementableActor.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "GameFramework/Actor.h" 7 | #include "LuaImplementableInterface.h" 8 | #include "LuaImplementableActor.generated.h" 9 | 10 | UCLASS() 11 | class BLUELUA_API ALuaImplementableActor : public AActor, public ILuaImplementableInterface 12 | { 13 | GENERATED_BODY() 14 | 15 | public: 16 | // Sets default values for this actor's properties 17 | ALuaImplementableActor(); 18 | 19 | protected: 20 | // Called when the game starts or when spawned 21 | virtual void BeginPlay() override; 22 | virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override; 23 | virtual void BeginDestroy() override; 24 | virtual void ProcessEvent(UFunction* Function, void* Parameters) override final; 25 | virtual FString OnInitBindingLuaPath_Implementation() override; 26 | virtual bool ShouldEnableLuaBinding_Implementation() override; 27 | 28 | protected: 29 | UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "LuaImplementable", meta = (AllowPrivateAccess = "true")) 30 | FString LuaFilePath; 31 | }; 32 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaImplementableInterface.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "UObject/ObjectMacros.h" 5 | #include "UObject/Interface.h" 6 | 7 | #include "LuaImplementableInterface.generated.h" 8 | 9 | class FLuaState; 10 | struct lua_State; 11 | 12 | UINTERFACE() 13 | class BLUELUA_API ULuaImplementableInterface : public UInterface 14 | { 15 | GENERATED_BODY() 16 | }; 17 | 18 | class BLUELUA_API ILuaImplementableInterface 19 | { 20 | GENERATED_BODY() 21 | 22 | public: 23 | bool IsLuaBound() const; 24 | bool CastToLua(); 25 | bool HasBPFunctionOverrding(const FString& FunctionName); 26 | 27 | static void CleanAllLuaImplementableObject(FLuaState* InLuaState = nullptr); 28 | 29 | static void ProcessBPFunctionOverride(UObject* Context, struct FFrame& Stack, void* const Z_Param__Result); 30 | 31 | protected: 32 | virtual bool OnInitLuaBinding(); 33 | virtual void OnReleaseLuaBinding(); 34 | virtual bool OnProcessLuaOverrideEvent(UFunction* Function, void* Parameters); 35 | 36 | template 37 | void LuaProcessEvent(UFunction* Function, void* Parameters) 38 | { 39 | if (!OnProcessLuaOverrideEvent(Function, Parameters)) 40 | { 41 | const EFunctionFlags FunctionFlags = Function->FunctionFlags; 42 | FNativeFuncPtr NativeFucPtr = Function->GetNativeFunc(); 43 | 44 | if (NativeFucPtr == &ILuaImplementableInterface::ProcessBPFunctionOverride) 45 | { 46 | if (!HasBPFunctionOverrding(Function->GetName())) 47 | { 48 | Function->FunctionFlags &= ~FUNC_Native; 49 | Function->SetNativeFunc(&UObject::ProcessInternal); 50 | } 51 | } 52 | 53 | Super* Object = Cast(this); 54 | Object->Super::ProcessEvent(Function, Parameters); 55 | 56 | Function->FunctionFlags = FunctionFlags; 57 | Function->SetNativeFunc(NativeFucPtr); 58 | } 59 | } 60 | 61 | UFUNCTION(BlueprintNativeEvent) 62 | FString OnInitBindingLuaPath(); 63 | virtual FString OnInitBindingLuaPath_Implementation(); 64 | 65 | UFUNCTION(BlueprintNativeEvent) 66 | bool ShouldEnableLuaBinding(); 67 | virtual bool ShouldEnableLuaBinding_Implementation(); 68 | 69 | virtual TSharedPtr OnInitLuaState(); 70 | 71 | bool InitBPFunctionOverriding(); 72 | void ClearBPFunctionOverriding(); 73 | bool PrepareLuaFunction(const FString& FunctionName); 74 | 75 | static void AddToLuaObjectList(FLuaState* InLuaState, ILuaImplementableInterface* Object); 76 | static void RemoveFromLuaObjectList(FLuaState* InLuaState, ILuaImplementableInterface* Object); 77 | 78 | static int FillBPFunctionOverrideOutProperty(struct lua_State* L); 79 | bool CallBPFunctionOverride(UFunction* Function, FFrame& Stack, void* const Z_Param__Result); 80 | 81 | protected: 82 | TSharedPtr LuaState; 83 | int ModuleReferanceIndex = -2; 84 | 85 | TSet OverridedBPFunctionList; 86 | 87 | static TMap> LuaImplementableObjects; 88 | }; 89 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaImplementableWidget.h: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Blueprint/UserWidget.h" 7 | #include "LuaImplementableInterface.h" 8 | #include "LuaImplementableWidget.generated.h" 9 | 10 | /** 11 | * 12 | */ 13 | UCLASS() 14 | class BLUELUA_API ULuaImplementableWidget : public UUserWidget, public ILuaImplementableInterface 15 | { 16 | GENERATED_BODY() 17 | 18 | protected: 19 | virtual void ProcessEvent(UFunction* Function, void* Parameters) override; 20 | virtual void NativeConstruct() override; 21 | virtual void NativeDestruct() override; 22 | virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime) override; 23 | virtual void BeginDestroy() override; 24 | virtual FString OnInitBindingLuaPath_Implementation() override; 25 | virtual bool ShouldEnableLuaBinding_Implementation() override; 26 | 27 | void TickActions(float InDeltaTime); 28 | 29 | protected: 30 | UPROPERTY(BlueprintReadOnly, EditAnywhere, Category = "LuaImplementable", meta = (AllowPrivateAccess = "true")) 31 | FString LuaFilePath; 32 | }; 33 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaObjectBase.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | struct lua_State; 6 | 7 | class FLuaState; 8 | 9 | class BLUELUA_API FLuaObjectBase 10 | { 11 | public: 12 | typedef int(*PushPropertyFunction)(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool bCopyValue); 13 | typedef bool(*FetchPropertyFunction)(lua_State* L, UProperty* Property, void* Params, int32 Index); 14 | 15 | static void Init(); 16 | static PushPropertyFunction GetPusher(UClass* Class); 17 | static FetchPropertyFunction GetFetcher(UClass* Class); 18 | 19 | static int PushProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object = nullptr, bool bCopyValue = true); 20 | static int PushStructProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool bCopyValue = true); 21 | static int PushEnumProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 22 | static int PushClassProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 23 | static int PushObjectProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 24 | static int PushArrayProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 25 | static int PushSetProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 26 | static int PushMapProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 27 | static int PushMulticastDelegateProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 28 | static int PushMulticastInlineDelegateProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 29 | static int PushMulticastSparseDelegateProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 30 | static int PushDelegateProperty(lua_State* L, UProperty* Property, void* Params, UObject* Object, bool); 31 | 32 | inline static int Push(lua_State* L, int8 Value); 33 | inline static int Push(lua_State* L, uint8 Value); 34 | inline static int Push(lua_State* L, int16 Value); 35 | inline static int Push(lua_State* L, uint16 Value); 36 | inline static int Push(lua_State* L, int32 Value); 37 | inline static int Push(lua_State* L, uint32 Value); 38 | inline static int Push(lua_State* L, int64 Value); 39 | inline static int Push(lua_State* L, uint64 Value); 40 | inline static int Push(lua_State* L, float Value); 41 | inline static int Push(lua_State* L, double Value); 42 | inline static int Push(lua_State* L, bool Value); 43 | inline static int Push(lua_State* L, const FString& Value); 44 | inline static int Push(lua_State* L, const FText& Value); 45 | inline static int Push(lua_State* L, const FName& Value); 46 | 47 | static bool FetchProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 48 | static bool FetchStructProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 49 | static bool FetchEnumProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 50 | static bool FetchClassProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 51 | static bool FetchObjectProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 52 | static bool FetchArrayProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 53 | static bool FetchSetProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 54 | static bool FetchMapProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 55 | static bool FetchMulticastDelegateProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 56 | static bool FetchMulticastInlineDelegateProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 57 | static bool FetchMulticastSparseDelegateProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 58 | static bool FetchDelegateProperty(lua_State* L, UProperty* Property, void* Params, int32 Index); 59 | 60 | inline static bool Fetch(lua_State* L, int32 Index, int8& Value); 61 | inline static bool Fetch(lua_State* L, int32 Index, uint8& Value); 62 | inline static bool Fetch(lua_State* L, int32 Index, int16& Value); 63 | inline static bool Fetch(lua_State* L, int32 Index, uint16& Value); 64 | inline static bool Fetch(lua_State* L, int32 Index, int32& Value); 65 | inline static bool Fetch(lua_State* L, int32 Index, uint32& Value); 66 | inline static bool Fetch(lua_State* L, int32 Index, int64& Value); 67 | inline static bool Fetch(lua_State* L, int32 Index, uint64& Value); 68 | inline static bool Fetch(lua_State* L, int32 Index, float& Value); 69 | inline static bool Fetch(lua_State* L, int32 Index, double& Value); 70 | inline static bool Fetch(lua_State* L, int32 Index, bool& Value); 71 | inline static bool Fetch(lua_State* L, int32 Index, FString& Value); 72 | inline static bool Fetch(lua_State* L, int32 Index, FText& Value); 73 | inline static bool Fetch(lua_State* L, int32 Index, FName& Value); 74 | 75 | protected: 76 | static int CallFunction(lua_State* L, UObject* Object, UFunction* Function, bool bIsParentDefaultFunction = false); 77 | }; 78 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaStackGuard.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | struct lua_State; 6 | 7 | class BLUELUA_API FLuaStackGuard 8 | { 9 | public: 10 | FLuaStackGuard(lua_State* L); 11 | FLuaStackGuard(lua_State* L, int32 Top); 12 | 13 | ~FLuaStackGuard(); 14 | 15 | private: 16 | lua_State* GuardingStack; 17 | int32 StackTop; 18 | }; 19 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | #include "UObject/GCObject.h" 5 | #include "UObject/WeakObjectPtr.h" 6 | #include "UObject/WeakObjectPtrTemplates.h" 7 | 8 | struct lua_State; 9 | 10 | class BLUELUA_API FLuaState : public FGCObject, public TSharedFromThis 11 | { 12 | public: 13 | FLuaState(); 14 | virtual ~FLuaState(); 15 | 16 | lua_State* GetState() const; 17 | 18 | bool DoBuffer(const uint8* Buffer, uint32 BufferSize, const char* Name = nullptr); 19 | bool DoString(const FString& String); 20 | bool DoFile(const FString& FilePath); 21 | bool CallLuaFunction(UFunction* SignatureFunction, void* Parameters, bool bWithSelf = true); 22 | bool CallLuaFunction(int32 InParamsCount, int32 OutParamsCount, bool bWithSelf = true); 23 | bool GetFromCache(void* InObject); 24 | bool AddToCache(void* InObject); 25 | 26 | void AddReference(UObject* Object, UObject* Owner); 27 | void RemoveReference(UObject* Object, UObject* Owner); 28 | void RemoveReferenceByOwner(UObject* Owner); 29 | void GetObjectsByOwner(UObject* Owner, TSet& Objects); 30 | 31 | void SetOwnerGameInstane(class UGameInstance* InOwnerGameInstane); 32 | class UGameInstance* GetOwnerGameInstance(); 33 | 34 | // Begin FGCObject interface 35 | virtual void AddReferencedObjects(FReferenceCollector& Collector) override; 36 | virtual FString GetReferencerName() const override; 37 | // End FGCObject interface 38 | 39 | inline static FLuaState* GetStateWrapper(lua_State* InL); 40 | 41 | protected: 42 | static int LuaError(lua_State* L); 43 | static int LuaPanic(lua_State* L); 44 | static int LuaPrint(lua_State* L); 45 | static int LuaSearcher(lua_State* L); 46 | static void* LuaAlloc(void* UserData, void* Ptr, size_t OldSize, size_t NewSize); 47 | 48 | static int LuaLoadClass(lua_State* L); 49 | static int LuaLoadStruct(lua_State* L); 50 | static int GetEnumValue(lua_State* L); 51 | 52 | static int FillOutProperty(lua_State* L); 53 | 54 | void OnPostGarbageCollect(); 55 | 56 | static FString MakeRelativePathToContent(const FString& InPath); 57 | 58 | protected: 59 | lua_State* L; 60 | 61 | int CacheObjectRefIndex; 62 | 63 | TMap> ReferencedObjectsWithOwner; 64 | 65 | FDelegateHandle PostGarbageCollectDelegate; 66 | 67 | TWeakObjectPtr OwnerGameInstane; 68 | }; 69 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaUClass.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaObjectBase.h" 6 | 7 | class BLUELUA_API FLuaUClass : public FLuaObjectBase 8 | { 9 | public: 10 | FLuaUClass(UClass* InSource); 11 | ~FLuaUClass(); 12 | 13 | static int Push(lua_State* L, UClass* InSource); 14 | static UClass* Fetch(lua_State* L, int32 Index); 15 | 16 | protected: 17 | static int Construct(lua_State* L); 18 | static int Index(lua_State* L); 19 | static int NewIndex(lua_State* L); 20 | static int ToString(lua_State* L); 21 | static int CallStaticUFunction(lua_State* L); 22 | 23 | protected: 24 | TWeakObjectPtr Source; 25 | 26 | static const char* UCLASS_METATABLE; 27 | }; -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaUDelegate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaObjectBase.h" 6 | 7 | class ULuaFunctionDelegate; 8 | class FLuaUDelegate; 9 | 10 | typedef FLuaUDelegate*(*FCreateDelegateFuncPtr)(lua_State* L, void* InSource, UFunction* InFunction); 11 | 12 | class BLUELUA_API FLuaUDelegate : public FLuaObjectBase 13 | { 14 | public: 15 | FLuaUDelegate(void* InSource, UFunction* InFunction); 16 | virtual ~FLuaUDelegate(); 17 | 18 | static int Push(lua_State* L, void* InSource, UFunction* InFunction, FCreateDelegateFuncPtr CreateDelegateFuncPtr, void* InBuffer = nullptr); 19 | static bool Fetch(lua_State* L, int32 Index, UFunction* InFunction, FScriptDelegate* InScriptDelegate); 20 | 21 | protected: 22 | static int Index(lua_State* L); 23 | static int ToString(lua_State* L); 24 | static int Add(lua_State* L); 25 | static int Remove(lua_State* L); 26 | static int Clear(lua_State* L); 27 | 28 | static const char* UDELEGATE_METATABLE; 29 | 30 | virtual void OnAdd(ULuaFunctionDelegate* LuaFunctionDelegate) = 0; 31 | virtual void OnRemove(ULuaFunctionDelegate* LuaFunctionDelegate) = 0; 32 | virtual void OnClear() = 0; 33 | virtual TArray OnGetAllObjects() const = 0; 34 | virtual FString OnGetName() = 0; 35 | 36 | protected: 37 | void* Source; 38 | UFunction* Function; 39 | }; 40 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaUObject.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaObjectBase.h" 6 | 7 | class BLUELUA_API FLuaUObject : public FLuaObjectBase 8 | { 9 | public: 10 | FLuaUObject(UObject* InSource, UObject* InParent); 11 | ~FLuaUObject(); 12 | 13 | static int Push(lua_State* L, UObject* InSource, UObject* InParent = nullptr); 14 | static UObject* Fetch(lua_State* L, int32 Index); 15 | 16 | static int LuaLoadObject(lua_State* L); 17 | static int LuaDestroyObject(lua_State* L); 18 | 19 | protected: 20 | static int Index(lua_State* L); 21 | static int NewIndex(lua_State* L); 22 | static int ToString(lua_State* L); 23 | static int CallUFunction(lua_State* L); 24 | static int CastToLua(lua_State* L); 25 | static int IsValid(lua_State* L); 26 | 27 | protected: 28 | TWeakObjectPtr Source; 29 | UObject* Parent; 30 | 31 | static const char* UOBJECT_METATABLE; 32 | }; 33 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaUScriptStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaObjectBase.h" 6 | 7 | class BLUELUA_API FLuaUScriptStruct : public FLuaObjectBase 8 | { 9 | public: 10 | FLuaUScriptStruct(UScriptStruct* InSource); 11 | ~FLuaUScriptStruct(); 12 | 13 | static int Push(lua_State* L, UScriptStruct* InSource); 14 | 15 | protected: 16 | static int Construct(lua_State* L); 17 | static int ToString(lua_State* L); 18 | 19 | protected: 20 | TWeakObjectPtr Source; 21 | 22 | static const char* USCRIPTSTRUCT_METATABLE; 23 | }; 24 | -------------------------------------------------------------------------------- /Source/Bluelua/Public/LuaUStruct.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "CoreMinimal.h" 4 | 5 | #include "LuaObjectBase.h" 6 | 7 | class BLUELUA_API FLuaUStruct : public FLuaObjectBase 8 | { 9 | public: 10 | FLuaUStruct(UScriptStruct* InSource, uint8* InScriptBuffer, bool InbCopyValue); 11 | ~FLuaUStruct(); 12 | 13 | int32 GetStructureSize() const; 14 | 15 | static int Push(lua_State* L, UScriptStruct* InSource, void* InBuffer = nullptr, bool InbCopyValue = true); 16 | static bool Fetch(lua_State* L, int32 Index, UScriptStruct* OutStruct, uint8* OutBuffer); 17 | 18 | protected: 19 | static int Index(lua_State* L); 20 | static int NewIndex(lua_State* L); 21 | static int GC(lua_State* L); 22 | static int ToString(lua_State* L); 23 | 24 | static class UProperty* FindStructPropertyByName(UScriptStruct* Source, FName Name); 25 | 26 | protected: 27 | TWeakObjectPtr Source; 28 | uint8* ScriptBuffer; 29 | bool bCopyValue; 30 | 31 | static const char* USTRUCT_METATABLE; 32 | }; 33 | -------------------------------------------------------------------------------- /Source/BlueluaEditor/BlueluaEditor.Build.cs: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class BlueluaEditor : ModuleRules 6 | { 7 | public BlueluaEditor(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicIncludePaths.AddRange( 12 | new string[] { 13 | // ... add public include paths required here ... 14 | } 15 | ); 16 | 17 | 18 | PrivateIncludePaths.AddRange( 19 | new string[] { 20 | // ... add other private include paths required here ... 21 | } 22 | ); 23 | 24 | 25 | PublicDependencyModuleNames.AddRange( 26 | new string[] 27 | { 28 | "Core", 29 | // ... add other public dependencies that you statically link with here ... 30 | } 31 | ); 32 | 33 | 34 | PrivateDependencyModuleNames.AddRange( 35 | new string[] 36 | { 37 | "CoreUObject", 38 | "Engine", 39 | "UMG", 40 | "UnrealEd", 41 | // ... add private dependencies that you statically link with here ... 42 | "Bluelua", 43 | } 44 | ); 45 | 46 | 47 | DynamicallyLoadedModuleNames.AddRange( 48 | new string[] 49 | { 50 | // ... add any modules that your module loads dynamically here ... 51 | } 52 | ); 53 | 54 | PublicDefinitions.Add("WITH_BLUELUA_EDITOR=1"); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Source/BlueluaEditor/Private/BlueluaEditor.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | #include "BlueluaEditor.h" 4 | #include "Editor.h" 5 | 6 | #include "Bluelua.h" 7 | #include "LuaImplementableInterface.h" 8 | 9 | #define LOCTEXT_NAMESPACE "FBlueluaEditorModule" 10 | 11 | void FBlueluaEditorModule::StartupModule() 12 | { 13 | FEditorDelegates::EndPIE.AddRaw(this, &FBlueluaEditorModule::OnEndPIE); 14 | } 15 | 16 | void FBlueluaEditorModule::ShutdownModule() 17 | { 18 | } 19 | 20 | void FBlueluaEditorModule::OnEndPIE(bool bIsSimulating) 21 | { 22 | ILuaImplementableInterface::CleanAllLuaImplementableObject(); 23 | 24 | FBlueluaModule::Get().ResetDefaultLuaState(); 25 | } 26 | 27 | #undef LOCTEXT_NAMESPACE 28 | 29 | IMPLEMENT_MODULE(FBlueluaEditorModule, BlueluaEditor) 30 | -------------------------------------------------------------------------------- /Source/BlueluaEditor/Public/BlueluaEditor.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | class FBlueluaEditorModule : public IModuleInterface 9 | { 10 | public: 11 | /** IModuleInterface implementation */ 12 | virtual void StartupModule() override; 13 | virtual void ShutdownModule() override; 14 | 15 | protected: 16 | void OnEndPIE(bool bIsSimulating); 17 | }; 18 | -------------------------------------------------------------------------------- /Source/LibLuasocket/LibLuasocket.Build.cs: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class LibLuasocket : ModuleRules 6 | { 7 | public LibLuasocket(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicDependencyModuleNames.AddRange(new string[] { "Core" }); 12 | 13 | PrivateDependencyModuleNames.AddRange(new string[] { "Liblua" }); 14 | 15 | bEnableShadowVariableWarnings = false; 16 | bEnableUndefinedIdentifierWarnings = false; 17 | 18 | PublicDefinitions.Add("WITH_LIBLUASOCKET=1"); 19 | 20 | if (Target.Configuration == UnrealTargetConfiguration.Debug || 21 | Target.Configuration == UnrealTargetConfiguration.DebugGame) 22 | { 23 | PrivateDefinitions.Add("LUASOCKET_DEBUG"); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/LibLuasocket/LibLuasocket.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "LibLuasocket.h" 4 | 5 | #include "lua.hpp" 6 | 7 | extern "C" { 8 | #include "luasocket.h" 9 | #include "mime.h" 10 | } 11 | 12 | IMPLEMENT_MODULE(FLibLuasocketModule, LibLuasocket); 13 | 14 | void FLibLuasocketModule::StartupModule() 15 | { 16 | 17 | } 18 | 19 | void FLibLuasocketModule::ShutdownModule() 20 | { 21 | 22 | } 23 | 24 | void FLibLuasocketModule::SetupLuasocket(struct lua_State* L) 25 | { 26 | luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 27 | 28 | lua_pushcfunction(L, luaopen_socket_core); 29 | lua_setfield(L, -2, "socket.core"); 30 | 31 | lua_pushcfunction(L, luaopen_mime_core); 32 | lua_setfield(L, -2, "mime.core"); 33 | 34 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketFtp); 35 | lua_setfield(L, -2, "socket.ftp"); 36 | 37 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketHeaders); 38 | lua_setfield(L, -2, "socket.headers"); 39 | 40 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketHttp); 41 | lua_setfield(L, -2, "socket.http"); 42 | 43 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketLtn12); 44 | lua_setfield(L, -2, "ltn12"); 45 | 46 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketMbox); 47 | lua_setfield(L, -2, "mbox"); 48 | 49 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketMime); 50 | lua_setfield(L, -2, "mime"); 51 | 52 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketSmtp); 53 | lua_setfield(L, -2, "socket.smtp"); 54 | 55 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketSocket); 56 | lua_setfield(L, -2, "socket"); 57 | 58 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketTp); 59 | lua_setfield(L, -2, "socket.tp"); 60 | 61 | lua_pushcfunction(L, &FLibLuasocketModule::OpenLuaSocketUrl); 62 | lua_setfield(L, -2, "socket.url"); 63 | 64 | lua_pop(L, 1); 65 | } 66 | 67 | int FLibLuasocketModule::OpenLuaSocketFtp(lua_State* L) 68 | { 69 | static const auto RawLua = 70 | #include "ftp.lua.inc" 71 | 72 | luaL_dostring(L, RawLua); 73 | return 1; 74 | } 75 | 76 | int FLibLuasocketModule::OpenLuaSocketHeaders(lua_State* L) 77 | { 78 | static const auto RawLua = 79 | #include "headers.lua.inc" 80 | 81 | luaL_dostring(L, RawLua); 82 | return 1; 83 | } 84 | 85 | int FLibLuasocketModule::OpenLuaSocketHttp(lua_State* L) 86 | { 87 | static const auto RawLua = 88 | #include "http.lua.inc" 89 | 90 | luaL_dostring(L, RawLua); 91 | return 1; 92 | } 93 | 94 | int FLibLuasocketModule::OpenLuaSocketLtn12(lua_State* L) 95 | { 96 | static const auto RawLua = 97 | #include "ltn12.lua.inc" 98 | 99 | luaL_dostring(L, RawLua); 100 | return 1; 101 | } 102 | 103 | int FLibLuasocketModule::OpenLuaSocketMbox(lua_State* L) 104 | { 105 | static const auto RawLua = 106 | #include "mbox.lua.inc" 107 | 108 | luaL_dostring(L, RawLua); 109 | return 1; 110 | } 111 | 112 | int FLibLuasocketModule::OpenLuaSocketMime(lua_State* L) 113 | { 114 | static const auto RawLua = 115 | #include "mime.lua.inc" 116 | 117 | luaL_dostring(L, RawLua); 118 | return 1; 119 | } 120 | 121 | int FLibLuasocketModule::OpenLuaSocketSmtp(lua_State* L) 122 | { 123 | static const auto RawLua = 124 | #include "smtp.lua.inc" 125 | 126 | luaL_dostring(L, RawLua); 127 | return 1; 128 | } 129 | 130 | int FLibLuasocketModule::OpenLuaSocketSocket(lua_State* L) 131 | { 132 | static const auto RawLua = 133 | #include "socket.lua.inc" 134 | 135 | luaL_dostring(L, RawLua); 136 | return 1; 137 | } 138 | 139 | int FLibLuasocketModule::OpenLuaSocketTp(lua_State* L) 140 | { 141 | static const auto RawLua = 142 | #include "tp.lua.inc" 143 | 144 | luaL_dostring(L, RawLua); 145 | return 1; 146 | } 147 | 148 | int FLibLuasocketModule::OpenLuaSocketUrl(lua_State* L) 149 | { 150 | static const auto RawLua = 151 | #include "url.lua.inc" 152 | 153 | luaL_dostring(L, RawLua); 154 | return 1; 155 | } 156 | -------------------------------------------------------------------------------- /Source/LibLuasocket/LibLuasocket.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | struct lua_State; 9 | 10 | class LIBLUASOCKET_API FLibLuasocketModule : public IModuleInterface 11 | { 12 | public: 13 | 14 | /** IModuleInterface implementation */ 15 | virtual void StartupModule() override; 16 | virtual void ShutdownModule() override; 17 | 18 | void SetupLuasocket(lua_State* L); 19 | 20 | static inline FLibLuasocketModule& Get() 21 | { 22 | return FModuleManager::LoadModuleChecked("LibLuasocket"); 23 | } 24 | 25 | static inline bool IsAvailable() 26 | { 27 | return FModuleManager::Get().IsModuleLoaded("LibLuasocket"); 28 | } 29 | 30 | protected: 31 | static int OpenLuaSocketFtp(lua_State* L); 32 | static int OpenLuaSocketHeaders(lua_State* L); 33 | static int OpenLuaSocketHttp(lua_State* L); 34 | static int OpenLuaSocketLtn12(lua_State* L); 35 | static int OpenLuaSocketMbox(lua_State* L); 36 | static int OpenLuaSocketMime(lua_State* L); 37 | static int OpenLuaSocketSmtp(lua_State* L); 38 | static int OpenLuaSocketSocket(lua_State* L); 39 | static int OpenLuaSocketTp(lua_State* L); 40 | static int OpenLuaSocketUrl(lua_State* L); 41 | }; 42 | -------------------------------------------------------------------------------- /Source/LibLuasocket/auxiliar.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * Auxiliar routines for class hierarchy manipulation 3 | * LuaSocket toolkit 4 | \*=========================================================================*/ 5 | #include 6 | #include 7 | 8 | #include "auxiliar.h" 9 | 10 | /*=========================================================================*\ 11 | * Exported functions 12 | \*=========================================================================*/ 13 | /*-------------------------------------------------------------------------*\ 14 | * Initializes the module 15 | \*-------------------------------------------------------------------------*/ 16 | int auxiliar_open(lua_State *L) { 17 | (void) L; 18 | return 0; 19 | } 20 | 21 | /*-------------------------------------------------------------------------*\ 22 | * Creates a new class with given methods 23 | * Methods whose names start with __ are passed directly to the metatable. 24 | \*-------------------------------------------------------------------------*/ 25 | void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func) { 26 | luaL_newmetatable(L, classname); /* mt */ 27 | /* create __index table to place methods */ 28 | lua_pushstring(L, "__index"); /* mt,"__index" */ 29 | lua_newtable(L); /* mt,"__index",it */ 30 | /* put class name into class metatable */ 31 | lua_pushstring(L, "class"); /* mt,"__index",it,"class" */ 32 | lua_pushstring(L, classname); /* mt,"__index",it,"class",classname */ 33 | lua_rawset(L, -3); /* mt,"__index",it */ 34 | /* pass all methods that start with _ to the metatable, and all others 35 | * to the index table */ 36 | for (; func->name; func++) { /* mt,"__index",it */ 37 | lua_pushstring(L, func->name); 38 | lua_pushcfunction(L, func->func); 39 | lua_rawset(L, func->name[0] == '_' ? -5: -3); 40 | } 41 | lua_rawset(L, -3); /* mt */ 42 | lua_pop(L, 1); 43 | } 44 | 45 | /*-------------------------------------------------------------------------*\ 46 | * Prints the value of a class in a nice way 47 | \*-------------------------------------------------------------------------*/ 48 | int auxiliar_tostring(lua_State *L) { 49 | char buf[32]; 50 | if (!lua_getmetatable(L, 1)) goto error; 51 | lua_pushstring(L, "__index"); 52 | lua_gettable(L, -2); 53 | if (!lua_istable(L, -1)) goto error; 54 | lua_pushstring(L, "class"); 55 | lua_gettable(L, -2); 56 | if (!lua_isstring(L, -1)) goto error; 57 | sprintf(buf, "%p", lua_touserdata(L, 1)); 58 | lua_pushfstring(L, "%s: %s", lua_tostring(L, -1), buf); 59 | return 1; 60 | error: 61 | lua_pushstring(L, "invalid object passed to 'auxiliar.c:__tostring'"); 62 | lua_error(L); 63 | return 1; 64 | } 65 | 66 | /*-------------------------------------------------------------------------*\ 67 | * Insert class into group 68 | \*-------------------------------------------------------------------------*/ 69 | void auxiliar_add2group(lua_State *L, const char *classname, const char *groupname) { 70 | luaL_getmetatable(L, classname); 71 | lua_pushstring(L, groupname); 72 | lua_pushboolean(L, 1); 73 | lua_rawset(L, -3); 74 | lua_pop(L, 1); 75 | } 76 | 77 | /*-------------------------------------------------------------------------*\ 78 | * Make sure argument is a boolean 79 | \*-------------------------------------------------------------------------*/ 80 | int auxiliar_checkboolean(lua_State *L, int objidx) { 81 | if (!lua_isboolean(L, objidx)) 82 | auxiliar_typeerror(L, objidx, lua_typename(L, LUA_TBOOLEAN)); 83 | return lua_toboolean(L, objidx); 84 | } 85 | 86 | /*-------------------------------------------------------------------------*\ 87 | * Return userdata pointer if object belongs to a given class, abort with 88 | * error otherwise 89 | \*-------------------------------------------------------------------------*/ 90 | void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx) { 91 | void *data = auxiliar_getclassudata(L, classname, objidx); 92 | if (!data) { 93 | char msg[45]; 94 | sprintf(msg, "%.35s expected", classname); 95 | luaL_argerror(L, objidx, msg); 96 | } 97 | return data; 98 | } 99 | 100 | /*-------------------------------------------------------------------------*\ 101 | * Return userdata pointer if object belongs to a given group, abort with 102 | * error otherwise 103 | \*-------------------------------------------------------------------------*/ 104 | void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx) { 105 | void *data = auxiliar_getgroupudata(L, groupname, objidx); 106 | if (!data) { 107 | char msg[45]; 108 | sprintf(msg, "%.35s expected", groupname); 109 | luaL_argerror(L, objidx, msg); 110 | } 111 | return data; 112 | } 113 | 114 | /*-------------------------------------------------------------------------*\ 115 | * Set object class 116 | \*-------------------------------------------------------------------------*/ 117 | void auxiliar_setclass(lua_State *L, const char *classname, int objidx) { 118 | luaL_getmetatable(L, classname); 119 | if (objidx < 0) objidx--; 120 | lua_setmetatable(L, objidx); 121 | } 122 | 123 | /*-------------------------------------------------------------------------*\ 124 | * Get a userdata pointer if object belongs to a given group. Return NULL 125 | * otherwise 126 | \*-------------------------------------------------------------------------*/ 127 | void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx) { 128 | if (!lua_getmetatable(L, objidx)) 129 | return NULL; 130 | lua_pushstring(L, groupname); 131 | lua_rawget(L, -2); 132 | if (lua_isnil(L, -1)) { 133 | lua_pop(L, 2); 134 | return NULL; 135 | } else { 136 | lua_pop(L, 2); 137 | return lua_touserdata(L, objidx); 138 | } 139 | } 140 | 141 | /*-------------------------------------------------------------------------*\ 142 | * Get a userdata pointer if object belongs to a given class. Return NULL 143 | * otherwise 144 | \*-------------------------------------------------------------------------*/ 145 | void *auxiliar_getclassudata(lua_State *L, const char *classname, int objidx) { 146 | return luaL_testudata(L, objidx, classname); 147 | } 148 | 149 | /*-------------------------------------------------------------------------*\ 150 | * Throws error when argument does not have correct type. 151 | * Used to be part of lauxlib in Lua 5.1, was dropped from 5.2. 152 | \*-------------------------------------------------------------------------*/ 153 | int auxiliar_typeerror (lua_State *L, int narg, const char *tname) { 154 | const char *msg = lua_pushfstring(L, "%s expected, got %s", tname, 155 | luaL_typename(L, narg)); 156 | return luaL_argerror(L, narg, msg); 157 | } 158 | 159 | -------------------------------------------------------------------------------- /Source/LibLuasocket/auxiliar.h: -------------------------------------------------------------------------------- 1 | #ifndef AUXILIAR_H 2 | #define AUXILIAR_H 3 | /*=========================================================================*\ 4 | * Auxiliar routines for class hierarchy manipulation 5 | * LuaSocket toolkit (but completely independent of other LuaSocket modules) 6 | * 7 | * A LuaSocket class is a name associated with Lua metatables. A LuaSocket 8 | * group is a name associated with a class. A class can belong to any number 9 | * of groups. This module provides the functionality to: 10 | * 11 | * - create new classes 12 | * - add classes to groups 13 | * - set the class of objects 14 | * - check if an object belongs to a given class or group 15 | * - get the userdata associated to objects 16 | * - print objects in a pretty way 17 | * 18 | * LuaSocket class names follow the convention {}. Modules 19 | * can define any number of classes and groups. The module tcp.c, for 20 | * example, defines the classes tcp{master}, tcp{client} and tcp{server} and 21 | * the groups tcp{client,server} and tcp{any}. Module functions can then 22 | * perform type-checking on their arguments by either class or group. 23 | * 24 | * LuaSocket metatables define the __index metamethod as being a table. This 25 | * table has one field for each method supported by the class, and a field 26 | * "class" with the class name. 27 | * 28 | * The mapping from class name to the corresponding metatable and the 29 | * reverse mapping are done using lauxlib. 30 | \*=========================================================================*/ 31 | 32 | #include "lua.h" 33 | #include "lauxlib.h" 34 | 35 | int auxiliar_open(lua_State *L); 36 | void auxiliar_newclass(lua_State *L, const char *classname, luaL_Reg *func); 37 | void auxiliar_add2group(lua_State *L, const char *classname, const char *group); 38 | void auxiliar_setclass(lua_State *L, const char *classname, int objidx); 39 | void *auxiliar_checkclass(lua_State *L, const char *classname, int objidx); 40 | void *auxiliar_checkgroup(lua_State *L, const char *groupname, int objidx); 41 | void *auxiliar_getclassudata(lua_State *L, const char *groupname, int objidx); 42 | void *auxiliar_getgroupudata(lua_State *L, const char *groupname, int objidx); 43 | int auxiliar_checkboolean(lua_State *L, int objidx); 44 | int auxiliar_tostring(lua_State *L); 45 | int auxiliar_typeerror(lua_State *L, int narg, const char *tname); 46 | 47 | #endif /* AUXILIAR_H */ 48 | -------------------------------------------------------------------------------- /Source/LibLuasocket/buffer.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * Input/Output interface for Lua programs 3 | * LuaSocket toolkit 4 | \*=========================================================================*/ 5 | #include "lua.h" 6 | #include "lauxlib.h" 7 | 8 | #include "buffer.h" 9 | 10 | /*=========================================================================*\ 11 | * Internal function prototypes 12 | \*=========================================================================*/ 13 | static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b); 14 | static int recvline(p_buffer buf, luaL_Buffer *b); 15 | static int recvall(p_buffer buf, luaL_Buffer *b); 16 | static int buffer_get(p_buffer buf, const char **data, size_t *count); 17 | static void buffer_skip(p_buffer buf, size_t count); 18 | static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent); 19 | 20 | /* min and max macros */ 21 | #ifndef MIN 22 | #define MIN(x, y) ((x) < (y) ? x : y) 23 | #endif 24 | #ifndef MAX 25 | #define MAX(x, y) ((x) > (y) ? x : y) 26 | #endif 27 | 28 | /*=========================================================================*\ 29 | * Exported functions 30 | \*=========================================================================*/ 31 | /*-------------------------------------------------------------------------*\ 32 | * Initializes module 33 | \*-------------------------------------------------------------------------*/ 34 | int buffer_open(lua_State *L) { 35 | (void) L; 36 | return 0; 37 | } 38 | 39 | /*-------------------------------------------------------------------------*\ 40 | * Initializes C structure 41 | \*-------------------------------------------------------------------------*/ 42 | void buffer_init(p_buffer buf, p_io io, p_timeout tm) { 43 | buf->first = buf->last = 0; 44 | buf->io = io; 45 | buf->tm = tm; 46 | buf->received = buf->sent = 0; 47 | buf->birthday = timeout_gettime(); 48 | } 49 | 50 | /*-------------------------------------------------------------------------*\ 51 | * object:getstats() interface 52 | \*-------------------------------------------------------------------------*/ 53 | int buffer_meth_getstats(lua_State *L, p_buffer buf) { 54 | lua_pushnumber(L, (lua_Number) buf->received); 55 | lua_pushnumber(L, (lua_Number) buf->sent); 56 | lua_pushnumber(L, timeout_gettime() - buf->birthday); 57 | return 3; 58 | } 59 | 60 | /*-------------------------------------------------------------------------*\ 61 | * object:setstats() interface 62 | \*-------------------------------------------------------------------------*/ 63 | int buffer_meth_setstats(lua_State *L, p_buffer buf) { 64 | buf->received = (long) luaL_optnumber(L, 2, (lua_Number) buf->received); 65 | buf->sent = (long) luaL_optnumber(L, 3, (lua_Number) buf->sent); 66 | if (lua_isnumber(L, 4)) buf->birthday = timeout_gettime() - lua_tonumber(L, 4); 67 | lua_pushnumber(L, 1); 68 | return 1; 69 | } 70 | 71 | /*-------------------------------------------------------------------------*\ 72 | * object:send() interface 73 | \*-------------------------------------------------------------------------*/ 74 | int buffer_meth_send(lua_State *L, p_buffer buf) { 75 | int top = lua_gettop(L); 76 | int err = IO_DONE; 77 | size_t size = 0, sent = 0; 78 | const char *data = luaL_checklstring(L, 2, &size); 79 | long start = (long) luaL_optnumber(L, 3, 1); 80 | long end = (long) luaL_optnumber(L, 4, -1); 81 | timeout_markstart(buf->tm); 82 | if (start < 0) start = (long) (size+start+1); 83 | if (end < 0) end = (long) (size+end+1); 84 | if (start < 1) start = (long) 1; 85 | if (end > (long) size) end = (long) size; 86 | if (start <= end) err = sendraw(buf, data+start-1, end-start+1, &sent); 87 | /* check if there was an error */ 88 | if (err != IO_DONE) { 89 | lua_pushnil(L); 90 | lua_pushstring(L, buf->io->error(buf->io->ctx, err)); 91 | lua_pushnumber(L, (lua_Number) (sent+start-1)); 92 | } else { 93 | lua_pushnumber(L, (lua_Number) (sent+start-1)); 94 | lua_pushnil(L); 95 | lua_pushnil(L); 96 | } 97 | #ifdef LUASOCKET_DEBUG 98 | /* push time elapsed during operation as the last return value */ 99 | lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm)); 100 | #endif 101 | return lua_gettop(L) - top; 102 | } 103 | 104 | /*-------------------------------------------------------------------------*\ 105 | * object:receive() interface 106 | \*-------------------------------------------------------------------------*/ 107 | int buffer_meth_receive(lua_State *L, p_buffer buf) { 108 | int err = IO_DONE, top = lua_gettop(L); 109 | luaL_Buffer b; 110 | size_t size; 111 | const char *part = luaL_optlstring(L, 3, "", &size); 112 | timeout_markstart(buf->tm); 113 | /* initialize buffer with optional extra prefix 114 | * (useful for concatenating previous partial results) */ 115 | luaL_buffinit(L, &b); 116 | luaL_addlstring(&b, part, size); 117 | /* receive new patterns */ 118 | if (!lua_isnumber(L, 2)) { 119 | const char *p= luaL_optstring(L, 2, "*l"); 120 | if (p[0] == '*' && p[1] == 'l') err = recvline(buf, &b); 121 | else if (p[0] == '*' && p[1] == 'a') err = recvall(buf, &b); 122 | else luaL_argcheck(L, 0, 2, "invalid receive pattern"); 123 | /* get a fixed number of bytes (minus what was already partially 124 | * received) */ 125 | } else { 126 | double n = lua_tonumber(L, 2); 127 | size_t wanted = (size_t) n; 128 | luaL_argcheck(L, n >= 0, 2, "invalid receive pattern"); 129 | if (size == 0 || wanted > size) 130 | err = recvraw(buf, wanted-size, &b); 131 | } 132 | /* check if there was an error */ 133 | if (err != IO_DONE) { 134 | /* we can't push anyting in the stack before pushing the 135 | * contents of the buffer. this is the reason for the complication */ 136 | luaL_pushresult(&b); 137 | lua_pushstring(L, buf->io->error(buf->io->ctx, err)); 138 | lua_pushvalue(L, -2); 139 | lua_pushnil(L); 140 | lua_replace(L, -4); 141 | } else { 142 | luaL_pushresult(&b); 143 | lua_pushnil(L); 144 | lua_pushnil(L); 145 | } 146 | #ifdef LUASOCKET_DEBUG 147 | /* push time elapsed during operation as the last return value */ 148 | lua_pushnumber(L, timeout_gettime() - timeout_getstart(buf->tm)); 149 | #endif 150 | return lua_gettop(L) - top; 151 | } 152 | 153 | /*-------------------------------------------------------------------------*\ 154 | * Determines if there is any data in the read buffer 155 | \*-------------------------------------------------------------------------*/ 156 | int buffer_isempty(p_buffer buf) { 157 | return buf->first >= buf->last; 158 | } 159 | 160 | /*=========================================================================*\ 161 | * Internal functions 162 | \*=========================================================================*/ 163 | /*-------------------------------------------------------------------------*\ 164 | * Sends a block of data (unbuffered) 165 | \*-------------------------------------------------------------------------*/ 166 | #define STEPSIZE 8192 167 | static int sendraw(p_buffer buf, const char *data, size_t count, size_t *sent) { 168 | p_io io = buf->io; 169 | p_timeout tm = buf->tm; 170 | size_t total = 0; 171 | int err = IO_DONE; 172 | while (total < count && err == IO_DONE) { 173 | size_t done = 0; 174 | size_t step = (count-total <= STEPSIZE)? count-total: STEPSIZE; 175 | err = io->send(io->ctx, data+total, step, &done, tm); 176 | total += done; 177 | } 178 | *sent = total; 179 | buf->sent += total; 180 | return err; 181 | } 182 | 183 | /*-------------------------------------------------------------------------*\ 184 | * Reads a fixed number of bytes (buffered) 185 | \*-------------------------------------------------------------------------*/ 186 | static int recvraw(p_buffer buf, size_t wanted, luaL_Buffer *b) { 187 | int err = IO_DONE; 188 | size_t total = 0; 189 | while (err == IO_DONE) { 190 | size_t count; const char *data; 191 | err = buffer_get(buf, &data, &count); 192 | count = MIN(count, wanted - total); 193 | luaL_addlstring(b, data, count); 194 | buffer_skip(buf, count); 195 | total += count; 196 | if (total >= wanted) break; 197 | } 198 | return err; 199 | } 200 | 201 | /*-------------------------------------------------------------------------*\ 202 | * Reads everything until the connection is closed (buffered) 203 | \*-------------------------------------------------------------------------*/ 204 | static int recvall(p_buffer buf, luaL_Buffer *b) { 205 | int err = IO_DONE; 206 | size_t total = 0; 207 | while (err == IO_DONE) { 208 | const char *data; size_t count; 209 | err = buffer_get(buf, &data, &count); 210 | total += count; 211 | luaL_addlstring(b, data, count); 212 | buffer_skip(buf, count); 213 | } 214 | if (err == IO_CLOSED) { 215 | if (total > 0) return IO_DONE; 216 | else return IO_CLOSED; 217 | } else return err; 218 | } 219 | 220 | /*-------------------------------------------------------------------------*\ 221 | * Reads a line terminated by a CR LF pair or just by a LF. The CR and LF 222 | * are not returned by the function and are discarded from the buffer 223 | \*-------------------------------------------------------------------------*/ 224 | static int recvline(p_buffer buf, luaL_Buffer *b) { 225 | int err = IO_DONE; 226 | while (err == IO_DONE) { 227 | size_t count, pos; const char *data; 228 | err = buffer_get(buf, &data, &count); 229 | pos = 0; 230 | while (pos < count && data[pos] != '\n') { 231 | /* we ignore all \r's */ 232 | if (data[pos] != '\r') luaL_addchar(b, data[pos]); 233 | pos++; 234 | } 235 | if (pos < count) { /* found '\n' */ 236 | buffer_skip(buf, pos+1); /* skip '\n' too */ 237 | break; /* we are done */ 238 | } else /* reached the end of the buffer */ 239 | buffer_skip(buf, pos); 240 | } 241 | return err; 242 | } 243 | 244 | /*-------------------------------------------------------------------------*\ 245 | * Skips a given number of bytes from read buffer. No data is read from the 246 | * transport layer 247 | \*-------------------------------------------------------------------------*/ 248 | static void buffer_skip(p_buffer buf, size_t count) { 249 | buf->received += count; 250 | buf->first += count; 251 | if (buffer_isempty(buf)) 252 | buf->first = buf->last = 0; 253 | } 254 | 255 | /*-------------------------------------------------------------------------*\ 256 | * Return any data available in buffer, or get more data from transport layer 257 | * if buffer is empty 258 | \*-------------------------------------------------------------------------*/ 259 | static int buffer_get(p_buffer buf, const char **data, size_t *count) { 260 | int err = IO_DONE; 261 | p_io io = buf->io; 262 | p_timeout tm = buf->tm; 263 | if (buffer_isempty(buf)) { 264 | size_t got; 265 | err = io->recv(io->ctx, buf->data, BUF_SIZE, &got, tm); 266 | buf->first = 0; 267 | buf->last = got; 268 | } 269 | *count = buf->last - buf->first; 270 | *data = buf->data + buf->first; 271 | return err; 272 | } 273 | -------------------------------------------------------------------------------- /Source/LibLuasocket/buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef BUF_H 2 | #define BUF_H 3 | /*=========================================================================*\ 4 | * Input/Output interface for Lua programs 5 | * LuaSocket toolkit 6 | * 7 | * Line patterns require buffering. Reading one character at a time involves 8 | * too many system calls and is very slow. This module implements the 9 | * LuaSocket interface for input/output on connected objects, as seen by 10 | * Lua programs. 11 | * 12 | * Input is buffered. Output is *not* buffered because there was no simple 13 | * way of making sure the buffered output data would ever be sent. 14 | * 15 | * The module is built on top of the I/O abstraction defined in io.h and the 16 | * timeout management is done with the timeout.h interface. 17 | \*=========================================================================*/ 18 | #include "lua.h" 19 | 20 | #include "io.h" 21 | #include "timeout.h" 22 | 23 | /* buffer size in bytes */ 24 | #define BUF_SIZE 8192 25 | 26 | /* buffer control structure */ 27 | typedef struct t_buffer_ { 28 | double birthday; /* throttle support info: creation time, */ 29 | size_t sent, received; /* bytes sent, and bytes received */ 30 | p_io io; /* IO driver used for this buffer */ 31 | p_timeout tm; /* timeout management for this buffer */ 32 | size_t first, last; /* index of first and last bytes of stored data */ 33 | char data[BUF_SIZE]; /* storage space for buffer data */ 34 | } t_buffer; 35 | typedef t_buffer *p_buffer; 36 | 37 | int buffer_open(lua_State *L); 38 | void buffer_init(p_buffer buf, p_io io, p_timeout tm); 39 | int buffer_meth_send(lua_State *L, p_buffer buf); 40 | int buffer_meth_receive(lua_State *L, p_buffer buf); 41 | int buffer_meth_getstats(lua_State *L, p_buffer buf); 42 | int buffer_meth_setstats(lua_State *L, p_buffer buf); 43 | int buffer_isempty(p_buffer buf); 44 | 45 | #endif /* BUF_H */ 46 | -------------------------------------------------------------------------------- /Source/LibLuasocket/except.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * Simple exception support 3 | * LuaSocket toolkit 4 | \*=========================================================================*/ 5 | #include 6 | 7 | #include "lua.h" 8 | #include "lauxlib.h" 9 | 10 | #include "except.h" 11 | 12 | #if LUA_VERSION_NUM < 502 13 | #define lua_pcallk(L, na, nr, err, ctx, cont) \ 14 | (((void)ctx),((void)cont),lua_pcall(L, na, nr, err)) 15 | #endif 16 | 17 | #if LUA_VERSION_NUM < 503 18 | typedef int lua_KContext; 19 | #endif 20 | 21 | /*=========================================================================*\ 22 | * Internal function prototypes. 23 | \*=========================================================================*/ 24 | static int global_protect(lua_State *L); 25 | static int global_newtry(lua_State *L); 26 | static int protected_(lua_State *L); 27 | static int finalize(lua_State *L); 28 | static int do_nothing(lua_State *L); 29 | 30 | /* except functions */ 31 | static luaL_Reg func[] = { 32 | {"newtry", global_newtry}, 33 | {"protect", global_protect}, 34 | {NULL, NULL} 35 | }; 36 | 37 | /*-------------------------------------------------------------------------*\ 38 | * Try factory 39 | \*-------------------------------------------------------------------------*/ 40 | static void wrap(lua_State *L) { 41 | lua_createtable(L, 1, 0); 42 | lua_pushvalue(L, -2); 43 | lua_rawseti(L, -2, 1); 44 | lua_pushvalue(L, lua_upvalueindex(1)); 45 | lua_setmetatable(L, -2); 46 | } 47 | 48 | static int finalize(lua_State *L) { 49 | if (!lua_toboolean(L, 1)) { 50 | lua_pushvalue(L, lua_upvalueindex(2)); 51 | lua_call(L, 0, 0); 52 | lua_settop(L, 2); 53 | wrap(L); 54 | lua_error(L); 55 | return 0; 56 | } else return lua_gettop(L); 57 | } 58 | 59 | static int do_nothing(lua_State *L) { 60 | (void) L; 61 | return 0; 62 | } 63 | 64 | static int global_newtry(lua_State *L) { 65 | lua_settop(L, 1); 66 | if (lua_isnil(L, 1)) lua_pushcfunction(L, do_nothing); 67 | lua_pushvalue(L, lua_upvalueindex(1)); 68 | lua_insert(L, -2); 69 | lua_pushcclosure(L, finalize, 2); 70 | return 1; 71 | } 72 | 73 | /*-------------------------------------------------------------------------*\ 74 | * Protect factory 75 | \*-------------------------------------------------------------------------*/ 76 | static int unwrap(lua_State *L) { 77 | if (lua_istable(L, -1) && lua_getmetatable(L, -1)) { 78 | int r = lua_rawequal(L, -1, lua_upvalueindex(1)); 79 | lua_pop(L, 1); 80 | if (r) { 81 | lua_pushnil(L); 82 | lua_rawgeti(L, -2, 1); 83 | return 1; 84 | } 85 | } 86 | return 0; 87 | } 88 | 89 | static int protected_finish(lua_State *L, int status, lua_KContext ctx) { 90 | (void)ctx; 91 | if (status != 0 && status != LUA_YIELD) { 92 | if (unwrap(L)) return 2; 93 | else return lua_error(L); 94 | } else return lua_gettop(L); 95 | } 96 | 97 | #if LUA_VERSION_NUM == 502 98 | static int protected_cont(lua_State *L) { 99 | int ctx = 0; 100 | int status = lua_getctx(L, &ctx); 101 | return protected_finish(L, status, ctx); 102 | } 103 | #else 104 | #define protected_cont protected_finish 105 | #endif 106 | 107 | static int protected_(lua_State *L) { 108 | int status; 109 | lua_pushvalue(L, lua_upvalueindex(2)); 110 | lua_insert(L, 1); 111 | status = lua_pcallk(L, lua_gettop(L) - 1, LUA_MULTRET, 0, 0, protected_cont); 112 | return protected_finish(L, status, 0); 113 | } 114 | 115 | static int global_protect(lua_State *L) { 116 | lua_settop(L, 1); 117 | lua_pushvalue(L, lua_upvalueindex(1)); 118 | lua_insert(L, 1); 119 | lua_pushcclosure(L, protected_, 2); 120 | return 1; 121 | } 122 | 123 | /*-------------------------------------------------------------------------*\ 124 | * Init module 125 | \*-------------------------------------------------------------------------*/ 126 | int except_open(lua_State *L) { 127 | lua_newtable(L); /* metatable for wrapped exceptions */ 128 | lua_pushboolean(L, 0); 129 | lua_setfield(L, -2, "__metatable"); 130 | luaL_setfuncs(L, func, 1); 131 | return 0; 132 | } 133 | -------------------------------------------------------------------------------- /Source/LibLuasocket/except.h: -------------------------------------------------------------------------------- 1 | #ifndef EXCEPT_H 2 | #define EXCEPT_H 3 | /*=========================================================================*\ 4 | * Exception control 5 | * LuaSocket toolkit (but completely independent from other modules) 6 | * 7 | * This provides support for simple exceptions in Lua. During the 8 | * development of the HTTP/FTP/SMTP support, it became aparent that 9 | * error checking was taking a substantial amount of the coding. These 10 | * function greatly simplify the task of checking errors. 11 | * 12 | * The main idea is that functions should return nil as their first return 13 | * values when they find an error, and return an error message (or value) 14 | * following nil. In case of success, as long as the first value is not nil, 15 | * the other values don't matter. 16 | * 17 | * The idea is to nest function calls with the "try" function. This function 18 | * checks the first value, and, if it's falsy, wraps the second value in a 19 | * table with metatable and calls "error" on it. Otherwise, it returns all 20 | * values it received. Basically, it works like the Lua "assert" function, 21 | * but it creates errors targeted specifically at "protect". 22 | * 23 | * The "newtry" function is a factory for "try" functions that call a 24 | * finalizer in protected mode before calling "error". 25 | * 26 | * The "protect" function returns a new function that behaves exactly like 27 | * the function it receives, but the new function catches exceptions thrown 28 | * by "try" functions and returns nil followed by the error message instead. 29 | * 30 | * With these three functions, it's easy to write functions that throw 31 | * exceptions on error, but that don't interrupt the user script. 32 | \*=========================================================================*/ 33 | 34 | #include "lua.h" 35 | 36 | int except_open(lua_State *L); 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /Source/LibLuasocket/headers.lua.inc: -------------------------------------------------------------------------------- 1 | R"[========]( 2 | ----------------------------------------------------------------------------- 3 | -- Canonic header field capitalization 4 | -- LuaSocket toolkit. 5 | -- Author: Diego Nehab 6 | ----------------------------------------------------------------------------- 7 | local socket = require("socket") 8 | socket.headers = {} 9 | local _M = socket.headers 10 | 11 | _M.canonic = { 12 | ["accept"] = "Accept", 13 | ["accept-charset"] = "Accept-Charset", 14 | ["accept-encoding"] = "Accept-Encoding", 15 | ["accept-language"] = "Accept-Language", 16 | ["accept-ranges"] = "Accept-Ranges", 17 | ["action"] = "Action", 18 | ["alternate-recipient"] = "Alternate-Recipient", 19 | ["age"] = "Age", 20 | ["allow"] = "Allow", 21 | ["arrival-date"] = "Arrival-Date", 22 | ["authorization"] = "Authorization", 23 | ["bcc"] = "Bcc", 24 | ["cache-control"] = "Cache-Control", 25 | ["cc"] = "Cc", 26 | ["comments"] = "Comments", 27 | ["connection"] = "Connection", 28 | ["content-description"] = "Content-Description", 29 | ["content-disposition"] = "Content-Disposition", 30 | ["content-encoding"] = "Content-Encoding", 31 | ["content-id"] = "Content-ID", 32 | ["content-language"] = "Content-Language", 33 | ["content-length"] = "Content-Length", 34 | ["content-location"] = "Content-Location", 35 | ["content-md5"] = "Content-MD5", 36 | ["content-range"] = "Content-Range", 37 | ["content-transfer-encoding"] = "Content-Transfer-Encoding", 38 | ["content-type"] = "Content-Type", 39 | ["cookie"] = "Cookie", 40 | ["date"] = "Date", 41 | ["diagnostic-code"] = "Diagnostic-Code", 42 | ["dsn-gateway"] = "DSN-Gateway", 43 | ["etag"] = "ETag", 44 | ["expect"] = "Expect", 45 | ["expires"] = "Expires", 46 | ["final-log-id"] = "Final-Log-ID", 47 | ["final-recipient"] = "Final-Recipient", 48 | ["from"] = "From", 49 | ["host"] = "Host", 50 | ["if-match"] = "If-Match", 51 | ["if-modified-since"] = "If-Modified-Since", 52 | ["if-none-match"] = "If-None-Match", 53 | ["if-range"] = "If-Range", 54 | ["if-unmodified-since"] = "If-Unmodified-Since", 55 | ["in-reply-to"] = "In-Reply-To", 56 | ["keywords"] = "Keywords", 57 | ["last-attempt-date"] = "Last-Attempt-Date", 58 | ["last-modified"] = "Last-Modified", 59 | ["location"] = "Location", 60 | ["max-forwards"] = "Max-Forwards", 61 | ["message-id"] = "Message-ID", 62 | ["mime-version"] = "MIME-Version", 63 | ["original-envelope-id"] = "Original-Envelope-ID", 64 | ["original-recipient"] = "Original-Recipient", 65 | ["pragma"] = "Pragma", 66 | ["proxy-authenticate"] = "Proxy-Authenticate", 67 | ["proxy-authorization"] = "Proxy-Authorization", 68 | ["range"] = "Range", 69 | ["received"] = "Received", 70 | ["received-from-mta"] = "Received-From-MTA", 71 | ["references"] = "References", 72 | ["referer"] = "Referer", 73 | ["remote-mta"] = "Remote-MTA", 74 | ["reply-to"] = "Reply-To", 75 | ["reporting-mta"] = "Reporting-MTA", 76 | ["resent-bcc"] = "Resent-Bcc", 77 | ["resent-cc"] = "Resent-Cc", 78 | ["resent-date"] = "Resent-Date", 79 | ["resent-from"] = "Resent-From", 80 | ["resent-message-id"] = "Resent-Message-ID", 81 | ["resent-reply-to"] = "Resent-Reply-To", 82 | ["resent-sender"] = "Resent-Sender", 83 | ["resent-to"] = "Resent-To", 84 | ["retry-after"] = "Retry-After", 85 | ["return-path"] = "Return-Path", 86 | ["sender"] = "Sender", 87 | ["server"] = "Server", 88 | ["smtp-remote-recipient"] = "SMTP-Remote-Recipient", 89 | ["status"] = "Status", 90 | ["subject"] = "Subject", 91 | ["te"] = "TE", 92 | ["to"] = "To", 93 | ["trailer"] = "Trailer", 94 | ["transfer-encoding"] = "Transfer-Encoding", 95 | ["upgrade"] = "Upgrade", 96 | ["user-agent"] = "User-Agent", 97 | ["vary"] = "Vary", 98 | ["via"] = "Via", 99 | ["warning"] = "Warning", 100 | ["will-retry-until"] = "Will-Retry-Until", 101 | ["www-authenticate"] = "WWW-Authenticate", 102 | ["x-mailer"] = "X-Mailer", 103 | } 104 | 105 | return _M 106 | )[========]"; -------------------------------------------------------------------------------- /Source/LibLuasocket/inet.h: -------------------------------------------------------------------------------- 1 | #ifndef INET_H 2 | #define INET_H 3 | /*=========================================================================*\ 4 | * Internet domain functions 5 | * LuaSocket toolkit 6 | * 7 | * This module implements the creation and connection of internet domain 8 | * sockets, on top of the socket.h interface, and the interface of with the 9 | * resolver. 10 | * 11 | * The function inet_aton is provided for the platforms where it is not 12 | * available. The module also implements the interface of the internet 13 | * getpeername and getsockname functions as seen by Lua programs. 14 | * 15 | * The Lua functions toip and tohostname are also implemented here. 16 | \*=========================================================================*/ 17 | #include "lua.h" 18 | #include "socket.h" 19 | #include "timeout.h" 20 | 21 | #ifdef _WIN32 22 | #define LUASOCKET_INET_ATON 23 | #endif 24 | 25 | int inet_open(lua_State *L); 26 | 27 | const char *inet_trycreate(p_socket ps, int family, int type, int protocol); 28 | const char *inet_tryconnect(p_socket ps, int *family, const char *address, 29 | const char *serv, p_timeout tm, struct addrinfo *connecthints); 30 | const char *inet_trybind(p_socket ps, int *family, const char *address, 31 | const char *serv, struct addrinfo *bindhints); 32 | const char *inet_trydisconnect(p_socket ps, int family, p_timeout tm); 33 | const char *inet_tryaccept(p_socket server, int family, p_socket client, p_timeout tm); 34 | 35 | int inet_meth_getpeername(lua_State *L, p_socket ps, int family); 36 | int inet_meth_getsockname(lua_State *L, p_socket ps, int family); 37 | 38 | int inet_optfamily(lua_State* L, int narg, const char* def); 39 | int inet_optsocktype(lua_State* L, int narg, const char* def); 40 | 41 | #ifdef LUASOCKET_INET_ATON 42 | int inet_aton(const char *cp, struct in_addr *inp); 43 | #endif 44 | 45 | #ifdef LUASOCKET_INET_PTON 46 | const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); 47 | int inet_pton(int af, const char *src, void *dst); 48 | #endif 49 | 50 | #endif /* INET_H */ 51 | -------------------------------------------------------------------------------- /Source/LibLuasocket/io.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * Input/Output abstraction 3 | * LuaSocket toolkit 4 | \*=========================================================================*/ 5 | #include "io.h" 6 | 7 | /*=========================================================================*\ 8 | * Exported functions 9 | \*=========================================================================*/ 10 | /*-------------------------------------------------------------------------*\ 11 | * Initializes C structure 12 | \*-------------------------------------------------------------------------*/ 13 | void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx) { 14 | io->send = send; 15 | io->recv = recv; 16 | io->error = error; 17 | io->ctx = ctx; 18 | } 19 | 20 | /*-------------------------------------------------------------------------*\ 21 | * I/O error strings 22 | \*-------------------------------------------------------------------------*/ 23 | const char *io_strerror(int err) { 24 | switch (err) { 25 | case IO_DONE: return NULL; 26 | case IO_CLOSED: return "closed"; 27 | case IO_TIMEOUT: return "timeout"; 28 | default: return "unknown error"; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Source/LibLuasocket/io.h: -------------------------------------------------------------------------------- 1 | #ifndef IO_H 2 | #define IO_H 3 | /*=========================================================================*\ 4 | * Input/Output abstraction 5 | * LuaSocket toolkit 6 | * 7 | * This module defines the interface that LuaSocket expects from the 8 | * transport layer for streamed input/output. The idea is that if any 9 | * transport implements this interface, then the buffer.c functions 10 | * automatically work on it. 11 | * 12 | * The module socket.h implements this interface, and thus the module tcp.h 13 | * is very simple. 14 | \*=========================================================================*/ 15 | #include 16 | #include "lua.h" 17 | 18 | #include "timeout.h" 19 | 20 | /* IO error codes */ 21 | enum { 22 | IO_DONE = 0, /* operation completed successfully */ 23 | IO_TIMEOUT = -1, /* operation timed out */ 24 | IO_CLOSED = -2, /* the connection has been closed */ 25 | IO_UNKNOWN = -3 26 | }; 27 | 28 | /* interface to error message function */ 29 | typedef const char *(*p_error) ( 30 | void *ctx, /* context needed by send */ 31 | int err /* error code */ 32 | ); 33 | 34 | /* interface to send function */ 35 | typedef int (*p_send) ( 36 | void *ctx, /* context needed by send */ 37 | const char *data, /* pointer to buffer with data to send */ 38 | size_t count, /* number of bytes to send from buffer */ 39 | size_t *sent, /* number of bytes sent uppon return */ 40 | p_timeout tm /* timeout control */ 41 | ); 42 | 43 | /* interface to recv function */ 44 | typedef int (*p_recv) ( 45 | void *ctx, /* context needed by recv */ 46 | char *data, /* pointer to buffer where data will be writen */ 47 | size_t count, /* number of bytes to receive into buffer */ 48 | size_t *got, /* number of bytes received uppon return */ 49 | p_timeout tm /* timeout control */ 50 | ); 51 | 52 | /* IO driver definition */ 53 | typedef struct t_io_ { 54 | void *ctx; /* context needed by send/recv */ 55 | p_send send; /* send function pointer */ 56 | p_recv recv; /* receive function pointer */ 57 | p_error error; /* strerror function */ 58 | } t_io; 59 | typedef t_io *p_io; 60 | 61 | void io_init(p_io io, p_send send, p_recv recv, p_error error, void *ctx); 62 | const char *io_strerror(int err); 63 | 64 | #endif /* IO_H */ 65 | 66 | -------------------------------------------------------------------------------- /Source/LibLuasocket/ltn12.lua.inc: -------------------------------------------------------------------------------- 1 | R"[========]( 2 | ----------------------------------------------------------------------------- 3 | -- LTN12 - Filters, sources, sinks and pumps. 4 | -- LuaSocket toolkit. 5 | -- Author: Diego Nehab 6 | ----------------------------------------------------------------------------- 7 | 8 | ----------------------------------------------------------------------------- 9 | -- Declare module 10 | ----------------------------------------------------------------------------- 11 | local string = require("string") 12 | local table = require("table") 13 | local unpack = unpack or table.unpack 14 | local base = _G 15 | local _M = {} 16 | if module then -- heuristic for exporting a global package table 17 | ltn12 = _M 18 | end 19 | local filter,source,sink,pump = {},{},{},{} 20 | 21 | _M.filter = filter 22 | _M.source = source 23 | _M.sink = sink 24 | _M.pump = pump 25 | 26 | local unpack = unpack or table.unpack 27 | local select = base.select 28 | 29 | -- 2048 seems to be better in windows... 30 | _M.BLOCKSIZE = 2048 31 | _M._VERSION = "LTN12 1.0.3" 32 | 33 | ----------------------------------------------------------------------------- 34 | -- Filter stuff 35 | ----------------------------------------------------------------------------- 36 | -- returns a high level filter that cycles a low-level filter 37 | function filter.cycle(low, ctx, extra) 38 | base.assert(low) 39 | return function(chunk) 40 | local ret 41 | ret, ctx = low(ctx, chunk, extra) 42 | return ret 43 | end 44 | end 45 | 46 | -- chains a bunch of filters together 47 | -- (thanks to Wim Couwenberg) 48 | function filter.chain(...) 49 | local arg = {...} 50 | local n = base.select('#',...) 51 | local top, index = 1, 1 52 | local retry = "" 53 | return function(chunk) 54 | retry = chunk and retry 55 | while true do 56 | if index == top then 57 | chunk = arg[index](chunk) 58 | if chunk == "" or top == n then return chunk 59 | elseif chunk then index = index + 1 60 | else 61 | top = top+1 62 | index = top 63 | end 64 | else 65 | chunk = arg[index](chunk or "") 66 | if chunk == "" then 67 | index = index - 1 68 | chunk = retry 69 | elseif chunk then 70 | if index == n then return chunk 71 | else index = index + 1 end 72 | else base.error("filter returned inappropriate nil") end 73 | end 74 | end 75 | end 76 | end 77 | 78 | ----------------------------------------------------------------------------- 79 | -- Source stuff 80 | ----------------------------------------------------------------------------- 81 | -- create an empty source 82 | local function empty() 83 | return nil 84 | end 85 | 86 | function source.empty() 87 | return empty 88 | end 89 | 90 | -- returns a source that just outputs an error 91 | function source.error(err) 92 | return function() 93 | return nil, err 94 | end 95 | end 96 | 97 | -- creates a file source 98 | function source.file(handle, io_err) 99 | if handle then 100 | return function() 101 | local chunk = handle:read(_M.BLOCKSIZE) 102 | if not chunk then handle:close() end 103 | return chunk 104 | end 105 | else return source.error(io_err or "unable to open file") end 106 | end 107 | 108 | -- turns a fancy source into a simple source 109 | function source.simplify(src) 110 | base.assert(src) 111 | return function() 112 | local chunk, err_or_new = src() 113 | src = err_or_new or src 114 | if not chunk then return nil, err_or_new 115 | else return chunk end 116 | end 117 | end 118 | 119 | -- creates string source 120 | function source.string(s) 121 | if s then 122 | local i = 1 123 | return function() 124 | local chunk = string.sub(s, i, i+_M.BLOCKSIZE-1) 125 | i = i + _M.BLOCKSIZE 126 | if chunk ~= "" then return chunk 127 | else return nil end 128 | end 129 | else return source.empty() end 130 | end 131 | 132 | -- creates table source 133 | function source.table(t) 134 | base.assert('table' == type(t)) 135 | local i = 0 136 | return function() 137 | i = i + 1 138 | return t[i] 139 | end 140 | end 141 | 142 | -- creates rewindable source 143 | function source.rewind(src) 144 | base.assert(src) 145 | local t = {} 146 | return function(chunk) 147 | if not chunk then 148 | chunk = table.remove(t) 149 | if not chunk then return src() 150 | else return chunk end 151 | else 152 | table.insert(t, chunk) 153 | end 154 | end 155 | end 156 | 157 | -- chains a source with one or several filter(s) 158 | function source.chain(src, f, ...) 159 | if ... then f=filter.chain(f, ...) end 160 | base.assert(src and f) 161 | local last_in, last_out = "", "" 162 | local state = "feeding" 163 | local err 164 | return function() 165 | if not last_out then 166 | base.error('source is empty!', 2) 167 | end 168 | while true do 169 | if state == "feeding" then 170 | last_in, err = src() 171 | if err then return nil, err end 172 | last_out = f(last_in) 173 | if not last_out then 174 | if last_in then 175 | base.error('filter returned inappropriate nil') 176 | else 177 | return nil 178 | end 179 | elseif last_out ~= "" then 180 | state = "eating" 181 | if last_in then last_in = "" end 182 | return last_out 183 | end 184 | else 185 | last_out = f(last_in) 186 | if last_out == "" then 187 | if last_in == "" then 188 | state = "feeding" 189 | else 190 | base.error('filter returned ""') 191 | end 192 | elseif not last_out then 193 | if last_in then 194 | base.error('filter returned inappropriate nil') 195 | else 196 | return nil 197 | end 198 | else 199 | return last_out 200 | end 201 | end 202 | end 203 | end 204 | end 205 | 206 | -- creates a source that produces contents of several sources, one after the 207 | -- other, as if they were concatenated 208 | -- (thanks to Wim Couwenberg) 209 | function source.cat(...) 210 | local arg = {...} 211 | local src = table.remove(arg, 1) 212 | return function() 213 | while src do 214 | local chunk, err = src() 215 | if chunk then return chunk end 216 | if err then return nil, err end 217 | src = table.remove(arg, 1) 218 | end 219 | end 220 | end 221 | 222 | ----------------------------------------------------------------------------- 223 | -- Sink stuff 224 | ----------------------------------------------------------------------------- 225 | -- creates a sink that stores into a table 226 | function sink.table(t) 227 | t = t or {} 228 | local f = function(chunk, err) 229 | if chunk then table.insert(t, chunk) end 230 | return 1 231 | end 232 | return f, t 233 | end 234 | 235 | -- turns a fancy sink into a simple sink 236 | function sink.simplify(snk) 237 | base.assert(snk) 238 | return function(chunk, err) 239 | local ret, err_or_new = snk(chunk, err) 240 | if not ret then return nil, err_or_new end 241 | snk = err_or_new or snk 242 | return 1 243 | end 244 | end 245 | 246 | -- creates a file sink 247 | function sink.file(handle, io_err) 248 | if handle then 249 | return function(chunk, err) 250 | if not chunk then 251 | handle:close() 252 | return 1 253 | else return handle:write(chunk) end 254 | end 255 | else return sink.error(io_err or "unable to open file") end 256 | end 257 | 258 | -- creates a sink that discards data 259 | local function null() 260 | return 1 261 | end 262 | 263 | function sink.null() 264 | return null 265 | end 266 | 267 | -- creates a sink that just returns an error 268 | function sink.error(err) 269 | return function() 270 | return nil, err 271 | end 272 | end 273 | 274 | -- chains a sink with one or several filter(s) 275 | function sink.chain(f, snk, ...) 276 | if ... then 277 | local args = { f, snk, ... } 278 | snk = table.remove(args, #args) 279 | f = filter.chain(unpack(args)) 280 | end 281 | base.assert(f and snk) 282 | return function(chunk, err) 283 | if chunk ~= "" then 284 | local filtered = f(chunk) 285 | local done = chunk and "" 286 | while true do 287 | local ret, snkerr = snk(filtered, err) 288 | if not ret then return nil, snkerr end 289 | if filtered == done then return 1 end 290 | filtered = f(done) 291 | end 292 | else return 1 end 293 | end 294 | end 295 | 296 | ----------------------------------------------------------------------------- 297 | -- Pump stuff 298 | ----------------------------------------------------------------------------- 299 | -- pumps one chunk from the source to the sink 300 | function pump.step(src, snk) 301 | local chunk, src_err = src() 302 | local ret, snk_err = snk(chunk, src_err) 303 | if chunk and ret then return 1 304 | else return nil, src_err or snk_err end 305 | end 306 | 307 | -- pumps all data from a source to a sink, using a step function 308 | function pump.all(src, snk, step) 309 | base.assert(src and snk) 310 | step = step or pump.step 311 | while true do 312 | local ret, err = step(src, snk) 313 | if not ret then 314 | if err then return nil, err 315 | else return 1 end 316 | end 317 | end 318 | end 319 | 320 | return _M 321 | )[========]"; -------------------------------------------------------------------------------- /Source/LibLuasocket/luasocket.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * LuaSocket toolkit 3 | * Networking support for the Lua language 4 | * Diego Nehab 5 | * 26/11/1999 6 | * 7 | * This library is part of an effort to progressively increase the network 8 | * connectivity of the Lua language. The Lua interface to networking 9 | * functions follows the Sockets API closely, trying to simplify all tasks 10 | * involved in setting up both client and server connections. The provided 11 | * IO routines, however, follow the Lua style, being very similar to the 12 | * standard Lua read and write functions. 13 | \*=========================================================================*/ 14 | 15 | /*=========================================================================*\ 16 | * Standard include files 17 | \*=========================================================================*/ 18 | #include "lua.h" 19 | #include "lauxlib.h" 20 | 21 | /*=========================================================================*\ 22 | * LuaSocket includes 23 | \*=========================================================================*/ 24 | #include "luasocket.h" 25 | #include "auxiliar.h" 26 | #include "except.h" 27 | #include "timeout.h" 28 | #include "buffer.h" 29 | #include "inet.h" 30 | #include "tcp.h" 31 | #include "udp.h" 32 | #include "select.h" 33 | 34 | /*-------------------------------------------------------------------------*\ 35 | * Internal function prototypes 36 | \*-------------------------------------------------------------------------*/ 37 | static int global_skip(lua_State *L); 38 | static int global_unload(lua_State *L); 39 | static int base_open(lua_State *L); 40 | 41 | /*-------------------------------------------------------------------------*\ 42 | * Modules and functions 43 | \*-------------------------------------------------------------------------*/ 44 | static const luaL_Reg mod[] = { 45 | {"auxiliar", auxiliar_open}, 46 | {"except", except_open}, 47 | {"timeout", timeout_open}, 48 | {"buffer", buffer_open}, 49 | {"inet", inet_open}, 50 | {"tcp", tcp_open}, 51 | {"udp", udp_open}, 52 | {"select", select_open}, 53 | {NULL, NULL} 54 | }; 55 | 56 | static luaL_Reg func[] = { 57 | {"skip", global_skip}, 58 | {"__unload", global_unload}, 59 | {NULL, NULL} 60 | }; 61 | 62 | /*-------------------------------------------------------------------------*\ 63 | * Skip a few arguments 64 | \*-------------------------------------------------------------------------*/ 65 | static int global_skip(lua_State *L) { 66 | int amount = (int) luaL_checkinteger(L, 1); 67 | int ret = lua_gettop(L) - amount - 1; 68 | return ret >= 0 ? ret : 0; 69 | } 70 | 71 | /*-------------------------------------------------------------------------*\ 72 | * Unloads the library 73 | \*-------------------------------------------------------------------------*/ 74 | static int global_unload(lua_State *L) { 75 | (void) L; 76 | socket_close(); 77 | return 0; 78 | } 79 | 80 | /*-------------------------------------------------------------------------*\ 81 | * Setup basic stuff. 82 | \*-------------------------------------------------------------------------*/ 83 | static int base_open(lua_State *L) { 84 | if (socket_open()) { 85 | /* export functions (and leave namespace table on top of stack) */ 86 | lua_newtable(L); 87 | luaL_setfuncs(L, func, 0); 88 | #ifdef LUASOCKET_DEBUG 89 | lua_pushstring(L, "_DEBUG"); 90 | lua_pushboolean(L, 1); 91 | lua_rawset(L, -3); 92 | #endif 93 | /* make version string available to scripts */ 94 | lua_pushstring(L, "_VERSION"); 95 | lua_pushstring(L, LUASOCKET_VERSION); 96 | lua_rawset(L, -3); 97 | return 1; 98 | } else { 99 | lua_pushstring(L, "unable to initialize library"); 100 | lua_error(L); 101 | return 0; 102 | } 103 | } 104 | 105 | /*-------------------------------------------------------------------------*\ 106 | * Initializes all library modules. 107 | \*-------------------------------------------------------------------------*/ 108 | LUASOCKET_API int luaopen_socket_core(lua_State *L) { 109 | int i; 110 | base_open(L); 111 | for (i = 0; mod[i].name; i++) mod[i].func(L); 112 | return 1; 113 | } 114 | -------------------------------------------------------------------------------- /Source/LibLuasocket/luasocket.h: -------------------------------------------------------------------------------- 1 | #ifndef LUASOCKET_H 2 | #define LUASOCKET_H 3 | /*=========================================================================*\ 4 | * LuaSocket toolkit 5 | * Networking support for the Lua language 6 | * Diego Nehab 7 | * 9/11/1999 8 | \*=========================================================================*/ 9 | #include "lua.h" 10 | 11 | /*-------------------------------------------------------------------------*\ 12 | * Current socket library version 13 | \*-------------------------------------------------------------------------*/ 14 | #define LUASOCKET_VERSION "LuaSocket 3.0-rc1" 15 | #define LUASOCKET_COPYRIGHT "Copyright (C) 1999-2013 Diego Nehab" 16 | 17 | /*-------------------------------------------------------------------------*\ 18 | * This macro prefixes all exported API functions 19 | \*-------------------------------------------------------------------------*/ 20 | #ifndef LUASOCKET_API 21 | #define LUASOCKET_API extern 22 | #endif 23 | 24 | /*-------------------------------------------------------------------------*\ 25 | * Initializes the library. 26 | \*-------------------------------------------------------------------------*/ 27 | LUASOCKET_API int luaopen_socket_core(lua_State *L); 28 | 29 | #endif /* LUASOCKET_H */ 30 | -------------------------------------------------------------------------------- /Source/LibLuasocket/mbox.lua.inc: -------------------------------------------------------------------------------- 1 | R"[========]( 2 | local _M = {} 3 | 4 | if module then 5 | mbox = _M 6 | end 7 | 8 | function _M.split_message(message_s) 9 | local message = {} 10 | message_s = string.gsub(message_s, "\r\n", "\n") 11 | string.gsub(message_s, "^(.-\n)\n", function (h) message.headers = h end) 12 | string.gsub(message_s, "^.-\n\n(.*)", function (b) message.body = b end) 13 | if not message.body then 14 | string.gsub(message_s, "^\n(.*)", function (b) message.body = b end) 15 | end 16 | if not message.headers and not message.body then 17 | message.headers = message_s 18 | end 19 | return message.headers or "", message.body or "" 20 | end 21 | 22 | function _M.split_headers(headers_s) 23 | local headers = {} 24 | headers_s = string.gsub(headers_s, "\r\n", "\n") 25 | headers_s = string.gsub(headers_s, "\n[ ]+", " ") 26 | string.gsub("\n" .. headers_s, "\n([^\n]+)", function (h) table.insert(headers, h) end) 27 | return headers 28 | end 29 | 30 | function _M.parse_header(header_s) 31 | header_s = string.gsub(header_s, "\n[ ]+", " ") 32 | header_s = string.gsub(header_s, "\n+", "") 33 | local _, __, name, value = string.find(header_s, "([^%s:]-):%s*(.*)") 34 | return name, value 35 | end 36 | 37 | function _M.parse_headers(headers_s) 38 | local headers_t = _M.split_headers(headers_s) 39 | local headers = {} 40 | for i = 1, #headers_t do 41 | local name, value = _M.parse_header(headers_t[i]) 42 | if name then 43 | name = string.lower(name) 44 | if headers[name] then 45 | headers[name] = headers[name] .. ", " .. value 46 | else headers[name] = value end 47 | end 48 | end 49 | return headers 50 | end 51 | 52 | function _M.parse_from(from) 53 | local _, __, name, address = string.find(from, "^%s*(.-)%s*%<(.-)%>") 54 | if not address then 55 | _, __, address = string.find(from, "%s*(.+)%s*") 56 | end 57 | name = name or "" 58 | address = address or "" 59 | if name == "" then name = address end 60 | name = string.gsub(name, '"', "") 61 | return name, address 62 | end 63 | 64 | function _M.split_mbox(mbox_s) 65 | local mbox = {} 66 | mbox_s = string.gsub(mbox_s, "\r\n", "\n") .."\n\nFrom \n" 67 | local nj, i, j = 1, 1, 1 68 | while 1 do 69 | i, nj = string.find(mbox_s, "\n\nFrom .-\n", j) 70 | if not i then break end 71 | local message = string.sub(mbox_s, j, i-1) 72 | table.insert(mbox, message) 73 | j = nj+1 74 | end 75 | return mbox 76 | end 77 | 78 | function _M.parse(mbox_s) 79 | local mbox = _M.split_mbox(mbox_s) 80 | for i = 1, #mbox do 81 | mbox[i] = _M.parse_message(mbox[i]) 82 | end 83 | return mbox 84 | end 85 | 86 | function _M.parse_message(message_s) 87 | local message = {} 88 | message.headers, message.body = _M.split_message(message_s) 89 | message.headers = _M.parse_headers(message.headers) 90 | return message 91 | end 92 | 93 | return _M 94 | )[========]"; -------------------------------------------------------------------------------- /Source/LibLuasocket/mime.h: -------------------------------------------------------------------------------- 1 | #ifndef MIME_H 2 | #define MIME_H 3 | /*=========================================================================*\ 4 | * Core MIME support 5 | * LuaSocket toolkit 6 | * 7 | * This module provides functions to implement transfer content encodings 8 | * and formatting conforming to RFC 2045. It is used by mime.lua, which 9 | * provide a higher level interface to this functionality. 10 | \*=========================================================================*/ 11 | #include "lua.h" 12 | 13 | /*-------------------------------------------------------------------------*\ 14 | * Current MIME library version 15 | \*-------------------------------------------------------------------------*/ 16 | #define MIME_VERSION "MIME 1.0.3" 17 | #define MIME_COPYRIGHT "Copyright (C) 2004-2013 Diego Nehab" 18 | #define MIME_AUTHORS "Diego Nehab" 19 | 20 | /*-------------------------------------------------------------------------*\ 21 | * This macro prefixes all exported API functions 22 | \*-------------------------------------------------------------------------*/ 23 | #ifndef MIME_API 24 | #define MIME_API extern 25 | #endif 26 | 27 | MIME_API int luaopen_mime_core(lua_State *L); 28 | 29 | #endif /* MIME_H */ 30 | -------------------------------------------------------------------------------- /Source/LibLuasocket/mime.lua.inc: -------------------------------------------------------------------------------- 1 | R"[========]( 2 | ----------------------------------------------------------------------------- 3 | -- MIME support for the Lua language. 4 | -- Author: Diego Nehab 5 | -- Conforming to RFCs 2045-2049 6 | ----------------------------------------------------------------------------- 7 | 8 | ----------------------------------------------------------------------------- 9 | -- Declare module and import dependencies 10 | ----------------------------------------------------------------------------- 11 | local base = _G 12 | local ltn12 = require("ltn12") 13 | local mime = require("mime.core") 14 | local io = require("io") 15 | local string = require("string") 16 | local _M = mime 17 | 18 | -- encode, decode and wrap algorithm tables 19 | local encodet, decodet, wrapt = {},{},{} 20 | 21 | _M.encodet = encodet 22 | _M.decodet = decodet 23 | _M.wrapt = wrapt 24 | 25 | -- creates a function that chooses a filter by name from a given table 26 | local function choose(table) 27 | return function(name, opt1, opt2) 28 | if base.type(name) ~= "string" then 29 | name, opt1, opt2 = "default", name, opt1 30 | end 31 | local f = table[name or "nil"] 32 | if not f then 33 | base.error("unknown key (" .. base.tostring(name) .. ")", 3) 34 | else return f(opt1, opt2) end 35 | end 36 | end 37 | 38 | -- define the encoding filters 39 | encodet['base64'] = function() 40 | return ltn12.filter.cycle(_M.b64, "") 41 | end 42 | 43 | encodet['quoted-printable'] = function(mode) 44 | return ltn12.filter.cycle(_M.qp, "", 45 | (mode == "binary") and "=0D=0A" or "\r\n") 46 | end 47 | 48 | -- define the decoding filters 49 | decodet['base64'] = function() 50 | return ltn12.filter.cycle(_M.unb64, "") 51 | end 52 | 53 | decodet['quoted-printable'] = function() 54 | return ltn12.filter.cycle(_M.unqp, "") 55 | end 56 | 57 | local function format(chunk) 58 | if chunk then 59 | if chunk == "" then return "''" 60 | else return string.len(chunk) end 61 | else return "nil" end 62 | end 63 | 64 | -- define the line-wrap filters 65 | wrapt['text'] = function(length) 66 | length = length or 76 67 | return ltn12.filter.cycle(_M.wrp, length, length) 68 | end 69 | wrapt['base64'] = wrapt['text'] 70 | wrapt['default'] = wrapt['text'] 71 | 72 | wrapt['quoted-printable'] = function() 73 | return ltn12.filter.cycle(_M.qpwrp, 76, 76) 74 | end 75 | 76 | -- function that choose the encoding, decoding or wrap algorithm 77 | _M.encode = choose(encodet) 78 | _M.decode = choose(decodet) 79 | _M.wrap = choose(wrapt) 80 | 81 | -- define the end-of-line normalization filter 82 | function _M.normalize(marker) 83 | return ltn12.filter.cycle(_M.eol, 0, marker) 84 | end 85 | 86 | -- high level stuffing filter 87 | function _M.stuff() 88 | return ltn12.filter.cycle(_M.dot, 2) 89 | end 90 | 91 | return _M 92 | )[========]"; -------------------------------------------------------------------------------- /Source/LibLuasocket/options.h: -------------------------------------------------------------------------------- 1 | #ifndef OPTIONS_H 2 | #define OPTIONS_H 3 | /*=========================================================================*\ 4 | * Common option interface 5 | * LuaSocket toolkit 6 | * 7 | * This module provides a common interface to socket options, used mainly by 8 | * modules UDP and TCP. 9 | \*=========================================================================*/ 10 | 11 | #include "lua.h" 12 | #include "socket.h" 13 | 14 | /* option registry */ 15 | typedef struct t_opt { 16 | const char *name; 17 | int (*func)(lua_State *L, p_socket ps); 18 | } t_opt; 19 | typedef t_opt *p_opt; 20 | 21 | /* supported options for setoption */ 22 | int opt_set_dontroute(lua_State *L, p_socket ps); 23 | int opt_set_broadcast(lua_State *L, p_socket ps); 24 | int opt_set_tcp_nodelay(lua_State *L, p_socket ps); 25 | int opt_set_keepalive(lua_State *L, p_socket ps); 26 | int opt_set_linger(lua_State *L, p_socket ps); 27 | int opt_set_reuseaddr(lua_State *L, p_socket ps); 28 | int opt_set_reuseport(lua_State *L, p_socket ps); 29 | int opt_set_ip_multicast_if(lua_State *L, p_socket ps); 30 | int opt_set_ip_multicast_ttl(lua_State *L, p_socket ps); 31 | int opt_set_ip_multicast_loop(lua_State *L, p_socket ps); 32 | int opt_set_ip_add_membership(lua_State *L, p_socket ps); 33 | int opt_set_ip_drop_membersip(lua_State *L, p_socket ps); 34 | int opt_set_ip6_unicast_hops(lua_State *L, p_socket ps); 35 | int opt_set_ip6_multicast_hops(lua_State *L, p_socket ps); 36 | int opt_set_ip6_multicast_loop(lua_State *L, p_socket ps); 37 | int opt_set_ip6_add_membership(lua_State *L, p_socket ps); 38 | int opt_set_ip6_drop_membersip(lua_State *L, p_socket ps); 39 | int opt_set_ip6_v6only(lua_State *L, p_socket ps); 40 | 41 | /* supported options for getoption */ 42 | int opt_get_dontroute(lua_State *L, p_socket ps); 43 | int opt_get_broadcast(lua_State *L, p_socket ps); 44 | int opt_get_reuseaddr(lua_State *L, p_socket ps); 45 | int opt_get_reuseport(lua_State *L, p_socket ps); 46 | int opt_get_tcp_nodelay(lua_State *L, p_socket ps); 47 | int opt_get_keepalive(lua_State *L, p_socket ps); 48 | int opt_get_linger(lua_State *L, p_socket ps); 49 | int opt_get_ip_multicast_loop(lua_State *L, p_socket ps); 50 | int opt_get_ip_multicast_if(lua_State *L, p_socket ps); 51 | int opt_get_error(lua_State *L, p_socket ps); 52 | int opt_get_ip6_multicast_loop(lua_State *L, p_socket ps); 53 | int opt_get_ip6_multicast_hops(lua_State *L, p_socket ps); 54 | int opt_get_ip6_unicast_hops(lua_State *L, p_socket ps); 55 | int opt_get_ip6_v6only(lua_State *L, p_socket ps); 56 | int opt_get_reuseport(lua_State *L, p_socket ps); 57 | 58 | /* invokes the appropriate option handler */ 59 | int opt_meth_setoption(lua_State *L, p_opt opt, p_socket ps); 60 | int opt_meth_getoption(lua_State *L, p_opt opt, p_socket ps); 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /Source/LibLuasocket/pierror.h: -------------------------------------------------------------------------------- 1 | #ifndef PIERROR_H 2 | #define PIERROR_H 3 | /*=========================================================================*\ 4 | * Error messages 5 | * Defines platform independent error messages 6 | \*=========================================================================*/ 7 | 8 | #define PIE_HOST_NOT_FOUND "host not found" 9 | #define PIE_ADDRINUSE "address already in use" 10 | #define PIE_ISCONN "already connected" 11 | #define PIE_ACCESS "permission denied" 12 | #define PIE_CONNREFUSED "connection refused" 13 | #define PIE_CONNABORTED "closed" 14 | #define PIE_CONNRESET "closed" 15 | #define PIE_TIMEDOUT "timeout" 16 | #define PIE_AGAIN "temporary failure in name resolution" 17 | #define PIE_BADFLAGS "invalid value for ai_flags" 18 | #define PIE_BADHINTS "invalid value for hints" 19 | #define PIE_FAIL "non-recoverable failure in name resolution" 20 | #define PIE_FAMILY "ai_family not supported" 21 | #define PIE_MEMORY "memory allocation failure" 22 | #define PIE_NONAME "host or service not provided, or not known" 23 | #define PIE_OVERFLOW "argument buffer overflow" 24 | #define PIE_PROTOCOL "resolved protocol is unknown" 25 | #define PIE_SERVICE "service not supported for socket type" 26 | #define PIE_SOCKTYPE "ai_socktype not supported" 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /Source/LibLuasocket/select.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * Select implementation 3 | * LuaSocket toolkit 4 | \*=========================================================================*/ 5 | #include 6 | 7 | #include "lua.h" 8 | #include "lauxlib.h" 9 | 10 | #include "socket.h" 11 | #include "timeout.h" 12 | #include "select.h" 13 | 14 | /*=========================================================================*\ 15 | * Internal function prototypes. 16 | \*=========================================================================*/ 17 | static t_socket getfd(lua_State *L); 18 | static int dirty(lua_State *L); 19 | static void collect_fd(lua_State *L, int tab, int itab, 20 | fd_set *set, t_socket *max_fd); 21 | static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set); 22 | static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, 23 | int itab, int tab, int start); 24 | static void make_assoc(lua_State *L, int tab); 25 | static int global_select(lua_State *L); 26 | 27 | /* functions in library namespace */ 28 | static luaL_Reg func[] = { 29 | {"select", global_select}, 30 | {NULL, NULL} 31 | }; 32 | 33 | /*=========================================================================*\ 34 | * Exported functions 35 | \*=========================================================================*/ 36 | /*-------------------------------------------------------------------------*\ 37 | * Initializes module 38 | \*-------------------------------------------------------------------------*/ 39 | int select_open(lua_State *L) { 40 | lua_pushstring(L, "_SETSIZE"); 41 | lua_pushinteger(L, FD_SETSIZE); 42 | lua_rawset(L, -3); 43 | lua_pushstring(L, "_SOCKETINVALID"); 44 | lua_pushinteger(L, SOCKET_INVALID); 45 | lua_rawset(L, -3); 46 | luaL_setfuncs(L, func, 0); 47 | return 0; 48 | } 49 | 50 | /*=========================================================================*\ 51 | * Global Lua functions 52 | \*=========================================================================*/ 53 | /*-------------------------------------------------------------------------*\ 54 | * Waits for a set of sockets until a condition is met or timeout. 55 | \*-------------------------------------------------------------------------*/ 56 | static int global_select(lua_State *L) { 57 | int rtab, wtab, itab, ret, ndirty; 58 | t_socket max_fd = SOCKET_INVALID; 59 | fd_set rset, wset; 60 | t_timeout tm; 61 | double t = luaL_optnumber(L, 3, -1); 62 | FD_ZERO(&rset); FD_ZERO(&wset); 63 | lua_settop(L, 3); 64 | lua_newtable(L); itab = lua_gettop(L); 65 | lua_newtable(L); rtab = lua_gettop(L); 66 | lua_newtable(L); wtab = lua_gettop(L); 67 | collect_fd(L, 1, itab, &rset, &max_fd); 68 | collect_fd(L, 2, itab, &wset, &max_fd); 69 | ndirty = check_dirty(L, 1, rtab, &rset); 70 | t = ndirty > 0? 0.0: t; 71 | timeout_init(&tm, t, -1); 72 | timeout_markstart(&tm); 73 | ret = socket_select(max_fd+1, &rset, &wset, NULL, &tm); 74 | if (ret > 0 || ndirty > 0) { 75 | return_fd(L, &rset, max_fd+1, itab, rtab, ndirty); 76 | return_fd(L, &wset, max_fd+1, itab, wtab, 0); 77 | make_assoc(L, rtab); 78 | make_assoc(L, wtab); 79 | return 2; 80 | } else if (ret == 0) { 81 | lua_pushstring(L, "timeout"); 82 | return 3; 83 | } else { 84 | luaL_error(L, "select failed"); 85 | return 3; 86 | } 87 | } 88 | 89 | /*=========================================================================*\ 90 | * Internal functions 91 | \*=========================================================================*/ 92 | static t_socket getfd(lua_State *L) { 93 | t_socket fd = SOCKET_INVALID; 94 | lua_pushstring(L, "getfd"); 95 | lua_gettable(L, -2); 96 | if (!lua_isnil(L, -1)) { 97 | lua_pushvalue(L, -2); 98 | lua_call(L, 1, 1); 99 | if (lua_isnumber(L, -1)) { 100 | double numfd = lua_tonumber(L, -1); 101 | fd = (numfd >= 0.0)? (t_socket) numfd: SOCKET_INVALID; 102 | } 103 | } 104 | lua_pop(L, 1); 105 | return fd; 106 | } 107 | 108 | static int dirty(lua_State *L) { 109 | int is = 0; 110 | lua_pushstring(L, "dirty"); 111 | lua_gettable(L, -2); 112 | if (!lua_isnil(L, -1)) { 113 | lua_pushvalue(L, -2); 114 | lua_call(L, 1, 1); 115 | is = lua_toboolean(L, -1); 116 | } 117 | lua_pop(L, 1); 118 | return is; 119 | } 120 | 121 | static void collect_fd(lua_State *L, int tab, int itab, 122 | fd_set *set, t_socket *max_fd) { 123 | int i = 1, n = 0; 124 | /* nil is the same as an empty table */ 125 | if (lua_isnil(L, tab)) return; 126 | /* otherwise we need it to be a table */ 127 | luaL_checktype(L, tab, LUA_TTABLE); 128 | for ( ;; ) { 129 | t_socket fd; 130 | lua_pushnumber(L, i); 131 | lua_gettable(L, tab); 132 | if (lua_isnil(L, -1)) { 133 | lua_pop(L, 1); 134 | break; 135 | } 136 | /* getfd figures out if this is a socket */ 137 | fd = getfd(L); 138 | if (fd != SOCKET_INVALID) { 139 | /* make sure we don't overflow the fd_set */ 140 | #ifdef _WIN32 141 | if (n >= FD_SETSIZE) 142 | luaL_argerror(L, tab, "too many sockets"); 143 | #else 144 | if (fd >= FD_SETSIZE) 145 | luaL_argerror(L, tab, "descriptor too large for set size"); 146 | #endif 147 | FD_SET(fd, set); 148 | n++; 149 | /* keep track of the largest descriptor so far */ 150 | if (*max_fd == SOCKET_INVALID || *max_fd < fd) 151 | *max_fd = fd; 152 | /* make sure we can map back from descriptor to the object */ 153 | lua_pushnumber(L, (lua_Number) fd); 154 | lua_pushvalue(L, -2); 155 | lua_settable(L, itab); 156 | } 157 | lua_pop(L, 1); 158 | i = i + 1; 159 | } 160 | } 161 | 162 | static int check_dirty(lua_State *L, int tab, int dtab, fd_set *set) { 163 | int ndirty = 0, i = 1; 164 | if (lua_isnil(L, tab)) 165 | return 0; 166 | for ( ;; ) { 167 | t_socket fd; 168 | lua_pushnumber(L, i); 169 | lua_gettable(L, tab); 170 | if (lua_isnil(L, -1)) { 171 | lua_pop(L, 1); 172 | break; 173 | } 174 | fd = getfd(L); 175 | if (fd != SOCKET_INVALID && dirty(L)) { 176 | lua_pushnumber(L, ++ndirty); 177 | lua_pushvalue(L, -2); 178 | lua_settable(L, dtab); 179 | FD_CLR(fd, set); 180 | } 181 | lua_pop(L, 1); 182 | i = i + 1; 183 | } 184 | return ndirty; 185 | } 186 | 187 | static void return_fd(lua_State *L, fd_set *set, t_socket max_fd, 188 | int itab, int tab, int start) { 189 | t_socket fd; 190 | for (fd = 0; fd < max_fd; fd++) { 191 | if (FD_ISSET(fd, set)) { 192 | lua_pushnumber(L, ++start); 193 | lua_pushnumber(L, (lua_Number) fd); 194 | lua_gettable(L, itab); 195 | lua_settable(L, tab); 196 | } 197 | } 198 | } 199 | 200 | static void make_assoc(lua_State *L, int tab) { 201 | int i = 1, atab; 202 | lua_newtable(L); atab = lua_gettop(L); 203 | for ( ;; ) { 204 | lua_pushnumber(L, i); 205 | lua_gettable(L, tab); 206 | if (!lua_isnil(L, -1)) { 207 | lua_pushnumber(L, i); 208 | lua_pushvalue(L, -2); 209 | lua_settable(L, atab); 210 | lua_pushnumber(L, i); 211 | lua_settable(L, atab); 212 | } else { 213 | lua_pop(L, 1); 214 | break; 215 | } 216 | i = i+1; 217 | } 218 | } 219 | 220 | -------------------------------------------------------------------------------- /Source/LibLuasocket/select.h: -------------------------------------------------------------------------------- 1 | #ifndef SELECT_H 2 | #define SELECT_H 3 | /*=========================================================================*\ 4 | * Select implementation 5 | * LuaSocket toolkit 6 | * 7 | * Each object that can be passed to the select function has to export 8 | * method getfd() which returns the descriptor to be passed to the 9 | * underlying select function. Another method, dirty(), should return 10 | * true if there is data ready for reading (required for buffered input). 11 | \*=========================================================================*/ 12 | 13 | int select_open(lua_State *L); 14 | 15 | #endif /* SELECT_H */ 16 | -------------------------------------------------------------------------------- /Source/LibLuasocket/smtp.lua.inc: -------------------------------------------------------------------------------- 1 | R"[========]( 2 | ----------------------------------------------------------------------------- 3 | -- SMTP client support for the Lua language. 4 | -- LuaSocket toolkit. 5 | -- Author: Diego Nehab 6 | ----------------------------------------------------------------------------- 7 | 8 | ----------------------------------------------------------------------------- 9 | -- Declare module and import dependencies 10 | ----------------------------------------------------------------------------- 11 | local base = _G 12 | local coroutine = require("coroutine") 13 | local string = require("string") 14 | local math = require("math") 15 | local os = require("os") 16 | local socket = require("socket") 17 | local tp = require("socket.tp") 18 | local ltn12 = require("ltn12") 19 | local headers = require("socket.headers") 20 | local mime = require("mime") 21 | 22 | socket.smtp = {} 23 | local _M = socket.smtp 24 | 25 | ----------------------------------------------------------------------------- 26 | -- Program constants 27 | ----------------------------------------------------------------------------- 28 | -- timeout for connection 29 | _M.TIMEOUT = 60 30 | -- default server used to send e-mails 31 | _M.SERVER = "localhost" 32 | -- default port 33 | _M.PORT = 25 34 | -- domain used in HELO command and default sendmail 35 | -- If we are under a CGI, try to get from environment 36 | _M.DOMAIN = os.getenv("SERVER_NAME") or "localhost" 37 | -- default time zone (means we don't know) 38 | _M.ZONE = "-0000" 39 | 40 | --------------------------------------------------------------------------- 41 | -- Low level SMTP API 42 | ----------------------------------------------------------------------------- 43 | local metat = { __index = {} } 44 | 45 | function metat.__index:greet(domain) 46 | self.try(self.tp:check("2..")) 47 | self.try(self.tp:command("EHLO", domain or _M.DOMAIN)) 48 | return socket.skip(1, self.try(self.tp:check("2.."))) 49 | end 50 | 51 | function metat.__index:mail(from) 52 | self.try(self.tp:command("MAIL", "FROM:" .. from)) 53 | return self.try(self.tp:check("2..")) 54 | end 55 | 56 | function metat.__index:rcpt(to) 57 | self.try(self.tp:command("RCPT", "TO:" .. to)) 58 | return self.try(self.tp:check("2..")) 59 | end 60 | 61 | function metat.__index:data(src, step) 62 | self.try(self.tp:command("DATA")) 63 | self.try(self.tp:check("3..")) 64 | self.try(self.tp:source(src, step)) 65 | self.try(self.tp:send("\r\n.\r\n")) 66 | return self.try(self.tp:check("2..")) 67 | end 68 | 69 | function metat.__index:quit() 70 | self.try(self.tp:command("QUIT")) 71 | return self.try(self.tp:check("2..")) 72 | end 73 | 74 | function metat.__index:close() 75 | return self.tp:close() 76 | end 77 | 78 | function metat.__index:login(user, password) 79 | self.try(self.tp:command("AUTH", "LOGIN")) 80 | self.try(self.tp:check("3..")) 81 | self.try(self.tp:send(mime.b64(user) .. "\r\n")) 82 | self.try(self.tp:check("3..")) 83 | self.try(self.tp:send(mime.b64(password) .. "\r\n")) 84 | return self.try(self.tp:check("2..")) 85 | end 86 | 87 | function metat.__index:plain(user, password) 88 | local auth = "PLAIN " .. mime.b64("\0" .. user .. "\0" .. password) 89 | self.try(self.tp:command("AUTH", auth)) 90 | return self.try(self.tp:check("2..")) 91 | end 92 | 93 | function metat.__index:auth(user, password, ext) 94 | if not user or not password then return 1 end 95 | if string.find(ext, "AUTH[^\n]+LOGIN") then 96 | return self:login(user, password) 97 | elseif string.find(ext, "AUTH[^\n]+PLAIN") then 98 | return self:plain(user, password) 99 | else 100 | self.try(nil, "authentication not supported") 101 | end 102 | end 103 | 104 | -- send message or throw an exception 105 | function metat.__index:send(mailt) 106 | self:mail(mailt.from) 107 | if base.type(mailt.rcpt) == "table" then 108 | for i,v in base.ipairs(mailt.rcpt) do 109 | self:rcpt(v) 110 | end 111 | else 112 | self:rcpt(mailt.rcpt) 113 | end 114 | self:data(ltn12.source.chain(mailt.source, mime.stuff()), mailt.step) 115 | end 116 | 117 | function _M.open(server, port, create) 118 | local tp = socket.try(tp.connect(server or _M.SERVER, port or _M.PORT, 119 | _M.TIMEOUT, create)) 120 | local s = base.setmetatable({tp = tp}, metat) 121 | -- make sure tp is closed if we get an exception 122 | s.try = socket.newtry(function() 123 | s:close() 124 | end) 125 | return s 126 | end 127 | 128 | -- convert headers to lowercase 129 | local function lower_headers(headers) 130 | local lower = {} 131 | for i,v in base.pairs(headers or lower) do 132 | lower[string.lower(i)] = v 133 | end 134 | return lower 135 | end 136 | 137 | --------------------------------------------------------------------------- 138 | -- Multipart message source 139 | ----------------------------------------------------------------------------- 140 | -- returns a hopefully unique mime boundary 141 | local seqno = 0 142 | local function newboundary() 143 | seqno = seqno + 1 144 | return string.format('%s%05d==%05u', os.date('%d%m%Y%H%M%S'), 145 | math.random(0, 99999), seqno) 146 | end 147 | 148 | -- send_message forward declaration 149 | local send_message 150 | 151 | -- yield the headers all at once, it's faster 152 | local function send_headers(tosend) 153 | local canonic = headers.canonic 154 | local h = "\r\n" 155 | for f,v in base.pairs(tosend) do 156 | h = (canonic[f] or f) .. ': ' .. v .. "\r\n" .. h 157 | end 158 | coroutine.yield(h) 159 | end 160 | 161 | -- yield multipart message body from a multipart message table 162 | local function send_multipart(mesgt) 163 | -- make sure we have our boundary and send headers 164 | local bd = newboundary() 165 | local headers = lower_headers(mesgt.headers or {}) 166 | headers['content-type'] = headers['content-type'] or 'multipart/mixed' 167 | headers['content-type'] = headers['content-type'] .. 168 | '; boundary="' .. bd .. '"' 169 | send_headers(headers) 170 | -- send preamble 171 | if mesgt.body.preamble then 172 | coroutine.yield(mesgt.body.preamble) 173 | coroutine.yield("\r\n") 174 | end 175 | -- send each part separated by a boundary 176 | for i, m in base.ipairs(mesgt.body) do 177 | coroutine.yield("\r\n--" .. bd .. "\r\n") 178 | send_message(m) 179 | end 180 | -- send last boundary 181 | coroutine.yield("\r\n--" .. bd .. "--\r\n\r\n") 182 | -- send epilogue 183 | if mesgt.body.epilogue then 184 | coroutine.yield(mesgt.body.epilogue) 185 | coroutine.yield("\r\n") 186 | end 187 | end 188 | 189 | -- yield message body from a source 190 | local function send_source(mesgt) 191 | -- make sure we have a content-type 192 | local headers = lower_headers(mesgt.headers or {}) 193 | headers['content-type'] = headers['content-type'] or 194 | 'text/plain; charset="iso-8859-1"' 195 | send_headers(headers) 196 | -- send body from source 197 | while true do 198 | local chunk, err = mesgt.body() 199 | if err then coroutine.yield(nil, err) 200 | elseif chunk then coroutine.yield(chunk) 201 | else break end 202 | end 203 | end 204 | 205 | -- yield message body from a string 206 | local function send_string(mesgt) 207 | -- make sure we have a content-type 208 | local headers = lower_headers(mesgt.headers or {}) 209 | headers['content-type'] = headers['content-type'] or 210 | 'text/plain; charset="iso-8859-1"' 211 | send_headers(headers) 212 | -- send body from string 213 | coroutine.yield(mesgt.body) 214 | end 215 | 216 | -- message source 217 | function send_message(mesgt) 218 | if base.type(mesgt.body) == "table" then send_multipart(mesgt) 219 | elseif base.type(mesgt.body) == "function" then send_source(mesgt) 220 | else send_string(mesgt) end 221 | end 222 | 223 | -- set defaul headers 224 | local function adjust_headers(mesgt) 225 | local lower = lower_headers(mesgt.headers) 226 | lower["date"] = lower["date"] or 227 | os.date("!%a, %d %b %Y %H:%M:%S ") .. (mesgt.zone or _M.ZONE) 228 | lower["x-mailer"] = lower["x-mailer"] or socket._VERSION 229 | -- this can't be overriden 230 | lower["mime-version"] = "1.0" 231 | return lower 232 | end 233 | 234 | function _M.message(mesgt) 235 | mesgt.headers = adjust_headers(mesgt) 236 | -- create and return message source 237 | local co = coroutine.create(function() send_message(mesgt) end) 238 | return function() 239 | local ret, a, b = coroutine.resume(co) 240 | if ret then return a, b 241 | else return nil, a end 242 | end 243 | end 244 | 245 | --------------------------------------------------------------------------- 246 | -- High level SMTP API 247 | ----------------------------------------------------------------------------- 248 | _M.send = socket.protect(function(mailt) 249 | local s = _M.open(mailt.server, mailt.port, mailt.create) 250 | local ext = s:greet(mailt.domain) 251 | s:auth(mailt.user, mailt.password, ext) 252 | s:send(mailt) 253 | s:quit() 254 | return s:close() 255 | end) 256 | 257 | return _M 258 | )[========]"; -------------------------------------------------------------------------------- /Source/LibLuasocket/socket.h: -------------------------------------------------------------------------------- 1 | #ifndef SOCKET_H 2 | #define SOCKET_H 3 | /*=========================================================================*\ 4 | * Socket compatibilization module 5 | * LuaSocket toolkit 6 | * 7 | * BSD Sockets and WinSock are similar, but there are a few irritating 8 | * differences. Also, not all *nix platforms behave the same. This module 9 | * (and the associated usocket.h and wsocket.h) factor these differences and 10 | * creates a interface compatible with the io.h module. 11 | \*=========================================================================*/ 12 | #include "io.h" 13 | 14 | /*=========================================================================*\ 15 | * Platform specific compatibilization 16 | \*=========================================================================*/ 17 | #ifdef _WIN32 18 | #include "wsocket.h" 19 | #else 20 | #include "usocket.h" 21 | #endif 22 | 23 | /*=========================================================================*\ 24 | * The connect and accept functions accept a timeout and their 25 | * implementations are somewhat complicated. We chose to move 26 | * the timeout control into this module for these functions in 27 | * order to simplify the modules that use them. 28 | \*=========================================================================*/ 29 | #include "timeout.h" 30 | 31 | /* we are lazy... */ 32 | typedef struct sockaddr SA; 33 | 34 | /*=========================================================================*\ 35 | * Functions bellow implement a comfortable platform independent 36 | * interface to sockets 37 | \*=========================================================================*/ 38 | int socket_open(void); 39 | int socket_close(void); 40 | void socket_destroy(p_socket ps); 41 | void socket_shutdown(p_socket ps, int how); 42 | int socket_sendto(p_socket ps, const char *data, size_t count, 43 | size_t *sent, SA *addr, socklen_t addr_len, p_timeout tm); 44 | int socket_recvfrom(p_socket ps, char *data, size_t count, 45 | size_t *got, SA *addr, socklen_t *addr_len, p_timeout tm); 46 | 47 | void socket_setnonblocking(p_socket ps); 48 | void socket_setblocking(p_socket ps); 49 | 50 | int socket_waitfd(p_socket ps, int sw, p_timeout tm); 51 | int socket_select(t_socket n, fd_set *rfds, fd_set *wfds, fd_set *efds, 52 | p_timeout tm); 53 | 54 | int socket_connect(p_socket ps, SA *addr, socklen_t addr_len, p_timeout tm); 55 | int socket_create(p_socket ps, int domain, int type, int protocol); 56 | int socket_bind(p_socket ps, SA *addr, socklen_t addr_len); 57 | int socket_listen(p_socket ps, int backlog); 58 | int socket_accept(p_socket ps, p_socket pa, SA *addr, 59 | socklen_t *addr_len, p_timeout tm); 60 | 61 | const char *socket_hoststrerror(int err); 62 | const char *socket_gaistrerror(int err); 63 | const char *socket_strerror(int err); 64 | 65 | /* these are perfect to use with the io abstraction module 66 | and the buffered input module */ 67 | int socket_send(p_socket ps, const char *data, size_t count, 68 | size_t *sent, p_timeout tm); 69 | int socket_recv(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); 70 | int socket_write(p_socket ps, const char *data, size_t count, 71 | size_t *sent, p_timeout tm); 72 | int socket_read(p_socket ps, char *data, size_t count, size_t *got, p_timeout tm); 73 | const char *socket_ioerror(p_socket ps, int err); 74 | 75 | int socket_gethostbyaddr(const char *addr, socklen_t len, struct hostent **hp); 76 | int socket_gethostbyname(const char *addr, struct hostent **hp); 77 | 78 | #endif /* SOCKET_H */ 79 | -------------------------------------------------------------------------------- /Source/LibLuasocket/socket.lua.inc: -------------------------------------------------------------------------------- 1 | R"[========]( 2 | ----------------------------------------------------------------------------- 3 | -- LuaSocket helper module 4 | -- Author: Diego Nehab 5 | ----------------------------------------------------------------------------- 6 | 7 | ----------------------------------------------------------------------------- 8 | -- Declare module and import dependencies 9 | ----------------------------------------------------------------------------- 10 | local base = _G 11 | local string = require("string") 12 | local math = require("math") 13 | local socket = require("socket.core") 14 | 15 | local _M = socket 16 | 17 | ----------------------------------------------------------------------------- 18 | -- Exported auxiliar functions 19 | ----------------------------------------------------------------------------- 20 | function _M.connect4(address, port, laddress, lport) 21 | return socket.connect(address, port, laddress, lport, "inet") 22 | end 23 | 24 | function _M.connect6(address, port, laddress, lport) 25 | return socket.connect(address, port, laddress, lport, "inet6") 26 | end 27 | 28 | function _M.bind(host, port, backlog) 29 | if host == "*" then host = "0.0.0.0" end 30 | local addrinfo, err = socket.dns.getaddrinfo(host); 31 | if not addrinfo then return nil, err end 32 | local sock, res 33 | err = "no info on address" 34 | for i, alt in base.ipairs(addrinfo) do 35 | if alt.family == "inet" then 36 | sock, err = socket.tcp4() 37 | else 38 | sock, err = socket.tcp6() 39 | end 40 | if not sock then return nil, err end 41 | sock:setoption("reuseaddr", true) 42 | res, err = sock:bind(alt.addr, port) 43 | if not res then 44 | sock:close() 45 | else 46 | res, err = sock:listen(backlog) 47 | if not res then 48 | sock:close() 49 | else 50 | return sock 51 | end 52 | end 53 | end 54 | return nil, err 55 | end 56 | 57 | _M.try = _M.newtry() 58 | 59 | function _M.choose(table) 60 | return function(name, opt1, opt2) 61 | if base.type(name) ~= "string" then 62 | name, opt1, opt2 = "default", name, opt1 63 | end 64 | local f = table[name or "nil"] 65 | if not f then base.error("unknown key (".. base.tostring(name) ..")", 3) 66 | else return f(opt1, opt2) end 67 | end 68 | end 69 | 70 | ----------------------------------------------------------------------------- 71 | -- Socket sources and sinks, conforming to LTN12 72 | ----------------------------------------------------------------------------- 73 | -- create namespaces inside LuaSocket namespace 74 | local sourcet, sinkt = {}, {} 75 | _M.sourcet = sourcet 76 | _M.sinkt = sinkt 77 | 78 | _M.BLOCKSIZE = 2048 79 | 80 | sinkt["close-when-done"] = function(sock) 81 | return base.setmetatable({ 82 | getfd = function() return sock:getfd() end, 83 | dirty = function() return sock:dirty() end 84 | }, { 85 | __call = function(self, chunk, err) 86 | if not chunk then 87 | sock:close() 88 | return 1 89 | else return sock:send(chunk) end 90 | end 91 | }) 92 | end 93 | 94 | sinkt["keep-open"] = function(sock) 95 | return base.setmetatable({ 96 | getfd = function() return sock:getfd() end, 97 | dirty = function() return sock:dirty() end 98 | }, { 99 | __call = function(self, chunk, err) 100 | if chunk then return sock:send(chunk) 101 | else return 1 end 102 | end 103 | }) 104 | end 105 | 106 | sinkt["default"] = sinkt["keep-open"] 107 | 108 | _M.sink = _M.choose(sinkt) 109 | 110 | sourcet["by-length"] = function(sock, length) 111 | return base.setmetatable({ 112 | getfd = function() return sock:getfd() end, 113 | dirty = function() return sock:dirty() end 114 | }, { 115 | __call = function() 116 | if length <= 0 then return nil end 117 | local size = math.min(socket.BLOCKSIZE, length) 118 | local chunk, err = sock:receive(size) 119 | if err then return nil, err end 120 | length = length - string.len(chunk) 121 | return chunk 122 | end 123 | }) 124 | end 125 | 126 | sourcet["until-closed"] = function(sock) 127 | local done 128 | return base.setmetatable({ 129 | getfd = function() return sock:getfd() end, 130 | dirty = function() return sock:dirty() end 131 | }, { 132 | __call = function() 133 | if done then return nil end 134 | local chunk, err, partial = sock:receive(socket.BLOCKSIZE) 135 | if not err then return chunk 136 | elseif err == "closed" then 137 | sock:close() 138 | done = 1 139 | return partial 140 | else return nil, err end 141 | end 142 | }) 143 | end 144 | 145 | 146 | sourcet["default"] = sourcet["until-closed"] 147 | 148 | _M.source = _M.choose(sourcet) 149 | 150 | return _M 151 | )[========]"; -------------------------------------------------------------------------------- /Source/LibLuasocket/tcp.h: -------------------------------------------------------------------------------- 1 | #ifndef TCP_H 2 | #define TCP_H 3 | /*=========================================================================*\ 4 | * TCP object 5 | * LuaSocket toolkit 6 | * 7 | * The tcp.h module is basicly a glue that puts together modules buffer.h, 8 | * timeout.h socket.h and inet.h to provide the LuaSocket TCP (AF_INET, 9 | * SOCK_STREAM) support. 10 | * 11 | * Three classes are defined: master, client and server. The master class is 12 | * a newly created tcp object, that has not been bound or connected. Server 13 | * objects are tcp objects bound to some local address. Client objects are 14 | * tcp objects either connected to some address or returned by the accept 15 | * method of a server object. 16 | \*=========================================================================*/ 17 | #include "lua.h" 18 | 19 | #include "buffer.h" 20 | #include "timeout.h" 21 | #include "socket.h" 22 | 23 | typedef struct t_tcp_ { 24 | t_socket sock; 25 | t_io io; 26 | t_buffer buf; 27 | t_timeout tm; 28 | int family; 29 | } t_tcp; 30 | 31 | typedef t_tcp *p_tcp; 32 | 33 | int tcp_open(lua_State *L); 34 | 35 | #endif /* TCP_H */ 36 | -------------------------------------------------------------------------------- /Source/LibLuasocket/timeout.c: -------------------------------------------------------------------------------- 1 | /*=========================================================================*\ 2 | * Timeout management functions 3 | * LuaSocket toolkit 4 | \*=========================================================================*/ 5 | #include 6 | #include 7 | #include 8 | 9 | #include "lua.h" 10 | #include "lauxlib.h" 11 | 12 | #include "auxiliar.h" 13 | #include "timeout.h" 14 | 15 | #ifdef _WIN32 16 | #include 17 | #else 18 | #include 19 | #include 20 | #endif 21 | 22 | /* min and max macros */ 23 | #ifndef MIN 24 | #define MIN(x, y) ((x) < (y) ? x : y) 25 | #endif 26 | #ifndef MAX 27 | #define MAX(x, y) ((x) > (y) ? x : y) 28 | #endif 29 | 30 | /*=========================================================================*\ 31 | * Internal function prototypes 32 | \*=========================================================================*/ 33 | static int timeout_lua_gettime(lua_State *L); 34 | static int timeout_lua_sleep(lua_State *L); 35 | 36 | static luaL_Reg func[] = { 37 | { "gettime", timeout_lua_gettime }, 38 | { "sleep", timeout_lua_sleep }, 39 | { NULL, NULL } 40 | }; 41 | 42 | /*=========================================================================*\ 43 | * Exported functions. 44 | \*=========================================================================*/ 45 | /*-------------------------------------------------------------------------*\ 46 | * Initialize structure 47 | \*-------------------------------------------------------------------------*/ 48 | void timeout_init(p_timeout tm, double block, double total) { 49 | tm->block = block; 50 | tm->total = total; 51 | } 52 | 53 | /*-------------------------------------------------------------------------*\ 54 | * Determines how much time we have left for the next system call, 55 | * if the previous call was successful 56 | * Input 57 | * tm: timeout control structure 58 | * Returns 59 | * the number of ms left or -1 if there is no time limit 60 | \*-------------------------------------------------------------------------*/ 61 | double timeout_get(p_timeout tm) { 62 | if (tm->block < 0.0 && tm->total < 0.0) { 63 | return -1; 64 | } else if (tm->block < 0.0) { 65 | double t = tm->total - timeout_gettime() + tm->start; 66 | return MAX(t, 0.0); 67 | } else if (tm->total < 0.0) { 68 | return tm->block; 69 | } else { 70 | double t = tm->total - timeout_gettime() + tm->start; 71 | return MIN(tm->block, MAX(t, 0.0)); 72 | } 73 | } 74 | 75 | /*-------------------------------------------------------------------------*\ 76 | * Returns time since start of operation 77 | * Input 78 | * tm: timeout control structure 79 | * Returns 80 | * start field of structure 81 | \*-------------------------------------------------------------------------*/ 82 | double timeout_getstart(p_timeout tm) { 83 | return tm->start; 84 | } 85 | 86 | /*-------------------------------------------------------------------------*\ 87 | * Determines how much time we have left for the next system call, 88 | * if the previous call was a failure 89 | * Input 90 | * tm: timeout control structure 91 | * Returns 92 | * the number of ms left or -1 if there is no time limit 93 | \*-------------------------------------------------------------------------*/ 94 | double timeout_getretry(p_timeout tm) { 95 | if (tm->block < 0.0 && tm->total < 0.0) { 96 | return -1; 97 | } else if (tm->block < 0.0) { 98 | double t = tm->total - timeout_gettime() + tm->start; 99 | return MAX(t, 0.0); 100 | } else if (tm->total < 0.0) { 101 | double t = tm->block - timeout_gettime() + tm->start; 102 | return MAX(t, 0.0); 103 | } else { 104 | double t = tm->total - timeout_gettime() + tm->start; 105 | return MIN(tm->block, MAX(t, 0.0)); 106 | } 107 | } 108 | 109 | /*-------------------------------------------------------------------------*\ 110 | * Marks the operation start time in structure 111 | * Input 112 | * tm: timeout control structure 113 | \*-------------------------------------------------------------------------*/ 114 | p_timeout timeout_markstart(p_timeout tm) { 115 | tm->start = timeout_gettime(); 116 | return tm; 117 | } 118 | 119 | /*-------------------------------------------------------------------------*\ 120 | * Gets time in s, relative to January 1, 1970 (UTC) 121 | * Returns 122 | * time in s. 123 | \*-------------------------------------------------------------------------*/ 124 | #ifdef _WIN32 125 | double timeout_gettime(void) { 126 | FILETIME ft; 127 | double t; 128 | GetSystemTimeAsFileTime(&ft); 129 | /* Windows file time (time since January 1, 1601 (UTC)) */ 130 | t = ft.dwLowDateTime/1.0e7 + ft.dwHighDateTime*(4294967296.0/1.0e7); 131 | /* convert to Unix Epoch time (time since January 1, 1970 (UTC)) */ 132 | return (t - 11644473600.0); 133 | } 134 | #else 135 | double timeout_gettime(void) { 136 | struct timeval v; 137 | gettimeofday(&v, (struct timezone *) NULL); 138 | /* Unix Epoch time (time since January 1, 1970 (UTC)) */ 139 | return v.tv_sec + v.tv_usec/1.0e6; 140 | } 141 | #endif 142 | 143 | /*-------------------------------------------------------------------------*\ 144 | * Initializes module 145 | \*-------------------------------------------------------------------------*/ 146 | int timeout_open(lua_State *L) { 147 | luaL_setfuncs(L, func, 0); 148 | return 0; 149 | } 150 | 151 | /*-------------------------------------------------------------------------*\ 152 | * Sets timeout values for IO operations 153 | * Lua Input: base, time [, mode] 154 | * time: time out value in seconds 155 | * mode: "b" for block timeout, "t" for total timeout. (default: b) 156 | \*-------------------------------------------------------------------------*/ 157 | int timeout_meth_settimeout(lua_State *L, p_timeout tm) { 158 | double t = luaL_optnumber(L, 2, -1); 159 | const char *mode = luaL_optstring(L, 3, "b"); 160 | switch (*mode) { 161 | case 'b': 162 | tm->block = t; 163 | break; 164 | case 'r': case 't': 165 | tm->total = t; 166 | break; 167 | default: 168 | luaL_argcheck(L, 0, 3, "invalid timeout mode"); 169 | break; 170 | } 171 | lua_pushnumber(L, 1); 172 | return 1; 173 | } 174 | 175 | /*-------------------------------------------------------------------------*\ 176 | * Gets timeout values for IO operations 177 | * Lua Output: block, total 178 | \*-------------------------------------------------------------------------*/ 179 | int timeout_meth_gettimeout(lua_State *L, p_timeout tm) { 180 | lua_pushnumber(L, tm->block); 181 | lua_pushnumber(L, tm->total); 182 | return 2; 183 | } 184 | 185 | /*=========================================================================*\ 186 | * Test support functions 187 | \*=========================================================================*/ 188 | /*-------------------------------------------------------------------------*\ 189 | * Returns the time the system has been up, in secconds. 190 | \*-------------------------------------------------------------------------*/ 191 | static int timeout_lua_gettime(lua_State *L) 192 | { 193 | lua_pushnumber(L, timeout_gettime()); 194 | return 1; 195 | } 196 | 197 | /*-------------------------------------------------------------------------*\ 198 | * Sleep for n seconds. 199 | \*-------------------------------------------------------------------------*/ 200 | #ifdef _WIN32 201 | int timeout_lua_sleep(lua_State *L) 202 | { 203 | double n = luaL_checknumber(L, 1); 204 | if (n < 0.0) n = 0.0; 205 | if (n < DBL_MAX/1000.0) n *= 1000.0; 206 | if (n > INT_MAX) n = INT_MAX; 207 | Sleep((int)n); 208 | return 0; 209 | } 210 | #else 211 | int timeout_lua_sleep(lua_State *L) 212 | { 213 | double n = luaL_checknumber(L, 1); 214 | struct timespec t, r; 215 | if (n < 0.0) n = 0.0; 216 | if (n > INT_MAX) n = INT_MAX; 217 | t.tv_sec = (int) n; 218 | n -= t.tv_sec; 219 | t.tv_nsec = (int) (n * 1000000000); 220 | if (t.tv_nsec >= 1000000000) t.tv_nsec = 999999999; 221 | while (nanosleep(&t, &r) != 0) { 222 | t.tv_sec = r.tv_sec; 223 | t.tv_nsec = r.tv_nsec; 224 | } 225 | return 0; 226 | } 227 | #endif 228 | -------------------------------------------------------------------------------- /Source/LibLuasocket/timeout.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMEOUT_H 2 | #define TIMEOUT_H 3 | /*=========================================================================*\ 4 | * Timeout management functions 5 | * LuaSocket toolkit 6 | \*=========================================================================*/ 7 | #include "lua.h" 8 | 9 | /* timeout control structure */ 10 | typedef struct t_timeout_ { 11 | double block; /* maximum time for blocking calls */ 12 | double total; /* total number of miliseconds for operation */ 13 | double start; /* time of start of operation */ 14 | } t_timeout; 15 | typedef t_timeout *p_timeout; 16 | 17 | int timeout_open(lua_State *L); 18 | void timeout_init(p_timeout tm, double block, double total); 19 | double timeout_get(p_timeout tm); 20 | double timeout_getretry(p_timeout tm); 21 | p_timeout timeout_markstart(p_timeout tm); 22 | double timeout_getstart(p_timeout tm); 23 | double timeout_gettime(void); 24 | int timeout_meth_settimeout(lua_State *L, p_timeout tm); 25 | int timeout_meth_gettimeout(lua_State *L, p_timeout tm); 26 | 27 | #define timeout_iszero(tm) ((tm)->block == 0.0) 28 | 29 | #endif /* TIMEOUT_H */ 30 | -------------------------------------------------------------------------------- /Source/LibLuasocket/tp.lua.inc: -------------------------------------------------------------------------------- 1 | R"[========]( 2 | ----------------------------------------------------------------------------- 3 | -- Unified SMTP/FTP subsystem 4 | -- LuaSocket toolkit. 5 | -- Author: Diego Nehab 6 | ----------------------------------------------------------------------------- 7 | 8 | ----------------------------------------------------------------------------- 9 | -- Declare module and import dependencies 10 | ----------------------------------------------------------------------------- 11 | local base = _G 12 | local string = require("string") 13 | local socket = require("socket") 14 | local ltn12 = require("ltn12") 15 | 16 | socket.tp = {} 17 | local _M = socket.tp 18 | 19 | ----------------------------------------------------------------------------- 20 | -- Program constants 21 | ----------------------------------------------------------------------------- 22 | _M.TIMEOUT = 60 23 | 24 | ----------------------------------------------------------------------------- 25 | -- Implementation 26 | ----------------------------------------------------------------------------- 27 | -- gets server reply (works for SMTP and FTP) 28 | local function get_reply(c) 29 | local code, current, sep 30 | local line, err = c:receive() 31 | local reply = line 32 | if err then return nil, err end 33 | code, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 34 | if not code then return nil, "invalid server reply" end 35 | if sep == "-" then -- reply is multiline 36 | repeat 37 | line, err = c:receive() 38 | if err then return nil, err end 39 | current, sep = socket.skip(2, string.find(line, "^(%d%d%d)(.?)")) 40 | reply = reply .. "\n" .. line 41 | -- reply ends with same code 42 | until code == current and sep == " " 43 | end 44 | return code, reply 45 | end 46 | 47 | -- metatable for sock object 48 | local metat = { __index = {} } 49 | 50 | function metat.__index:getpeername() 51 | return self.c:getpeername() 52 | end 53 | 54 | function metat.__index:getsockname() 55 | return self.c:getpeername() 56 | end 57 | 58 | function metat.__index:check(ok) 59 | local code, reply = get_reply(self.c) 60 | if not code then return nil, reply end 61 | if base.type(ok) ~= "function" then 62 | if base.type(ok) == "table" then 63 | for i, v in base.ipairs(ok) do 64 | if string.find(code, v) then 65 | return base.tonumber(code), reply 66 | end 67 | end 68 | return nil, reply 69 | else 70 | if string.find(code, ok) then return base.tonumber(code), reply 71 | else return nil, reply end 72 | end 73 | else return ok(base.tonumber(code), reply) end 74 | end 75 | 76 | function metat.__index:command(cmd, arg) 77 | cmd = string.upper(cmd) 78 | if arg then 79 | return self.c:send(cmd .. " " .. arg.. "\r\n") 80 | else 81 | return self.c:send(cmd .. "\r\n") 82 | end 83 | end 84 | 85 | function metat.__index:sink(snk, pat) 86 | local chunk, err = self.c:receive(pat) 87 | return snk(chunk, err) 88 | end 89 | 90 | function metat.__index:send(data) 91 | return self.c:send(data) 92 | end 93 | 94 | function metat.__index:receive(pat) 95 | return self.c:receive(pat) 96 | end 97 | 98 | function metat.__index:getfd() 99 | return self.c:getfd() 100 | end 101 | 102 | function metat.__index:dirty() 103 | return self.c:dirty() 104 | end 105 | 106 | function metat.__index:getcontrol() 107 | return self.c 108 | end 109 | 110 | function metat.__index:source(source, step) 111 | local sink = socket.sink("keep-open", self.c) 112 | local ret, err = ltn12.pump.all(source, sink, step or ltn12.pump.step) 113 | return ret, err 114 | end 115 | 116 | -- closes the underlying c 117 | function metat.__index:close() 118 | self.c:close() 119 | return 1 120 | end 121 | 122 | -- connect with server and return c object 123 | function _M.connect(host, port, timeout, create) 124 | local c, e = (create or socket.tcp)() 125 | if not c then return nil, e end 126 | c:settimeout(timeout or _M.TIMEOUT) 127 | local r, e = c:connect(host, port) 128 | if not r then 129 | c:close() 130 | return nil, e 131 | end 132 | return base.setmetatable({c = c}, metat) 133 | end 134 | 135 | return _M 136 | )[========]"; -------------------------------------------------------------------------------- /Source/LibLuasocket/udp.h: -------------------------------------------------------------------------------- 1 | #ifndef UDP_H 2 | #define UDP_H 3 | /*=========================================================================*\ 4 | * UDP object 5 | * LuaSocket toolkit 6 | * 7 | * The udp.h module provides LuaSocket with support for UDP protocol 8 | * (AF_INET, SOCK_DGRAM). 9 | * 10 | * Two classes are defined: connected and unconnected. UDP objects are 11 | * originally unconnected. They can be "connected" to a given address 12 | * with a call to the setpeername function. The same function can be used to 13 | * break the connection. 14 | \*=========================================================================*/ 15 | #include "lua.h" 16 | 17 | #include "timeout.h" 18 | #include "socket.h" 19 | 20 | #define UDP_DATAGRAMSIZE 8192 21 | 22 | typedef struct t_udp_ { 23 | t_socket sock; 24 | t_timeout tm; 25 | int family; 26 | } t_udp; 27 | typedef t_udp *p_udp; 28 | 29 | int udp_open(lua_State *L); 30 | 31 | #endif /* UDP_H */ 32 | -------------------------------------------------------------------------------- /Source/LibLuasocket/usocket.h: -------------------------------------------------------------------------------- 1 | #ifndef USOCKET_H 2 | #define USOCKET_H 3 | /*=========================================================================*\ 4 | * Socket compatibilization module for Unix 5 | * LuaSocket toolkit 6 | \*=========================================================================*/ 7 | 8 | /*=========================================================================*\ 9 | * BSD include files 10 | \*=========================================================================*/ 11 | 12 | #ifndef _WIN32 13 | 14 | /* error codes */ 15 | #include 16 | /* close function */ 17 | #include 18 | /* fnctnl function and associated constants */ 19 | #include 20 | /* struct sockaddr */ 21 | #include 22 | /* socket function */ 23 | #include 24 | /* struct timeval */ 25 | #include 26 | /* gethostbyname and gethostbyaddr functions */ 27 | #include 28 | /* sigpipe handling */ 29 | #include 30 | /* IP stuff*/ 31 | #include 32 | #include 33 | /* TCP options (nagle algorithm disable) */ 34 | #include 35 | #include 36 | 37 | #ifndef SO_REUSEPORT 38 | #define SO_REUSEPORT SO_REUSEADDR 39 | #endif 40 | 41 | /* Some platforms use IPV6_JOIN_GROUP instead if 42 | * IPV6_ADD_MEMBERSHIP. The semantics are same, though. */ 43 | #ifndef IPV6_ADD_MEMBERSHIP 44 | #ifdef IPV6_JOIN_GROUP 45 | #define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP 46 | #endif /* IPV6_JOIN_GROUP */ 47 | #endif /* !IPV6_ADD_MEMBERSHIP */ 48 | 49 | /* Same with IPV6_DROP_MEMBERSHIP / IPV6_LEAVE_GROUP. */ 50 | #ifndef IPV6_DROP_MEMBERSHIP 51 | #ifdef IPV6_LEAVE_GROUP 52 | #define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP 53 | #endif /* IPV6_LEAVE_GROUP */ 54 | #endif /* !IPV6_DROP_MEMBERSHIP */ 55 | 56 | typedef int t_socket; 57 | typedef t_socket *p_socket; 58 | typedef struct sockaddr_storage t_sockaddr_storage; 59 | 60 | #define SOCKET_INVALID (-1) 61 | 62 | #endif // _WIN32 63 | 64 | #endif /* USOCKET_H */ 65 | -------------------------------------------------------------------------------- /Source/LibLuasocket/wsocket.h: -------------------------------------------------------------------------------- 1 | #ifndef WSOCKET_H 2 | #define WSOCKET_H 3 | /*=========================================================================*\ 4 | * Socket compatibilization module for Win32 5 | * LuaSocket toolkit 6 | \*=========================================================================*/ 7 | 8 | /*=========================================================================*\ 9 | * WinSock include files 10 | \*=========================================================================*/ 11 | 12 | #ifdef _WIN32 13 | 14 | #include 15 | #include 16 | 17 | typedef int socklen_t; 18 | typedef SOCKADDR_STORAGE t_sockaddr_storage; 19 | typedef SOCKET t_socket; 20 | typedef t_socket *p_socket; 21 | 22 | #ifndef IPV6_V6ONLY 23 | #define IPV6_V6ONLY 27 24 | #endif 25 | 26 | #define SOCKET_INVALID (INVALID_SOCKET) 27 | 28 | #ifndef SO_REUSEPORT 29 | #define SO_REUSEPORT SO_REUSEADDR 30 | #endif 31 | 32 | #ifndef AI_NUMERICSERV 33 | #define AI_NUMERICSERV (0) 34 | #endif 35 | 36 | #endif // _WIN32 37 | 38 | #endif /* WSOCKET_H */ 39 | -------------------------------------------------------------------------------- /Source/LuaPanda/LuaPanda.Build.cs: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | using UnrealBuildTool; 4 | 5 | public class LuaPanda : ModuleRules 6 | { 7 | public LuaPanda(ReadOnlyTargetRules Target) : base(Target) 8 | { 9 | PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; 10 | 11 | PublicDependencyModuleNames.AddRange(new string[] { "Core" }); 12 | 13 | PrivateDependencyModuleNames.AddRange(new string[] { "Liblua" }); 14 | 15 | bEnableShadowVariableWarnings = false; 16 | bEnableUndefinedIdentifierWarnings = false; 17 | 18 | PublicDefinitions.Add("WITH_LUAPANDA=1"); 19 | PrivateDefinitions.Add("USE_SOURCE_CODE"); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Source/LuaPanda/LuaPanda.cpp: -------------------------------------------------------------------------------- 1 | // Fill out your copyright notice in the Description page of Project Settings. 2 | 3 | #include "LuaPanda.h" 4 | 5 | #include "lua.hpp" 6 | #include "libpdebug.h" 7 | 8 | IMPLEMENT_MODULE(FLuaPanda, LuaPanda); 9 | 10 | void FLuaPanda::StartupModule() 11 | { 12 | 13 | } 14 | 15 | void FLuaPanda::ShutdownModule() 16 | { 17 | 18 | } 19 | 20 | void FLuaPanda::SetupLuaPanda(struct lua_State* L) 21 | { 22 | pdebug_init(L); 23 | 24 | luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); 25 | 26 | lua_pushcfunction(L, &FLuaPanda::OpenLuaPanda); 27 | lua_setfield(L, -2, "LuaPanda"); 28 | 29 | lua_pushcfunction(L, &FLuaPanda::OpenDebugTools); 30 | lua_setfield(L, -2, "DebugTools"); 31 | 32 | lua_pop(L, 1); 33 | } 34 | 35 | int FLuaPanda::OpenLuaPanda(lua_State* L) 36 | { 37 | static const auto RawLua1 = 38 | #include "LuaPanda.1.lua.inc" 39 | 40 | static const auto RawLua2 = 41 | #include "LuaPanda.2.lua.inc" 42 | 43 | static const auto RawLua3 = 44 | #include "LuaPanda.3.lua.inc" 45 | 46 | static const auto RawLua4 = 47 | #include "LuaPanda.4.lua.inc" 48 | 49 | static const auto RawLua5 = 50 | #include "LuaPanda.5.lua.inc" 51 | 52 | static const int32 ContentSize = 100 * 1024; 53 | static ANSICHAR LuaContent[ContentSize] = { 0 }; 54 | if (LuaContent[0] == 0) 55 | { 56 | FCStringAnsi::Snprintf(LuaContent, ContentSize, "%s%s%s%s%s", RawLua1, RawLua2, RawLua3, RawLua4, RawLua5); 57 | } 58 | 59 | luaL_dostring(L, LuaContent); 60 | return 1; 61 | } 62 | 63 | int FLuaPanda::OpenDebugTools(lua_State* L) 64 | { 65 | static const auto RawLua = 66 | #include "DebugTools.lua.inc" 67 | 68 | luaL_dostring(L, RawLua); 69 | return 1; 70 | } 71 | -------------------------------------------------------------------------------- /Source/LuaPanda/LuaPanda.h: -------------------------------------------------------------------------------- 1 | // Copyright 1998-2018 Epic Games, Inc. All Rights Reserved. 2 | 3 | #pragma once 4 | 5 | #include "CoreMinimal.h" 6 | #include "Modules/ModuleManager.h" 7 | 8 | struct lua_State; 9 | 10 | class LUAPANDA_API FLuaPanda : public IModuleInterface 11 | { 12 | public: 13 | 14 | /** IModuleInterface implementation */ 15 | virtual void StartupModule() override; 16 | virtual void ShutdownModule() override; 17 | 18 | void SetupLuaPanda(lua_State* L); 19 | 20 | static inline FLuaPanda& Get() 21 | { 22 | return FModuleManager::LoadModuleChecked("LuaPanda"); 23 | } 24 | 25 | static inline bool IsAvailable() 26 | { 27 | return FModuleManager::Get().IsModuleLoaded("LuaPanda"); 28 | } 29 | 30 | protected: 31 | static int OpenLuaPanda(lua_State* L); 32 | static int OpenDebugTools(lua_State* L); 33 | }; 34 | -------------------------------------------------------------------------------- /Source/LuaPanda/libpdebug.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBPDEBUG_H 2 | #define LIBPDEBUG_H 3 | 4 | //1.使用源码编译,要打开宏USE_SOURCE_CODE. win下要设置LUA_INTEGER和lua版本号 5 | #define LUA_DEBUGGER_NAME "LuaPanda" //debugger's name in LuaDebug.lua 6 | #define HOOK_LIB_VERSION "1.9.15" //lib version 7 | //#define USE_SOURCE_CODE //using source code to build 8 | #if !defined(USE_SOURCE_CODE) && defined(_WIN32) 9 | #define LUA_INTEGER long long //set LUA_INTEGER. In 501 is ptrdiff_t. 503 can set longlong(64bit) or int(32bit) 10 | #define LUA_VERSION_NUM 503 //lua version used by WIN32 build lib. eg. 501,503 11 | #endif 12 | //setting end 13 | 14 | #if !defined(USE_SOURCE_CODE) && defined(_WIN32) 15 | #include 16 | #include 17 | #else 18 | //2.如果lua源码是C++形式,注释掉下面extern "C" 19 | extern "C"{ 20 | #include "lua.h" 21 | #include "lualib.h" 22 | #include "lauxlib.h" 23 | #include "luaconf.h" 24 | } 25 | #endif 26 | 27 | //3.如果lua代码在命名空间中,要设置用户命名空间. 防止找不到lua方法 28 | //using namespace slua; 29 | 30 | #ifdef USE_SOURCE_CODE 31 | extern "C" void pdebug_init(lua_State* L); 32 | #endif 33 | 34 | #if !defined(USE_SOURCE_CODE) && defined(_WIN32) 35 | /* 36 | ** Lua - An Extensible Extension Language 37 | ** Lua.org, PUC-Rio, Brazil (http://www.lua.org) 38 | ** See Copyright Notice at the end of this file 39 | */ 40 | #if LUA_VERSION_NUM == 501 41 | #define lua_getglobal(L,s) lua_getfield(L, LUA_GLOBALSINDEX, (s)) 42 | #endif 43 | 44 | #define LUA_TNONE (-1) 45 | #define LUA_TNIL 0 46 | #define LUA_TBOOLEAN 1 47 | #define LUA_TLIGHTUSERDATA 2 48 | #define LUA_TNUMBER 3 49 | #define LUA_TSTRING 4 50 | #define LUA_TTABLE 5 51 | #define LUA_TFUNCTION 6 52 | #define LUA_TUSERDATA 7 53 | #define LUA_TTHREAD 8 54 | #define LUA_NUMBER double 55 | #define LUA_REGISTRYINDEX (-10000) 56 | #define LUA_ENVIRONINDEX (-10001) 57 | #define LUA_GLOBALSINDEX (-10002) 58 | #define lua_upvalueindex(i) (LUA_GLOBALSINDEX-(i)) 59 | #define LUA_IDSIZE 60 60 | #define LUA_HOOKCALL 0 61 | #define LUA_HOOKRET 1 62 | #define LUA_HOOKLINE 2 63 | #define LUA_HOOKCOUNT 3 64 | #define LUA_HOOKTAILRET 4 65 | #define LUA_MASKCALL (1 << LUA_HOOKCALL) 66 | #define LUA_MASKRET (1 << LUA_HOOKRET) 67 | #define LUA_MASKLINE (1 << LUA_HOOKLINE) 68 | #define LUA_MASKCOUNT (1 << LUA_HOOKCOUNT) 69 | #define luaL_checkstring(L,n) (luaL_checklstring(L, (n), NULL)) 70 | #define lua_tostring(L,i) lua_tolstring(L, (i), NULL) 71 | #define lua_istable(L,n) (lua_type(L, (n)) == LUA_TTABLE) 72 | #define lua_isfunction(L,n) (lua_type(L, (n)) == LUA_TFUNCTION) 73 | #define lua_pop(L,n) lua_settop(L, -(n)-1) 74 | #define lua_newtable(L) lua_createtable(L, 0, 0) 75 | 76 | struct lua_State; 77 | struct lua_Debug { 78 | int event; 79 | const char *name; /* (n) */ 80 | const char *namewhat; /* (n) `global', `local', `field', `method' */ 81 | const char *what; /* (S) `Lua', `C', `main', `tail' */ 82 | const char *source; /* (S) */ 83 | int currentline; /* (l) */ 84 | int nups; /* (u) number of upvalues */ 85 | int linedefined; /* (S) */ 86 | int lastlinedefined; /* (S) */ 87 | char short_src[LUA_IDSIZE]; /* (S) */ 88 | /* private part */ 89 | int i_ci; /* active function */ 90 | }; 91 | 92 | typedef LUA_INTEGER lua_Integer; 93 | typedef LUA_NUMBER lua_Number; 94 | typedef int (*lua_CFunction) (lua_State *L); 95 | typedef struct luaL_Reg { 96 | const char *name; 97 | lua_CFunction func; 98 | } luaL_Reg; 99 | 100 | #define LUA_KCONTEXT ptrdiff_t 101 | typedef LUA_KCONTEXT lua_KContext; 102 | 103 | //lua function 104 | typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar); 105 | typedef int (*lua_KFunction) (lua_State *L, int status, lua_KContext ctx); 106 | typedef const lua_Number *(*luaDLL_version)(lua_State *L); 107 | typedef void (*luaLDLL_register)(lua_State *L, const char *libname, const luaL_Reg *l); 108 | typedef int (*luaDLL_gettop)(lua_State *L); 109 | typedef const char *(*luaDLL_pushstring)(lua_State *L, const char *s); 110 | typedef int (*luaDLL_settop)(lua_State *L, int idx); 111 | typedef int (*luaDLL_tointeger)(lua_State *L, int idx); 112 | typedef int (*luaDLL_next)(lua_State *L, int idx); 113 | typedef int (*luaDLL_pcall)(lua_State *L, int nargs, int nresults, int errfunc); 114 | typedef void (*luaDLL_pushnil)(lua_State *L); 115 | typedef void (*luaDLL_getfield)(lua_State *L, int idx, const char *k); 116 | typedef int (*luaDLL_getinfo)(lua_State *L, const char *what, void *ar); 117 | typedef void (*luaDLL_pushinteger) (lua_State *L, lua_Integer n); 118 | #if LUA_VERSION_NUM == 501 119 | typedef int(*luaDLL_sethook)(lua_State *L, void* func, int mask, int count); 120 | #else 121 | typedef void (*luaDLL_sethook)(lua_State *L, lua_Hook f, int mask, int count); 122 | #endif 123 | typedef void (*luaDLL_pushnumber)(lua_State *L, lua_Number n); 124 | typedef lua_Number (*luaDLL_checknumber)(lua_State *L, int narg); 125 | typedef const char *(*luaDLL_checklstring)(lua_State *L, int narg, size_t *len); 126 | typedef const char *(*luaDLL_tolstring)(lua_State *L, int idx, size_t *len); 127 | typedef int (*luaDLL_type)(lua_State *L, int idx); 128 | //5.3 129 | typedef void (*luaDLL_createtable)(lua_State *L, int narray, int nrec); 130 | typedef void (*luaDLL_setfuncs)(lua_State *L, const luaL_Reg *l, int nup); 131 | typedef lua_Integer(*luaDLL_tointegerx)(lua_State *L, int idx, int *pisnum); 132 | typedef int (*luaDLL_getglobal)(lua_State *L, const char *name); 133 | typedef int (*luaDLL_pcallk)(lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k); 134 | 135 | luaDLL_version lua_version; 136 | luaDLL_gettop lua_gettop; 137 | luaDLL_pushstring lua_pushstring; 138 | luaLDLL_register luaL_register; 139 | luaDLL_settop lua_settop; 140 | luaDLL_pcall lua_pcall; 141 | luaDLL_pushnumber lua_pushnumber; 142 | luaDLL_checklstring luaL_checklstring; 143 | luaDLL_tointeger lua_tointeger; 144 | luaDLL_pushnil lua_pushnil; 145 | luaDLL_getfield lua_getfield; 146 | luaDLL_next lua_next; 147 | luaDLL_getinfo lua_getinfo; 148 | luaDLL_sethook lua_sethook; 149 | luaDLL_checknumber luaL_checknumber; 150 | luaDLL_type lua_type; 151 | luaDLL_tolstring lua_tolstring; 152 | luaDLL_pushinteger lua_pushinteger; 153 | // 154 | HMODULE hInstLibrary; 155 | 156 | //slua-ue header 157 | #if LUA_VERSION_NUM > 501 158 | //5.3 159 | luaDLL_createtable lua_createtable; 160 | luaDLL_setfuncs luaL_setfuncs; 161 | luaDLL_tointegerx lua_tointegerx; 162 | luaDLL_getglobal lua_getglobal; 163 | luaDLL_pcallk lua_pcallk; 164 | #define lua_pcall(L,n,r,f) lua_pcallk(L, (n), (r), (f), 0, NULL) 165 | #define lua_tointeger(L,i) lua_tointegerx(L,(i),NULL); 166 | 167 | #define PURE_API =0 168 | namespace slua { 169 | struct LuaInterface { 170 | virtual const lua_Number *lua_version(lua_State *L) PURE_API; 171 | virtual const char *lua_pushstring(lua_State *L, const char *s) PURE_API; 172 | virtual int lua_gettop(lua_State *L) PURE_API; 173 | virtual void lua_settop(lua_State *L, int index) PURE_API; 174 | virtual int lua_pcallk(lua_State *L, int nargs, int nresults, int msgh, lua_KContext ctx, lua_KFunction k) PURE_API; 175 | virtual void lua_pushnumber(lua_State *L, lua_Number n) PURE_API; 176 | virtual const char *luaL_checklstring(lua_State *L, int arg, size_t *l) PURE_API; 177 | virtual const char *lua_tolstring(lua_State *L, int index, size_t *len) PURE_API; 178 | virtual int lua_type(lua_State *L, int index) PURE_API; 179 | virtual lua_Integer lua_tointegerx(lua_State *L, int index, int *isnum) PURE_API; 180 | virtual void lua_pushnil(lua_State *L) PURE_API; 181 | virtual int lua_getfield(lua_State *L, int index, const char *k) PURE_API; 182 | virtual int lua_next(lua_State *L, int index) PURE_API; 183 | virtual int lua_getinfo(lua_State *L, const char *what, lua_Debug *ar) PURE_API; 184 | virtual void lua_sethook(lua_State *L, lua_Hook f, int mask, int count) PURE_API; 185 | virtual lua_Number luaL_checknumber(lua_State *L, int arg) PURE_API; 186 | virtual void lua_createtable(lua_State *L, int narr, int nrec) PURE_API; 187 | virtual void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup) PURE_API; 188 | virtual int lua_getglobal(lua_State *L, const char *name) PURE_API; 189 | }; 190 | } 191 | typedef slua::LuaInterface* (*dll_GetLuaInterface)(); 192 | dll_GetLuaInterface getInter; 193 | #endif //LUA_VERSION_NUM > 501 194 | #endif //_WIN32 195 | #endif //LIBPDEBUG_H 196 | /****************************************************************************** 197 | * Copyright (C) 1994-2008 Lua.org, PUC-Rio. All rights reserved. 198 | * 199 | * Permission is hereby granted, free of charge, to any person obtaining 200 | * a copy of this software and associated documentation files (the 201 | * "Software"), to deal in the Software without restriction, including 202 | * without limitation the rights to use, copy, modify, merge, publish, 203 | * distribute, sublicense, and/or sell copies of the Software, and to 204 | * permit persons to whom the Software is furnished to do so, subject to 205 | * the following conditions: 206 | * 207 | * The above copyright notice and this permission notice shall be 208 | * included in all copies or substantial portions of the Software. 209 | * 210 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 211 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 212 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 213 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 214 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 215 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 216 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 217 | ******************************************************************************/ 218 | --------------------------------------------------------------------------------