diff --git a/SlipeServer.Console/Program.cs b/SlipeServer.Console/Program.cs index 7d2036c9..f9d87e97 100644 --- a/SlipeServer.Console/Program.cs +++ b/SlipeServer.Console/Program.cs @@ -22,6 +22,7 @@ using System.IO; using System.Threading; using SlipeServer.Example; +using SlipeServer.Scripting.Luau; namespace SlipeServer.Console; @@ -108,6 +109,7 @@ public Program(string[] args) }); builder.AddLua(); + builder.AddLuauTranspiler(); builder.AddPhysics(); builder.AddParachuteResource(); builder.AddLuaControllers(); diff --git a/SlipeServer.Console/test.lua b/SlipeServer.Console/test.lua index 92ea066e..54472bef 100644 --- a/SlipeServer.Console/test.lua +++ b/SlipeServer.Console/test.lua @@ -1,4 +1,10 @@ -if(isSlipeServer)then +type Point = { x: number, y: number } + +local p: Point = { x = 1, y = 2 } + +print("Point with luau:", p.x, p.y); + +if(isSlipeServer)then local object = createObject(321, 5, 5, 5) setElementPosition(object, 50, 50, 250) setElementRotation(object, 180, 180, 90) diff --git a/SlipeServer.Example/SlipeServer.Example.csproj b/SlipeServer.Example/SlipeServer.Example.csproj index ad69586e..d78e26fa 100644 --- a/SlipeServer.Example/SlipeServer.Example.csproj +++ b/SlipeServer.Example/SlipeServer.Example.csproj @@ -10,6 +10,7 @@ + diff --git a/SlipeServer.Lua/LuaService.cs b/SlipeServer.Lua/LuaService.cs index 10e0f464..c5b28b5c 100644 --- a/SlipeServer.Lua/LuaService.cs +++ b/SlipeServer.Lua/LuaService.cs @@ -18,15 +18,17 @@ public class LuaService private readonly MtaServer server; private readonly ILogger logger; private readonly RootElement root; + private readonly ScriptTransformationPipeline scriptTransformationPipeline; private readonly Dictionary scripts = []; private readonly Dictionary methods = []; private readonly LuaTranslator translator = new(); - public LuaService(MtaServer server, ILogger logger, RootElement root) + public LuaService(MtaServer server, ILogger logger, RootElement root, ScriptTransformationPipeline scriptTransformationPipeline) { this.server = server; this.logger = logger; this.root = root; + this.scriptTransformationPipeline = scriptTransformationPipeline; } public void LoadDefinitions(object methodSet) @@ -132,7 +134,10 @@ public void LoadScript(string identifier, string code) LoadGlobals(script); LoadDefinitions(script); - script.DoString(code, codeFriendlyName: identifier); + using var ms = new MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(code)); + var stream = this.scriptTransformationPipeline.Transform(ms, "lua"); + + script.DoStream(stream, codeFriendlyName: identifier); } public void LoadScript(string identifier, string[] codes) diff --git a/SlipeServer.Lua/LuaServiceCollectionExtensions.cs b/SlipeServer.Lua/LuaServiceCollectionExtensions.cs index 9defe844..bf4cce3d 100644 --- a/SlipeServer.Lua/LuaServiceCollectionExtensions.cs +++ b/SlipeServer.Lua/LuaServiceCollectionExtensions.cs @@ -7,14 +7,13 @@ public static class LuaServiceCollectionExtensions { public static void AddLua(this IServiceCollection services) { - services.AddSingleton(); - services.AddSingleton(); + services.AddScripting(); services.AddSingleton(); } public static void AddLua(this IServiceCollection services) where T : class, IScriptEventRuntime { - services.AddSingleton(); + services.AddScripting(); services.AddSingleton(); } } diff --git a/SlipeServer.Luau/LuauToLuaTransform.cs b/SlipeServer.Luau/LuauToLuaTransform.cs new file mode 100644 index 00000000..8e79ac28 --- /dev/null +++ b/SlipeServer.Luau/LuauToLuaTransform.cs @@ -0,0 +1,42 @@ +using System.Text; +using Loretta.CodeAnalysis; +using Loretta.CodeAnalysis.Lua; +using Loretta.CodeAnalysis.Lua.Syntax; +using Loretta.CodeAnalysis.Text; + +namespace SlipeServer.Scripting.Luau; + +internal sealed class LuauToLuaTransform : IScriptTransform +{ + public Stream Transform(Stream data, string lang) + { + if (lang != "lua") + return data; + + SourceText sourceText = SourceText.From(data, Encoding.UTF8); + + var syntaxTree = LuaSyntaxTree.ParseText(sourceText, options: new LuaParseOptions(LuaSyntaxOptions.Luau), path: "script.lua"); + + var root = syntaxTree.GetRoot(); + + var rewriter = new TypeAnnotationRemover(); + var strippedRoot = rewriter.Visit(root); + + var outData = new MemoryStream(); + var writer = new StreamWriter(outData); + strippedRoot.WriteTo(writer); + writer.Flush(); + return outData; + } + + class TypeAnnotationRemover : LuaSyntaxRewriter + { + public override SyntaxNode? Visit(SyntaxNode? node) + { + if (node is TypeDeclarationStatementSyntax or TypeBindingSyntax) + return null; + + return base.Visit(node); + } + } +} diff --git a/SlipeServer.Luau/ServerBuilderExtensions.cs b/SlipeServer.Luau/ServerBuilderExtensions.cs new file mode 100644 index 00000000..7e79d431 --- /dev/null +++ b/SlipeServer.Luau/ServerBuilderExtensions.cs @@ -0,0 +1,16 @@ +using SlipeServer.Server.ServerBuilders; + +namespace SlipeServer.Scripting.Luau; + +public static class ServerBuilderExtensions +{ + public static ServerBuilder AddLuauTranspiler(this ServerBuilder builder) + { + builder.ConfigureServices(services => + { + services.AddLuauTranspiler(); + }); + + return builder; + } +} diff --git a/SlipeServer.Luau/ServiceCollectionExtensions.cs b/SlipeServer.Luau/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..4ae4946c --- /dev/null +++ b/SlipeServer.Luau/ServiceCollectionExtensions.cs @@ -0,0 +1,12 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace SlipeServer.Scripting.Luau; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddLuauTranspiler(this IServiceCollection services) + { + services.AddSingleton(); + return services; + } +} diff --git a/SlipeServer.Luau/SlipeServer.Luau.csproj b/SlipeServer.Luau/SlipeServer.Luau.csproj new file mode 100644 index 00000000..3b9e7e84 --- /dev/null +++ b/SlipeServer.Luau/SlipeServer.Luau.csproj @@ -0,0 +1,19 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + diff --git a/SlipeServer.Scripting/ScriptTransformationPipeline.cs b/SlipeServer.Scripting/ScriptTransformationPipeline.cs new file mode 100644 index 00000000..95729a04 --- /dev/null +++ b/SlipeServer.Scripting/ScriptTransformationPipeline.cs @@ -0,0 +1,39 @@ +using System.Collections.Generic; +using System.IO; +using System.Linq; + +namespace SlipeServer.Scripting; + +public interface IScriptTransform +{ + Stream Transform(Stream data, string lang); +} + +public sealed class ScriptTransformationPipeline +{ + private readonly List scriptTransforms; + + public ScriptTransformationPipeline(IEnumerable scriptTransforms) + { + this.scriptTransforms = scriptTransforms.ToList(); + } + + public void Add(IScriptTransform scriptTransform) + { + this.scriptTransforms.Add(scriptTransform); + } + + public Stream Transform(Stream data, string lang) + { + var transformedData = data; + + foreach (var transformation in this.scriptTransforms) + { + transformedData = transformation.Transform(transformedData, lang); + transformedData.Position = 0; + } + + return transformedData; + + } +} diff --git a/SlipeServer.Scripting/ServiceCollectionExtensions.cs b/SlipeServer.Scripting/ServiceCollectionExtensions.cs new file mode 100644 index 00000000..a3987d9d --- /dev/null +++ b/SlipeServer.Scripting/ServiceCollectionExtensions.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; + +namespace SlipeServer.Scripting; + +public static class ServiceCollectionExtensions +{ + public static void AddScripting(this IServiceCollection services) + { + services.TryAddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + } + + public static void AddScripting(this IServiceCollection services) where T : class, IScriptEventRuntime + { + services.TryAddSingleton(); + services.AddSingleton(); + } +} diff --git a/SlipeServer.sln b/SlipeServer.sln index 7b55d3ae..0caf2ff6 100644 --- a/SlipeServer.sln +++ b/SlipeServer.sln @@ -58,7 +58,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SlipeServer.Hosting", "Slip EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SlipeServer.WebHostBuilderExample", "SlipeServer.WebHostBuilderExample\SlipeServer.WebHostBuilderExample.csproj", "{ED9BDF71-BEDA-4C55-B6FA-360B3A5259E8}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SlipeServer.Example", "SlipeServer.Example\SlipeServer.Example.csproj", "{E11F25F8-8DBD-412C-9504-B42CA8083D96}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SlipeServer.Example", "SlipeServer.Example\SlipeServer.Example.csproj", "{E11F25F8-8DBD-412C-9504-B42CA8083D96}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SlipeServer.Luau", "SlipeServer.Luau\SlipeServer.Luau.csproj", "{882D841E-E5E8-4876-BB19-05B58C4B3AE8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -450,6 +452,26 @@ Global {E11F25F8-8DBD-412C-9504-B42CA8083D96}.Release|x64.Build.0 = Release|Any CPU {E11F25F8-8DBD-412C-9504-B42CA8083D96}.Release|x86.ActiveCfg = Release|Any CPU {E11F25F8-8DBD-412C-9504-B42CA8083D96}.Release|x86.Build.0 = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|ARM32.ActiveCfg = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|ARM32.Build.0 = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|ARM64.ActiveCfg = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|ARM64.Build.0 = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|x64.ActiveCfg = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|x64.Build.0 = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|x86.ActiveCfg = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Debug|x86.Build.0 = Debug|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|Any CPU.Build.0 = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|ARM32.ActiveCfg = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|ARM32.Build.0 = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|ARM64.ActiveCfg = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|ARM64.Build.0 = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|x64.ActiveCfg = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|x64.Build.0 = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|x86.ActiveCfg = Release|Any CPU + {882D841E-E5E8-4876-BB19-05B58C4B3AE8}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -479,6 +501,7 @@ Global {DB94A24C-3B3C-4C12-8B87-55F6503960E7} = {7287CD6F-078B-470F-B508-74A442D98B64} {ED9BDF71-BEDA-4C55-B6FA-360B3A5259E8} = {9A8750C3-0CC3-411D-A234-7869E2D54ECD} {E11F25F8-8DBD-412C-9504-B42CA8083D96} = {9A8750C3-0CC3-411D-A234-7869E2D54ECD} + {882D841E-E5E8-4876-BB19-05B58C4B3AE8} = {DEAEE2A1-118A-4ED7-8CC5-7C446ED97AE3} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E5DA52B5-6C04-4C6F-B5E3-3A7441C58986}