From 023ab72d1f1aa58a5ab3b75c5f0eaf8774a08bab Mon Sep 17 00:00:00 2001 From: Sebastian Jura <22455534+CrosRoad95@users.noreply.github.com> Date: Sun, 19 May 2024 07:32:17 +0200 Subject: [PATCH 1/8] Add blip lua definitions --- SlipeServer.Console/test.lua | 9 ++ SlipeServer.Lua/LuaTranslator.cs | 4 + .../Definitions/BlipScriptDefinition.cs | 91 +++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 SlipeServer.Scripting/Definitions/BlipScriptDefinition.cs diff --git a/SlipeServer.Console/test.lua b/SlipeServer.Console/test.lua index 76214453..1510884f 100644 --- a/SlipeServer.Console/test.lua +++ b/SlipeServer.Console/test.lua @@ -28,6 +28,15 @@ print("md5 test: ", md5("qwerty") == "D8578EDF8458CE06FBC5BB76A58C5CA4"); print("sha256 test: ", sha256("qwerty") == "65E84BE33532FB784C48129675F9EFF3A682B27168C0EA744B2CF58EE02337C5"); print("custom definitions:",add(2,2), substract(2,2)) + + -- Begin blips + local blip = createBlip(100, 0,0, 51, 0, 0, 0, 255); + print("blip color:", getBlipColor(blip)) + print("blip icon:", getBlipIcon(blip)) + print("blip ordering:", getBlipOrdering(blip)) + print("blip size:", getBlipSize(blip)) + print("blip visible distance:", getBlipVisibleDistance(blip)) + -- End blips end createExplosion(-10, 0,0, 4); diff --git a/SlipeServer.Lua/LuaTranslator.cs b/SlipeServer.Lua/LuaTranslator.cs index 619a6e90..d885ba5e 100644 --- a/SlipeServer.Lua/LuaTranslator.cs +++ b/SlipeServer.Lua/LuaTranslator.cs @@ -52,6 +52,8 @@ public IEnumerable ToDynValues(object? obj) DynValue.NewNumber(color.B), DynValue.NewNumber(color.A), }; + if (obj is BlipIcon blipIcon) + return new DynValue[] { DynValue.NewNumber((int)blipIcon) }; if (obj is Vector2 vector2) return new DynValue[] { @@ -131,6 +133,8 @@ public IEnumerable ToDynValues(object? obj) return GetBooleanFromDynValue(dynValues.Dequeue()); if (targetType == typeof(Table)) return GetTableFromDynValue(dynValues.Dequeue()); + if (targetType == typeof(BlipIcon)) + return (BlipIcon)GetInt32FromDynValue(dynValues.Dequeue()); if (typeof(Player).IsAssignableFrom(targetType)) return dynValues.Dequeue()?.UserData?.Object; if (typeof(Element).IsAssignableFrom(targetType)) diff --git a/SlipeServer.Scripting/Definitions/BlipScriptDefinition.cs b/SlipeServer.Scripting/Definitions/BlipScriptDefinition.cs new file mode 100644 index 00000000..d15854ff --- /dev/null +++ b/SlipeServer.Scripting/Definitions/BlipScriptDefinition.cs @@ -0,0 +1,91 @@ +using SlipeServer.Server; +using SlipeServer.Server.Elements; +using System.Drawing; +using System.Numerics; + +namespace SlipeServer.Scripting.Definitions; +/// +/// https://wiki.multitheftauto.com/wiki/Server_Scripting_Functions#Blip_functions +/// +public class BlipScriptDefinition +{ + private readonly MtaServer server; + + public BlipScriptDefinition(MtaServer server) + { + this.server = server; + } + + [ScriptFunctionDefinition("createBlip")] + public Blip CreateBlip(Vector3 position, BlipIcon icon, byte size = 2, int red = 255, int green = 0, int blue = 0, int alpha = 255, short ordering = 0, ushort visibleDistance = 16383) + { + return new Blip(position, icon, visibleDistance) + { + Color = Color.FromArgb(alpha, red, green, blue), + Size = size, + Ordering = ordering + }.AssociateWith(this.server); + } + + // TODO: Attach to element + [ScriptFunctionDefinition("createBlipAttachedTo")] + public Blip CreateBlipAttachedTo(Element element, BlipIcon icon, byte size = 2, int red = 255, int green = 0, int blue = 0, int alpha = 255, short ordering = 0, ushort visibleDistance = 16383) + { + return new Blip(element.Position, icon, visibleDistance) + { + Color = Color.FromArgb(alpha, red, green, blue), + Size = size, + Ordering = ordering, + }.AssociateWith(this.server); + } + + [ScriptFunctionDefinition("getBlipColor")] + public Color GetBlipColor(Blip blip) => blip.Color; + + [ScriptFunctionDefinition("getBlipIcon")] + public BlipIcon GetBlipIcon(Blip blip) => blip.Icon; + + [ScriptFunctionDefinition("getBlipOrdering")] + public short GetBlipOrdering(Blip blip) => blip.Ordering; + + [ScriptFunctionDefinition("getBlipSize")] + public byte GetBlipSize(Blip blip) => blip.Size; + + [ScriptFunctionDefinition("getBlipVisibleDistance")] + public ushort GetBlipVisibleDistance(Blip blip) => blip.VisibleDistance; + + [ScriptFunctionDefinition("setBlipColor")] + public bool SetBlipColor(Blip blip, int red, int green, int blue, int alpha) + { + blip.Color = Color.FromArgb(alpha, red, green, blue); + return true; + } + + [ScriptFunctionDefinition("setBlipIcon")] + public bool SetBlipIcon(Blip blip, BlipIcon icon) + { + blip.Icon = icon; + return true; + } + + [ScriptFunctionDefinition("setBlipOrdering")] + public bool SetBlipOrdering(Blip blip, short ordering) + { + blip.Ordering = ordering; + return true; + } + + [ScriptFunctionDefinition("setBlipSize")] + public bool SetBlipSize(Blip blip, byte size) + { + blip.Size = size; + return true; + } + + [ScriptFunctionDefinition("setBlipVisibleDistance")] + public bool SetBlipVisibleDistance(Blip blip, ushort visibleDistance) + { + blip.VisibleDistance = visibleDistance; + return true; + } +} From 81132f94a7bffe30b58f47995e7aba1005a4aa6e Mon Sep 17 00:00:00 2001 From: Sebastian Jura <22455534+CrosRoad95@users.noreply.github.com> Date: Sun, 19 May 2024 14:57:21 +0200 Subject: [PATCH 2/8] First working resource --- .../XmlConfigurationProvider.cs | 49 ++- .../SlipeServer.Hosting.csproj | 2 +- SlipeServer.Legacy/LegacyMtaServer.cs | 115 +++++++ SlipeServer.Legacy/LegacyServerService.cs | 74 +++++ SlipeServer.Legacy/SlipeServer.Legacy.csproj | 28 ++ SlipeServer.LegacyServer/Program.cs | 4 + .../SlipeServer.LegacyServer.csproj | 40 +++ .../mods/deathmatch/mtaserver.conf | 308 ++++++++++++++++++ .../mods/deathmatch/resources/hello/c.lua | 2 + .../mods/deathmatch/resources/hello/meta.xml | 4 + .../mods/deathmatch/resources/hello/s.lua | 2 + SlipeServer.Lua/LuaScript.cs | 26 ++ SlipeServer.Lua/LuaScriptingRuntimeService.cs | 32 ++ SlipeServer.Lua/LuaScriptingService.cs | 34 ++ SlipeServer.Lua/LuaService.cs | 4 +- .../LuaServiceCollectionExtensions.cs | 15 +- SlipeServer.Lua/LuaTranslator.cs | 2 + .../Definitions/AssertionScriptDefinition.cs | 32 ++ SlipeServer.Scripting/IScript.cs | 6 + SlipeServer.Scripting/IScriptContext.cs | 14 + .../IScriptingRuntimeService.cs | 8 + SlipeServer.Scripting/IScriptingService.cs | 7 + SlipeServer.Scripting/ScriptingException.cs | 10 + .../ServerResourcesService.cs | 85 +++++ .../ServiceCollectionExtensions.cs | 11 + .../MetaXmlResourceInterpreterTests.cs | 4 +- SlipeServer.Server/Configuration.cs | 12 + SlipeServer.Server/MtaServer.cs | 2 +- .../Connection/JoinDataPacketHandler.cs | 2 +- .../Interpreters/BasicResourceInterpreter.cs | 4 +- .../Interpreters/IResourceInterpreter.cs | 3 +- .../Resources/Interpreters/Meta/MetaXml.cs | 43 ++- .../MetaXmlResourceInterpreter.cs | 36 +- .../SlipeLuaResourceInterpreter.cs | 6 +- .../Providers/FileSystemResourceProvider.cs | 34 +- .../Resources/Providers/IResourceProvider.cs | 2 + SlipeServer.Server/Resources/Resource.cs | 19 ++ .../ResourceServerBuilderExtensions.cs | 15 +- SlipeServer.Server/SlipeServer.Server.csproj | 6 +- SlipeServer.sln | 48 ++- 40 files changed, 1107 insertions(+), 43 deletions(-) create mode 100644 SlipeServer.Legacy/LegacyMtaServer.cs create mode 100644 SlipeServer.Legacy/LegacyServerService.cs create mode 100644 SlipeServer.Legacy/SlipeServer.Legacy.csproj create mode 100644 SlipeServer.LegacyServer/Program.cs create mode 100644 SlipeServer.LegacyServer/SlipeServer.LegacyServer.csproj create mode 100644 SlipeServer.LegacyServer/mods/deathmatch/mtaserver.conf create mode 100644 SlipeServer.LegacyServer/mods/deathmatch/resources/hello/c.lua create mode 100644 SlipeServer.LegacyServer/mods/deathmatch/resources/hello/meta.xml create mode 100644 SlipeServer.LegacyServer/mods/deathmatch/resources/hello/s.lua create mode 100644 SlipeServer.Lua/LuaScript.cs create mode 100644 SlipeServer.Lua/LuaScriptingRuntimeService.cs create mode 100644 SlipeServer.Lua/LuaScriptingService.cs create mode 100644 SlipeServer.Scripting/Definitions/AssertionScriptDefinition.cs create mode 100644 SlipeServer.Scripting/IScript.cs create mode 100644 SlipeServer.Scripting/IScriptContext.cs create mode 100644 SlipeServer.Scripting/IScriptingRuntimeService.cs create mode 100644 SlipeServer.Scripting/IScriptingService.cs create mode 100644 SlipeServer.Scripting/ScriptingException.cs create mode 100644 SlipeServer.Scripting/ServerResourcesService.cs create mode 100644 SlipeServer.Scripting/ServiceCollectionExtensions.cs diff --git a/SlipeServer.ConfigurationProviders/Configurations/XmlConfigurationProvider.cs b/SlipeServer.ConfigurationProviders/Configurations/XmlConfigurationProvider.cs index 239e55ac..3e5b28a2 100644 --- a/SlipeServer.ConfigurationProviders/Configurations/XmlConfigurationProvider.cs +++ b/SlipeServer.ConfigurationProviders/Configurations/XmlConfigurationProvider.cs @@ -1,6 +1,7 @@ using SlipeServer.Server; using SlipeServer.Server.Enums; using System; +using System.Collections.Generic; using System.Linq; using System.Xml; @@ -19,22 +20,30 @@ public XmlConfigurationProvider(string fileName) ushort result; + var startupResources = new List(); + foreach (XmlNode node in xmlConfig.FirstChild.ChildNodes) { switch (node.Name) { - case "serverName": + case "servername": this.Configuration.ServerName = node.InnerText; break; - case "host": - this.Configuration.Host = node.InnerText; + case "serverip": + if(node.InnerText == "auto" || node.InnerText == "any") + { + this.Configuration.Host = ""; + } else + { + this.Configuration.Host = node.InnerText; + } break; - case "port": + case "serverport": if (ushort.TryParse(node.InnerText, out result)) this.Configuration.Port = result; break; - case "maxPlayers": + case "maxplayers": if (ushort.TryParse(node.InnerText, out result)) this.Configuration.MaxPlayerCount = result; @@ -43,19 +52,19 @@ public XmlConfigurationProvider(string fileName) this.Configuration.Password = node.InnerText; break; - case "httpPort": + case "httpport": this.Configuration.HttpPort = ushort.Parse(node.InnerText); break; - case "httpUrl": + case "httpurl": this.Configuration.HttpUrl = node.InnerText; break; - case "httpHost": + case "httphost": this.Configuration.HttpHost = node.InnerText; break; - case "httpConnectionsPerClient": + case "httpmaxconnectionsperclient": this.Configuration.HttpConnectionsPerClient = int.Parse(node.InnerText); break; @@ -102,7 +111,29 @@ public XmlConfigurationProvider(string fileName) case "IsVoiceEnabled": this.Configuration.IsVoiceEnabled = bool.Parse(node.InnerText); break; + + case "resource": + var startupResource = new StartupResource(); + foreach (XmlAttribute item in node.Attributes) + { + switch (item.Name) + { + case "src": + startupResource.Name = item.Value; + break; + case "startup": + startupResource.Start = item.Value == "1" || item.Value == "true"; + break; + case "protected": + startupResource.Protected = item.Value == "1" || item.Value == "true"; + break; + } + } + startupResources.Add(startupResource); + break; } } + + this.Configuration.StartupResources = startupResources.ToArray(); } } diff --git a/SlipeServer.Hosting/SlipeServer.Hosting.csproj b/SlipeServer.Hosting/SlipeServer.Hosting.csproj index bb04be80..442e7ad9 100644 --- a/SlipeServer.Hosting/SlipeServer.Hosting.csproj +++ b/SlipeServer.Hosting/SlipeServer.Hosting.csproj @@ -8,7 +8,7 @@ - + diff --git a/SlipeServer.Legacy/LegacyMtaServer.cs b/SlipeServer.Legacy/LegacyMtaServer.cs new file mode 100644 index 00000000..90b9226d --- /dev/null +++ b/SlipeServer.Legacy/LegacyMtaServer.cs @@ -0,0 +1,115 @@ +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Logging; +using SlipeServer.Server.Resources.Serving; +using SlipeServer.Server.Mappers; +using SlipeServer.ConfigurationProviders.Configurations; +using Microsoft.Extensions.Options; +using SlipeServer.Lua; +using SlipeServer.Server.Resources.Interpreters; +using Microsoft.Extensions.Logging.Console; +using Microsoft.Extensions.Logging.Abstractions; +using SlipeServer.Server.Resources; + +namespace SlipeServer.Legacy; + +public class CustomConsoleFormatter : ConsoleFormatter +{ + private readonly SimpleConsoleFormatterOptions formatterOptions; + + public CustomConsoleFormatter(IOptionsMonitor options) + : base("customFormatter") + { + this.formatterOptions = new SimpleConsoleFormatterOptions + { + TimestampFormat = "[HH:mm:ss] " + }; + } + + public override void Write(in LogEntry logEntry, IExternalScopeProvider? scopeProvider, TextWriter textWriter) + { + if (textWriter == null) + { + throw new ArgumentNullException(nameof(textWriter)); + } + + var timestamp = DateTime.Now.ToString(this.formatterOptions.TimestampFormat); + textWriter.Write(timestamp); + textWriter.Write(logEntry.Formatter(logEntry.State, logEntry.Exception)); + textWriter.Write(Environment.NewLine); + } +} + +public class LegacyMtaServer +{ + private readonly IHost app; + private readonly Configuration configuration; + + public LegacyMtaServer() + { + var builder = Host.CreateDefaultBuilder(); + + var mtaServerConfiguration = new XmlConfigurationProvider("mods/deathmatch/mtaserver.conf"); + + this.configuration = mtaServerConfiguration.Configuration; + this.configuration.ResourceDirectory = "mods/deathmatch/resources"; + + builder.ConfigureServices((hostBuilderContext, services) => + { + services.AddLogging(configure => + { + configure.AddConsole(options => + { + options.FormatterName = "customFormatter"; + }); + configure.AddConsoleFormatter(); + }); + + services.AddSingleton(); + services.AddLua(); + services.AddHttpClient(); + services.AddDefaultMtaServerServices(); + services.AddResourceInterpreter(); + services.AddMtaServer(mtaServerConfiguration.Configuration, builder => + { + builder.AddDefaultServices(); + builder.AddDefaultLuaMappings(); + builder.AddDefaultNetWrapper(); + }); + + services.AddSingleton(); + services.AddHostedService(); + services.AddHostedService(); + + services.TryAddSingleton(x => x.GetRequiredService>()); + }); + + builder.ConfigureMtaServers((context, configure) => + { + var isDevelopment = context.HostingEnvironment.IsDevelopment(); + var exceptBehaviours = isDevelopment ? ServerBuilderDefaultBehaviours.MasterServerAnnouncementBehaviour : ServerBuilderDefaultBehaviours.None; + + configure.AddDefaultPacketHandlers(); + configure.AddDefaultBehaviours(exceptBehaviours); + configure.StartResourceServers(); + }); + + this.app = builder.Build(); + } + + public async Task RunAsync() + { + Console.WriteLine("=================================================================="); + Console.WriteLine("= Multi Theft Auto: San Andreas v1.6"); + Console.WriteLine("= Server name : {0}", this.configuration.ServerName); + Console.WriteLine("= Server IP address: {0}", this.configuration.Host); + Console.WriteLine("= Server port : {0}", this.configuration.Port); + Console.WriteLine("="); + Console.WriteLine("= Log file : {0}", "none"); + Console.WriteLine("= Maximum players : {0}", this.configuration.MaxPlayerCount); + Console.WriteLine("= HTTP port : {0}", this.configuration.HttpPort); + Console.WriteLine("= Voice Chat : {0}", this.configuration.IsVoiceEnabled ? "Enabled" : "Disabled"); + Console.WriteLine("= Bandwidth saving : {0}", "TODO"); + Console.WriteLine("=================================================================="); + await this.app.RunAsync(); + } +} diff --git a/SlipeServer.Legacy/LegacyServerService.cs b/SlipeServer.Legacy/LegacyServerService.cs new file mode 100644 index 00000000..3cc513f4 --- /dev/null +++ b/SlipeServer.Legacy/LegacyServerService.cs @@ -0,0 +1,74 @@ +using Microsoft.Extensions.Logging; +using SlipeServer.Lua; +using SlipeServer.Scripting; +using SlipeServer.Server.Resources; +using SlipeServer.Server.Resources.Interpreters; +using SlipeServer.Server.Resources.Providers; + +namespace SlipeServer.Legacy; + +internal sealed class LegacyServerService : IHostedService +{ + private readonly IResourceProvider resourceProvider; + private readonly IEnumerable resourceInterpreters; + private readonly ILogger logger; + private readonly MtaServer mtaServer; + private readonly ResourceService resourceService; + private readonly ServerResourcesService serverResourcesService; + private readonly IScriptEventRuntime scriptEventRuntime; + private readonly LuaService luaService; + + public LegacyServerService(IResourceProvider resourceProvider, IEnumerable resourceInterpreters, ILogger logger, MtaServer mtaServer, ResourceService resourceService, ServerResourcesService serverResourcesService, IScriptEventRuntime scriptEventRuntime, LuaService luaService) + { + foreach (var resourceInterpreter in resourceInterpreters) + resourceProvider.AddResourceInterpreter(resourceInterpreter); + + this.resourceProvider = resourceProvider; + this.resourceInterpreters = resourceInterpreters; + this.logger = logger; + this.mtaServer = mtaServer; + this.resourceService = resourceService; + this.serverResourcesService = serverResourcesService; + this.scriptEventRuntime = scriptEventRuntime; + this.luaService = luaService; + } + + public Task StartAsync(CancellationToken cancellationToken) + { + this.scriptEventRuntime.LoadDefaultEvents(); + this.luaService.LoadDefaultDefinitions(); + + this.resourceProvider.Refresh(); + var resources = this.resourceProvider.GetResources().ToArray(); + this.logger.LogInformation("Resources: {loadedResourcesCount} loaded, {failedResourcesCount} failed", resources.Length, 0); + if (this.mtaServer.HasPassword) + { + this.logger.LogInformation("Server password set to '{serverPassword}'", mtaServer.Password); + } + this.logger.LogInformation("Starting resources..."); + foreach (var startupResource in this.mtaServer.Configuration.StartupResources) + { + var resource = resources.FirstOrDefault(x => x.Name == startupResource.Name); + if(resource != null) + { + this.resourceService.StartResource(startupResource.Name); + var serverResource = this.resourceProvider.GetServerResource(startupResource.Name); + serverResourcesService.Create(serverResource); + } else + { + this.logger.LogWarning("ERROR: Couldn't find resource {resourceName}. Check it exists.", startupResource.Name); + } + } + this.mtaServer.Start(); + this.logger.LogInformation("Server started and is ready to accept connections!"); + this.logger.LogInformation("To stop the server, type 'shutdown' or press Ctrl-C"); + this.logger.LogInformation("Type 'help' for a list of commands."); + return Task.CompletedTask; + } + + public Task StopAsync(CancellationToken cancellationToken) + { + this.mtaServer.Stop(); + return Task.CompletedTask; + } +} diff --git a/SlipeServer.Legacy/SlipeServer.Legacy.csproj b/SlipeServer.Legacy/SlipeServer.Legacy.csproj new file mode 100644 index 00000000..f86c4d31 --- /dev/null +++ b/SlipeServer.Legacy/SlipeServer.Legacy.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + enable + enable + + + + + + + + + + + + + + + + + + + + + + diff --git a/SlipeServer.LegacyServer/Program.cs b/SlipeServer.LegacyServer/Program.cs new file mode 100644 index 00000000..b6fdec0d --- /dev/null +++ b/SlipeServer.LegacyServer/Program.cs @@ -0,0 +1,4 @@ +using SlipeServer.Legacy; + +var server = new LegacyMtaServer(); +await server.RunAsync(); diff --git a/SlipeServer.LegacyServer/SlipeServer.LegacyServer.csproj b/SlipeServer.LegacyServer/SlipeServer.LegacyServer.csproj new file mode 100644 index 00000000..ee81dcd5 --- /dev/null +++ b/SlipeServer.LegacyServer/SlipeServer.LegacyServer.csproj @@ -0,0 +1,40 @@ + + + + Exe + net8.0 + enable + enable + + + + x86 + + + + x86 + + + + x86 + + + + x86 + + + + x64 + + + + + + + + + Always + + + + \ No newline at end of file diff --git a/SlipeServer.LegacyServer/mods/deathmatch/mtaserver.conf b/SlipeServer.LegacyServer/mods/deathmatch/mtaserver.conf new file mode 100644 index 00000000..c66b4ab2 --- /dev/null +++ b/SlipeServer.LegacyServer/mods/deathmatch/mtaserver.conf @@ -0,0 +1,308 @@ + + + + Default MTA Server + + + + + + + auto + + + + 22003 + + + 32 + + + 22005 + + + + + + 5 + + + 20 + + + + + + none + + + + + + + + + + + + + + + + 1 + + + + + + 1 + + + 0 + + + + + + medium + + + + 100 + + 1500 + + 500 + + 400 + + 2000 + + 400 + + 100 + + 100 + + + 1 + + + 0 + + + 150 + + + 0 + + + server-id.keys + + + logs/server.log + + + logs/server_auth.log + + + logs/db.log + + + + + + acl.xml + + + logs/scripts.log + + + 0 + + + 0 + + + 1 + + + 74 + + + 0 + + + 1 + + + 4 + + + + + + backups + + + 3 + + + 5 + + + 1 + + + 1 + + + Admin + + + 1 + + + 127.0.0.1 + + + 1 + + + 1000 + 100 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/SlipeServer.LegacyServer/mods/deathmatch/resources/hello/c.lua b/SlipeServer.LegacyServer/mods/deathmatch/resources/hello/c.lua new file mode 100644 index 00000000..881425c8 --- /dev/null +++ b/SlipeServer.LegacyServer/mods/deathmatch/resources/hello/c.lua @@ -0,0 +1,2 @@ +print("hello client"); +outputChatBox("hello client"); \ No newline at end of file diff --git a/SlipeServer.LegacyServer/mods/deathmatch/resources/hello/meta.xml b/SlipeServer.LegacyServer/mods/deathmatch/resources/hello/meta.xml new file mode 100644 index 00000000..47a9e465 --- /dev/null +++ b/SlipeServer.LegacyServer/mods/deathmatch/resources/hello/meta.xml @@ -0,0 +1,4 @@ + +