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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
using SlipeServer.Server.ServerBuilders;

namespace SlipeServer.Console.AdditionalResources;
public static class ServerBuilderExtensions
public static partial class ServerBuilderExtensions
{
public static void AddParachuteResource(this ServerBuilder builder)
{
Expand Down
15 changes: 8 additions & 7 deletions SlipeServer.Console/Logic/LuaTestLogic.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,24 @@ ILogger logger
this.eventRuntime = eventRuntime;
this.luaService = luaService;
this.logger = logger;
commandService.AddCommand("lua").Triggered += (source, args) => Init();
//commandService.AddCommand("lua").Triggered += (source, args) => Init();
Init();
}

private void Init()
{
this.eventRuntime.LoadDefaultEvents();

this.luaService.LoadDefaultDefinitions();

this.luaService.LoadDefinitions<CustomMathDefinition>();
this.luaService.LoadDefinitions<TestDefinition>();

using FileStream testLua = File.OpenRead("test.lua");
using StreamReader reader = new StreamReader(testLua);
try
{
this.luaService.LoadScript("test.lua", reader.ReadToEnd());
Script createdScript = this.luaService.LoadScript("test.lua", reader.ReadToEnd());

this.luaService.LoadDefaultDefinitions(createdScript);
this.luaService.LoadDefinitions<CustomMathDefinition>(createdScript);
this.luaService.LoadDefinitions<TestDefinition>(createdScript);

}
catch (InterpreterException ex)
{
Expand Down
1 change: 1 addition & 0 deletions SlipeServer.Console/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using SlipeServer.Server;
using SlipeServer.Server.Loggers;
using SlipeServer.Server.PacketHandling.Handlers.Middleware;
using SlipeServer.Server.Resources.Providers;
using SlipeServer.Server.ServerBuilders;
using System;
using System.Threading;
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
outputChatBox("I am a second resource")
outputChatBox("This is the second resource")
17 changes: 16 additions & 1 deletion SlipeServer.Console/test.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
if(isSlipeServer)then

iprint("This is a message on server printed using iprint", "This is the second Argument from iprint")

local customElement = createElement("MyCustomType")
iprint("Custom Element ", customElement)

--setElementData(customElement, "dummyKey", "dummyValue")

--local elementData = getElementData(customElement, "dummyKey")

--iprint("Element Data Is ", elementData)

local object = createObject(321, 5, 5, 5)
setElementPosition(object, 50, 50, 250)
setElementRotation(object, 180, 180, 90)
Expand All @@ -20,6 +32,8 @@

outputDebugString("Debug message, elapsed time: "..getTickCount())

print("iprint is ", iprint)

print("base64 test:", base64Encode("sample text"), base64Decode(base64Encode("sample text")))
print("Some color: ", tocolor(235,23,77,159), tocolor(235,23,77,159) == -1611983027)
print("getColorFromString: ", getColorFromString("#ff0000"));
Expand Down Expand Up @@ -81,4 +95,5 @@ addCommandHandler("foo3", commandHandler3)
addCommandHandler("foo4", commandHandler2)
addCommandHandler("foo4", commandHandler3)
removeCommandHandler("foo3", commandHandler2)
removeCommandHandler("foo4")
removeCommandHandler("foo4")

48 changes: 29 additions & 19 deletions SlipeServer.Lua/LuaService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public class LuaService
private readonly ILogger logger;
private readonly RootElement root;
private readonly Dictionary<string, Script> scripts;
private readonly Dictionary<string, LuaMethod> methods;
private readonly Dictionary<Script, Dictionary<string, LuaMethod>> methods;
private readonly LuaTranslator translator;

public LuaService(MtaServer server, ILogger logger, RootElement root)
Expand All @@ -28,23 +28,24 @@ public LuaService(MtaServer server, ILogger logger, RootElement root)
this.logger = logger;
this.root = root;
this.scripts = new Dictionary<string, Script>();
this.methods = new Dictionary<string, LuaMethod>();
this.methods = new Dictionary<Script, Dictionary<string, LuaMethod>>();
this.translator = new LuaTranslator();
}

public void LoadDefinitions(object methodSet)
public void LoadDefinitions(object methodSet, Script owner)
{
foreach (var method in methodSet.GetType().GetMethods()
.Where(method => method.CustomAttributes
.Any(attribute => attribute.AttributeType == typeof(ScriptFunctionDefinitionAttribute))))
{
var attribute = method.GetCustomAttribute<ScriptFunctionDefinitionAttribute>();

if (this.methods.ContainsKey(attribute!.NiceName))
if (methods.TryGetValue(owner, out Dictionary<string, LuaMethod>? _) && this.methods[owner].ContainsKey(attribute!.NiceName))
throw new Exception($"Lua name conflict for '{attribute.NiceName}'");

var methodParameters = method.GetParameters();
this.methods[attribute.NiceName] = (values) =>
this.methods.TryAdd(owner, new Dictionary<string, LuaMethod>());
this.methods[owner][attribute.NiceName] = (values) =>
{
var valueQueue = new Queue<DynValue>(values.AsEnumerable());

Expand All @@ -55,7 +56,7 @@ public void LoadDefinitions(object methodSet)
{
if (valueQueue.Any())
{
parameters[i] = this.translator.FromDynValue(methodParameters[i].ParameterType, valueQueue);
parameters[i] = this.translator.FromDynValue(methodParameters[i].ParameterType, valueQueue, owner);
} else
{
if (!methodParameters[i].IsOptional)
Expand All @@ -74,40 +75,43 @@ public void LoadDefinitions(object methodSet)
}
var result = method.Invoke(methodSet, parameters);

return this.translator.ToDynValues(result).ToArray();
return this.translator.ToDynValues(result, owner).ToArray();
};
}
}

public void LoadDefinitions<T>()
public void LoadDefinitions<T>(Script script)
{
LoadDefinitions(this.server.Instantiate<T>()!);
LoadDefinitions(this.server.Instantiate<T>()!, script);
}

public void LoadDefaultDefinitions()
public void LoadDefaultDefinitions(Script script)
{
foreach (var type in typeof(ScriptFunctionDefinitionAttribute).Assembly.DefinedTypes
.Where(type => type.GetMethods()
.Any(method => method.CustomAttributes
.Any(attribute => attribute.AttributeType == typeof(ScriptFunctionDefinitionAttribute)))))
{
LoadDefinitions(this.server.Instantiate(type));
LoadDefinitions(this.server.Instantiate(type), script);
}
}

public void LoadScript(string identifier, string code)
public Script LoadScript(string identifier, string code)
{
var script = new Script(CoreModules.Preset_SoftSandbox);
script.Options.DebugPrint = (value) => this.logger.LogInformation(value);
this.scripts[identifier] = script;

LoadGlobals(script);
LoadDefaultDefinitions(script);
LoadDefinitions(script);

script.DoString(code, codeFriendlyName: identifier);

return script;
}

public void LoadScript(string identifier, string[] codes)
public Script LoadScript(string identifier, string[] codes)
{
var script = new Script(CoreModules.Preset_SoftSandbox);
script.Options.DebugPrint = (value) =>
Expand All @@ -118,18 +122,22 @@ public void LoadScript(string identifier, string[] codes)
this.scripts[identifier] = script;

LoadGlobals(script);
LoadDefaultDefinitions(script);
LoadDefinitions(script);

foreach (var code in codes)
script.DoString(code, codeFriendlyName: identifier);

return script;
}

public async Task LoadScriptFromPath(string path) => LoadScript(path, await File.ReadAllTextAsync(path));
public async Task LoadScriptFromPaths(string identifier, string[] paths)
public async Task<Script> LoadScriptFromPath(string path) => LoadScript(path, await File.ReadAllTextAsync(path));
public async Task<Script> LoadScriptFromPaths(string identifier, string[] paths)
{
var codeTasks = paths.Select(path => File.ReadAllTextAsync(path));
await Task.WhenAll(codeTasks);
LoadScript(identifier, codeTasks.Select(task => task.Result).ToArray());
var script = LoadScript(identifier, codeTasks.Select(task => task.Result).ToArray());
return script;
}

public void UnloadScript(string identifier)
Expand All @@ -140,18 +148,20 @@ public void UnloadScript(string identifier)
private void LoadDefinitions(Script script)
{
StringBuilder stringBuilder = new StringBuilder();
foreach (var definition in this.methods)
foreach (var definition in this.methods[script])
{
script.Globals["real" + definition.Key] = definition.Value;
stringBuilder.AppendLine($"function {definition.Key}(...) return table.unpack(real{definition.Key}({{...}})) end");
}
//LoadDefaultDefinitions(script);

script.DoString(stringBuilder.ToString(), codeFriendlyName: "SlipeDefinitions");
}

private void LoadGlobals(Script script)
{
script.Globals["root"] = this.translator.ToDynValues(this.root).First();
script.Globals["isSlipeServer"] = this.translator.ToDynValues(true).First();
script.Globals["root"] = this.translator.ToDynValues(this.root, script).First();
script.Globals["isSlipeServer"] = this.translator.ToDynValues(true, script).First();
}

public delegate DynValue[] LuaMethod(params DynValue[] values);
Expand Down
47 changes: 41 additions & 6 deletions SlipeServer.Lua/LuaTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public LuaTranslator()
UserData.RegisterType<Element>(InteropAccessMode.Hardwired);
}

public IEnumerable<DynValue> ToDynValues(object? obj)
public IEnumerable<DynValue> ToDynValues(object? obj, Script owner)
{
if (obj == null)
return new DynValue[] { DynValue.Nil };
Expand Down Expand Up @@ -66,7 +66,7 @@ public IEnumerable<DynValue> ToDynValues(object? obj)
DynValue.NewNumber(vector3.Z)
};
if (obj is Delegate del)
return new DynValue[] { DynValue.NewCallback((context, arguments) => ToDynValues(del.DynamicInvoke(arguments.GetArray())!).First()) };
return new DynValue[] { DynValue.NewCallback((context, arguments) => ToDynValues(del.DynamicInvoke(arguments.GetArray())!, owner).First()) };
if (obj is Table table)
return new DynValue[] { DynValue.NewTable(table) };
if (obj is DynValue dynValue)
Expand All @@ -75,7 +75,8 @@ public IEnumerable<DynValue> ToDynValues(object? obj)
if (obj is IEnumerable<string> stringEnumerable)
return stringEnumerable.Select(x => DynValue.NewString(x)).ToArray();
if (obj is IEnumerable<object> enumerable)
return enumerable.Select(x => ToDynValues(x)).SelectMany(x => x).ToArray();
return enumerable.Select(x => ToDynValues(x, owner)).SelectMany(x => x).ToArray();


throw new NotImplementedException($"Conversion to Lua for {obj.GetType()} not implemented");
}
Expand All @@ -93,7 +94,7 @@ public IEnumerable<DynValue> ToDynValues(object? obj)
public bool GetBooleanFromDynValue(DynValue dynValue) => dynValue.Boolean;
public Table GetTableFromDynValue(DynValue dynValue) => dynValue.Table;

public object FromDynValue(Type targetType, Queue<DynValue> dynValues)
public object FromDynValue(Type targetType, Queue<DynValue> dynValues, Script owner)
{
if (targetType == typeof(Color) || targetType == typeof(Color?))
{
Expand Down Expand Up @@ -133,17 +134,51 @@ public object FromDynValue(Type targetType, Queue<DynValue> dynValues)
return GetTableFromDynValue(dynValues.Dequeue());
if (typeof(Element).IsAssignableFrom(targetType))
return dynValues.Dequeue().UserData.Object;
if (targetType == typeof(IEnumerable<string>))
{
List<string> args = new List<string> { };

foreach (DynValue arg in dynValues)
{
args.Add(GetStringFromDynValue(arg));
}
return args;
}
if (targetType == typeof(IEnumerable<object>))
{
List<object> args = new List<object>();

foreach (DynValue arg in dynValues)
{
switch (arg.Type)
{
case DataType.String:
args.Add(GetStringFromDynValue(arg));
break;
case DataType.UserData:
var obj = (Element)arg.UserData.Object;
args.Add(obj.Name + ":" + obj.GetHashCode());
break;
case DataType.Number:
// TODO: This may result in data loss [Add more cases of number conversion]
args.Add(GetInt32FromDynValue(arg));
break;
}
}
return args;
}
if (targetType == typeof(ScriptCallbackDelegateWrapper))
{
var callback = dynValues.Dequeue().Function;
return new ScriptCallbackDelegateWrapper(parameters => callback.Call(ToDynValues(parameters)), callback);
return new ScriptCallbackDelegateWrapper(parameters => callback.Call(ToDynValues(parameters, owner)), callback);
}
if (targetType == typeof(EventDelegate))
{
var callback = dynValues.Dequeue().Function;
return (EventDelegate)((element, parameters) => callback.Call(new DynValue[] { UserData.Create(element) }.Concat(ToDynValues(parameters))));
return (EventDelegate)((element, parameters) => callback.Call(new DynValue[] { UserData.Create(element) }.Concat(ToDynValues(parameters, owner))));
}


throw new NotImplementedException($"Conversion from Lua for {targetType} not implemented");
}
}
27 changes: 26 additions & 1 deletion SlipeServer.Scripting/Definitions/DebugScriptDefinitions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
using Microsoft.Extensions.Logging;
using MoonSharp.Interpreter;
using SlipeServer.Server.Services;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SlipeServer.Scripting.Definitions;

Expand All @@ -21,5 +26,25 @@ public void OutputDebugString(string message)
this.logger.LogDebug(message);
}


[ScriptFunctionDefinition("iprint")]
public void Print(IEnumerable<object> toPrint)
{
toPrint = (List<object>)toPrint;
StringBuilder sb = new StringBuilder();
int i = 0;
int len = toPrint.Count();
foreach (var printable in toPrint)
{
string? stringRepresentation = printable.ToString();
sb.Append(stringRepresentation ?? "NoStringRepresentation");
if (i != len-1)
{
sb.Append(", ");
}
i++;
}
string message = sb.ToString();
this.debugLog.Output(message);
this.logger.LogInformation(message);
}
}
Loading