Reworked on resource loading, Added RegisterCommands overload to register commands from an instance.
This commit is contained in:
@ -31,6 +31,8 @@ namespace RageCoop.Client.Menus
|
||||
public static NativeMenu LastMenu { get; set; } = Menu;
|
||||
#region ITEMS
|
||||
private static readonly NativeItem _usernameItem = new NativeItem("Username") { AltTitle = Main.Settings.Username };
|
||||
private static readonly NativeItem _passwordItem = new NativeItem("Password") { AltTitle = new string('*',Main.Settings.Password.Length) };
|
||||
|
||||
public static readonly NativeItem ServerIpItem = new NativeItem("Server IP") { AltTitle = Main.Settings.LastServerAddress };
|
||||
private static readonly NativeItem _serverConnectItem = new NativeItem("Connect");
|
||||
private static readonly NativeItem _aboutItem = new NativeItem("About", "~y~SOURCE~s~~n~" +
|
||||
@ -51,6 +53,7 @@ namespace RageCoop.Client.Menus
|
||||
Menu.Title.Color = Color.FromArgb(255, 165, 0);
|
||||
|
||||
_usernameItem.Activated += UsernameActivated;
|
||||
_passwordItem.Activated+=_passwordActivated;
|
||||
ServerIpItem.Activated += ServerIpActivated;
|
||||
_serverConnectItem.Activated += (sender, item) => { Networking.ToggleConnection(Main.Settings.LastServerAddress); };
|
||||
|
||||
@ -58,6 +61,7 @@ namespace RageCoop.Client.Menus
|
||||
Menu.AddSubMenu(ServersMenu.Menu);
|
||||
|
||||
Menu.Add(_usernameItem);
|
||||
Menu.Add(_passwordItem);
|
||||
Menu.Add(ServerIpItem);
|
||||
Menu.Add(_serverConnectItem);
|
||||
|
||||
@ -76,6 +80,8 @@ namespace RageCoop.Client.Menus
|
||||
|
||||
Menu.Add(_aboutItem);
|
||||
}
|
||||
|
||||
|
||||
public static bool ShowPopUp(string prompt, string title,string subtitle,string error,bool showbackground)
|
||||
{
|
||||
PopUp.Prompt=prompt;
|
||||
@ -113,6 +119,16 @@ namespace RageCoop.Client.Menus
|
||||
}
|
||||
}
|
||||
|
||||
private static void _passwordActivated(object sender, System.EventArgs e)
|
||||
{
|
||||
string newPass = Game.GetUserInput(WindowTitle.EnterMessage20, "", 20);
|
||||
if (!string.IsNullOrWhiteSpace(newPass))
|
||||
{
|
||||
Main.Settings.Password = newPass;
|
||||
Util.SaveSettings();
|
||||
_passwordItem.AltTitle = new string('*', newPass.Length);
|
||||
}
|
||||
}
|
||||
public static void ServerIpActivated(object a, System.EventArgs b)
|
||||
{
|
||||
string newServerIp = Game.GetUserInput(WindowTitle.EnterMessage60, ServerIpItem.AltTitle, 60);
|
||||
|
@ -39,7 +39,7 @@ namespace RageCoop.Client
|
||||
});
|
||||
}
|
||||
|
||||
public static void ToggleConnection(string address,string password=null)
|
||||
public static void ToggleConnection(string address,string username=null,string password=null)
|
||||
{
|
||||
if (IsOnServer)
|
||||
{
|
||||
@ -48,6 +48,7 @@ namespace RageCoop.Client
|
||||
else
|
||||
{
|
||||
password = password ?? Main.Settings.Password;
|
||||
username=username ?? Main.Settings.Username;
|
||||
// 623c92c287cc392406e7aaaac1c0f3b0 = RAGECOOP
|
||||
NetPeerConfiguration config = new NetPeerConfiguration("623c92c287cc392406e7aaaac1c0f3b0")
|
||||
{
|
||||
@ -85,7 +86,7 @@ namespace RageCoop.Client
|
||||
var handshake=new Packets.Handshake()
|
||||
{
|
||||
PedID = Main.LocalPlayerID,
|
||||
Username = Main.Settings.Username,
|
||||
Username =username,
|
||||
ModVersion = Main.CurrentVersion,
|
||||
PassHashEncrypted=Security.Encrypt(password.GetHash())
|
||||
};
|
||||
|
@ -3,7 +3,6 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
|
||||
<OutputPath>D:\Games\Grand Theft Auto V\Scripts\RageCoop</OutputPath>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<ProduceReferenceAssembly>False</ProduceReferenceAssembly>
|
||||
@ -13,13 +12,26 @@
|
||||
<AssemblyVersion>0.5.0</AssemblyVersion>
|
||||
<FileVersion>0.5.0</FileVersion>
|
||||
<Version>0.5.0</Version>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Authors>RAGECOOP</Authors>
|
||||
<Description>An API reference for developing client-side resource for RAGECOOP</Description>
|
||||
<PackageProjectUrl>https://ragecoop.online/</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/RAGECOOP/RAGECOOP-V</RepositoryUrl>
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<Optimize>True</Optimize>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
<Content Include="favicon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\RageCoop.Core\RageCoop.Core.csproj" />
|
||||
|
@ -31,11 +31,7 @@ namespace RageCoop.Client.Scripting
|
||||
List<InputArgument> arguments = new List<InputArgument>();
|
||||
int i;
|
||||
var ty = (byte)e.Args[0];
|
||||
Main.Logger.Debug($"gettype");
|
||||
Main.Logger.Flush();
|
||||
TypeCode returnType=(TypeCode)ty;
|
||||
Main.Logger.Debug($"typeok");
|
||||
Main.Logger.Flush();
|
||||
i = returnType==TypeCode.Empty ? 1 : 2;
|
||||
var hash = (Hash)e.Args[i++];
|
||||
for(; i<e.Args.Count;i++)
|
||||
|
@ -3,21 +3,17 @@
|
||||
/// <summary>
|
||||
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded, you should use <see cref="OnStart"/>. to initiate your script.
|
||||
/// </summary>
|
||||
public abstract class ClientScript:Core.Scripting.IScriptable
|
||||
public abstract class ClientScript:Core.Scripting.Scriptable
|
||||
{
|
||||
/// <summary>
|
||||
/// This method would be called from main thread shortly after all scripts have been loaded.
|
||||
/// </summary>
|
||||
public abstract void OnStart();
|
||||
public override abstract void OnStart();
|
||||
|
||||
/// <summary>
|
||||
/// This method would be called from main thread when the client disconnected from the server, you MUST terminate all background jobs/threads in this method.
|
||||
/// </summary>
|
||||
public abstract void OnStop();
|
||||
public override abstract void OnStop();
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="Core.Scripting.Resource"/> object this script belongs to, this property will be initiated before <see cref="OnStart"/> (will be null if you access it in the constructor).
|
||||
/// </summary>
|
||||
public Core.Scripting.Resource CurrentResource { get; internal set; }
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
using System.IO;
|
||||
using RageCoop.Core.Scripting;
|
||||
using Ionic.Zip;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
|
||||
namespace RageCoop.Client.Scripting
|
||||
{
|
||||
@ -15,7 +15,6 @@ namespace RageCoop.Client.Scripting
|
||||
{
|
||||
foreach (var s in d.Scripts)
|
||||
{
|
||||
(s as ClientScript).CurrentResource=d;
|
||||
Main.QueueAction(() => s.OnStart());
|
||||
}
|
||||
}
|
||||
@ -37,23 +36,23 @@ namespace RageCoop.Client.Scripting
|
||||
/// <summary>
|
||||
/// Load all resources from the server
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the directory containing the resources.</param>
|
||||
/// <param name="path">The path to the directory containing all resources to load.</param>
|
||||
public void Load(string path)
|
||||
{
|
||||
Unload();
|
||||
foreach (var d in Directory.GetDirectories(path))
|
||||
{
|
||||
Directory.Delete(d, true);
|
||||
}
|
||||
using (var zip = ZipFile.Read(Path.Combine(path, "Resources.zip")))
|
||||
{
|
||||
zip.ExtractAll(path, ExtractExistingFileAction.OverwriteSilently);
|
||||
if(Path.GetFileName(d).ToLower() != "data")
|
||||
{
|
||||
Directory.Delete(d, true);
|
||||
}
|
||||
}
|
||||
Directory.CreateDirectory(path);
|
||||
foreach (var resource in Directory.GetDirectories(path))
|
||||
{
|
||||
if (Path.GetFileName(resource).ToLower()!="data") { continue; }
|
||||
Logger?.Info($"Loading resource: {Path.GetFileName(resource)}");
|
||||
LoadResource(resource);
|
||||
LoadResource(resource,Path.Combine(path,"data"));
|
||||
}
|
||||
StartAll();
|
||||
}
|
||||
|
BIN
RageCoop.Client/favicon.ico
Normal file
BIN
RageCoop.Client/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
@ -22,6 +22,11 @@
|
||||
<None Include="Lidgren.Network\Lidgren.Network.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>..\libs\Newtonsoft.Json.dll</HintPath>
|
||||
|
@ -1,15 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Linq;
|
||||
namespace RageCoop.Core.Scripting
|
||||
{
|
||||
public interface IScriptable
|
||||
{
|
||||
void OnStart();
|
||||
void OnStop();
|
||||
}
|
||||
}
|
27
RageCoop.Core/Scripting/Resource.cs
Normal file
27
RageCoop.Core/Scripting/Resource.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace RageCoop.Core.Scripting
|
||||
{
|
||||
public class Resource
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the resource
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
/// <summary>
|
||||
/// A resource-specific folder that can be used to store your files.
|
||||
/// </summary>
|
||||
public string DataFolder { get;internal set; }
|
||||
public List<Scriptable> Scripts { get; internal set; } = new List<Scriptable>();
|
||||
public Dictionary<string,ResourceFile> Files { get; internal set; }=new Dictionary<string,ResourceFile>();
|
||||
}
|
||||
public class ResourceFile
|
||||
{
|
||||
public string Name { get; internal set; }
|
||||
public bool IsDirectory { get; internal set; }
|
||||
public Func<Stream> GetStream { get; internal set; }
|
||||
}
|
||||
}
|
@ -5,23 +5,13 @@ using System.Reflection;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
|
||||
[assembly: InternalsVisibleTo("RageCoop.Server")]
|
||||
[assembly: InternalsVisibleTo("RageCoop.Client")]
|
||||
namespace RageCoop.Core.Scripting
|
||||
{
|
||||
public class Resource
|
||||
{
|
||||
/// <summary>
|
||||
/// Name of the resource
|
||||
/// </summary>
|
||||
public string Name { get;internal set; }
|
||||
/// <summary>
|
||||
/// The directory of current resource
|
||||
/// </summary>
|
||||
public string Directory { get;internal set; }
|
||||
public List<IScriptable> Scripts { get; internal set; }=new List<IScriptable>();
|
||||
}
|
||||
|
||||
internal class ResourceLoader
|
||||
{
|
||||
protected List<string> ToIgnore = new List<string>
|
||||
@ -40,20 +30,77 @@ namespace RageCoop.Core.Scripting
|
||||
Logger = logger;
|
||||
}
|
||||
/// <summary>
|
||||
/// Load all assemblies inside the resource directory.
|
||||
/// Load a resource from a directory.
|
||||
/// </summary>
|
||||
/// <param name="path">Path of the directory.</param>
|
||||
protected void LoadResource(string path)
|
||||
protected void LoadResource(string path,string dataFolderRoot)
|
||||
{
|
||||
var r = new Resource()
|
||||
{
|
||||
Scripts = new List<IScriptable>(),
|
||||
Scripts = new List<Scriptable>(),
|
||||
Name=Path.GetFileName(path),
|
||||
Directory=path,
|
||||
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileName(path))
|
||||
};
|
||||
foreach (var f in Directory.GetFiles(path, "*.dll"))
|
||||
Directory.CreateDirectory(r.DataFolder);
|
||||
foreach (var dir in Directory.GetDirectories(path, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
LoadScriptsFromAssembly(f, r);
|
||||
r.Files.Add(dir, new ResourceFile()
|
||||
{
|
||||
IsDirectory=true,
|
||||
Name=dir.Substring(path.Length+1)
|
||||
});
|
||||
}
|
||||
foreach (var file in Directory.GetFiles(path,"*",SearchOption.AllDirectories))
|
||||
{
|
||||
var relativeName = file.Substring(path.Length+1);
|
||||
var rfile = new ResourceFile()
|
||||
{
|
||||
GetStream=() => { return new FileStream(file, FileMode.Open, FileAccess.Read); },
|
||||
IsDirectory=false,
|
||||
Name=relativeName
|
||||
};
|
||||
if (file.EndsWith(".dll"))
|
||||
{
|
||||
LoadScriptsFromAssembly(rfile,file, r);
|
||||
}
|
||||
r.Files.Add(relativeName,rfile);
|
||||
}
|
||||
LoadedResources.Add(r);
|
||||
}
|
||||
/// <summary>
|
||||
/// Load a resource from a zip
|
||||
/// </summary>
|
||||
/// <param name="file"></param>
|
||||
protected void LoadResource(ZipFile file,string dataFolderRoot)
|
||||
{
|
||||
var r = new Resource()
|
||||
{
|
||||
Scripts = new List<Scriptable>(),
|
||||
Name=Path.GetFileNameWithoutExtension(file.Name),
|
||||
DataFolder=Path.Combine(dataFolderRoot, Path.GetFileNameWithoutExtension(file.Name))
|
||||
};
|
||||
Directory.CreateDirectory(r.DataFolder);
|
||||
|
||||
foreach (ZipEntry entry in file)
|
||||
{
|
||||
ResourceFile rFile;
|
||||
r.Files.Add(entry.Name, rFile=new ResourceFile()
|
||||
{
|
||||
Name=entry.Name,
|
||||
IsDirectory=entry.IsDirectory,
|
||||
});
|
||||
if (!entry.IsDirectory)
|
||||
{
|
||||
rFile.GetStream=() => { return file.GetInputStream(entry); };
|
||||
if (entry.Name.EndsWith(".dll"))
|
||||
{
|
||||
var tmp = Path.GetTempFileName();
|
||||
var f = File.OpenWrite(tmp);
|
||||
rFile.GetStream().CopyTo(f);
|
||||
f.Close();
|
||||
LoadScriptsFromAssembly(rFile, tmp, r, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
LoadedResources.Add(r);
|
||||
}
|
||||
@ -62,31 +109,38 @@ namespace RageCoop.Core.Scripting
|
||||
/// </summary>
|
||||
/// <param name="path">The path to the assembly file to load.</param>
|
||||
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
|
||||
protected bool LoadScriptsFromAssembly(string path, Resource domain)
|
||||
private bool LoadScriptsFromAssembly(ResourceFile file,string path, Resource resource,bool shadowCopy=true)
|
||||
{
|
||||
lock (LoadedResources)
|
||||
{
|
||||
if (!IsManagedAssembly(path)) { return false; }
|
||||
if (ToIgnore.Contains(Path.GetFileName(path))) { try { File.Delete(path); } catch { }; return false; }
|
||||
if (ToIgnore.Contains(file.Name)) { try { File.Delete(path); } catch { }; return false; }
|
||||
|
||||
Logger?.Debug($"Loading assembly {Path.GetFileName(path)} ...");
|
||||
Logger?.Debug($"Loading assembly {file.Name} ...");
|
||||
|
||||
Assembly assembly;
|
||||
|
||||
try
|
||||
{
|
||||
var temp = Path.GetTempFileName();
|
||||
File.Copy(path, temp, true);
|
||||
assembly = Assembly.LoadFrom(temp);
|
||||
if (shadowCopy)
|
||||
{
|
||||
var temp = Path.GetTempFileName();
|
||||
File.Copy(path, temp, true);
|
||||
assembly = Assembly.LoadFrom(temp);
|
||||
}
|
||||
else
|
||||
{
|
||||
assembly = Assembly.LoadFrom(path);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error("Unable to load "+Path.GetFileName(path));
|
||||
Logger?.Error("Unable to load "+file.Name);
|
||||
Logger?.Error(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return LoadScriptsFromAssembly(assembly, path, domain);
|
||||
return LoadScriptsFromAssembly(file,assembly, path, resource);
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
@ -95,7 +149,7 @@ namespace RageCoop.Core.Scripting
|
||||
/// <param name="filename">The path to the file associated with this assembly.</param>
|
||||
/// <param name="assembly">The assembly to load.</param>
|
||||
/// <returns><see langword="true" /> on success, <see langword="false" /> otherwise</returns>
|
||||
private bool LoadScriptsFromAssembly(Assembly assembly, string filename, Resource toload)
|
||||
private bool LoadScriptsFromAssembly(ResourceFile rfile,Assembly assembly, string filename, Resource toload)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
@ -110,7 +164,10 @@ namespace RageCoop.Core.Scripting
|
||||
try
|
||||
{
|
||||
// Invoke script constructor
|
||||
toload.Scripts.Add(constructor.Invoke(null) as IScriptable);
|
||||
var script = constructor.Invoke(null) as Scriptable;
|
||||
script.CurrentResource = toload;
|
||||
script.CurrentFile=rfile;
|
||||
toload.Scripts.Add(script);
|
||||
count++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@ -127,7 +184,7 @@ namespace RageCoop.Core.Scripting
|
||||
}
|
||||
catch (ReflectionTypeLoadException ex)
|
||||
{
|
||||
Logger?.Error($"Failed to load assembly {Path.GetFileName(filename)}: ");
|
||||
Logger?.Error($"Failed to load assembly {rfile.Name}: ");
|
||||
Logger?.Error(ex);
|
||||
foreach (var e in ex.LoaderExceptions)
|
||||
{
|
||||
@ -136,7 +193,7 @@ namespace RageCoop.Core.Scripting
|
||||
return false;
|
||||
}
|
||||
|
||||
Logger?.Info($"Loaded {count} script(s) in {Path.GetFileName(filename)}");
|
||||
Logger?.Info($"Loaded {count} script(s) in {rfile.Name}");
|
||||
return count != 0;
|
||||
}
|
||||
private bool IsManagedAssembly(string filename)
|
||||
|
25
RageCoop.Core/Scripting/Scriptable.cs
Normal file
25
RageCoop.Core/Scripting/Scriptable.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Linq;
|
||||
namespace RageCoop.Core.Scripting
|
||||
{
|
||||
public abstract class Scriptable
|
||||
{
|
||||
public abstract void OnStart();
|
||||
public abstract void OnStop();
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="ResourceFile"/> instance where this script is loaded from.
|
||||
/// </summary>
|
||||
public ResourceFile CurrentFile { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="Resource"/> object this script belongs to, this property will be initiated before <see cref="OnStart"/> (will be null if you access it in the constructor).
|
||||
/// </summary>
|
||||
public Resource CurrentResource { get; internal set; }
|
||||
}
|
||||
}
|
@ -9,11 +9,14 @@
|
||||
<PackageProjectUrl>https://ragecoop.online/</PackageProjectUrl>
|
||||
<PackageRequireLicenseAcceptance>True</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<Product>$(AssemblyName)-V</Product>
|
||||
<PackageId>RAGECOOP-V</PackageId>
|
||||
<Product>$(AssemblyName)</Product>
|
||||
<PackageId>RageCoop.Server</PackageId>
|
||||
<Authors>RAGECOOP</Authors>
|
||||
<Version>0.5</Version>
|
||||
<DebugType>embedded</DebugType>
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<Description>An library for hosting a RAGECOOP server or API reference for developing a resource.</Description>
|
||||
<ApplicationIcon>favicon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
@ -23,7 +26,11 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DotNetZip" Version="1.16.0" />
|
||||
<Content Include="favicon.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="SharpZipLib" Version="1.3.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
using Lidgren.Network;
|
||||
using RageCoop.Core;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
|
||||
namespace RageCoop.Server.Scripting
|
||||
@ -221,14 +222,30 @@ namespace RageCoop.Server.Scripting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register a class of commands
|
||||
/// Register all commands in a static class
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The name of your class with functions</typeparam>
|
||||
/// <typeparam name="T">Your static class with commands</typeparam>
|
||||
public void RegisterCommands<T>()
|
||||
{
|
||||
Server.RegisterCommands<T>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register all commands inside an class instance
|
||||
/// </summary>
|
||||
/// <param name="obj">The instance of type containing the commands</param>
|
||||
public void RegisterCommands(object obj)
|
||||
{
|
||||
IEnumerable<MethodInfo> commands = obj.GetType().GetMethods().Where(method => method.GetCustomAttributes(typeof(Command), false).Any());
|
||||
|
||||
foreach (MethodInfo method in commands)
|
||||
{
|
||||
Command attribute = method.GetCustomAttribute<Command>(true);
|
||||
RegisterCommand(attribute.Name, attribute.Usage, attribute.ArgsLength,
|
||||
(ctx) => { method.Invoke(obj, new object[] { ctx }); });
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send an event and data to the specified clients. Use <see cref="Client.SendCustomEvent(int, List{object})"/> if you want to send event to individual client.
|
||||
/// </summary>
|
||||
|
@ -34,7 +34,7 @@ namespace RageCoop.Server.Scripting
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The hashed value of client password, sent with RSA asymmetric encryption.
|
||||
/// The client password hashed with SHA256 algorithm.
|
||||
/// </summary>
|
||||
public string PasswordHash { get; set; }
|
||||
public IPEndPoint EndPoint { get; set; }
|
||||
|
@ -5,7 +5,7 @@ using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using RageCoop.Core.Scripting;
|
||||
using System.IO;
|
||||
using Ionic.Zip;
|
||||
using ICSharpCode.SharpZipLib.Zip;
|
||||
using System.Reflection;
|
||||
namespace RageCoop.Server.Scripting
|
||||
{
|
||||
@ -16,64 +16,95 @@ namespace RageCoop.Server.Scripting
|
||||
{
|
||||
Server = server;
|
||||
}
|
||||
|
||||
public bool HasClientResources = false;
|
||||
private List<string> ClientResourceZips=new List<string>();
|
||||
public bool HasClientResources { get; private set; }
|
||||
public void LoadAll()
|
||||
{
|
||||
#region CLIENT
|
||||
var path = Path.Combine("Resources", "Client");
|
||||
var tmp = Path.Combine("Resources", "ClientTemp");
|
||||
Directory.CreateDirectory(path);
|
||||
var clientResources = Directory.GetDirectories(path);
|
||||
if (clientResources.Length!=0)
|
||||
if (Directory.Exists(tmp))
|
||||
{
|
||||
foreach(var dir in Directory.GetDirectories(tmp))
|
||||
{
|
||||
Directory.Delete(dir, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Directory.CreateDirectory(tmp);
|
||||
}
|
||||
var resourceFolders = Directory.GetDirectories(path,"*",SearchOption.TopDirectoryOnly);
|
||||
if (resourceFolders.Length!=0)
|
||||
{
|
||||
// Pack client side resources as a zip file
|
||||
Logger?.Info("Packing client-side resources");
|
||||
|
||||
try
|
||||
{
|
||||
var zippath = Path.Combine(path, "Resources.zip");
|
||||
if (File.Exists(zippath))
|
||||
HasClientResources=true;
|
||||
foreach (var resourceFolder in resourceFolders)
|
||||
{
|
||||
// Pack client side resource as a zip file
|
||||
Logger?.Info("Packing client-side resource:"+resourceFolder);
|
||||
var zipPath = Path.Combine(tmp, Path.GetFileName(resourceFolder));
|
||||
try
|
||||
{
|
||||
File.Delete(zippath);
|
||||
using (ZipFile zip = ZipFile.Create(zipPath))
|
||||
{
|
||||
foreach (var dir in Directory.GetDirectories(resourceFolder, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
zip.AddDirectory(dir.Substring(resourceFolder.Length+1));
|
||||
}
|
||||
foreach (var file in Directory.GetFiles(resourceFolder, "*", SearchOption.AllDirectories))
|
||||
{
|
||||
zip.Add(file,file.Substring(resourceFolder.Length+1));
|
||||
}
|
||||
zip.Close();
|
||||
ClientResourceZips.Add(zipPath);
|
||||
}
|
||||
}
|
||||
using (ZipFile zip = new ZipFile())
|
||||
catch (Exception ex)
|
||||
{
|
||||
zip.AddDirectory(path);
|
||||
zip.Save(zippath);
|
||||
Logger?.Error($"Failed to pack client resource:{resourceFolder}");
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
HasClientResources=true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger?.Error("Failed to pack client resources");
|
||||
Logger?.Error(ex);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
var packed = Directory.GetFiles(path, "*.zip", SearchOption.TopDirectoryOnly);
|
||||
if (packed.Length>0)
|
||||
{
|
||||
HasClientResources =true;
|
||||
ClientResourceZips.AddRange(packed);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region SERVER
|
||||
path = Path.Combine("Resources", "Server");
|
||||
#region SERVER
|
||||
path = Path.Combine("Resources", "Server");
|
||||
var dataFolder = Path.Combine(path, "data");
|
||||
Directory.CreateDirectory(path);
|
||||
foreach (var resource in Directory.GetDirectories(path))
|
||||
{
|
||||
if (Path.GetFileName(resource).ToLower()=="data") { continue; }
|
||||
Logger?.Info($"Loading resource: {Path.GetFileName(resource)}");
|
||||
LoadResource(resource);
|
||||
LoadResource(resource,dataFolder);
|
||||
}
|
||||
foreach(var resource in Directory.GetFiles(path, "*.zip", SearchOption.TopDirectoryOnly))
|
||||
{
|
||||
Logger?.Info($"Loading resource: {Path.GetFileName(resource)}");
|
||||
LoadResource(new ZipFile(resource), dataFolder);
|
||||
}
|
||||
|
||||
// Start scripts
|
||||
lock (LoadedResources)
|
||||
{
|
||||
foreach (var d in LoadedResources)
|
||||
foreach (var r in LoadedResources)
|
||||
{
|
||||
foreach (ServerScript s in d.Scripts)
|
||||
foreach (ServerScript s in r.Scripts)
|
||||
{
|
||||
s.CurrentResource = d;
|
||||
s.API=Server.API;
|
||||
try
|
||||
{
|
||||
Logger?.Debug("Starting script:"+s.CurrentFile.Name);
|
||||
s.OnStart();
|
||||
}
|
||||
catch(Exception ex) {Logger?.Error($"Failed to start resource: {d.Name}"); Logger?.Error(ex); }
|
||||
catch(Exception ex) {Logger?.Error($"Failed to start resource: {r.Name}"); Logger?.Error(ex); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
using System;
|
||||
using RageCoop.Core.Scripting;
|
||||
|
||||
namespace RageCoop.Server.Scripting
|
||||
{
|
||||
/// <summary>
|
||||
/// Inherit from this class, constructor will be called automatically, but other scripts might have yet been loaded and <see cref="API"/> will be null, you should use <see cref="OnStart"/>. to initiate your script.
|
||||
/// </summary>
|
||||
public abstract class ServerScript :Core.Scripting.IScriptable
|
||||
public abstract class ServerScript : Scriptable
|
||||
{
|
||||
/// <summary>
|
||||
/// This method would be called from main thread after all scripts have been loaded.
|
||||
/// </summary>
|
||||
public abstract void OnStart();
|
||||
public override abstract void OnStart();
|
||||
|
||||
/// <summary>
|
||||
/// This method would be called from main thread when the server is shutting down, you MUST terminate all background jobs/threads in this method.
|
||||
/// </summary>
|
||||
public abstract void OnStop();
|
||||
/// <summary>
|
||||
/// Get the <see cref="Core.Scripting.Resource"/> object this script belongs to, this property will be initiated before <see cref="OnStart"/> (will be null if you access it in the constructor).
|
||||
/// </summary>
|
||||
public Core.Scripting.Resource CurrentResource { get;internal set; }
|
||||
public override abstract void OnStop();
|
||||
|
||||
public API API { get; set; }
|
||||
}
|
||||
|
@ -24,21 +24,21 @@ namespace RageCoop.Server
|
||||
public string Address { get; set; }
|
||||
}
|
||||
|
||||
internal class Server
|
||||
public class Server
|
||||
{
|
||||
private readonly string _compatibleVersion = "V0_5";
|
||||
public BaseScript BaseScript { get; set; }=new BaseScript();
|
||||
public readonly Settings MainSettings = Util.Read<Settings>("Settings.xml");
|
||||
public NetServer MainNetServer;
|
||||
internal BaseScript BaseScript { get; set; }=new BaseScript();
|
||||
internal readonly Settings MainSettings = Util.Read<Settings>("Settings.xml");
|
||||
internal NetServer MainNetServer;
|
||||
|
||||
public readonly Dictionary<Command, Action<CommandContext>> Commands = new();
|
||||
public readonly Dictionary<long,Client> Clients = new();
|
||||
internal readonly Dictionary<Command, Action<CommandContext>> Commands = new();
|
||||
internal readonly Dictionary<long,Client> Clients = new();
|
||||
private System.Timers.Timer SendPlayerTimer = new System.Timers.Timer(5000);
|
||||
|
||||
private Dictionary<int,FileTransfer> InProgressFileTransfers=new();
|
||||
private Resources Resources;
|
||||
public API API;
|
||||
public Logger Logger;
|
||||
public API API { get; private set; }
|
||||
internal Logger Logger;
|
||||
private Security Security;
|
||||
public Server(Logger logger=null)
|
||||
{
|
||||
@ -58,8 +58,7 @@ namespace RageCoop.Server
|
||||
Port = MainSettings.Port,
|
||||
MaximumConnections = MainSettings.MaxPlayers,
|
||||
EnableUPnP = false,
|
||||
AutoFlushSendQueue = true,
|
||||
MaximumTransmissionUnit=2000, // PublicKeyResponse
|
||||
AutoFlushSendQueue = true
|
||||
};
|
||||
|
||||
config.EnableMessageType(NetIncomingMessageType.ConnectionApproval);
|
||||
@ -436,7 +435,7 @@ namespace RageCoop.Server
|
||||
MainNetServer.Recycle(message);
|
||||
}
|
||||
object _sendPlayersLock=new object();
|
||||
public void SendPlayerInfos()
|
||||
internal void SendPlayerInfos()
|
||||
{
|
||||
lock (_sendPlayersLock)
|
||||
{
|
||||
@ -499,7 +498,7 @@ namespace RageCoop.Server
|
||||
try
|
||||
{
|
||||
Security.AddConnection(connection.RemoteEndPoint, packet.AesKeyCrypted,packet.AesIVCrypted);
|
||||
passhash=Security.Decrypt(packet.PassHashEncrypted,connection.RemoteEndPoint).GetString();
|
||||
passhash=BitConverter.ToString(Security.Decrypt(packet.PassHashEncrypted, connection.RemoteEndPoint)).Replace("-", String.Empty);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -759,7 +758,7 @@ namespace RageCoop.Server
|
||||
Logger?.Info(packet.Username + ": " + packet.Message);
|
||||
}
|
||||
|
||||
public void SendChatMessage(string username, string message, List<NetConnection> targets = null)
|
||||
internal void SendChatMessage(string username, string message, List<NetConnection> targets = null)
|
||||
{
|
||||
if (MainNetServer.Connections.Count==0) { return; }
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
@ -768,14 +767,14 @@ namespace RageCoop.Server
|
||||
|
||||
MainNetServer.SendMessage(outgoingMessage, targets ?? MainNetServer.Connections, NetDeliveryMethod.ReliableOrdered, (byte)ConnectionChannel.Chat);
|
||||
}
|
||||
public void SendChatMessage(string username, string message, NetConnection target)
|
||||
internal void SendChatMessage(string username, string message, NetConnection target)
|
||||
{
|
||||
SendChatMessage(username, message, new List<NetConnection>() { target });
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
public void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
||||
internal void RegisterCommand(string name, string usage, short argsLength, Action<CommandContext> callback)
|
||||
{
|
||||
Command command = new(name) { Usage = usage, ArgsLength = argsLength };
|
||||
|
||||
@ -786,7 +785,7 @@ namespace RageCoop.Server
|
||||
|
||||
Commands.Add(command, callback);
|
||||
}
|
||||
public void RegisterCommand(string name, Action<CommandContext> callback)
|
||||
internal void RegisterCommand(string name, Action<CommandContext> callback)
|
||||
{
|
||||
Command command = new(name);
|
||||
|
||||
@ -798,7 +797,7 @@ namespace RageCoop.Server
|
||||
Commands.Add(command, callback);
|
||||
}
|
||||
|
||||
public void RegisterCommands<T>()
|
||||
internal void RegisterCommands<T>()
|
||||
{
|
||||
IEnumerable<MethodInfo> commands = typeof(T).GetMethods().Where(method => method.GetCustomAttributes(typeof(Command), false).Any());
|
||||
|
||||
@ -810,7 +809,7 @@ namespace RageCoop.Server
|
||||
}
|
||||
}
|
||||
|
||||
public void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
|
||||
internal void SendFile(string path,string name,Client client,Action<float> updateCallback=null)
|
||||
{
|
||||
int id = RequestFileID();
|
||||
var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
@ -890,7 +889,7 @@ namespace RageCoop.Server
|
||||
/// <param name="p"></param>
|
||||
/// <param name="channel"></param>
|
||||
/// <param name="method"></param>
|
||||
public void Send(Packet p,Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
||||
internal void Send(Packet p,Client client, ConnectionChannel channel = ConnectionChannel.Default, NetDeliveryMethod method = NetDeliveryMethod.UnreliableSequenced)
|
||||
{
|
||||
NetOutgoingMessage outgoingMessage = MainNetServer.CreateMessage();
|
||||
p.Pack(outgoingMessage);
|
||||
|
BIN
RageCoop.Server/favicon.ico
Normal file
BIN
RageCoop.Server/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
Reference in New Issue
Block a user