Get command system working, permissions system and ModAPI extensions in progress

This commit is contained in:
John Gross
2017-01-11 00:19:21 -08:00
parent 4949982fa8
commit 10836cbbb2
27 changed files with 625 additions and 149 deletions

View File

@@ -1,6 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using VRage.Game;
using VRage.Game.ModAPI;
namespace Torch.API namespace Torch.API
{ {
@@ -12,7 +14,9 @@ namespace Torch.API
Dictionary<ulong, IPlayer> Players { get; } Dictionary<ulong, IPlayer> Players { get; }
List<IChatItem> Chat { get; } List<IChatItem> Chat { get; }
void SendMessage(string message); void SendMessage(string message);
void SendMessage(string message, long playerId, string author = "Server", string font = MyFontEnum.Blue);
void KickPlayer(ulong id); void KickPlayer(ulong id);
void BanPlayer(ulong id, bool banned = true); void BanPlayer(ulong id, bool banned = true);
IMyPlayer GetPlayerBySteamId(ulong id);
} }
} }

View File

@@ -8,7 +8,7 @@ namespace Torch.API
public interface IPluginManager : IEnumerable<ITorchPlugin> public interface IPluginManager : IEnumerable<ITorchPlugin>
{ {
void UpdatePlugins(); void UpdatePlugins();
void LoadPlugins(); void Init();
void UnloadPlugins(); void UnloadPlugins();
} }
} }

View File

@@ -11,6 +11,7 @@ namespace Torch.API
event Action SessionLoaded; event Action SessionLoaded;
IMultiplayer Multiplayer { get; } IMultiplayer Multiplayer { get; }
IPluginManager Plugins { get; } IPluginManager Plugins { get; }
Version Version { get; }
void Invoke(Action action); void Invoke(Action action);
void InvokeBlocking(Action action); void InvokeBlocking(Action action);
Task InvokeAsync(Action action); Task InvokeAsync(Action action);

View File

@@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Game.Entities.Blocks;
using Sandbox.ModAPI.Ingame;
using VRage.Game.ModAPI.Ingame;
namespace Torch.API.ModAPI.Ingame
{
public static class GridExtensions
{
}
public static class PistonExtensions
{
public static IMyCubeGrid GetConnectedGrid(this IMyPistonBase pistonBase)
{
if (!pistonBase.IsAttached)
return null;
return ((Sandbox.ModAPI.IMyPistonBase)pistonBase).TopGrid;
}
}
public static class RotorExtensions
{
public static IMyCubeGrid GetConnectedGrid(this IMyMotorStator rotorBase)
{
if (!rotorBase.IsAttached)
return null;
return ((Sandbox.ModAPI.IMyMotorStator)rotorBase).RotorGrid;
}
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Torch.API.ModAPI
{
public static class TorchAPI
{
}
}

View File

@@ -38,6 +38,24 @@
</Reference> </Reference>
<Reference Include="PresentationCore" /> <Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" /> <Reference Include="PresentationFramework" />
<Reference Include="Sandbox.Common">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\Sandbox.Common.dll</HintPath>
</Reference>
<Reference Include="Sandbox.Game">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\Sandbox.Game.dll</HintPath>
</Reference>
<Reference Include="Sandbox.Graphics">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\Sandbox.Graphics.dll</HintPath>
</Reference>
<Reference Include="SpaceEngineers.Game">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\SpaceEngineers.Game.dll</HintPath>
</Reference>
<Reference Include="SpaceEngineers.ObjectBuilders">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\SpaceEngineers.ObjectBuilders.dll</HintPath>
</Reference>
<Reference Include="SpaceEngineers.ObjectBuilders.XmlSerializers">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\SpaceEngineers.ObjectBuilders.XmlSerializers.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@@ -55,11 +73,41 @@
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.dll</HintPath> <HintPath>C:\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="VRage.Audio">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Audio.dll</HintPath>
</Reference>
<Reference Include="VRage.Game">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Game.dll</HintPath>
</Reference>
<Reference Include="VRage.Game.XmlSerializers">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Game.XmlSerializers.dll</HintPath>
</Reference>
<Reference Include="VRage.Input">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Input.dll</HintPath>
</Reference>
<Reference Include="VRage.Library, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="VRage.Library, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Library.dll</HintPath> <HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Library.dll</HintPath>
<Private>False</Private> <Private>False</Private>
</Reference> </Reference>
<Reference Include="VRage.Math">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Math.dll</HintPath>
</Reference>
<Reference Include="VRage.Native">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Native.dll</HintPath>
</Reference>
<Reference Include="VRage.OpenVRWrapper">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.OpenVRWrapper.dll</HintPath>
</Reference>
<Reference Include="VRage.Render">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Render.dll</HintPath>
</Reference>
<Reference Include="VRage.Render11">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Render11.dll</HintPath>
</Reference>
<Reference Include="VRage.Scripting">
<HintPath>..\..\..\..\..\..\..\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Scripting.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="ConnectionState.cs" /> <Compile Include="ConnectionState.cs" />
@@ -70,6 +118,8 @@
<Compile Include="ITorchPlugin.cs" /> <Compile Include="ITorchPlugin.cs" />
<Compile Include="IServerControls.cs" /> <Compile Include="IServerControls.cs" />
<Compile Include="ITorchBase.cs" /> <Compile Include="ITorchBase.cs" />
<Compile Include="ModAPI\Ingame\GridExtensions.cs" />
<Compile Include="ModAPI\TorchAPI.cs" />
<Compile Include="PluginAttribute.cs" /> <Compile Include="PluginAttribute.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup> </ItemGroup>

View File

@@ -1,5 +1,7 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Configuration.Install;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -34,6 +36,18 @@ namespace Torch.Server
if (args.FirstOrDefault() == "-svcinstall") if (args.FirstOrDefault() == "-svcinstall")
{ {
/* Working on installing the service properly instead of with sc.exe
_log.Info("Installing service");
var installer = new TorchServiceInstaller();
installer.Context = new InstallContext(Path.Combine(Directory.GetCurrentDirectory(), "svclog.log"), null);
installer.Context.Parameters.Add("name", "Torch DS");
installer.Install(new Hashtable
{
{"name", "Torch DS"}
});
_log.Info("Service Installed");*/
var runArgs = string.Join(" ", args.Skip(1)); var runArgs = string.Join(" ", args.Skip(1));
_log.Info($"Installing Torch as a service with arguments '{runArgs}'"); _log.Info($"Installing Torch as a service with arguments '{runArgs}'");
var startInfo = new ProcessStartInfo var startInfo = new ProcessStartInfo

View File

@@ -27,14 +27,22 @@ namespace Torch.Server
{ {
public Thread GameThread { get; private set; } public Thread GameThread { get; private set; }
public bool IsRunning { get; private set; } public bool IsRunning { get; private set; }
public bool IsService { get; set; } public bool IsService { get; }
public string InstancePath { get; private set; }
public string InstanceName { get; }
public event Action SessionLoading; public event Action SessionLoading;
private readonly AutoResetEvent _stopHandle = new AutoResetEvent(false); private readonly AutoResetEvent _stopHandle = new AutoResetEvent(false);
internal TorchServer() internal TorchServer(string instanceName = null)
{ {
if (instanceName != null)
{
IsService = true;
InstanceName = instanceName;
}
MySession.OnLoading += OnSessionLoading; MySession.OnLoading += OnSessionLoading;
} }
@@ -59,6 +67,8 @@ namespace Torch.Server
}; };
var gameVersion = MyPerGameSettings.BasicGameInfo.GameVersion; var gameVersion = MyPerGameSettings.BasicGameInfo.GameVersion;
MyFinalBuildConstants.APP_VERSION = gameVersion ?? 0; MyFinalBuildConstants.APP_VERSION = gameVersion ?? 0;
InstancePath = InstanceName != null ? GetInstancePath(true, InstanceName) : GetInstancePath();
} }
private void OnSessionLoading() private void OnSessionLoading()
@@ -87,7 +97,7 @@ namespace Torch.Server
Environment.SetEnvironmentVariable("SteamAppId", MyPerServerSettings.AppId.ToString()); Environment.SetEnvironmentVariable("SteamAppId", MyPerServerSettings.AppId.ToString());
Log.Trace("Invoking RunMain"); Log.Trace("Invoking RunMain");
try { Reflection.InvokeStaticMethod(typeof(DedicatedServer), "RunMain", "Torch", null, IsService, true); } try { Reflection.InvokeStaticMethod(typeof(DedicatedServer), "RunMain", InstanceName, InstancePath, false, true); }
catch (Exception e) catch (Exception e)
{ {
Log.Error(e); Log.Error(e);
@@ -131,6 +141,14 @@ namespace Torch.Server
IsRunning = false; IsRunning = false;
} }
private string GetInstancePath(bool isService = false, string instanceName = "Torch")
{
if (isService)
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), MyPerServerSettings.GameDSName, instanceName);
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), MyPerServerSettings.GameDSName);
}
private void CleanupProfilers() private void CleanupProfilers()
{ {
typeof(MyRenderProfiler).GetField("m_threadProfiler", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, null); typeof(MyRenderProfiler).GetField("m_threadProfiler", BindingFlags.Static | BindingFlags.NonPublic).SetValue(null, null);

View File

@@ -12,7 +12,7 @@ namespace Torch.Server
class TorchService : ServiceBase class TorchService : ServiceBase
{ {
public const string Name = "Torch (SEDS)"; public const string Name = "Torch (SEDS)";
private readonly TorchServer _server = new TorchServer(); private TorchServer _server;
private static Logger _log = LogManager.GetLogger("Torch"); private static Logger _log = LogManager.GetLogger("Torch");
public TorchService() public TorchService()
@@ -30,9 +30,9 @@ namespace Torch.Server
protected override void OnStart(string[] args) protected override void OnStart(string[] args)
{ {
base.OnStart(args); base.OnStart(args);
_server = new TorchServer("Torch");
_server.Init(); _server.Init();
_server.RunArgs = args; _server.RunArgs = args;
_server.IsService = true;
Task.Run(() => _server.Start()); Task.Run(() => _server.Start());
} }

View File

@@ -11,7 +11,7 @@ using System.Threading.Tasks;
namespace Torch.Server namespace Torch.Server
{ {
[RunInstaller(true)] [RunInstaller(true)]
class TorchServiceInstaller : Installer public class TorchServiceInstaller : Installer
{ {
private ServiceInstaller _serviceInstaller; private ServiceInstaller _serviceInstaller;

View File

@@ -8,7 +8,7 @@ namespace Torch.Commands
{ {
public class CategoryAttribute : Attribute public class CategoryAttribute : Attribute
{ {
public string[] Path { get; } public List<string> Path { get; }
/// <summary> /// <summary>
/// Specifies where to add the class's commands in the command tree. /// Specifies where to add the class's commands in the command tree.
@@ -16,7 +16,7 @@ namespace Torch.Commands
/// <param name="path">Command path, e.g. "/admin config" -> "admin, config"</param> /// <param name="path">Command path, e.g. "/admin config" -> "admin, config"</param>
public CategoryAttribute(params string[] path) public CategoryAttribute(params string[] path)
{ {
Path = path; Path = path.Select(i => i.ToLower()).ToList();
} }
} }
} }

View File

@@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using Torch.API; using Torch.API;
@@ -12,7 +13,7 @@ namespace Torch.Commands
public string Description { get; } public string Description { get; }
public string HelpText { get; } public string HelpText { get; }
public Type Module { get; } public Type Module { get; }
public string[] Path { get; } public List<string> Path { get; } = new List<string>();
public ITorchPlugin Plugin { get; } public ITorchPlugin Plugin { get; }
private readonly MethodInfo _method; private readonly MethodInfo _method;
@@ -31,16 +32,13 @@ namespace Torch.Commands
_method = commandMethod; _method = commandMethod;
Module = commandMethod.DeclaringType; Module = commandMethod.DeclaringType;
var path = commandAttribute.Path;
if (moduleAttribute != null) if (moduleAttribute != null)
{ {
var modPath = moduleAttribute.Path; Path.AddRange(moduleAttribute.Path);
var comPath = commandAttribute.Path;
path = new string[modPath.Length + comPath.Length];
modPath.CopyTo(path, 0);
comPath.CopyTo(path, modPath.Length);
} }
Path = path; Path.AddRange(commandAttribute.Path);
Name = commandAttribute.Name; Name = commandAttribute.Name;
Description = commandAttribute.Description; Description = commandAttribute.Description;
HelpText = commandAttribute.HelpText; HelpText = commandAttribute.HelpText;
@@ -50,7 +48,7 @@ namespace Torch.Commands
{ {
var moduleInstance = (CommandModule)Activator.CreateInstance(Module); var moduleInstance = (CommandModule)Activator.CreateInstance(Module);
moduleInstance.Context = context; moduleInstance.Context = context;
_method.Invoke(moduleInstance, new object[0]); _method.Invoke(moduleInstance, null);
} }
} }
} }

View File

@@ -1,4 +1,6 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
namespace Torch.Commands namespace Torch.Commands
{ {
@@ -7,14 +9,16 @@ namespace Torch.Commands
public string Name { get; } public string Name { get; }
public string Description { get; } public string Description { get; }
public string HelpText { get; } public string HelpText { get; }
public string[] Path { get; } public List<string> Path { get; } = new List<string>();
public CommandAttribute(string name, string description = "", string helpText = "", params string[] path) public CommandAttribute(string name, string description = "", string helpText = null, params string[] path)
{ {
Name = name; Name = name;
Description = description; Description = description;
HelpText = helpText; HelpText = helpText ?? description;
Path = path.Length > 0 ? path : new [] {name.ToLower()};
Path.AddRange(path.Select(x => x.ToLower()));
Path.Add(name.ToLower());
} }
} }
} }

View File

@@ -1,36 +1,34 @@
using System.Linq; using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Torch.API; using Torch.API;
using VRage.Game;
using VRage.Game.ModAPI; using VRage.Game.ModAPI;
namespace Torch.Commands namespace Torch.Commands
{ {
public struct CommandContext public class CommandContext
{ {
public ITorchPlugin Plugin { get; } public ITorchPlugin Plugin { get; }
public ITorchBase Torch { get; } public ITorchBase Torch { get; }
public IMyPlayer Player { get; } public IMyPlayer Player { get; }
public string[] Args { get; } public List<string> Args { get; }
/// <summary> /// <summary>
/// Splits the argument by single words and quoted blocks. /// Splits the argument by single words and quoted blocks.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public CommandContext(ITorchBase torch, ITorchPlugin plugin, IMyPlayer player, params string[] args) public CommandContext(ITorchBase torch, ITorchPlugin plugin, IMyPlayer player, List<string> args = null)
{ {
Torch = torch; Torch = torch;
Plugin = plugin; Plugin = plugin;
Player = player; Player = player;
Args = args; Args = args ?? new List<string>();
}
/* public void Respond(string message, string sender = "Server", string font = MyFontEnum.Blue)
var split = Regex.Split(Args, "(\"[^\"]+\"|\\S+)");
for (var i = 0; i < split.Length; i++)
{ {
split[i] = Regex.Replace(split[i], "\"", ""); Torch.Multiplayer.SendMessage(message, Player.PlayerID, sender, font);
}
return split;*/
} }
} }
} }

View File

@@ -1,47 +1,36 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text.RegularExpressions;
using NLog; using NLog;
using Torch.API; using Torch.API;
using Torch.Managers;
using VRage.Game.ModAPI; using VRage.Game.ModAPI;
using VRage.Network;
namespace Torch.Commands namespace Torch.Commands
{ {
public class PermissionGroup
{
public List<ulong> Members { get; }
public List<Permission> Permissions { get; }
}
public class PermissionUser
{
public ulong SteamID { get; }
public List<PermissionGroup> Groups { get; }
public List<Permission> Permissions { get; }
}
public class Permission
{
public string[] Path { get; }
public bool Allow { get; }
}
public class CommandManager public class CommandManager
{ {
public ITorchBase Torch { get; }
public char Prefix { get; set; } public char Prefix { get; set; }
public Dictionary<string, Command> Commands { get; } = new Dictionary<string, Command>(); public CommandTree Commands { get; set; } = new CommandTree();
private Logger _log = LogManager.GetLogger(nameof(CommandManager)); private Logger _log = LogManager.GetLogger(nameof(CommandManager));
private readonly ITorchBase _torch;
private readonly ChatManager _chatManager = ChatManager.Instance;
public CommandManager(ITorchBase torch, char prefix = '/') public CommandManager(ITorchBase torch, char prefix = '/')
{ {
Torch = torch; _torch = torch;
Prefix = prefix; Prefix = prefix;
_chatManager.MessageRecieved += HandleCommand;
RegisterCommandModule(typeof(TorchCommands));
} }
public bool HasPermission(ulong steamId, Command command) public bool HasPermission(ulong steamId, Command command)
{ {
_log.Warn("Command permissions not implemented");
return true; return true;
} }
@@ -50,39 +39,72 @@ namespace Torch.Commands
return command.Length > 1 && command[0] == Prefix; return command.Length > 1 && command[0] == Prefix;
} }
public void RegisterPluginCommands(ITorchPlugin plugin) public void RegisterCommandModule(Type moduleType, ITorchPlugin plugin = null)
{ {
var assembly = plugin.GetType().Assembly; if (!moduleType.IsSubclassOf(typeof(CommandModule)))
foreach (var type in assembly.ExportedTypes) return;
{
if (!type.IsSubclassOf(typeof(CommandModule)))
continue;
foreach (var method in type.GetMethods()) foreach (var method in moduleType.GetMethods())
{ {
var commandAttrib = method.GetCustomAttribute<CommandAttribute>(); var commandAttrib = method.GetCustomAttribute<CommandAttribute>();
if (commandAttrib == null) if (commandAttrib == null)
continue; continue;
var command = new Command(plugin, method); var command = new Command(plugin, method);
_log.Info($"Registering command '{string.Join(".", command.Path)}' from plugin '{plugin.Name}'"); var cmdPath = string.Join(".", command.Path);
} _log.Info($"Registering command '{cmdPath}'");
if (!Commands.AddCommand(command))
_log.Error($"Command path {cmdPath} is already registered.");
} }
} }
public void HandleCommand(string command, ulong steamId = 0) public void RegisterPluginCommands(ITorchPlugin plugin)
{ {
if (!IsCommand(command)) var assembly = plugin.GetType().Assembly;
foreach (var type in assembly.ExportedTypes)
{
RegisterCommandModule(type, plugin);
}
}
public void HandleCommand(ChatMsg msg, ref bool sendToOthers)
{
if (msg.Text.Length < 1 || msg.Text[0] != Prefix)
return; return;
var cmdNameEnd = command.Length - command.IndexOf(" ", StringComparison.InvariantCultureIgnoreCase); sendToOthers = false;
var cmdName = command.Substring(1, cmdNameEnd);
if (!Commands.ContainsKey(cmdName)) var player = _torch.Multiplayer.GetPlayerBySteamId(msg.Author);
if (player == null)
{
_log.Error($"Command {msg.Text} invoked by nonexistant player");
return;
}
var cmdText = new string(msg.Text.Skip(1).ToArray());
var split = Regex.Matches(cmdText, "(\"[^\"]+\"|\\S+)").Cast<Match>().Select(x => x.ToString().Replace("\"", "")).ToList();
if (split.Count == 0)
return; return;
string arg = ""; var command = Commands.ParseCommand(split, out List<string> args);
if (command.Length > cmdNameEnd + 1)
arg = command.Substring(cmdNameEnd + 1); if (command != null)
{
var cmdPath = string.Join(".", command.Path);
if (!HasPermission(msg.Author, command))
{
_log.Info($"{player.DisplayName} tried to use command {cmdPath} without permission");
return;
}
_log.Trace($"Invoking {cmdPath} for player {player.DisplayName}");
var context = new CommandContext(_torch, command.Plugin, player, args);
command.Invoke(context);
_log.Info($"Player {player.DisplayName} ran command '{msg.Text}'");
}
} }
} }
} }

View File

@@ -3,29 +3,42 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using VRage.Collections;
using VRage.Library.Collections; using VRage.Library.Collections;
namespace Torch.Commands namespace Torch.Commands
{ {
public class CommandTree public class CommandTree
{ {
private Dictionary<string, Node> RootNodes { get; } = new Dictionary<string, Node>(); public DictionaryReader<string, CommandNode> Root { get; }
private readonly Dictionary<string, CommandNode> _root = new Dictionary<string, CommandNode>();
public CommandTree()
{
Root = new DictionaryReader<string, CommandNode>(_root);
}
public bool AddCommand(Command command) public bool AddCommand(Command command)
{ {
var root = command.Path.First(); var root = command.Path.First();
var node = RootNodes.ContainsKey(root) ? RootNodes[root] : new Node(root);
for (var i = 1; i < command.Path.Length; i++) if (!_root.ContainsKey(root))
{
_root.Add(root, new CommandNode(root));
}
var node = _root[root];
for (var i = 1; i < command.Path.Count; i++)
{ {
var current = command.Path[i]; var current = command.Path[i];
if (node.Nodes.ContainsKey(current)) if (node.Subcommands.ContainsKey(current))
{ {
node = node.Nodes[current]; node = node.Subcommands[current];
continue; continue;
} }
var newNode = new Node(current); var newNode = new CommandNode(current);
node.AddNode(newNode); node.AddNode(newNode);
node = newNode; node = newNode;
} }
@@ -37,59 +50,119 @@ namespace Torch.Commands
return true; return true;
} }
public Command ParseCommand(ulong steamId, string[] command, out string[] args) /// <summary>
/// Get a command node from the tree.
/// </summary>
/// <param name="path">Path to the command node.</param>
/// <param name="commandNode"></param>
/// <returns>The index of the first argument in the path or -1 if the node doesn't exist.</returns>
public int GetNode(List<string> path, out CommandNode commandNode)
{ {
args = new string[0]; commandNode = null;
var root = command.First(); var root = path.FirstOrDefault();
if (!RootNodes.ContainsKey(root)) if (root == null)
return null; return -1;
var node = RootNodes[root]; if (!_root.ContainsKey(root))
for (var i = 1; i < command.Length; i++) return -1;
var node = _root[root];
var i = 1;
for (; i < path.Count; i++)
{ {
var current = command[i]; var current = path[i];
if (node.Nodes.ContainsKey(current)) if (node.Subcommands.ContainsKey(current))
{ {
node = node.Nodes[current]; node = node.Subcommands[current];
continue; }
} }
args = new string[command.Length - i]; commandNode = node;
Array.Copy(command, i, args, 0, args.Length); return path.Count - i + 1;
} }
if (!node.IsCommand) public Command ParseCommand(List<string> path, out List<string> args)
return null; {
args = new List<string>();
var skip = GetNode(path, out CommandNode node);
args.AddRange(path.Skip(skip));
return node.Command; return node.Command;
} }
private class Node
public string GetTreeString()
{ {
public Dictionary<string, Node> Nodes { get; } = new Dictionary<string, Node>(); var indent = 0;
var sb = new StringBuilder();
foreach (var node in _root)
{
DebugNode(node.Value, sb, ref indent);
}
return sb.ToString();
}
private void DebugNode(CommandNode commandNode, StringBuilder sb, ref int indent)
{
sb.AppendLine(new string(' ', indent) + commandNode.Name);
indent += 2;
foreach (var n in commandNode.Subcommands)
{
DebugNode(n.Value, sb, ref indent);
}
indent -= 2;
}
public class CommandNode
{
public CommandNode Parent { get; private set; }
public DictionaryReader<string, CommandNode> Subcommands { get; }
private readonly Dictionary<string, CommandNode> _subcommands = new Dictionary<string, CommandNode>();
public string Name { get; } public string Name { get; }
public Command Command { get; set; } public Command Command { get; set; }
public bool IsCommand => Command != null; public bool IsCommand => Command != null;
public bool IsEmpty => !IsCommand && Nodes.Count == 0; public bool IsEmpty => !IsCommand && _subcommands.Count == 0;
public Node(string name, Command command = null) public CommandNode(string name)
{ {
Subcommands = new DictionaryReader<string, CommandNode>(_subcommands);
Name = name; Name = name;
}
public CommandNode(Command command)
{
Name = command.Name;
Command = command; Command = command;
} }
public void AddNode(Node node) public bool TryGetChild(string name, out CommandNode node)
{ {
Nodes.Add(node.Name, node); return Subcommands.TryGetValue(name, out node);
}
} }
public enum InvokeResult public List<string> GetPath()
{ {
Success, var path = new List<string> {Name};
NoCommand, if (Parent != null)
NoPermission path.InsertRange(0, Parent.GetPath());
return path;
}
public void AddNode(CommandNode commandNode)
{
commandNode.Parent = this;
_subcommands.Add(commandNode.Name, commandNode);
}
public void RemoveNode(CommandNode commandNode)
{
commandNode.Parent = null;
_subcommands.Remove(commandNode.Name);
}
} }
} }
} }

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VRage.Game.ModAPI;
namespace Torch.Commands
{
public class DefaultPermissionAttribute : Attribute
{
public MyPromoteLevel Level { get; }
public DefaultPermissionAttribute(MyPromoteLevel level)
{
Level = level;
}
}
}

View File

@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Sandbox.Game.World;
using VRage.Game.ModAPI;
namespace Torch.Commands.Permissions
{
public class PermissionGroup
{
public List<ulong> Members { get; }
public List<Permission> Permissions { get; }
public void AddMember(PermissionUser user)
{
Members.Add(user.SteamID);
user.Groups.Add(this);
}
public void RemoveMember(PermissionUser user)
{
user.Groups.Remove(this);
Members.Remove(user.SteamID);
}
}
public class PermissionUser
{
public ulong SteamID { get; }
public List<PermissionGroup> Groups { get; }
public List<Permission> Permissions { get; }
public void AddToGroup(PermissionGroup group)
{
group.Members.Add(SteamID);
Groups.Add(group);
}
public void RemoveFromGroup(PermissionGroup group)
{
group.Members.Remove(SteamID);
Groups.Remove(group);
}
public void HasPermission()
{
var promoteLevel = MySession.Static.GetUserPromoteLevel(SteamID);
}
}
public class Permission
{
public string[] Path { get; }
public bool Allow { get; }
public Dictionary<string, Permission> Children { get; } = new Dictionary<string, Permission>();
}
public class PermissonsSystem
{
public Dictionary<string, PermissionGroup> Groups { get; } = new Dictionary<string, PermissionGroup>();
public Dictionary<long, PermissionUser> Users { get; } = new Dictionary<long, PermissionUser>();
public void GenerateDefaultGroups()
{
foreach (var name in Enum.GetNames(typeof(MyPromoteLevel)))
{
Groups.Add(name, new PermissionGroup());
}
}
}
}

View File

@@ -0,0 +1,68 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Torch.Managers;
namespace Torch.Commands
{
public class TorchCommands : CommandModule
{
[Command("dbgcmd")]
public void Dbgcmd()
{
var commandManager = ((PluginManager)Context.Torch.Plugins).Commands;
Console.WriteLine(commandManager.Commands.GetTreeString());
}
[Command("help", "Displays help for a command")]
public void Help()
{
var commandManager = ((PluginManager)Context.Torch.Plugins).Commands;
commandManager.Commands.GetNode(Context.Args, out CommandTree.CommandNode node);
if (node != null)
{
var command = node.Command;
var children = node.Subcommands.Select(x => x.Key);
var sb = new StringBuilder();
if (command != null)
sb.AppendLine(command.HelpText);
if (children.Any())
sb.AppendLine($"Subcommands: {string.Join(", ", children)}");
Context.Respond(sb.ToString());
}
else
{
var topNodeNames = commandManager.Commands.Root.Select(x => x.Key);
Context.Respond($"Top level commands: {string.Join(", ", topNodeNames)}");
}
}
[Command("ver", "Shows the running Torch version.")]
public void Version()
{
var ver = Context.Torch.Version;
Context.Respond($"Torch version: {ver}");
}
[Command("plugins", "Lists the currently loaded plugins.")]
public void Plugins()
{
var plugins = Context.Torch.Plugins.Select(p => p.Name);
Context.Respond($"Loaded plugins: {string.Join(", ", plugins)}");
}
[Command("stop", "Stops the server.")]
public void Stop()
{
Context.Respond("Stopping server.");
Context.Torch.Stop();
}
}
}

View File

@@ -11,7 +11,7 @@ namespace Torch.Managers
{ {
public class ChatManager public class ChatManager
{ {
public ChatManager() private ChatManager()
{ {
NetworkManager.Instance.RegisterNetworkHandlers(new ChatIntercept()); NetworkManager.Instance.RegisterNetworkHandlers(new ChatIntercept());
} }

View File

@@ -27,7 +27,7 @@ using VRage.Library.Collections;
using VRage.Network; using VRage.Network;
using VRage.Utils; using VRage.Utils;
namespace Torch namespace Torch.Managers
{ {
/// <summary> /// <summary>
/// Provides a proxy to the game's multiplayer-related functions. /// Provides a proxy to the game's multiplayer-related functions.
@@ -38,13 +38,11 @@ namespace Torch
public event Action<IPlayer> PlayerLeft; public event Action<IPlayer> PlayerLeft;
public event Action<IChatItem> MessageReceived; public event Action<IChatItem> MessageReceived;
//public MTObservableCollection<MyPlayer> PlayersView { get; } = new MTObservableCollection<MyPlayer>();
//public MTObservableCollection<ChatItem> ChatView { get; } = new MTObservableCollection<ChatItem>();
public List<IChatItem> Chat { get; } = new List<IChatItem>(); public List<IChatItem> Chat { get; } = new List<IChatItem>();
public Dictionary<ulong, IPlayer> Players { get; } = new Dictionary<ulong, IPlayer>(); public Dictionary<ulong, IPlayer> Players { get; } = new Dictionary<ulong, IPlayer>();
public Player LocalPlayer { get; private set; } public Player LocalPlayer { get; private set; }
private readonly ITorchBase _torch; private readonly ITorchBase _torch;
private static Logger _log = LogManager.GetLogger("Torch"); private static Logger _log = LogManager.GetLogger(nameof(MultiplayerManager));
private Dictionary<MyPlayer.PlayerId, MyPlayer> _onlinePlayers; private Dictionary<MyPlayer.PlayerId, MyPlayer> _onlinePlayers;
internal MultiplayerManager(ITorchBase torch) internal MultiplayerManager(ITorchBase torch)
@@ -53,11 +51,11 @@ namespace Torch
_torch.SessionLoaded += OnSessionLoaded; _torch.SessionLoaded += OnSessionLoaded;
} }
public void KickPlayer(ulong steamId) => _torch.InvokeAsync(() => MyMultiplayer.Static.KickClient(steamId)); public void KickPlayer(ulong steamId) => _torch.Invoke(() => MyMultiplayer.Static.KickClient(steamId));
public void BanPlayer(ulong steamId, bool banned = true) public void BanPlayer(ulong steamId, bool banned = true)
{ {
_torch.InvokeAsync(() => _torch.Invoke(() =>
{ {
MyMultiplayer.Static.BanClient(steamId, banned); MyMultiplayer.Static.BanClient(steamId, banned);
if (_gameOwnerIds.ContainsKey(steamId)) if (_gameOwnerIds.ContainsKey(steamId))
@@ -65,19 +63,29 @@ namespace Torch
}); });
} }
public IMyPlayer GetPlayerByDisplayName(string displayName)
{
return _onlinePlayers.FirstOrDefault(x => x.Value.DisplayName == displayName).Value;
}
public IMyPlayer GetPlayerBySteamId(ulong steamId) public IMyPlayer GetPlayerBySteamId(ulong steamId)
{ {
_onlinePlayers.TryGetValue(new MyPlayer.PlayerId(steamId), out MyPlayer p); _onlinePlayers.TryGetValue(new MyPlayer.PlayerId(steamId), out MyPlayer p);
return p; return p;
} }
public void SendMessage(string message)
{
SendMessage(message, 0);
}
/// <summary> /// <summary>
/// Send a message in chat. /// Send a message in chat.
/// </summary> /// </summary>
public void SendMessage(string message) public void SendMessage(string message, long playerId, string author = "Server", string font = MyFontEnum.Blue)
{ {
MyMultiplayer.Static.SendChatMessage(message); var msg = new ScriptedChatMsg {Author = author, Font = font, Target = playerId, Text = message};
//ChatView.Add(new ChatItem(LocalPlayer, message)); MyMultiplayerBase.SendScriptedChatMessage(ref msg);
} }
private void OnSessionLoaded() private void OnSessionLoaded()
@@ -156,6 +164,8 @@ namespace Torch
private HashSet<ulong> _waitingForGroup; private HashSet<ulong> _waitingForGroup;
private HashSet<ulong> _waitingForFriends; private HashSet<ulong> _waitingForFriends;
private Dictionary<ulong, ulong> _gameOwnerIds = new Dictionary<ulong, ulong>(); private Dictionary<ulong, ulong> _gameOwnerIds = new Dictionary<ulong, ulong>();
private IMultiplayer _multiplayerImplementation;
/// <summary> /// <summary>
/// Removes Keen's hooks into some Steam events so we have full control over client authentication /// Removes Keen's hooks into some Steam events so we have full control over client authentication
/// </summary> /// </summary>

View File

@@ -14,13 +14,13 @@ namespace Torch.Managers
{ {
public class NetworkManager public class NetworkManager
{ {
public NetworkManager() private NetworkManager()
{ {
if (ReflectionUnitTest()) if (ReflectionUnitTest())
InitNetworkIntercept(); InitNetworkIntercept();
} }
private static Logger _log = LogManager.GetLogger("Torch"); private static Logger _log = LogManager.GetLogger(nameof(NetworkManager));
private static NetworkManager _instance; private static NetworkManager _instance;
public static NetworkManager Instance => _instance ?? (_instance = new NetworkManager()); public static NetworkManager Instance => _instance ?? (_instance = new NetworkManager());
@@ -77,7 +77,7 @@ namespace Torch.Managers
//PrintDebug(); //PrintDebug();
//ApplicationLog.Info("Initialized network intercept!"); _log.Debug("Initialized network intercept");
} }
#region Network Intercept #region Network Intercept
@@ -100,8 +100,8 @@ namespace Torch.Managers
} }
catch (Exception ex) catch (Exception ex)
{ {
_log.Error(ex); _log.Fatal(ex);
//ApplicationLog.Error(ex, "~Error processing event!"); _log.Fatal(ex, "~Error processing event!");
//crash after logging, bad things could happen if we continue on with bad data //crash after logging, bad things could happen if we continue on with bad data
throw; throw;
} }
@@ -175,8 +175,8 @@ namespace Torch.Managers
} }
catch (Exception ex) catch (Exception ex)
{ {
_log.Error(ex); _log.Fatal(ex);
//ApplicationLog.Error(ex, "Error when returning control to game server!"); _log.Fatal(ex, "Error when returning control to game server!");
//crash after logging, bad things could happen if we continue on with bad data //crash after logging, bad things could happen if we continue on with bad data
throw; throw;
} }
@@ -191,7 +191,7 @@ namespace Torch.Managers
if (item.GetType().FullName == handlerType) if (item.GetType().FullName == handlerType)
{ {
//if (ExtenderOptions.IsDebugging) //if (ExtenderOptions.IsDebugging)
// ApplicationLog.BaseLog.Error("Network handler already registered! " + handlerType); _log.Error("Network handler already registered! " + handlerType);
toRemove.Add(item); toRemove.Add(item);
} }
} }

View File

@@ -14,11 +14,12 @@ using Sandbox;
using Sandbox.ModAPI; using Sandbox.ModAPI;
using Torch.API; using Torch.API;
using Torch.Commands; using Torch.Commands;
using Torch.Managers;
using VRage.Plugins; using VRage.Plugins;
using VRage.Collections; using VRage.Collections;
using VRage.Library.Collections; using VRage.Library.Collections;
namespace Torch namespace Torch.Managers
{ {
public class PluginManager : IPluginManager public class PluginManager : IPluginManager
{ {
@@ -28,13 +29,15 @@ namespace Torch
private readonly List<ITorchPlugin> _plugins = new List<ITorchPlugin>(); private readonly List<ITorchPlugin> _plugins = new List<ITorchPlugin>();
private readonly PluginUpdater _updater; private readonly PluginUpdater _updater;
private readonly CommandManager _commands; public CommandManager Commands { get; private set; }
public float LastUpdateMs => _lastUpdateMs;
private volatile float _lastUpdateMs;
public PluginManager(ITorchBase torch) public PluginManager(ITorchBase torch)
{ {
_torch = torch; _torch = torch;
_updater = new PluginUpdater(this); _updater = new PluginUpdater(this);
_commands = new CommandManager(_torch);
if (!Directory.Exists(PluginDir)) if (!Directory.Exists(PluginDir))
Directory.CreateDirectory(PluginDir); Directory.CreateDirectory(PluginDir);
@@ -42,6 +45,9 @@ namespace Torch
InitUpdater(); InitUpdater();
} }
/// <summary>
/// Adds the plugin updater plugin to VRage's plugin system.
/// </summary>
private void InitUpdater() private void InitUpdater()
{ {
var fieldName = "m_plugins"; var fieldName = "m_plugins";
@@ -52,11 +58,20 @@ namespace Torch
pluginList.Add(_updater); pluginList.Add(_updater);
} }
/// <summary>
/// Updates loaded plugins in parallel.
/// </summary>
public void UpdatePlugins() public void UpdatePlugins()
{ {
var s = Stopwatch.StartNew();
Parallel.ForEach(_plugins, p => p.Update()); Parallel.ForEach(_plugins, p => p.Update());
s.Stop();
_lastUpdateMs = (float)s.Elapsed.TotalMilliseconds;
} }
/// <summary>
/// Unloads all plugins.
/// </summary>
public void UnloadPlugins() public void UnloadPlugins()
{ {
foreach (var plugin in _plugins) foreach (var plugin in _plugins)
@@ -66,10 +81,13 @@ namespace Torch
} }
/// <summary> /// <summary>
/// Load and create instances of all plugins in the <see cref="PluginDir"/> folder. /// Loads and creates instances of all plugins in the <see cref="PluginDir"/> folder.
/// </summary> /// </summary>
public void LoadPlugins() public void Init()
{ {
var network = NetworkManager.Instance;
Commands = new CommandManager(_torch);
_log.Info("Loading plugins"); _log.Info("Loading plugins");
var pluginsPath = Path.Combine(Directory.GetCurrentDirectory(), PluginDir); var pluginsPath = Path.Combine(Directory.GetCurrentDirectory(), PluginDir);
var dlls = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories); var dlls = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);
@@ -91,7 +109,7 @@ namespace Torch
_log.Info($"Loading plugin {plugin.Name} ({plugin.Version})"); _log.Info($"Loading plugin {plugin.Name} ({plugin.Version})");
_plugins.Add(plugin); _plugins.Add(plugin);
_commands.RegisterPluginCommands(plugin); Commands.RegisterPluginCommands(plugin);
} }
catch (Exception e) catch (Exception e)
{ {
@@ -132,6 +150,7 @@ namespace Torch
private class PluginUpdater : IPlugin private class PluginUpdater : IPlugin
{ {
private readonly IPluginManager _manager; private readonly IPluginManager _manager;
public PluginUpdater(IPluginManager manager) public PluginUpdater(IPluginManager manager)
{ {
_manager = manager; _manager = manager;
@@ -139,7 +158,7 @@ namespace Torch
public void Init(object obj) public void Init(object obj)
{ {
_manager.LoadPlugins(); _manager.Init();
} }
public void Update() public void Update()

View File

@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Torch.API;
using Torch.API.ModAPI.Ingame;
using VRage.Scripting;
namespace Torch.Managers
{
public class ScriptingManager
{
private MyScriptWhitelist _whitelist;
public void Init()
{
_whitelist = MyScriptCompiler.Static.Whitelist;
MyScriptCompiler.Static.AddConditionalCompilationSymbols("TORCH");
MyScriptCompiler.Static.AddReferencedAssemblies(typeof(ITorchBase).Assembly.Location);
MyScriptCompiler.Static.AddImplicitIngameNamespacesFromTypes(typeof(GridExtensions));
/*
//dump whitelist
var whitelist = new StringBuilder();
foreach (var pair in MyScriptCompiler.Static.Whitelist.GetWhitelist())
{
var split = pair.Key.Split(',');
whitelist.AppendLine("|-");
whitelist.AppendLine($"|{pair.Value} || {split[0]} || {split[1]}");
}
Log.Info(whitelist);*/
}
public void UnwhitelistType(Type t)
{
throw new NotImplementedException();
}
}
}

View File

@@ -16,20 +16,27 @@ namespace Torch
{ {
public static class SteamHelper public static class SteamHelper
{ {
private static Thread _callbackThread; private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
private static Logger _log = LogManager.GetLogger("Torch"); private static CancellationToken _cancelToken;
private static Logger _log = LogManager.GetLogger(nameof(SteamHelper));
public static void Init() public static void Init()
{ {
_callbackThread = new Thread(() => _cancelToken = _tokenSource.Token;
Task.Run(() =>
{ {
while (true) while (!_cancelToken.IsCancellationRequested)
{ {
SteamAPI.Instance.RunCallbacks(); SteamAPI.Instance.RunCallbacks();
Thread.Sleep(100); Thread.Sleep(100);
} }
}) {Name = "SteamAPICallbacks"}; });
_callbackThread.Start(); }
public static void StopCallbackLoop()
{
_tokenSource.Cancel();
} }
public static MySteamWorkshop.SubscribedItem GetItemInfo(ulong itemId) public static MySteamWorkshop.SubscribedItem GetItemInfo(ulong itemId)
@@ -55,7 +62,7 @@ namespace Torch
} }
else else
{ {
_log.Warn($"Failed to get item info for {itemId}"); _log.Error($"Failed to get item info for {itemId}");
} }
mre.Set(); mre.Set();
@@ -78,7 +85,7 @@ namespace Torch
if (!b && result.Details.Result == Result.OK) if (!b && result.Details.Result == Result.OK)
details = result.Details; details = result.Details;
else else
_log.Warn($"Failed to get item details for {itemId}"); _log.Error($"Failed to get item details for {itemId}");
re.Set(); re.Set();
}); });

View File

@@ -152,11 +152,15 @@
<Compile Include="Commands\CommandContext.cs" /> <Compile Include="Commands\CommandContext.cs" />
<Compile Include="Commands\CommandManager.cs" /> <Compile Include="Commands\CommandManager.cs" />
<Compile Include="Commands\CommandTree.cs" /> <Compile Include="Commands\CommandTree.cs" />
<Compile Include="Commands\DefaultPermissionAttribute.cs" />
<Compile Include="Commands\Permissions\PermissonsSystem.cs" />
<Compile Include="Commands\TorchCommands.cs" />
<Compile Include="Managers\ChatManager.cs" /> <Compile Include="Managers\ChatManager.cs" />
<Compile Include="Managers\NetworkManager\NetworkHandlerBase.cs" /> <Compile Include="Managers\NetworkManager\NetworkHandlerBase.cs" />
<Compile Include="Managers\NetworkManager\NetworkManager.cs" /> <Compile Include="Managers\NetworkManager\NetworkManager.cs" />
<Compile Include="MultiplayerManager.cs" /> <Compile Include="Managers\MultiplayerManager.cs" />
<Compile Include="Reflection.cs" /> <Compile Include="Reflection.cs" />
<Compile Include="Managers\ScriptingManager.cs" />
<Compile Include="TorchBase.cs" /> <Compile Include="TorchBase.cs" />
<Compile Include="Player.cs" /> <Compile Include="Player.cs" />
<Compile Include="Collections\PlayerInfoCache.cs" /> <Compile Include="Collections\PlayerInfoCache.cs" />
@@ -169,7 +173,7 @@
<Compile Include="SteamHelper.cs" /> <Compile Include="SteamHelper.cs" />
<Compile Include="Extensions\StringExtensions.cs" /> <Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="ViewModels\ViewModel.cs" /> <Compile Include="ViewModels\ViewModel.cs" />
<Compile Include="PluginManager.cs" /> <Compile Include="Managers\PluginManager.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="ViewModels\PluginViewModel.cs" /> <Compile Include="ViewModels\PluginViewModel.cs" />
</ItemGroup> </ItemGroup>

View File

@@ -3,12 +3,15 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using NLog; using NLog;
using Sandbox; using Sandbox;
using Sandbox.ModAPI;
using Torch.API; using Torch.API;
using Torch.Managers;
using VRage.Scripting; using VRage.Scripting;
namespace Torch namespace Torch
@@ -22,6 +25,7 @@ namespace Torch
[Obsolete] [Obsolete]
public static ITorchBase Instance { get; private set; } public static ITorchBase Instance { get; private set; }
protected static Logger Log = LogManager.GetLogger("Torch"); protected static Logger Log = LogManager.GetLogger("Torch");
public Version Version { get; protected set; }
public string[] RunArgs { get; set; } public string[] RunArgs { get; set; }
public IPluginManager Plugins { get; protected set; } public IPluginManager Plugins { get; protected set; }
public IMultiplayer Multiplayer { get; protected set; } public IMultiplayer Multiplayer { get; protected set; }
@@ -41,6 +45,7 @@ namespace Torch
Instance = this; Instance = this;
Version = Assembly.GetExecutingAssembly().GetName().Version;
RunArgs = new string[0]; RunArgs = new string[0];
Plugins = new PluginManager(this); Plugins = new PluginManager(this);
Multiplayer = new MultiplayerManager(this); Multiplayer = new MultiplayerManager(this);
@@ -116,9 +121,6 @@ namespace Torch
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
_init = true; _init = true;
MyScriptCompiler.Static.AddConditionalCompilationSymbols("TORCH");
MyScriptCompiler.Static.AddReferencedAssemblies(typeof(ITorchBase).Assembly.Location);
MyScriptCompiler.Static.AddReferencedAssemblies(typeof(TorchBase).Assembly.Location);
} }
private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)