First test build
This commit is contained in:
@@ -6,10 +6,11 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Torch.API
|
namespace Torch.API
|
||||||
{
|
{
|
||||||
public interface IChatItem
|
public interface IChatMessage
|
||||||
{
|
{
|
||||||
IPlayer Player { get; }
|
DateTime Timestamp { get; }
|
||||||
|
ulong SteamId { get; }
|
||||||
|
string Name { get; }
|
||||||
string Message { get; }
|
string Message { get; }
|
||||||
DateTime Time { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -6,17 +6,18 @@ using VRage.Game.ModAPI;
|
|||||||
|
|
||||||
namespace Torch.API
|
namespace Torch.API
|
||||||
{
|
{
|
||||||
|
public delegate void MessageReceivedDel(IChatMessage message, ref bool sendToOthers);
|
||||||
|
|
||||||
public interface IMultiplayer
|
public interface IMultiplayer
|
||||||
{
|
{
|
||||||
event Action<IPlayer> PlayerJoined;
|
event Action<ulong> PlayerJoined;
|
||||||
event Action<IPlayer> PlayerLeft;
|
event Action<ulong, ConnectionState> PlayerLeft;
|
||||||
event Action<IChatItem> MessageReceived;
|
event MessageReceivedDel MessageReceived;
|
||||||
Dictionary<ulong, IPlayer> Players { get; }
|
|
||||||
List<IChatItem> Chat { get; }
|
|
||||||
void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Blue);
|
void SendMessage(string message, string author = "Server", long playerId = 0, string font = MyFontEnum.Blue);
|
||||||
void KickPlayer(ulong id);
|
void KickPlayer(ulong steamId);
|
||||||
void BanPlayer(ulong id, bool banned = true);
|
void BanPlayer(ulong steamId, bool banned = true);
|
||||||
IMyPlayer GetPlayerBySteamId(ulong id);
|
IMyPlayer GetPlayerBySteamId(ulong id);
|
||||||
IMyPlayer GetPlayerByName(string name);
|
IMyPlayer GetPlayerByName(string name);
|
||||||
|
MTObservableCollection<IChatMessage> ChatHistory { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,18 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Torch.API
|
|
||||||
{
|
|
||||||
public interface IPlayer
|
|
||||||
{
|
|
||||||
ulong SteamId { get; }
|
|
||||||
List<ulong> IdentityIds { get; }
|
|
||||||
string Name { get; }
|
|
||||||
ConnectionState State { get; }
|
|
||||||
DateTime LastConnected { get; }
|
|
||||||
void SetConnectionState(ConnectionState state);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -3,6 +3,7 @@ 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.Game.ModAPI;
|
||||||
|
|
||||||
namespace Torch.API
|
namespace Torch.API
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,7 @@ namespace Torch.API
|
|||||||
void InvokeBlocking(Action action);
|
void InvokeBlocking(Action action);
|
||||||
Task InvokeAsync(Action action);
|
Task InvokeAsync(Action action);
|
||||||
string[] RunArgs { get; set; }
|
string[] RunArgs { get; set; }
|
||||||
|
bool IsOnGameThread();
|
||||||
void Start();
|
void Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
void Init();
|
void Init();
|
||||||
@@ -28,6 +30,7 @@ namespace Torch.API
|
|||||||
{
|
{
|
||||||
bool IsRunning { get; }
|
bool IsRunning { get; }
|
||||||
string InstancePath { get; }
|
string InstancePath { get; }
|
||||||
|
void Start(IMyConfigDedicated config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITorchClient : ITorchBase
|
public interface ITorchClient : ITorchBase
|
||||||
|
@@ -69,6 +69,9 @@
|
|||||||
<Reference Include="System.Data" />
|
<Reference Include="System.Data" />
|
||||||
<Reference Include="System.Net.Http" />
|
<Reference Include="System.Net.Http" />
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="Torch">
|
||||||
|
<HintPath>..\Torch.Server\bin\x64\Release\Torch.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
<Reference Include="VRage">
|
<Reference Include="VRage">
|
||||||
<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>
|
||||||
@@ -111,9 +114,8 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="ConnectionState.cs" />
|
<Compile Include="ConnectionState.cs" />
|
||||||
<Compile Include="IChatItem.cs" />
|
<Compile Include="IChatMessage.cs" />
|
||||||
<Compile Include="IMultiplayer.cs" />
|
<Compile Include="IMultiplayer.cs" />
|
||||||
<Compile Include="IPlayer.cs" />
|
|
||||||
<Compile Include="IPluginManager.cs" />
|
<Compile Include="IPluginManager.cs" />
|
||||||
<Compile Include="ITorchPlugin.cs" />
|
<Compile Include="ITorchPlugin.cs" />
|
||||||
<Compile Include="IServerControls.cs" />
|
<Compile Include="IServerControls.cs" />
|
||||||
|
@@ -12,5 +12,5 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.35.456")]
|
[assembly: AssemblyVersion("1.0.89.455")]
|
||||||
[assembly: AssemblyFileVersion("1.0.35.456")]
|
[assembly: AssemblyFileVersion("1.0.89.455")]
|
18
Torch.Server/NativeMethods.cs
Normal file
18
Torch.Server/NativeMethods.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Torch.Server
|
||||||
|
{
|
||||||
|
public class NativeMethods
|
||||||
|
{
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern bool AllocConsole();
|
||||||
|
|
||||||
|
[DllImport("kernel32")]
|
||||||
|
public static extern bool FreeConsole();
|
||||||
|
}
|
||||||
|
}
|
@@ -28,6 +28,7 @@ namespace Torch.Server
|
|||||||
private static ITorchServer _server;
|
private static ITorchServer _server;
|
||||||
private static Logger _log = LogManager.GetLogger("Torch");
|
private static Logger _log = LogManager.GetLogger("Torch");
|
||||||
|
|
||||||
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
if (!Environment.UserInteractive)
|
if (!Environment.UserInteractive)
|
||||||
@@ -41,16 +42,16 @@ namespace Torch.Server
|
|||||||
|
|
||||||
var configName = args.FirstOrDefault() ?? "TorchConfig.xml";
|
var configName = args.FirstOrDefault() ?? "TorchConfig.xml";
|
||||||
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
|
var configPath = Path.Combine(Directory.GetCurrentDirectory(), configName);
|
||||||
ServerConfig options;
|
TorchConfig options;
|
||||||
if (File.Exists(configName))
|
if (File.Exists(configName))
|
||||||
{
|
{
|
||||||
_log.Info($"Loading config {configPath}");
|
_log.Info($"Loading config {configPath}");
|
||||||
options = ServerConfig.LoadFrom(configPath);
|
options = TorchConfig.LoadFrom(configPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_log.Info($"Generating default config at {configPath}");
|
_log.Info($"Generating default config at {configPath}");
|
||||||
options = new ServerConfig();
|
options = new TorchConfig();
|
||||||
options.SaveTo(configPath);
|
options.SaveTo(configPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +118,9 @@ namespace Torch.Server
|
|||||||
|
|
||||||
_server = new TorchServer(options);
|
_server = new TorchServer(options);
|
||||||
_server.Init();
|
_server.Init();
|
||||||
_server.Start();
|
var ui = new TorchUI((TorchServer)_server);
|
||||||
|
ui.LoadConfig(options);
|
||||||
|
ui.ShowDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -12,5 +12,5 @@ using System.Runtime.InteropServices;
|
|||||||
[assembly: AssemblyCulture("")]
|
[assembly: AssemblyCulture("")]
|
||||||
[assembly: ComVisible(false)]
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
[assembly: AssemblyVersion("1.0.35.456")]
|
[assembly: AssemblyVersion("1.0.89.455")]
|
||||||
[assembly: AssemblyFileVersion("1.0.35.456")]
|
[assembly: AssemblyFileVersion("1.0.89.455")]
|
@@ -152,12 +152,13 @@
|
|||||||
<Reference Include="PresentationFramework" />
|
<Reference Include="PresentationFramework" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="NativeMethods.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs">
|
<Compile Include="Properties\AssemblyInfo.cs">
|
||||||
<AutoGen>True</AutoGen>
|
<AutoGen>True</AutoGen>
|
||||||
<DesignTime>True</DesignTime>
|
<DesignTime>True</DesignTime>
|
||||||
<DependentUpon>AssemblyInfo.tt</DependentUpon>
|
<DependentUpon>AssemblyInfo.tt</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="ServerConfig.cs" />
|
<Compile Include="TorchConfig.cs" />
|
||||||
<Compile Include="TorchService.cs">
|
<Compile Include="TorchService.cs">
|
||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -165,12 +166,19 @@
|
|||||||
<SubType>Component</SubType>
|
<SubType>Component</SubType>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="ViewModels\ConfigDedicatedViewModel.cs" />
|
<Compile Include="ViewModels\ConfigDedicatedViewModel.cs" />
|
||||||
|
<Compile Include="ViewModels\SessionSettingsViewModel.cs" />
|
||||||
<Compile Include="Views\AddWorkshopItemsDialog.xaml.cs">
|
<Compile Include="Views\AddWorkshopItemsDialog.xaml.cs">
|
||||||
<DependentUpon>AddWorkshopItemsDialog.xaml</DependentUpon>
|
<DependentUpon>AddWorkshopItemsDialog.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\ChatControl.xaml.cs">
|
<Compile Include="Views\ChatControl.xaml.cs">
|
||||||
<DependentUpon>ChatControl.xaml</DependentUpon>
|
<DependentUpon>ChatControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Views\CollectionEditor.xaml.cs">
|
||||||
|
<DependentUpon>CollectionEditor.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Views\ConfigControl.xaml.cs">
|
||||||
|
<DependentUpon>ConfigControl.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Views\ModsControl.xaml.cs">
|
<Compile Include="Views\ModsControl.xaml.cs">
|
||||||
<DependentUpon>ModsControl.xaml</DependentUpon>
|
<DependentUpon>ModsControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -182,9 +190,6 @@
|
|||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="TorchServer.cs" />
|
<Compile Include="TorchServer.cs" />
|
||||||
<Compile Include="Views\PropertyGrid.xaml.cs">
|
|
||||||
<DependentUpon>PropertyGrid.xaml</DependentUpon>
|
|
||||||
</Compile>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Properties\Resources.Designer.cs">
|
<Compile Include="Properties\Resources.Designer.cs">
|
||||||
@@ -229,6 +234,14 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Views\CollectionEditor.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
|
<Page Include="Views\ConfigControl.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Views\ModsControl.xaml">
|
<Page Include="Views\ModsControl.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
@@ -241,10 +254,6 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="Views\PropertyGrid.xaml">
|
|
||||||
<SubType>Designer</SubType>
|
|
||||||
<Generator>MSBuild:Compile</Generator>
|
|
||||||
</Page>
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Resource Include="torchicon.ico" />
|
<Resource Include="torchicon.ico" />
|
||||||
|
@@ -10,7 +10,7 @@ using VRage.Dedicated;
|
|||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
{
|
{
|
||||||
public class ServerConfig
|
public class TorchConfig
|
||||||
{
|
{
|
||||||
private static Logger _log = LogManager.GetLogger("Config");
|
private static Logger _log = LogManager.GetLogger("Config");
|
||||||
|
|
||||||
@@ -18,8 +18,11 @@ namespace Torch.Server
|
|||||||
public string InstanceName { get; set; }
|
public string InstanceName { get; set; }
|
||||||
public int Autosave { get; set; }
|
public int Autosave { get; set; }
|
||||||
public bool AutoRestart { get; set; }
|
public bool AutoRestart { get; set; }
|
||||||
|
public bool LogChat { get; set; }
|
||||||
|
|
||||||
public ServerConfig(string instanceName = "Torch", string instancePath = null, int autosaveInterval = 5, bool autoRestart = false)
|
public TorchConfig() : this("Torch") { }
|
||||||
|
|
||||||
|
public TorchConfig(string instanceName = "Torch", string instancePath = null, int autosaveInterval = 5, bool autoRestart = false)
|
||||||
{
|
{
|
||||||
InstanceName = instanceName;
|
InstanceName = instanceName;
|
||||||
InstancePath = instancePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Torch", InstanceName);
|
InstancePath = instancePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Torch", InstanceName);
|
||||||
@@ -27,15 +30,15 @@ namespace Torch.Server
|
|||||||
AutoRestart = autoRestart;
|
AutoRestart = autoRestart;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ServerConfig LoadFrom(string path)
|
public static TorchConfig LoadFrom(string path)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var serializer = new XmlSerializer(typeof(ServerConfig));
|
var serializer = new XmlSerializer(typeof(TorchConfig));
|
||||||
ServerConfig config;
|
TorchConfig config;
|
||||||
using (var f = File.OpenRead(path))
|
using (var f = File.OpenRead(path))
|
||||||
{
|
{
|
||||||
config = (ServerConfig)serializer.Deserialize(f);
|
config = (TorchConfig)serializer.Deserialize(f);
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
@@ -50,7 +53,7 @@ namespace Torch.Server
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var serializer = new XmlSerializer(typeof(ServerConfig));
|
var serializer = new XmlSerializer(typeof(TorchConfig));
|
||||||
using (var f = File.OpenWrite(path))
|
using (var f = File.OpenWrite(path))
|
||||||
{
|
{
|
||||||
serializer.Serialize(f, this);
|
serializer.Serialize(f, this);
|
@@ -18,9 +18,12 @@ using Sandbox.Game;
|
|||||||
using Sandbox.Game.Gui;
|
using Sandbox.Game.Gui;
|
||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using SpaceEngineers.Game;
|
using SpaceEngineers.Game;
|
||||||
|
using SteamSDK;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using VRage.Dedicated;
|
using VRage.Dedicated;
|
||||||
|
using VRage.FileSystem;
|
||||||
using VRage.Game;
|
using VRage.Game;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
using VRage.Game.SessionComponents;
|
using VRage.Game.SessionComponents;
|
||||||
using VRage.Profiler;
|
using VRage.Profiler;
|
||||||
|
|
||||||
@@ -30,22 +33,24 @@ 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 string InstancePath { get; }
|
public string InstancePath { get; private set; }
|
||||||
public string InstanceName { get; }
|
public string InstanceName { get; private set; }
|
||||||
|
|
||||||
private readonly AutoResetEvent _stopHandle = new AutoResetEvent(false);
|
private readonly AutoResetEvent _stopHandle = new AutoResetEvent(false);
|
||||||
|
|
||||||
internal TorchServer(ServerConfig options)
|
public TorchServer(TorchConfig options = null)
|
||||||
{
|
{
|
||||||
InstanceName = options.InstanceName;
|
var opt = options ?? new TorchConfig();
|
||||||
InstancePath = options.InstancePath;
|
|
||||||
|
InstanceName = opt.InstanceName;
|
||||||
|
InstancePath = opt.InstancePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
base.Init();
|
base.Init();
|
||||||
|
|
||||||
Log.Info($"Server instance {InstanceName} at path {InstancePath}");
|
Log.Info($"Init server instance '{InstanceName}' at path '{InstancePath}'");
|
||||||
|
|
||||||
MyFakes.ENABLE_INFINARIO = false;
|
MyFakes.ENABLE_INFINARIO = false;
|
||||||
MyPerGameSettings.SendLogToKeen = false;
|
MyPerGameSettings.SendLogToKeen = false;
|
||||||
@@ -55,16 +60,30 @@ namespace Torch.Server
|
|||||||
MyPerServerSettings.GameDSDescription = "Your place for space engineering, destruction and exploring.";
|
MyPerServerSettings.GameDSDescription = "Your place for space engineering, destruction and exploring.";
|
||||||
MySessionComponentExtDebug.ForceDisable = true;
|
MySessionComponentExtDebug.ForceDisable = true;
|
||||||
MyPerServerSettings.AppId = 244850u;
|
MyPerServerSettings.AppId = 244850u;
|
||||||
ConfigForm<MyObjectBuilder_SessionSettings>.GameAttributes = Game.SpaceEngineers;
|
|
||||||
ConfigForm<MyObjectBuilder_SessionSettings>.OnReset = delegate
|
|
||||||
{
|
|
||||||
SpaceEngineersGame.SetupBasicGameInfo();
|
|
||||||
SpaceEngineersGame.SetupPerGameSettings();
|
|
||||||
};
|
|
||||||
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();
|
//TODO: Allows players to filter servers for Torch in the server browser.
|
||||||
|
//SteamServerAPI.Instance.GameServer.SetKeyValue("SM", "Torch");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConfig(IMyConfigDedicated config)
|
||||||
|
{
|
||||||
|
MySandboxGame.ConfigDedicated = config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetInstance(string path = null, string name = null)
|
||||||
|
{
|
||||||
|
if (path != null)
|
||||||
|
InstancePath = path;
|
||||||
|
if (name != null)
|
||||||
|
InstanceName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(IMyConfigDedicated config)
|
||||||
|
{
|
||||||
|
SetConfig(config);
|
||||||
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -103,10 +122,7 @@ namespace Torch.Server
|
|||||||
|
|
||||||
if (Thread.CurrentThread.ManagedThreadId != GameThread?.ManagedThreadId && MySandboxGame.Static.IsRunning)
|
if (Thread.CurrentThread.ManagedThreadId != GameThread?.ManagedThreadId && MySandboxGame.Static.IsRunning)
|
||||||
{
|
{
|
||||||
Log.Info("Requesting server stop.");
|
Invoke(Stop);
|
||||||
MySandboxGame.Static.Invoke(Stop);
|
|
||||||
_stopHandle.WaitOne(10000);
|
|
||||||
Log.Error("Server stop timed out.");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -33,9 +33,9 @@ namespace Torch.Server
|
|||||||
base.OnStart(args);
|
base.OnStart(args);
|
||||||
|
|
||||||
string configName = args.Length > 0 ? args[0] : "TorchConfig.xml";
|
string configName = args.Length > 0 ? args[0] : "TorchConfig.xml";
|
||||||
var options = new ServerConfig("Torch");
|
var options = new TorchConfig("Torch");
|
||||||
if (File.Exists(configName))
|
if (File.Exists(configName))
|
||||||
options = ServerConfig.LoadFrom(configName);
|
options = TorchConfig.LoadFrom(configName);
|
||||||
else
|
else
|
||||||
options.SaveTo(configName);
|
options.SaveTo(configName);
|
||||||
|
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@@ -11,27 +12,97 @@ namespace Torch.Server.ViewModels
|
|||||||
{
|
{
|
||||||
public class ConfigDedicatedViewModel : ViewModel
|
public class ConfigDedicatedViewModel : ViewModel
|
||||||
{
|
{
|
||||||
public IMyConfigDedicated Config { get; }
|
private MyConfigDedicated<MyObjectBuilder_SessionSettings> _config;
|
||||||
|
|
||||||
public MTObservableCollection<string> Administrators { get; } = new MTObservableCollection<string>();
|
public ConfigDedicatedViewModel()
|
||||||
public MTObservableCollection<ulong> BannedPlayers { get; } = new MTObservableCollection<ulong>();
|
{
|
||||||
|
_config = new MyConfigDedicated<MyObjectBuilder_SessionSettings>("");
|
||||||
|
SessionSettings = new SessionSettingsViewModel(_config.SessionSettings);
|
||||||
|
Administrators = new ObservableCollection<string>(_config.Administrators);
|
||||||
|
Banned = new ObservableCollection<ulong>(_config.Banned);
|
||||||
|
Mods = new ObservableCollection<ulong>(_config.Mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConfigDedicatedViewModel(MyConfigDedicated<MyObjectBuilder_SessionSettings> configDedicated)
|
||||||
|
{
|
||||||
|
_config = configDedicated;
|
||||||
|
SessionSettings = new SessionSettingsViewModel(_config.SessionSettings);
|
||||||
|
Administrators = new ObservableCollection<string>(_config.Administrators);
|
||||||
|
Banned = new ObservableCollection<ulong>(_config.Banned);
|
||||||
|
Mods = new ObservableCollection<ulong>(_config.Mods);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionSettingsViewModel SessionSettings { get; }
|
||||||
|
|
||||||
|
public ObservableCollection<string> WorldPaths { get; } = new ObservableCollection<string>();
|
||||||
|
public ObservableCollection<string> Administrators { get; }
|
||||||
|
public ObservableCollection<ulong> Banned { get; }
|
||||||
|
public ObservableCollection<ulong> Mods { get; }
|
||||||
|
|
||||||
public int AsteroidAmount
|
public int AsteroidAmount
|
||||||
{
|
{
|
||||||
get { return Config.AsteroidAmount; }
|
get { return _config.AsteroidAmount; }
|
||||||
set { Config.AsteroidAmount = value; OnPropertyChanged(); }
|
set { _config.AsteroidAmount = value; OnPropertyChanged(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigDedicatedViewModel(IMyConfigDedicated config)
|
public ulong GroupId
|
||||||
{
|
{
|
||||||
Config = config;
|
get { return _config.GroupID; }
|
||||||
Config.Administrators.ForEach(x => Administrators.Add(x));
|
set { _config.GroupID = value; OnPropertyChanged(); }
|
||||||
Config.Banned.ForEach(x => BannedPlayers.Add(x));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void FlushConfig()
|
public bool IgnoreLastSession
|
||||||
{
|
{
|
||||||
Config.Administrators = Administrators.ToList();
|
get { return _config.IgnoreLastSession; }
|
||||||
|
set { _config.IgnoreLastSession = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string IP
|
||||||
|
{
|
||||||
|
get { return _config.IP; }
|
||||||
|
set { _config.IP = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Port
|
||||||
|
{
|
||||||
|
get { return _config.ServerPort; }
|
||||||
|
set { _config.ServerPort = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ServerName
|
||||||
|
{
|
||||||
|
get { return _config.ServerName; }
|
||||||
|
set { _config.ServerName = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool PauseGameWhenEmpty
|
||||||
|
{
|
||||||
|
get { return _config.PauseGameWhenEmpty; }
|
||||||
|
set { _config.PauseGameWhenEmpty = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PremadeCheckpointPath
|
||||||
|
{
|
||||||
|
get { return _config.PremadeCheckpointPath; }
|
||||||
|
set { _config.PremadeCheckpointPath = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string LoadWorld
|
||||||
|
{
|
||||||
|
get { return _config.LoadWorld; }
|
||||||
|
set { _config.LoadWorld = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int SteamPort
|
||||||
|
{
|
||||||
|
get { return _config.SteamPort; }
|
||||||
|
set { _config.SteamPort = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string WorldName
|
||||||
|
{
|
||||||
|
get { return _config.WorldName; }
|
||||||
|
set { _config.WorldName = value; OnPropertyChanged(); }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
335
Torch.Server/ViewModels/SessionSettingsViewModel.cs
Normal file
335
Torch.Server/ViewModels/SessionSettingsViewModel.cs
Normal file
@@ -0,0 +1,335 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.Library.Utils;
|
||||||
|
|
||||||
|
namespace Torch.Server.ViewModels
|
||||||
|
{
|
||||||
|
public class SessionSettingsViewModel : ViewModel
|
||||||
|
{
|
||||||
|
private MyObjectBuilder_SessionSettings _settings;
|
||||||
|
|
||||||
|
public SessionSettingsViewModel()
|
||||||
|
{
|
||||||
|
_settings = new MyObjectBuilder_SessionSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SessionSettingsViewModel(MyObjectBuilder_SessionSettings settings)
|
||||||
|
{
|
||||||
|
_settings = settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Multipliers
|
||||||
|
public float InventorySizeMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.InventorySizeMultiplier; }
|
||||||
|
set { _settings.InventorySizeMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float RefinerySpeedMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.RefinerySpeedMultiplier; }
|
||||||
|
set { _settings.RefinerySpeedMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float AssemblerEfficiencyMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.AssemblerEfficiencyMultiplier; }
|
||||||
|
set { _settings.AssemblerEfficiencyMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float AssemblerSpeedMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.AssemblerSpeedMultiplier; }
|
||||||
|
set { _settings.AssemblerSpeedMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GrinderSpeedMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.GrinderSpeedMultiplier; }
|
||||||
|
set { _settings.GrinderSpeedMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float HackSpeedMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.HackSpeedMultiplier; }
|
||||||
|
set { _settings.HackSpeedMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region NPCs
|
||||||
|
public bool EnableDrones
|
||||||
|
{
|
||||||
|
get { return _settings.EnableDrones; }
|
||||||
|
set { _settings.EnableDrones = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableEncounters
|
||||||
|
{
|
||||||
|
get { return _settings.EnableEncounters; }
|
||||||
|
set { _settings.EnableEncounters = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableSpiders
|
||||||
|
{
|
||||||
|
get { return _settings.EnableSpiders; }
|
||||||
|
set { _settings.EnableSpiders = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableWolves
|
||||||
|
{
|
||||||
|
get { return _settings.EnableWolfs; }
|
||||||
|
set { _settings.EnableWolfs = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableCargoShips
|
||||||
|
{
|
||||||
|
get { return _settings.CargoShipsEnabled; }
|
||||||
|
set { _settings.CargoShipsEnabled = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Environment
|
||||||
|
public bool EnableSunRotation
|
||||||
|
{
|
||||||
|
get { return _settings.EnableSunRotation; }
|
||||||
|
set { _settings.EnableSunRotation = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableAirtightness
|
||||||
|
{
|
||||||
|
get { return _settings.EnableOxygenPressurization; }
|
||||||
|
set { _settings.EnableOxygenPressurization = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableOxygen
|
||||||
|
{
|
||||||
|
get { return _settings.EnableOxygen; }
|
||||||
|
set { _settings.EnableOxygen = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableDestructibleBlocks
|
||||||
|
{
|
||||||
|
get { return _settings.DestructibleBlocks; }
|
||||||
|
set { _settings.DestructibleBlocks = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableToolShake
|
||||||
|
{
|
||||||
|
get { return _settings.EnableToolShake; }
|
||||||
|
set { _settings.EnableToolShake = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableVoxelDestruction
|
||||||
|
{
|
||||||
|
get { return _settings.EnableVoxelDestruction; }
|
||||||
|
set { _settings.EnableVoxelDestruction = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<string> EnvironmentHostilityValues => Enum.GetNames(typeof(MyEnvironmentHostilityEnum)).ToList();
|
||||||
|
|
||||||
|
public string EnvironmentHostility
|
||||||
|
{
|
||||||
|
get { return _settings.EnvironmentHostility.ToString(); }
|
||||||
|
set { Enum.TryParse(value, true, out _settings.EnvironmentHostility); OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableFlora
|
||||||
|
{
|
||||||
|
get { return _settings.EnableFlora; }
|
||||||
|
set { _settings.EnableFlora = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
public List<string> GameModeValues => Enum.GetNames(typeof(MyGameModeEnum)).ToList();
|
||||||
|
|
||||||
|
public string GameMode
|
||||||
|
{
|
||||||
|
get { return _settings.GameMode.ToString(); }
|
||||||
|
set { Enum.TryParse(value, true, out _settings.GameMode); OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableAutoHealing
|
||||||
|
{
|
||||||
|
get { return _settings.AutoHealing; }
|
||||||
|
set { _settings.AutoHealing = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableCopyPaste
|
||||||
|
{
|
||||||
|
get { return _settings.EnableCopyPaste; }
|
||||||
|
set { _settings.EnableCopyPaste = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ShowPlayerNamesOnHud
|
||||||
|
{
|
||||||
|
get { return _settings.ShowPlayerNamesOnHud; }
|
||||||
|
set { _settings.ShowPlayerNamesOnHud = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableThirdPerson
|
||||||
|
{
|
||||||
|
get { return _settings.Enable3rdPersonView; }
|
||||||
|
set { _settings.Enable3rdPersonView = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableSpectator
|
||||||
|
{
|
||||||
|
get { return _settings.EnableSpectator; }
|
||||||
|
set { _settings.EnableSpectator = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SpawnWithTools
|
||||||
|
{
|
||||||
|
get { return _settings.SpawnWithTools; }
|
||||||
|
set { _settings.SpawnWithTools = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableConvertToStation
|
||||||
|
{
|
||||||
|
get { return _settings.EnableConvertToStation; }
|
||||||
|
set { _settings.EnableConvertToStation = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableJetpack
|
||||||
|
{
|
||||||
|
get { return _settings.EnableJetpack; }
|
||||||
|
set { _settings.EnableJetpack = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableRemoteOwnerRemoval
|
||||||
|
{
|
||||||
|
get { return _settings.EnableRemoteBlockRemoval; }
|
||||||
|
set { _settings.EnableRemoteBlockRemoval = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableRespawnShips
|
||||||
|
{
|
||||||
|
get { return _settings.EnableRespawnShips; }
|
||||||
|
set { _settings.EnableRespawnShips = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableScripterRole
|
||||||
|
{
|
||||||
|
get { return _settings.EnableScripterRole; }
|
||||||
|
set { _settings.EnableScripterRole = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableRealisticSound
|
||||||
|
{
|
||||||
|
get { return _settings.RealisticSound; }
|
||||||
|
set { _settings.RealisticSound = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ResetOwnership
|
||||||
|
{
|
||||||
|
get { return _settings.ResetOwnership; }
|
||||||
|
set { _settings.ResetOwnership = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DeleteRespawnShips
|
||||||
|
{
|
||||||
|
get { return _settings.RespawnShipDelete; }
|
||||||
|
set { _settings.RespawnShipDelete = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableThrusterDamage
|
||||||
|
{
|
||||||
|
get { return _settings.ThrusterDamage; }
|
||||||
|
set { _settings.ThrusterDamage = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableWeapons
|
||||||
|
{
|
||||||
|
get { return _settings.WeaponsEnabled; }
|
||||||
|
set { _settings.WeaponsEnabled = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EnableIngameScripts
|
||||||
|
{
|
||||||
|
get { return _settings.EnableIngameScripts; }
|
||||||
|
set { _settings.EnableIngameScripts = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint AutosaveInterval
|
||||||
|
{
|
||||||
|
get { return _settings.AutoSaveInMinutes; }
|
||||||
|
set { _settings.AutoSaveInMinutes = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int FloraDensity
|
||||||
|
{
|
||||||
|
get { return _settings.FloraDensity; }
|
||||||
|
set { _settings.FloraDensity = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float FloraDensityMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.FloraDensityMultiplier; }
|
||||||
|
set { _settings.FloraDensityMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public short MaxBackupSaves
|
||||||
|
{
|
||||||
|
get { return _settings.MaxBackupSaves; }
|
||||||
|
set { _settings.MaxBackupSaves = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MaxBlocksPerPlayer
|
||||||
|
{
|
||||||
|
get { return _settings.MaxBlocksPerPlayer; }
|
||||||
|
set { _settings.MaxBlocksPerPlayer = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public short MaxFloatingObjects
|
||||||
|
{
|
||||||
|
get { return _settings.MaxFloatingObjects; }
|
||||||
|
set { _settings.MaxFloatingObjects = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MaxGridSize
|
||||||
|
{
|
||||||
|
get { return _settings.MaxGridSize; }
|
||||||
|
set { _settings.MaxGridSize = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public short MaxPlayers
|
||||||
|
{
|
||||||
|
get { return _settings.MaxPlayers; }
|
||||||
|
set { _settings.MaxPlayers = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int PhysicsIterations
|
||||||
|
{
|
||||||
|
get { return _settings.PhysicsIterations; }
|
||||||
|
set { _settings.PhysicsIterations = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float SpawnTimeMultiplier
|
||||||
|
{
|
||||||
|
get { return _settings.SpawnShipTimeMultiplier; }
|
||||||
|
set { _settings.SpawnShipTimeMultiplier = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public float SunRotationInterval
|
||||||
|
{
|
||||||
|
get { return _settings.SunRotationIntervalMinutes; }
|
||||||
|
set { _settings.SunRotationIntervalMinutes = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ViewDistance
|
||||||
|
{
|
||||||
|
get { return _settings.ViewDistance; }
|
||||||
|
set { _settings.ViewDistance = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int WorldSize
|
||||||
|
{
|
||||||
|
get { return _settings.ViewDistance; }
|
||||||
|
set { _settings.WorldSizeKm = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -36,17 +36,17 @@ namespace Torch.Server
|
|||||||
|
|
||||||
public void BindServer(ITorchServer server)
|
public void BindServer(ITorchServer server)
|
||||||
{
|
{
|
||||||
_server = server;
|
//ChatItems.ItemsSource = server.Multiplayer.ChatHistory;
|
||||||
server.Multiplayer.MessageReceived += Refresh;
|
//server.Multiplayer.MessageReceived += Refresh;
|
||||||
Refresh();
|
//Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Refresh(IChatItem chatItem = null)
|
private void Refresh(IChatMessage chatItem = null)
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
ChatItems.ItemsSource = null;
|
ChatItems.ItemsSource = null;
|
||||||
ChatItems.ItemsSource = _server.Multiplayer.Chat;
|
//ChatItems.ItemsSource = _server.Multiplayer.Chat;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
Torch.Server/Views/CollectionEditor.xaml
Normal file
13
Torch.Server/Views/CollectionEditor.xaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<Window x:Class="Torch.Server.Views.CollectionEditor"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:Torch.Server.Views"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="Edit Collection" Height="300" Width="300">
|
||||||
|
<DockPanel>
|
||||||
|
<Button Content="Done" Margin="3" Click="OkButton_OnClick" DockPanel.Dock="Bottom"/>
|
||||||
|
<TextBox x:Name="ItemList" TextWrapping="Wrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" Margin="3"/>
|
||||||
|
</DockPanel>
|
||||||
|
</Window>
|
63
Torch.Server/Views/CollectionEditor.xaml.cs
Normal file
63
Torch.Server/Views/CollectionEditor.xaml.cs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for CollectionEditor.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class CollectionEditor : Window
|
||||||
|
{
|
||||||
|
public CollectionEditor()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Edit<T>(ICollection<T> collection, string name)
|
||||||
|
{
|
||||||
|
ItemList.Text = string.Join("\r\n", collection.Select(x => x.ToString()));
|
||||||
|
Title = name;
|
||||||
|
|
||||||
|
WindowStartupLocation = WindowStartupLocation.CenterOwner;
|
||||||
|
ShowDialog();
|
||||||
|
|
||||||
|
var parsed = new List<T>();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var converter = TypeDescriptor.GetConverter(typeof(T));
|
||||||
|
foreach (var item in ItemList.Text.Split(new[] {'\r', '\n'}, StringSplitOptions.RemoveEmptyEntries))
|
||||||
|
{
|
||||||
|
parsed.Add((T)converter.ConvertFromString(item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
MessageBox.Show("Error parsing list, check your input.", "Edit Error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
collection.Clear();
|
||||||
|
foreach (var item in parsed)
|
||||||
|
collection.Add(item);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OkButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
183
Torch.Server/Views/ConfigControl.xaml
Normal file
183
Torch.Server/Views/ConfigControl.xaml
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
<UserControl x:Class="Torch.Server.Views.ConfigControl"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:Torch.Server.Views"
|
||||||
|
xmlns:viewModels="clr-namespace:Torch.Server.ViewModels"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Background="White">
|
||||||
|
<UserControl.DataContext>
|
||||||
|
<viewModels:ConfigDedicatedViewModel/>
|
||||||
|
</UserControl.DataContext>
|
||||||
|
<StackPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<Label Content="World:" DockPanel.Dock="Left"/>
|
||||||
|
<ComboBox Text="{Binding LoadWorld}" ItemsSource="{Binding WorldPaths}" IsEditable="True" Margin="3"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<StackPanel Margin="3" DockPanel.Dock="Left">
|
||||||
|
<Label Content="Server Name"/>
|
||||||
|
<TextBox Text="{Binding ServerName}" Margin="3,0,3,3" Width="130"/>
|
||||||
|
<Label Content="World Name"/>
|
||||||
|
<TextBox Text="{Binding WorldName}" Margin="3,0,3,3" Width="130"/>
|
||||||
|
<Label Content="Whitelist Group ID"/>
|
||||||
|
<TextBox Text="{Binding GroupId}" Margin="3,0,3,3" Width="130"/>
|
||||||
|
<Label Content="Server IP"/>
|
||||||
|
<StackPanel Orientation="Horizontal" Margin="3,0,3,3">
|
||||||
|
<TextBox Text="{Binding IP}" Width="100" Height="20"/>
|
||||||
|
<Label Content=":"></Label>
|
||||||
|
<TextBox Text="{Binding Port}" Width="50" Height="20"/>
|
||||||
|
</StackPanel>
|
||||||
|
<Label Content="Steam Port"/>
|
||||||
|
<TextBox Text="{Binding SteamPort}" Width="130" Margin="3,0,3,3"/>
|
||||||
|
<CheckBox IsChecked="{Binding IgnoreLastSession}" Content="Ignore Last Session" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding PauseGameWhenEmpty}" Content="Pause When Empty" Margin="3"/>
|
||||||
|
<Label Content="Banned Players"/>
|
||||||
|
<ListBox ItemsSource="{Binding Banned}" Width="130" Margin="3,0,3,3" Height="100" MouseDoubleClick="Banned_OnMouseDoubleClick"/>
|
||||||
|
<Label Content="Administrators"/>
|
||||||
|
<ListBox ItemsSource="{Binding Administrators}" Width="130" Margin="3,0,3,3" Height="100" MouseDoubleClick="Administrators_OnMouseDoubleClick"/>
|
||||||
|
<Label Content="Mods"/>
|
||||||
|
<ListBox ItemsSource="{Binding Mods}" Width="130" Margin="3,0,3,3" Height="100" MouseDoubleClick="Mods_OnMouseDoubleClick"/>
|
||||||
|
</StackPanel>
|
||||||
|
<ScrollViewer Margin="3" DockPanel.Dock="Right">
|
||||||
|
<StackPanel DataContext="{Binding SessionSettings}">
|
||||||
|
<Expander Header="Multipliers">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding InventorySizeMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Inventory Size"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding RefinerySpeedMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Refinery Speed"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding AssemblerEfficiencyMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Assembler Efficiency"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding AssemblerSpeedMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Assembler Speed"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding GrinderSpeedMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Grinder Speed"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding HackSpeedMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Hacking Speed"/>
|
||||||
|
</DockPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="NPCs">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<CheckBox IsChecked="{Binding EnableDrones}" Content="Enable Drones" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableEncounters}" Content="Enable Encounters" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableSpiders}" Content="Enable Spiders" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableWolves}" Content="Enable Wolves" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableCargoShips}" Content="Enable Cargo Ships" Margin="3"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="Environment">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<CheckBox IsChecked="{Binding EnableSunRotation}" Content="Enable Sun Rotation" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableAirtightness}" Content="Enable Airtightness" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableOxygen}" Content="Enable Oxygen" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableDestructibleBlocks}" Content="Enable Destructible Blocks" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableToolShake}" Content="Enable Tool Shake" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableVoxelDestruction}" Content="Enable Voxel Destruction" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableFlora}" Content="Enable Flora" Margin="3"/>
|
||||||
|
<DockPanel>
|
||||||
|
<ComboBox SelectedItem="{Binding EnvironmentHostility}" ItemsSource="{Binding EnvironmentHostilityValues}" Margin="3" Width="100" DockPanel.Dock="Left"/>
|
||||||
|
<Label Content="Environment Hostility"></Label>
|
||||||
|
</DockPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="Players">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<CheckBox IsChecked="{Binding EnableAutoHealing}" Content="Auto Healing" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableCopyPaste}" Content="Enable Copy/Paste" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding ShowPlayerNamesOnHud}" Content="Show Player Names on HUD" Margin="3"/>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
<Expander Header="Miscellaneous">
|
||||||
|
<StackPanel Margin="10,0,0,0">
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding AutosaveInterval}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Autosave Interval (minutes)"/>
|
||||||
|
</DockPanel>
|
||||||
|
<CheckBox IsChecked="{Binding EnableThirdPerson}" Content="Enable 3rd Person Camera" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableConvertToStation}" Content="Enable Convert to Station" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableJetpack}" Content="Enable Jetpack" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableRemoteOwnerRemoval}" Content="Enable Remote Ownership Removal" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableRespawnShips}" Content="Enable Respawn Ships" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableScripterRole}" Content="Enable Scripter Role" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableSpectator}" Content="Enable Spectator Camera" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableRealisticSound}" Content="Enable Realistic Sound" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding ResetOwnership}" Content="Reset Ownership" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding DeleteRespawnShips}" Content="Remove Respawn Ships on Logoff" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableThrusterDamage}" Content="Enable Thruster Damage" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableWeapons}" Content="Enable Weapons" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding EnableIngameScripts}" Content="Enable Ingame Scripts" Margin="3"/>
|
||||||
|
<CheckBox IsChecked="{Binding SpawnWithTools}" Content="Spawn With Tools" Margin="3"/>
|
||||||
|
<DockPanel>
|
||||||
|
<ComboBox SelectedItem="{Binding GameMode}" ItemsSource="{Binding GameModeValues}" Margin="3" Width="100" DockPanel.Dock="Left"/>
|
||||||
|
<Label Content="Game Mode"></Label>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding FloraDensity}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Flora Density"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding FloraDensityMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Flora Density Multiplier"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding MaxBackupSaves}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Max Backup Saves"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding MaxBlocksPerPlayer}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Max Blocks Per Player"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding MaxFloatingObjects}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Max Floating Objects"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding MaxGridSize}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Max Grid Size"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding MaxPlayers}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Max Players"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel ToolTip="Increases physics precision at the cost of performance.">
|
||||||
|
<TextBox Text="{Binding PhysicsIterations}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Physics Iterations"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding SpawnTimeMultiplier}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Respawn Time Multiplier"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding SunRotationInterval}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="Sun Rotation Interval (mins)"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding ViewDistance}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="View Distance (meters)"/>
|
||||||
|
</DockPanel>
|
||||||
|
<DockPanel>
|
||||||
|
<TextBox Text="{Binding WorldSize}" Margin="3" Width="70"/>
|
||||||
|
<Label Content="World Size (km)"/>
|
||||||
|
</DockPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Expander>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</DockPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
|
|
87
Torch.Server/Views/ConfigControl.xaml.cs
Normal file
87
Torch.Server/Views/ConfigControl.xaml.cs
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
using Sandbox.Engine.Utils;
|
||||||
|
using Torch.Server.ViewModels;
|
||||||
|
using VRage.Game;
|
||||||
|
using Path = System.IO.Path;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for ConfigControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class ConfigControl : UserControl
|
||||||
|
{
|
||||||
|
public MyConfigDedicated<MyObjectBuilder_SessionSettings> Config { get; set; }
|
||||||
|
private ConfigDedicatedViewModel _viewModel;
|
||||||
|
private string _configPath;
|
||||||
|
|
||||||
|
public ConfigControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
LoadDedicatedConfig(@"C:\ProgramData\Torch\Torch\SpaceEngineers-Dedicated.cfg");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveConfig()
|
||||||
|
{
|
||||||
|
Config.Save(_configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadDedicatedConfig(string path)
|
||||||
|
{
|
||||||
|
Config = new MyConfigDedicated<MyObjectBuilder_SessionSettings>(path);
|
||||||
|
Config.Load(path);
|
||||||
|
|
||||||
|
_viewModel = new ConfigDedicatedViewModel(Config);
|
||||||
|
DataContext = _viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadDedicatedConfig(TorchConfig torchConfig)
|
||||||
|
{
|
||||||
|
var path = Path.Combine(torchConfig.InstancePath, "SpaceEngineers-Dedicated.cfg");
|
||||||
|
Config = new MyConfigDedicated<MyObjectBuilder_SessionSettings>(path);
|
||||||
|
Config.Load(path);
|
||||||
|
_configPath = path;
|
||||||
|
|
||||||
|
_viewModel = new ConfigDedicatedViewModel(Config);
|
||||||
|
var worldFolders = Directory.EnumerateDirectories(Path.Combine(torchConfig.InstancePath, "Saves"));
|
||||||
|
|
||||||
|
foreach (var f in worldFolders)
|
||||||
|
_viewModel.WorldPaths.Add(f);
|
||||||
|
|
||||||
|
DataContext = _viewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Banned_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
var editor = new CollectionEditor {Owner = Window.GetWindow(this)};
|
||||||
|
editor.Edit(_viewModel.Banned, "Banned Players");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Administrators_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
var editor = new CollectionEditor { Owner = Window.GetWindow(this) };
|
||||||
|
editor.Edit(_viewModel.Administrators, "Administrators");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Mods_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
var editor = new CollectionEditor { Owner = Window.GetWindow(this) };
|
||||||
|
editor.Edit(_viewModel.Mods, "Mods");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -7,14 +7,18 @@
|
|||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<StackPanel Margin="0,0,0,0" Orientation="Vertical">
|
<StackPanel Margin="0,0,0,0" Orientation="Vertical">
|
||||||
<Label Content="Mods" Margin="5,5,5,5"/>
|
<Label Content="Mods" Margin="5,5,5,5"/>
|
||||||
<ListView x:Name="ModList" HorizontalAlignment="Left" Height="265" VerticalAlignment="Top" Width="300" Margin="5,5,5,5" MouseDoubleClick="modList_OnMouesDoubleClick">
|
<ListView x:Name="ModList" HorizontalAlignment="Left" Height="265" VerticalAlignment="Top" Width="300" Margin="5,5,5,5" MouseDoubleClick="modList_OnMouseDoubleClick">
|
||||||
<ListView.ItemTemplate>
|
<ListView.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding FriendlyName}" ToolTip="{Binding Description}"/>
|
<TextBlock Text="{Binding FriendlyName}" ToolTip="{Binding Description}"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListView.ItemTemplate>
|
</ListView.ItemTemplate>
|
||||||
</ListView>
|
</ListView>
|
||||||
<Button x:Name="AddBtn" Content="Add Mods" Click="addBtn_Click" Margin="5,5,5,5"/>
|
<DockPanel>
|
||||||
<Button x:Name="RemBtn" Content="Remove Mods" Margin="5,5,5,5" Click="remBtn_Click"/>
|
<Button x:Name="RemBtn" Width="70" Content="Remove" Margin="3" Click="remBtn_Click" DockPanel.Dock="Right"/>
|
||||||
|
<Button x:Name="AddBtn" Width="70" Content="Add" Click="addBtn_Click" Margin="3" DockPanel.Dock="Right"/>
|
||||||
|
<Label Content="Mod ID:"/>
|
||||||
|
<TextBox x:Name="ModIdBox" Margin="3" DockPanel.Dock="Left"/>
|
||||||
|
</DockPanel>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@@ -31,23 +31,33 @@ namespace Torch.Server
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addBtn_Click(object sender, RoutedEventArgs e)
|
private void addBtn_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
ulong[] mods;
|
||||||
|
if (!string.IsNullOrEmpty(ModIdBox.Text))
|
||||||
|
{
|
||||||
|
mods = new ulong[1];
|
||||||
|
ulong.TryParse(ModIdBox.Text, out mods[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
var dialog = new AddModsDialog();
|
var dialog = new AddModsDialog();
|
||||||
dialog.ShowDialog();
|
dialog.ShowDialog();
|
||||||
|
mods = dialog.Result;
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var id in dialog.Result)
|
foreach (var id in mods)
|
||||||
{
|
{
|
||||||
var details = SteamHelper.GetItemDetails(id);
|
var details = SteamHelper.GetItemDetails(id);
|
||||||
if (details.FileType != WorkshopFileType.Community)
|
if (details.FileType != WorkshopFileType.Community)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var item = SteamHelper.GetModItem(details);
|
var item = SteamHelper.GetModItem(details);
|
||||||
var desc = string.Join("\n", details.Description.ReadLines(5, true), "Double click to open the workshop page.");
|
var desc = details.Description.Length < 500 ? details.Description : details.Description.Substring(0, 500);
|
||||||
ModList.Items.Add(new ModViewModel(item, desc));
|
ModList.Items.Add(new ModViewModel(item, desc));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void modList_OnMouesDoubleClick(object sender, MouseButtonEventArgs e)
|
private void modList_OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
var box = (ListView)sender;
|
var box = (ListView)sender;
|
||||||
if (box.SelectedItem == null)
|
if (box.SelectedItem == null)
|
||||||
|
@@ -19,6 +19,7 @@ using Sandbox.Game.Multiplayer;
|
|||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using SteamSDK;
|
using SteamSDK;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
|
|
||||||
namespace Torch.Server
|
namespace Torch.Server
|
||||||
{
|
{
|
||||||
@@ -37,35 +38,35 @@ namespace Torch.Server
|
|||||||
public void BindServer(ITorchServer server)
|
public void BindServer(ITorchServer server)
|
||||||
{
|
{
|
||||||
_server = server;
|
_server = server;
|
||||||
server.Multiplayer.PlayerJoined += Refresh;
|
//server.Multiplayer.PlayerJoined += Refresh;
|
||||||
server.Multiplayer.PlayerLeft += Refresh;
|
//server.Multiplayer.PlayerLeft += Refresh;
|
||||||
Refresh();
|
Refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Refresh(IPlayer player = null)
|
private void Refresh(IMyPlayer player = null)
|
||||||
{
|
{
|
||||||
Dispatcher.Invoke(() =>
|
Dispatcher.Invoke(() =>
|
||||||
{
|
{
|
||||||
PlayerList.ItemsSource = null;
|
PlayerList.ItemsSource = null;
|
||||||
PlayerList.ItemsSource = _server.Multiplayer.Players;
|
//PlayerList.ItemsSource = _server.Multiplayer.Players;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void KickButton_Click(object sender, RoutedEventArgs e)
|
private void KickButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var player = PlayerList.SelectedItem as IPlayer;
|
var player = PlayerList.SelectedItem as IMyPlayer;
|
||||||
if (player != null)
|
if (player != null)
|
||||||
{
|
{
|
||||||
_server.Multiplayer.KickPlayer(player.SteamId);
|
_server.Multiplayer.KickPlayer(player.SteamUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BanButton_Click(object sender, RoutedEventArgs e)
|
private void BanButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var player = PlayerList.SelectedItem as IPlayer;
|
var player = PlayerList.SelectedItem as IMyPlayer;
|
||||||
if (player != null)
|
if (player != null)
|
||||||
{
|
{
|
||||||
_server.Multiplayer.BanPlayer(player.SteamId);
|
_server.Multiplayer.BanPlayer(player.SteamUserId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,15 +0,0 @@
|
|||||||
<UserControl x:Class="Torch.Server.Views.PropertyGrid"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:local="clr-namespace:Torch.Server.Views"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DesignHeight="300" d:DesignWidth="300">
|
|
||||||
<DataGrid x:Name="Grid" AutoGenerateColumns="False">
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridTextColumn x:Name="NameCol" Width="1*" Header="Name" Binding="{Binding Name}" IsReadOnly="True"/>
|
|
||||||
<DataGridTemplateColumn x:Name="ValCol" Width="1*" Header="Value"/>
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
</UserControl>
|
|
@@ -1,68 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Data;
|
|
||||||
using System.Windows.Documents;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using System.Windows.Navigation;
|
|
||||||
using System.Windows.Shapes;
|
|
||||||
|
|
||||||
namespace Torch.Server.Views
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for PropertyGrid.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class PropertyGrid : UserControl
|
|
||||||
{
|
|
||||||
public PropertyGrid()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetObject(object obj)
|
|
||||||
{
|
|
||||||
var props = obj.GetType().GetProperties();
|
|
||||||
foreach (var prop in props)
|
|
||||||
{
|
|
||||||
var p = prop.GetValue(obj);
|
|
||||||
Grid.Items.Add(new PropertyView(p, prop.Name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PropertyView : ViewModel
|
|
||||||
{
|
|
||||||
private object _obj;
|
|
||||||
|
|
||||||
public string Name { get; }
|
|
||||||
public string Value { get { return _obj.ToString(); } }
|
|
||||||
public DataTemplate ValueEditTemplate;
|
|
||||||
|
|
||||||
public PropertyView(object obj, string name)
|
|
||||||
{
|
|
||||||
Name = name;
|
|
||||||
_obj = obj;
|
|
||||||
|
|
||||||
ValueEditTemplate = new DataTemplate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
public class PropertyGridDataTemplateSelector : DataTemplateSelector
|
|
||||||
{
|
|
||||||
public override DataTemplate SelectTemplate(object item, DependencyObject container)
|
|
||||||
{
|
|
||||||
if (item is IEnumerable)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
|
@@ -6,7 +6,7 @@
|
|||||||
xmlns:local="clr-namespace:Torch.Server"
|
xmlns:local="clr-namespace:Torch.Server"
|
||||||
xmlns:views="clr-namespace:Torch.Server.Views"
|
xmlns:views="clr-namespace:Torch.Server.Views"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Piston" Height="600" Width="900">
|
Title="Torch" Height="900" Width="600">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<StackPanel DockPanel.Dock="Top" Margin="5,5,5,5" Orientation="Horizontal">
|
<StackPanel DockPanel.Dock="Top" Margin="5,5,5,5" Orientation="Horizontal">
|
||||||
<Button x:Name="BtnStart" Content="Start" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left" Click="BtnStart_Click" IsDefault="True"/>
|
<Button x:Name="BtnStart" Content="Start" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left" Click="BtnStart_Click" IsDefault="True"/>
|
||||||
@@ -17,10 +17,10 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TabControl x:Name="TabControl" DockPanel.Dock="Bottom" Margin="5,0,5,5">
|
<TabControl x:Name="TabControl" DockPanel.Dock="Bottom" Margin="5,0,5,5">
|
||||||
<TabItem Header="Configuration">
|
<TabItem Header="Configuration">
|
||||||
<DockPanel>
|
<StackPanel>
|
||||||
<local:ModsControl/>
|
<TextBox x:Name="InstancePathBox" Margin="3" Height="20" TextChanged="InstancePathBox_OnTextChanged"/>
|
||||||
<views:PropertyGrid x:Name="PropGrid"/>
|
<views:ConfigControl x:Name="ConfigControl" Margin="3"/>
|
||||||
</DockPanel>
|
</StackPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Chat/Players">
|
<TabItem Header="Chat/Players">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
|
@@ -27,7 +27,8 @@ namespace Torch.Server
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class TorchUI : Window
|
public partial class TorchUI : Window
|
||||||
{
|
{
|
||||||
private ITorchServer _server;
|
private TorchServer _server;
|
||||||
|
private TorchConfig _config;
|
||||||
private DateTime _startTime;
|
private DateTime _startTime;
|
||||||
private readonly Timer _uiUpdate = new Timer
|
private readonly Timer _uiUpdate = new Timer
|
||||||
{
|
{
|
||||||
@@ -35,7 +36,7 @@ namespace Torch.Server
|
|||||||
AutoReset = true,
|
AutoReset = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
public TorchUI(ITorchServer server)
|
public TorchUI(TorchServer server)
|
||||||
{
|
{
|
||||||
_server = server;
|
_server = server;
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
@@ -46,6 +47,19 @@ namespace Torch.Server
|
|||||||
PlayerList.BindServer(server);
|
PlayerList.BindServer(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void LoadConfig(TorchConfig config)
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(config.InstancePath))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_config = config;
|
||||||
|
Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
ConfigControl.LoadDedicatedConfig(config);
|
||||||
|
InstancePathBox.Text = config.InstancePath;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void UiUpdate_Elapsed(object sender, ElapsedEventArgs e)
|
private void UiUpdate_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
{
|
{
|
||||||
UpdateUptime();
|
UpdateUptime();
|
||||||
@@ -67,7 +81,8 @@ namespace Torch.Server
|
|||||||
((Button) sender).IsEnabled = false;
|
((Button) sender).IsEnabled = false;
|
||||||
BtnStop.IsEnabled = true;
|
BtnStop.IsEnabled = true;
|
||||||
_uiUpdate.Start();
|
_uiUpdate.Start();
|
||||||
new Thread(() => _server.Start()).Start();
|
ConfigControl.SaveConfig();
|
||||||
|
new Thread(() => _server.Start(ConfigControl.Config)).Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -83,12 +98,23 @@ namespace Torch.Server
|
|||||||
|
|
||||||
protected override void OnClosing(CancelEventArgs e)
|
protected override void OnClosing(CancelEventArgs e)
|
||||||
{
|
{
|
||||||
|
if (_server?.IsRunning ?? false)
|
||||||
_server.Stop();
|
_server.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnRestart_Click(object sender, RoutedEventArgs e)
|
private void BtnRestart_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
//Program.FullRestart();
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InstancePathBox_OnTextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var name = (sender as TextBox).Text;
|
||||||
|
|
||||||
|
_server.SetInstance(null, name);
|
||||||
|
_config.InstancePath = name;
|
||||||
|
|
||||||
|
LoadConfig(_config);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
10
Torch.sln
10
Torch.sln
@@ -1,7 +1,7 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio 15
|
# Visual Studio 15
|
||||||
VisualStudioVersion = 15.0.25928.0
|
VisualStudioVersion = 15.0.26127.3
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch", "Torch\Torch.csproj", "{7E01635C-3B67-472E-BCD6-C5539564F214}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch", "Torch\Torch.csproj", "{7E01635C-3B67-472E-BCD6-C5539564F214}"
|
||||||
EndProject
|
EndProject
|
||||||
@@ -13,8 +13,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Server", "Torch.Serve
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Launcher", "Torch.Launcher\Torch.Launcher.csproj", "{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Torch.Launcher", "Torch.Launcher\Torch.Launcher.csproj", "{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{ABD18A6C-F638-44E9-8E55-DEDEA321C600}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7AD02A71-1D4C-48F9-A8C1-789A5512424F}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
NLog.config = NLog.config
|
NLog.config = NLog.config
|
||||||
@@ -58,12 +56,6 @@ Global
|
|||||||
{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}.Release|Any CPU.ActiveCfg = Release|x64
|
{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}.Release|Any CPU.ActiveCfg = Release|x64
|
||||||
{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}.Release|x64.ActiveCfg = Release|x64
|
{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}.Release|x64.ActiveCfg = Release|x64
|
||||||
{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}.Release|x64.Build.0 = Release|x64
|
{19292801-5B9C-4EE0-961F-0FA37B3A6C3D}.Release|x64.Build.0 = Release|x64
|
||||||
{ABD18A6C-F638-44E9-8E55-DEDEA321C600}.Debug|Any CPU.ActiveCfg = Debug|x64
|
|
||||||
{ABD18A6C-F638-44E9-8E55-DEDEA321C600}.Debug|x64.ActiveCfg = Debug|x64
|
|
||||||
{ABD18A6C-F638-44E9-8E55-DEDEA321C600}.Debug|x64.Build.0 = Debug|x64
|
|
||||||
{ABD18A6C-F638-44E9-8E55-DEDEA321C600}.Release|Any CPU.ActiveCfg = Release|x64
|
|
||||||
{ABD18A6C-F638-44E9-8E55-DEDEA321C600}.Release|x64.ActiveCfg = Release|x64
|
|
||||||
{ABD18A6C-F638-44E9-8E55-DEDEA321C600}.Release|x64.Build.0 = Release|x64
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
37
Torch/ChatMessage.cs
Normal file
37
Torch/ChatMessage.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Engine.Networking;
|
||||||
|
using Torch.API;
|
||||||
|
using VRage.Network;
|
||||||
|
|
||||||
|
namespace Torch
|
||||||
|
{
|
||||||
|
public struct ChatMessage : IChatMessage
|
||||||
|
{
|
||||||
|
public DateTime Timestamp { get; }
|
||||||
|
public ulong SteamId { get; }
|
||||||
|
public string Name { get; }
|
||||||
|
public string Message { get; }
|
||||||
|
|
||||||
|
public ChatMessage(DateTime timestamp, ulong steamId, string name, string message)
|
||||||
|
{
|
||||||
|
Timestamp = timestamp;
|
||||||
|
SteamId = steamId;
|
||||||
|
Name = name;
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChatMessage FromChatMsg(ChatMsg msg, DateTime dt = default(DateTime))
|
||||||
|
{
|
||||||
|
return new ChatMessage(
|
||||||
|
dt == default(DateTime) ? DateTime.Now : dt,
|
||||||
|
msg.Author,
|
||||||
|
MyMultiplayer.Static.GetMemberName(msg.Author),
|
||||||
|
msg.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -9,6 +9,25 @@ namespace Torch.Collections
|
|||||||
public class KeyTree<TKey, TValue>
|
public class KeyTree<TKey, TValue>
|
||||||
{
|
{
|
||||||
private Dictionary<TKey, KeyTreeNode<TKey, TValue>> _nodes = new Dictionary<TKey, KeyTreeNode<TKey, TValue>>();
|
private Dictionary<TKey, KeyTreeNode<TKey, TValue>> _nodes = new Dictionary<TKey, KeyTreeNode<TKey, TValue>>();
|
||||||
|
|
||||||
|
public KeyTreeNode<TKey, TValue> this[TKey key] => _nodes[key];
|
||||||
|
|
||||||
|
public void AddNode(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
_nodes.Add(key, new KeyTreeNode<TKey, TValue>(key, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool RemoveNode(TKey key)
|
||||||
|
{
|
||||||
|
return _nodes.Remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<KeyTreeNode<TKey, TValue>> Traverse()
|
||||||
|
{
|
||||||
|
foreach (var node in _nodes.Values)
|
||||||
|
foreach (var child in node.Traverse())
|
||||||
|
yield return child;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KeyTreeNode<TKey, TValue>
|
public class KeyTreeNode<TKey, TValue>
|
||||||
@@ -26,6 +45,8 @@ namespace Torch.Collections
|
|||||||
Value = value;
|
Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public KeyTreeNode<TKey, TValue> this[TKey key] => _children[key];
|
||||||
|
|
||||||
public KeyTreeNode<TKey, TValue> GetChild(TKey key)
|
public KeyTreeNode<TKey, TValue> GetChild(TKey key)
|
||||||
{
|
{
|
||||||
if (_children.TryGetValue(key, out KeyTreeNode<TKey, TValue> value))
|
if (_children.TryGetValue(key, out KeyTreeNode<TKey, TValue> value))
|
||||||
|
@@ -1,37 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Torch.API;
|
|
||||||
|
|
||||||
namespace Torch
|
|
||||||
{
|
|
||||||
public static class PlayerInfoCache
|
|
||||||
{
|
|
||||||
private static readonly Dictionary<ulong, Player> _cache = new Dictionary<ulong, Player>();
|
|
||||||
|
|
||||||
public static Player GetOrCreate(ulong steamId)
|
|
||||||
{
|
|
||||||
if (_cache.TryGetValue(steamId, out Player info))
|
|
||||||
return info;
|
|
||||||
|
|
||||||
info = new Player(steamId) {State = ConnectionState.Unknown};
|
|
||||||
_cache.Add(steamId, info);
|
|
||||||
return info;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Add(Player info)
|
|
||||||
{
|
|
||||||
if (_cache.ContainsKey(info.SteamId))
|
|
||||||
return;
|
|
||||||
|
|
||||||
_cache.Add(info.SteamId, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Reset()
|
|
||||||
{
|
|
||||||
_cache.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -25,12 +25,17 @@ namespace Torch.Commands
|
|||||||
/// The command arguments split by spaces and quotes. Ex. "this is" a command -> {this is, a, command}
|
/// The command arguments split by spaces and quotes. Ex. "this is" a command -> {this is, a, command}
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<string> Args { get; }
|
public List<string> Args { get; }
|
||||||
|
/// <summary>
|
||||||
|
/// The non-split argument string.
|
||||||
|
/// </summary>
|
||||||
|
public string RawArgs { get; }
|
||||||
|
|
||||||
public CommandContext(ITorchBase torch, ITorchPlugin plugin, IMyPlayer player, List<string> args = null)
|
public CommandContext(ITorchBase torch, ITorchPlugin plugin, IMyPlayer player, string rawArgs = null, List<string> args = null)
|
||||||
{
|
{
|
||||||
Torch = torch;
|
Torch = torch;
|
||||||
Plugin = plugin;
|
Plugin = plugin;
|
||||||
Player = player;
|
Player = player;
|
||||||
|
RawArgs = rawArgs;
|
||||||
Args = args ?? new List<string>();
|
Args = args ?? new List<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -19,13 +19,12 @@ namespace Torch.Commands
|
|||||||
public CommandTree Commands { get; set; } = new CommandTree();
|
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 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;
|
ChatManager.Instance.MessageRecieved += HandleCommand;
|
||||||
RegisterCommandModule(typeof(TorchCommands));
|
RegisterCommandModule(typeof(TorchCommands));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,12 +83,7 @@ namespace Torch.Commands
|
|||||||
}
|
}
|
||||||
|
|
||||||
var cmdText = new string(msg.Text.Skip(1).ToArray());
|
var cmdText = new string(msg.Text.Skip(1).ToArray());
|
||||||
var split = Regex.Matches(cmdText, "(\"[^\"]+\"|\\S+)").Cast<Match>().Select(x => x.ToString().Replace("\"", "")).ToList();
|
var command = Commands.GetCommand(cmdText, out string argText);
|
||||||
|
|
||||||
if (split.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var command = Commands.ParseCommand(split, out List<string> args);
|
|
||||||
|
|
||||||
if (command != null)
|
if (command != null)
|
||||||
{
|
{
|
||||||
@@ -102,8 +96,9 @@ namespace Torch.Commands
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var splitArgs = Regex.Matches(argText, "(\"[^\"]+\"|\\S+)").Cast<Match>().Select(x => x.ToString().Replace("\"", "")).ToList();
|
||||||
_log.Trace($"Invoking {cmdPath} for player {player.DisplayName}");
|
_log.Trace($"Invoking {cmdPath} for player {player.DisplayName}");
|
||||||
var context = new CommandContext(_torch, command.Plugin, player, args);
|
var context = new CommandContext(_torch, command.Plugin, player, argText, splitArgs);
|
||||||
command.Invoke(context);
|
command.Invoke(context);
|
||||||
_log.Info($"Player {player.DisplayName} ran command '{msg.Text}'");
|
_log.Info($"Player {player.DisplayName} ran command '{msg.Text}'");
|
||||||
}
|
}
|
||||||
|
@@ -3,6 +3,7 @@ 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 Torch.API;
|
||||||
using VRage.Collections;
|
using VRage.Collections;
|
||||||
using VRage.Library.Collections;
|
using VRage.Library.Collections;
|
||||||
|
|
||||||
@@ -75,13 +76,17 @@ namespace Torch.Commands
|
|||||||
{
|
{
|
||||||
node = node.Subcommands[current];
|
node = node.Subcommands[current];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
commandNode = node;
|
commandNode = node;
|
||||||
return path.Count - i + 1;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Command ParseCommand(List<string> path, out List<string> args)
|
public Command GetCommand(List<string> path, out List<string> args)
|
||||||
{
|
{
|
||||||
args = new List<string>();
|
args = new List<string>();
|
||||||
var skip = GetNode(path, out CommandNode node);
|
var skip = GetNode(path, out CommandNode node);
|
||||||
@@ -89,6 +94,29 @@ namespace Torch.Commands
|
|||||||
return node.Command;
|
return node.Command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Command GetCommand(string commandText, out string argText)
|
||||||
|
{
|
||||||
|
var split = commandText.Split(new []{' '}, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||||
|
var skip = GetNode(split, out CommandNode node);
|
||||||
|
if (skip == -1)
|
||||||
|
{
|
||||||
|
argText = "";
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (split.Count > skip)
|
||||||
|
{
|
||||||
|
var substringIndex = commandText.IndexOf(split[skip]);
|
||||||
|
if (substringIndex <= commandText.Length)
|
||||||
|
{
|
||||||
|
argText = commandText.Substring(substringIndex);
|
||||||
|
return node.Command;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
argText = "";
|
||||||
|
return node.Command;
|
||||||
|
}
|
||||||
|
|
||||||
public string GetTreeString()
|
public string GetTreeString()
|
||||||
{
|
{
|
||||||
@@ -102,6 +130,17 @@ namespace Torch.Commands
|
|||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<CommandNode> WalkTree(CommandNode root = null)
|
||||||
|
{
|
||||||
|
foreach (var node in root?.GetChildren() ?? _root.Values)
|
||||||
|
{
|
||||||
|
yield return node;
|
||||||
|
|
||||||
|
foreach (var child in WalkTree(node))
|
||||||
|
yield return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void DebugNode(CommandNode commandNode, StringBuilder sb, ref int indent)
|
private void DebugNode(CommandNode commandNode, StringBuilder sb, ref int indent)
|
||||||
{
|
{
|
||||||
sb.AppendLine(new string(' ', indent) + commandNode.Name);
|
sb.AppendLine(new string(' ', indent) + commandNode.Name);
|
||||||
@@ -143,6 +182,11 @@ namespace Torch.Commands
|
|||||||
return Subcommands.TryGetValue(name, out node);
|
return Subcommands.TryGetValue(name, out node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<CommandNode> GetChildren()
|
||||||
|
{
|
||||||
|
return _subcommands.Values;
|
||||||
|
}
|
||||||
|
|
||||||
public List<string> GetPath()
|
public List<string> GetPath()
|
||||||
{
|
{
|
||||||
var path = new List<string> {Name};
|
var path = new List<string> {Name};
|
||||||
|
@@ -1,19 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -3,21 +3,20 @@ 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 NLog;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using VRage;
|
||||||
using VRage.Library.Collections;
|
using VRage.Library.Collections;
|
||||||
using VRage.Network;
|
using VRage.Network;
|
||||||
|
using VRage.Serialization;
|
||||||
using VRage.Utils;
|
using VRage.Utils;
|
||||||
|
|
||||||
namespace Torch.Managers
|
namespace Torch.Managers
|
||||||
{
|
{
|
||||||
public class ChatManager
|
public class ChatManager
|
||||||
{
|
{
|
||||||
private ChatManager()
|
public static ChatManager Instance { get; } = new ChatManager();
|
||||||
{
|
private static Logger _log = LogManager.GetLogger(nameof(ChatManager));
|
||||||
NetworkManager.Instance.RegisterNetworkHandlers(new ChatIntercept());
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ChatManager _instance;
|
|
||||||
public static ChatManager Instance => _instance ?? (_instance = new ChatManager());
|
|
||||||
|
|
||||||
public delegate void MessageRecievedDel(ChatMsg msg, ref bool sendToOthers);
|
public delegate void MessageRecievedDel(ChatMsg msg, ref bool sendToOthers);
|
||||||
|
|
||||||
@@ -25,6 +24,22 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
internal void RaiseMessageRecieved(ChatMsg msg, ref bool sendToOthers) =>
|
internal void RaiseMessageRecieved(ChatMsg msg, ref bool sendToOthers) =>
|
||||||
MessageRecieved?.Invoke(msg, ref sendToOthers);
|
MessageRecieved?.Invoke(msg, ref sendToOthers);
|
||||||
|
|
||||||
|
public void Init()
|
||||||
|
{
|
||||||
|
//HACK
|
||||||
|
MyMultiplayer.Static.ChatMessageReceived += Static_ChatMessageReceived;
|
||||||
|
_log.Warn("Chat intercept broken, chat hiding will not work!");
|
||||||
|
//NetworkManager.Instance.RegisterNetworkHandlers(new ChatIntercept());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Static_ChatMessageReceived(ulong arg1, string arg2, SteamSDK.ChatEntryTypeEnum arg3)
|
||||||
|
{
|
||||||
|
var msg = new ChatMsg {Author = arg1, Text = arg2};
|
||||||
|
var sendToOthers = true;
|
||||||
|
|
||||||
|
RaiseMessageRecieved(msg, ref sendToOthers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class ChatIntercept : NetworkHandlerBase
|
internal class ChatIntercept : NetworkHandlerBase
|
||||||
@@ -53,11 +68,32 @@ namespace Torch.Managers
|
|||||||
return _unitTestResult.Value;
|
return _unitTestResult.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Handle(ulong remoteUserId, CallSite site, BitStream stream, object obj)
|
public override bool Handle(ulong remoteUserId, CallSite site, BitStream stream, object obj, MyPacket packet)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
var msg = new ChatMsg();
|
var msg = new ChatMsg();
|
||||||
|
|
||||||
base.Serialize(site.MethodInfo, stream, ref msg);
|
var msgLength = stream.ByteLength - stream.BytePosition - 8;
|
||||||
|
var bytes = new byte[msgLength];
|
||||||
|
stream.ReadBytes(bytes, stream.BytePosition, msgLength);
|
||||||
|
|
||||||
|
msg.Text = Encoding.Unicode.GetString(bytes);
|
||||||
|
msg.Author = stream.ReadUInt64();
|
||||||
|
|
||||||
|
var log = LogManager.GetLogger("HandleDebug");
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
foreach (char c in msg.Text.ToCharArray())
|
||||||
|
{
|
||||||
|
sb.Append(Convert.ToString(c, 2).PadLeft(16, '0'));
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Debug(sb.ToString());*/
|
||||||
|
//stream.ResetRead(packet);
|
||||||
|
//var msg = MySerializer.CreateAndRead<ChatMsg>(stream);
|
||||||
|
|
||||||
|
var msg = new ChatMsg();
|
||||||
|
Serialize(site.MethodInfo, stream, ref msg);
|
||||||
|
|
||||||
bool sendToOthers = true;
|
bool sendToOthers = true;
|
||||||
ChatManager.Instance.RaiseMessageRecieved(msg, ref sendToOthers);
|
ChatManager.Instance.RaiseMessageRecieved(msg, ref sendToOthers);
|
||||||
|
349
Torch/Managers/EntityManager.cs
Normal file
349
Torch/Managers/EntityManager.cs
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Timers;
|
||||||
|
using NLog;
|
||||||
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Game.Entities;
|
||||||
|
using Sandbox.Game.Entities.Blocks;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
|
using SpaceEngineers.Game.Entities.Blocks;
|
||||||
|
using SpaceEngineers.Game.ModAPI;
|
||||||
|
using Torch.API;
|
||||||
|
using VRage;
|
||||||
|
using VRage.Collections;
|
||||||
|
using VRage.Game;
|
||||||
|
using VRage.Game.Entity;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
|
using VRage.Groups;
|
||||||
|
using VRage.ModAPI;
|
||||||
|
using VRage.ObjectBuilders;
|
||||||
|
using VRage.Sync;
|
||||||
|
using VRageMath;
|
||||||
|
|
||||||
|
namespace Torch.Managers
|
||||||
|
{
|
||||||
|
public class EntityManager
|
||||||
|
{
|
||||||
|
private readonly ITorchBase _torch;
|
||||||
|
private static readonly Logger Log = LogManager.GetLogger(nameof(EntityManager));
|
||||||
|
|
||||||
|
public EntityManager(ITorchBase torch)
|
||||||
|
{
|
||||||
|
_torch = torch;
|
||||||
|
_torch.SessionLoaded += () => InitConcealment(60000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExportGrid(IMyCubeGrid grid, string path)
|
||||||
|
{
|
||||||
|
var ob = grid.GetObjectBuilder(true);
|
||||||
|
using (var f = File.Open(path, FileMode.CreateNew))
|
||||||
|
MyObjectBuilderSerializer.SerializeXML(f, ob);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ImportGrid(string path, Vector3D position)
|
||||||
|
{
|
||||||
|
MyObjectBuilder_EntityBase gridOb;
|
||||||
|
using (var f = File.OpenRead(path))
|
||||||
|
MyObjectBuilderSerializer.DeserializeXML(f, out gridOb);
|
||||||
|
|
||||||
|
var grid = MyEntities.CreateFromObjectBuilderParallel(gridOb);
|
||||||
|
grid.PositionComp.SetPosition(position);
|
||||||
|
MyEntities.Add(grid);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Concealment
|
||||||
|
|
||||||
|
private readonly List<ConcealGroup> _concealGroups = new List<ConcealGroup>();
|
||||||
|
private MyDynamicAABBTreeD _concealedAabbTree;
|
||||||
|
|
||||||
|
public void GetConcealedGrids(List<IMyCubeGrid> grids)
|
||||||
|
{
|
||||||
|
_concealGroups.SelectMany(x => x.Grids).ForEach(grids.Add);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Timer _concealTimer;
|
||||||
|
private Timer _revealTimer;
|
||||||
|
private volatile bool _concealInProgress;
|
||||||
|
|
||||||
|
public void InitConcealment(double concealInterval)
|
||||||
|
{
|
||||||
|
Log.Info($"Initializing concealment to run every {concealInterval}ms");
|
||||||
|
_concealedAabbTree = new MyDynamicAABBTreeD(MyConstants.GAME_PRUNING_STRUCTURE_AABB_EXTENSION);
|
||||||
|
_concealTimer = new Timer(concealInterval);
|
||||||
|
_concealTimer.Elapsed += ConcealTimerElapsed;
|
||||||
|
_concealTimer.Start();
|
||||||
|
_revealTimer = new Timer(1000);
|
||||||
|
_revealTimer.Elapsed += RevealTimerElapsed;
|
||||||
|
_revealTimer.Start();
|
||||||
|
MySession.Static.Players.PlayerRequesting += RevealSpawns;
|
||||||
|
MyMultiplayer.Static.ClientJoined += RevealCryoPod;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RevealTimerElapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
_torch.Invoke(() => RevealNearbyGrids(MyMultiplayer.Static.ViewDistance));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RevealCryoPod(ulong steamId)
|
||||||
|
{
|
||||||
|
_torch.Invoke(() =>
|
||||||
|
{
|
||||||
|
Log.Debug(nameof(RevealCryoPod));
|
||||||
|
for (var i = _concealGroups.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var group = _concealGroups[i];
|
||||||
|
|
||||||
|
if (group.IsCryoOccupied(steamId))
|
||||||
|
{
|
||||||
|
RevealGroup(group);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RevealSpawns(PlayerRequestArgs args)
|
||||||
|
{
|
||||||
|
_torch.Invoke(() =>
|
||||||
|
{
|
||||||
|
Log.Debug(nameof(RevealSpawns));
|
||||||
|
var identityId = MySession.Static.Players.TryGetIdentityId(args.PlayerId.SteamId);
|
||||||
|
if (identityId == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (var i = _concealGroups.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
var group = _concealGroups[i];
|
||||||
|
|
||||||
|
if (group.IsMedicalRoomAvailable(identityId))
|
||||||
|
RevealGroup(group);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConcealTimerElapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
if (_concealInProgress)
|
||||||
|
{
|
||||||
|
Log.Warn($"Concealment taking longer to complete than the conceal interval of {_concealTimer.Interval}ms");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_concealInProgress = true;
|
||||||
|
Log.Debug("Running concealment");
|
||||||
|
_torch.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (MyAPIGateway.Session == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var viewDistance = MyMultiplayer.Static.ViewDistance;
|
||||||
|
var concealDistance = viewDistance > 50000 ? viewDistance : 50000;
|
||||||
|
|
||||||
|
ConcealDistantGrids(concealDistance * 2);
|
||||||
|
_concealInProgress = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ConcealEntity(IMyEntity entity)
|
||||||
|
{
|
||||||
|
if (entity != entity.GetTopMostParent())
|
||||||
|
throw new InvalidOperationException("Can only conceal top-level entities.");
|
||||||
|
|
||||||
|
MyGamePruningStructure.Remove((MyEntity)entity);
|
||||||
|
entity.Physics?.Deactivate();
|
||||||
|
UnregisterRecursive(entity);
|
||||||
|
|
||||||
|
void UnregisterRecursive(IMyEntity e)
|
||||||
|
{
|
||||||
|
MyEntities.UnregisterForUpdate((MyEntity)e);
|
||||||
|
foreach (var child in e.Hierarchy.Children)
|
||||||
|
UnregisterRecursive(child.Entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RevealEntity(IMyEntity entity)
|
||||||
|
{
|
||||||
|
if (entity != entity.GetTopMostParent())
|
||||||
|
throw new InvalidOperationException("Can only conceal top-level entities.");
|
||||||
|
|
||||||
|
MyGamePruningStructure.Add((MyEntity)entity);
|
||||||
|
entity.Physics?.Activate();
|
||||||
|
RegisterRecursive(entity);
|
||||||
|
|
||||||
|
void RegisterRecursive(IMyEntity e)
|
||||||
|
{
|
||||||
|
MyEntities.RegisterForUpdate((MyEntity)e);
|
||||||
|
foreach (var child in e.Hierarchy.Children)
|
||||||
|
RegisterRecursive(child.Entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ConcealGroup(ConcealGroup group)
|
||||||
|
{
|
||||||
|
if (_concealGroups.Any(g => g.Id == group.Id))
|
||||||
|
return false;
|
||||||
|
Log.Info($"Concealing grids: {string.Join(", ", group.Grids.Select(g => g.DisplayName))}");
|
||||||
|
group.ConcealTime = DateTime.Now;
|
||||||
|
group.Grids.ForEach(ConcealEntity);
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
group.UpdatePostConceal();
|
||||||
|
var aabb = group.WorldAABB;
|
||||||
|
group.ProxyId = _concealedAabbTree.AddProxy(ref aabb, group, 0);
|
||||||
|
Log.Debug($"Group {group.Id} cached");
|
||||||
|
_torch.Invoke(() => _concealGroups.Add(group));
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RevealGroup(ConcealGroup group)
|
||||||
|
{
|
||||||
|
Log.Info($"Revealing grids: {string.Join(", ", group.Grids.Select(g => g.DisplayName))}");
|
||||||
|
group.Grids.ForEach(RevealEntity);
|
||||||
|
_concealGroups.Remove(group);
|
||||||
|
_concealedAabbTree.RemoveProxy(group.ProxyId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly List<ConcealGroup> _intersectGroups = new List<ConcealGroup>();
|
||||||
|
public void RevealGridsInSphere(BoundingSphereD sphere)
|
||||||
|
{
|
||||||
|
_concealedAabbTree.OverlapAllBoundingSphere(ref sphere, _intersectGroups);
|
||||||
|
foreach (var group in _intersectGroups)
|
||||||
|
{
|
||||||
|
RevealGroup(group);
|
||||||
|
}
|
||||||
|
_intersectGroups.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RevealNearbyGrids(double distanceFromPlayers)
|
||||||
|
{
|
||||||
|
var playerSpheres = GetPlayerBoundingSpheres(distanceFromPlayers);
|
||||||
|
foreach (var sphere in playerSpheres)
|
||||||
|
{
|
||||||
|
RevealGridsInSphere(sphere);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ConcealDistantGrids(double distanceFromPlayers)
|
||||||
|
{
|
||||||
|
var playerSpheres = GetPlayerBoundingSpheres(distanceFromPlayers);
|
||||||
|
|
||||||
|
foreach (var group in MyCubeGridGroups.Static.Physical.Groups)
|
||||||
|
{
|
||||||
|
var volume = group.GetWorldAABB();
|
||||||
|
if (playerSpheres.Any(s => s.Contains(volume) != ContainmentType.Disjoint))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
ConcealGroup(new ConcealGroup(group));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<BoundingSphereD> GetPlayerBoundingSpheres(double distance)
|
||||||
|
{
|
||||||
|
return ((MyPlayerCollection)MyAPIGateway.Multiplayer.Players).GetOnlinePlayers()
|
||||||
|
.Where(p => p.Controller?.ControlledEntity != null)
|
||||||
|
.Select(p => new BoundingSphereD(p.Controller.ControlledEntity.Entity.PositionComp.GetPosition(), distance)).ToList();
|
||||||
|
}
|
||||||
|
#endregion Concealment
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class GroupExtensions
|
||||||
|
{
|
||||||
|
public static BoundingBoxD GetWorldAABB(this MyGroups<MyCubeGrid, MyGridPhysicalGroupData>.Group group)
|
||||||
|
{
|
||||||
|
var grids = group.Nodes.Select(n => n.NodeData);
|
||||||
|
|
||||||
|
var startPos = grids.First().PositionComp.GetPosition();
|
||||||
|
var box = new BoundingBoxD(startPos, startPos);
|
||||||
|
|
||||||
|
foreach (var aabb in grids.Select(g => g.PositionComp.WorldAABB))
|
||||||
|
box.Include(aabb);
|
||||||
|
|
||||||
|
return box;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ConcealGroup
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Entity ID of the first grid in the group.
|
||||||
|
/// </summary>
|
||||||
|
public long Id { get; }
|
||||||
|
public DateTime ConcealTime { get; set; }
|
||||||
|
public BoundingBoxD WorldAABB { get; private set; }
|
||||||
|
public List<MyCubeGrid> Grids { get; }
|
||||||
|
public List<MyMedicalRoom> MedicalRooms { get; } = new List<MyMedicalRoom>();
|
||||||
|
public List<MyCryoChamber> CryoChambers { get; } = new List<MyCryoChamber>();
|
||||||
|
internal volatile int ProxyId = -1;
|
||||||
|
|
||||||
|
public ConcealGroup(MyGroups<MyCubeGrid, MyGridPhysicalGroupData>.Group group)
|
||||||
|
{
|
||||||
|
Grids = group.Nodes.Select(n => n.NodeData).ToList();
|
||||||
|
Id = Grids.First().EntityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdatePostConceal()
|
||||||
|
{
|
||||||
|
UpdateAABB();
|
||||||
|
CacheSpawns();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAABB()
|
||||||
|
{
|
||||||
|
var startPos = Grids.First().PositionComp.GetPosition();
|
||||||
|
var box = new BoundingBoxD(startPos, startPos);
|
||||||
|
|
||||||
|
foreach (var aabb in Grids.Select(g => g.PositionComp.WorldAABB))
|
||||||
|
box.Include(aabb);
|
||||||
|
|
||||||
|
WorldAABB = box;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CacheSpawns()
|
||||||
|
{
|
||||||
|
MedicalRooms.Clear();
|
||||||
|
CryoChambers.Clear();
|
||||||
|
|
||||||
|
foreach (var block in Grids.SelectMany(x => x.GetFatBlocks()))
|
||||||
|
{
|
||||||
|
if (block is MyMedicalRoom medical)
|
||||||
|
MedicalRooms.Add(medical);
|
||||||
|
else if (block is MyCryoChamber cryo)
|
||||||
|
CryoChambers.Add(cryo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsMedicalRoomAvailable(long identityId)
|
||||||
|
{
|
||||||
|
foreach (var room in MedicalRooms)
|
||||||
|
{
|
||||||
|
if (room.HasPlayerAccess(identityId) && room.IsWorking)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsCryoOccupied(ulong steamId)
|
||||||
|
{
|
||||||
|
var currentIdField = typeof(MyCryoChamber).GetField("m_currentPlayerId", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||||
|
|
||||||
|
foreach (var chamber in CryoChambers)
|
||||||
|
{
|
||||||
|
var value = (MyPlayer.PlayerId?)currentIdField.GetValue(chamber);
|
||||||
|
if (value?.SteamId == steamId)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -18,6 +18,7 @@ using Sandbox;
|
|||||||
using Sandbox.Engine.Multiplayer;
|
using Sandbox.Engine.Multiplayer;
|
||||||
using Sandbox.Game.Multiplayer;
|
using Sandbox.Game.Multiplayer;
|
||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
|
using Sandbox.ModAPI;
|
||||||
using SteamSDK;
|
using SteamSDK;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.ViewModels;
|
using Torch.ViewModels;
|
||||||
@@ -34,21 +35,30 @@ namespace Torch.Managers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class MultiplayerManager : IMultiplayer
|
public class MultiplayerManager : IMultiplayer
|
||||||
{
|
{
|
||||||
public event Action<IPlayer> PlayerJoined;
|
public event Action<ulong> PlayerJoined;
|
||||||
public event Action<IPlayer> PlayerLeft;
|
public event Action<ulong, ConnectionState> PlayerLeft;
|
||||||
public event Action<IChatItem> MessageReceived;
|
public event MessageReceivedDel MessageReceived;
|
||||||
|
|
||||||
public List<IChatItem> Chat { get; } = new List<IChatItem>();
|
public MTObservableCollection<IChatMessage> ChatHistory { get; } = new MTObservableCollection<IChatMessage>();
|
||||||
public Dictionary<ulong, IPlayer> Players { get; } = new Dictionary<ulong, IPlayer>();
|
public Dictionary<ulong, IMyPlayer> Players { get; } = new Dictionary<ulong, IMyPlayer>();
|
||||||
public Player LocalPlayer { get; private set; }
|
public IMyPlayer LocalPlayer => MySession.Static.LocalHumanPlayer;
|
||||||
private readonly ITorchBase _torch;
|
private readonly ITorchBase _torch;
|
||||||
private static Logger _log = LogManager.GetLogger(nameof(MultiplayerManager));
|
private static Logger _log = LogManager.GetLogger(nameof(MultiplayerManager));
|
||||||
|
private static Logger _chatLog = LogManager.GetLogger("Chat");
|
||||||
private Dictionary<MyPlayer.PlayerId, MyPlayer> _onlinePlayers;
|
private Dictionary<MyPlayer.PlayerId, MyPlayer> _onlinePlayers;
|
||||||
|
|
||||||
internal MultiplayerManager(ITorchBase torch)
|
internal MultiplayerManager(ITorchBase torch)
|
||||||
{
|
{
|
||||||
_torch = torch;
|
_torch = torch;
|
||||||
_torch.SessionLoaded += OnSessionLoaded;
|
_torch.SessionLoaded += OnSessionLoaded;
|
||||||
|
ChatManager.Instance.MessageRecieved += Instance_MessageRecieved;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Instance_MessageRecieved(ChatMsg msg, ref bool sendToOthers)
|
||||||
|
{
|
||||||
|
var message = ChatMessage.FromChatMsg(msg);
|
||||||
|
ChatHistory.Add(message);
|
||||||
|
MessageReceived?.Invoke(message, ref sendToOthers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void KickPlayer(ulong steamId) => _torch.Invoke(() => MyMultiplayer.Static.KickClient(steamId));
|
public void KickPlayer(ulong steamId) => _torch.Invoke(() => MyMultiplayer.Static.KickClient(steamId));
|
||||||
@@ -74,6 +84,11 @@ namespace Torch.Managers
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string GetSteamUsername(ulong steamId)
|
||||||
|
{
|
||||||
|
return MyMultiplayer.Static.GetMemberName(steamId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a message in chat.
|
/// Send a message in chat.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -85,12 +100,8 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
private void OnSessionLoaded()
|
private void OnSessionLoaded()
|
||||||
{
|
{
|
||||||
LocalPlayer = new Player(MyMultiplayer.Static.ServerId) { Name = "Server", State = ConnectionState.Connected };
|
|
||||||
|
|
||||||
MyMultiplayer.Static.ChatMessageReceived += OnChatMessage;
|
|
||||||
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
||||||
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
||||||
MySession.Static.Players.PlayerRequesting += OnPlayerRequesting;
|
|
||||||
|
|
||||||
_onlinePlayers = MySession.Static.Players.GetPrivateField<Dictionary<MyPlayer.PlayerId, MyPlayer>>("m_players");
|
_onlinePlayers = MySession.Static.Players.GetPrivateField<Dictionary<MyPlayer.PlayerId, MyPlayer>>("m_players");
|
||||||
|
|
||||||
@@ -102,40 +113,6 @@ namespace Torch.Managers
|
|||||||
_waitingForGroup = (HashSet<ulong>)typeof(MyDedicatedServerBase).GetField("m_waitingForGroup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(MyMultiplayer.Static);
|
_waitingForGroup = (HashSet<ulong>)typeof(MyDedicatedServerBase).GetField("m_waitingForGroup", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(MyMultiplayer.Static);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnChatMessage(ulong steamId, string message, ChatEntryTypeEnum chatType)
|
|
||||||
{
|
|
||||||
var player = MyMultiplayer.Static.GetMemberName(steamId);
|
|
||||||
if (string.IsNullOrEmpty(player))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var info = new ChatItem(new Player(steamId), message);
|
|
||||||
Chat.Add(info);
|
|
||||||
MessageReceived?.Invoke(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a client logs in and hits the respawn screen.
|
|
||||||
/// </summary>
|
|
||||||
private void OnPlayerRequesting(PlayerRequestArgs args)
|
|
||||||
{
|
|
||||||
var steamId = args.PlayerId.SteamId;
|
|
||||||
|
|
||||||
IPlayer player;
|
|
||||||
if (!Players.ContainsKey(steamId))
|
|
||||||
{
|
|
||||||
player = new Player(steamId) { State = ConnectionState.Connected };
|
|
||||||
Players.Add(steamId, player);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
player = Players[steamId];
|
|
||||||
player.SetConnectionState(ConnectionState.Connected);
|
|
||||||
}
|
|
||||||
|
|
||||||
_log.Info($"{player.Name} connected.");
|
|
||||||
PlayerJoined?.Invoke(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnClientKicked(ulong steamId)
|
private void OnClientKicked(ulong steamId)
|
||||||
{
|
{
|
||||||
OnClientLeft(steamId, ChatMemberStateChangeEnum.Kicked);
|
OnClientLeft(steamId, ChatMemberStateChangeEnum.Kicked);
|
||||||
@@ -143,13 +120,8 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
private void OnClientLeft(ulong steamId, ChatMemberStateChangeEnum stateChange)
|
private void OnClientLeft(ulong steamId, ChatMemberStateChangeEnum stateChange)
|
||||||
{
|
{
|
||||||
if (!Players.ContainsKey(steamId))
|
_log.Info($"{GetSteamUsername(steamId)} disconnected ({(ConnectionState)stateChange}).");
|
||||||
return;
|
PlayerLeft?.Invoke(steamId, (ConnectionState)stateChange);
|
||||||
|
|
||||||
var player = Players[steamId];
|
|
||||||
_log.Info($"{player.Name} disconnected ({(ConnectionState)stateChange}).");
|
|
||||||
player.SetConnectionState((ConnectionState)stateChange);
|
|
||||||
PlayerLeft?.Invoke(player);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: Split the following into a new file?
|
//TODO: Split the following into a new file?
|
||||||
@@ -299,8 +271,8 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
private void UserAccepted(ulong steamId)
|
private void UserAccepted(ulong steamId)
|
||||||
{
|
{
|
||||||
//TODO: Raise user joined event here
|
|
||||||
typeof(MyDedicatedServerBase).GetMethod("UserAccepted", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(MyMultiplayer.Static, new object[] {steamId});
|
typeof(MyDedicatedServerBase).GetMethod("UserAccepted", BindingFlags.NonPublic | BindingFlags.Instance).Invoke(MyMultiplayer.Static, new object[] {steamId});
|
||||||
|
PlayerJoined?.Invoke(steamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UserRejected(ulong steamId, JoinResult reason)
|
private void UserRejected(ulong steamId, JoinResult reason)
|
||||||
|
@@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using VRage;
|
||||||
using VRage.Library.Collections;
|
using VRage.Library.Collections;
|
||||||
using VRage.Network;
|
using VRage.Network;
|
||||||
using VRage.Serialization;
|
using VRage.Serialization;
|
||||||
@@ -27,7 +28,7 @@ namespace Torch.Managers
|
|||||||
/// <param name="stream"></param>
|
/// <param name="stream"></param>
|
||||||
/// <param name="obj"></param>
|
/// <param name="obj"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public abstract bool Handle(ulong remoteUserId, CallSite site, BitStream stream, object obj);
|
public abstract bool Handle(ulong remoteUserId, CallSite site, BitStream stream, object obj, MyPacket packet);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Extracts method arguments from the bitstream or packs them back in, depending on stream read mode.
|
/// Extracts method arguments from the bitstream or packs them back in, depending on stream read mode.
|
||||||
|
@@ -14,29 +14,15 @@ namespace Torch.Managers
|
|||||||
{
|
{
|
||||||
public class NetworkManager
|
public class NetworkManager
|
||||||
{
|
{
|
||||||
private NetworkManager()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (ReflectionUnitTest())
|
|
||||||
InitNetworkIntercept();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Error("Error initializing network intercept");
|
|
||||||
_log.Error(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Logger _log = LogManager.GetLogger(nameof(NetworkManager));
|
private static Logger _log = LogManager.GetLogger(nameof(NetworkManager));
|
||||||
private static NetworkManager _instance;
|
public static NetworkManager Instance { get; } = new NetworkManager();
|
||||||
public static NetworkManager Instance => _instance ?? (_instance = new NetworkManager());
|
|
||||||
|
|
||||||
private const string MyTransportLayerField = "TransportLayer";
|
private const string MyTransportLayerField = "TransportLayer";
|
||||||
private const string TypeTableField = "m_typeTable";
|
private const string TypeTableField = "m_typeTable";
|
||||||
private const string TransportHandlersField = "m_handlers";
|
private const string TransportHandlersField = "m_handlers";
|
||||||
private MyTypeTable m_typeTable = new MyTypeTable();
|
private MyTypeTable m_typeTable = new MyTypeTable();
|
||||||
private HashSet<NetworkHandlerBase> _networkHandlers = new HashSet<NetworkHandlerBase>();
|
private HashSet<NetworkHandlerBase> _networkHandlers = new HashSet<NetworkHandlerBase>();
|
||||||
|
private bool _init;
|
||||||
|
|
||||||
private bool ReflectionUnitTest(bool suppress = false)
|
private bool ReflectionUnitTest(bool suppress = false)
|
||||||
{
|
{
|
||||||
@@ -70,8 +56,16 @@ namespace Torch.Managers
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Loads the network intercept system
|
/// Loads the network intercept system
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void InitNetworkIntercept()
|
public void Init()
|
||||||
{
|
{
|
||||||
|
if (_init)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_init = true;
|
||||||
|
|
||||||
|
if (!ReflectionUnitTest())
|
||||||
|
throw new InvalidOperationException("Reflection unit test failed.");
|
||||||
|
|
||||||
m_typeTable = typeof(MyReplicationLayerBase).GetField(TypeTableField, BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(MyMultiplayer.ReplicationLayer) as MyTypeTable;
|
m_typeTable = typeof(MyReplicationLayerBase).GetField(TypeTableField, BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(MyMultiplayer.ReplicationLayer) as MyTypeTable;
|
||||||
//don't bother with nullchecks here, it was all handled in ReflectionUnitTest
|
//don't bother with nullchecks here, it was all handled in ReflectionUnitTest
|
||||||
var transportType = typeof(MySyncLayer).GetField(MyTransportLayerField, BindingFlags.NonPublic | BindingFlags.Instance).FieldType;
|
var transportType = typeof(MySyncLayer).GetField(MyTransportLayerField, BindingFlags.NonPublic | BindingFlags.Instance).FieldType;
|
||||||
@@ -163,7 +157,7 @@ namespace Torch.Managers
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (handler.CanHandle(site))
|
if (handler.CanHandle(site))
|
||||||
discard |= handler.Handle(packet.Sender.Value, site, stream, obj);
|
discard |= handler.Handle(packet.Sender.Value, site, stream, obj, packet);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
@@ -21,14 +21,13 @@ using VRage.Library.Collections;
|
|||||||
|
|
||||||
namespace Torch.Managers
|
namespace Torch.Managers
|
||||||
{
|
{
|
||||||
public class PluginManager : IPluginManager
|
public class PluginManager : IPluginManager, IPlugin
|
||||||
{
|
{
|
||||||
private readonly ITorchBase _torch;
|
private readonly ITorchBase _torch;
|
||||||
private static Logger _log = LogManager.GetLogger(nameof(PluginManager));
|
private static Logger _log = LogManager.GetLogger(nameof(PluginManager));
|
||||||
public const string PluginDir = "Plugins";
|
public const string PluginDir = "Plugins";
|
||||||
|
|
||||||
private readonly List<ITorchPlugin> _plugins = new List<ITorchPlugin>();
|
private readonly List<ITorchPlugin> _plugins = new List<ITorchPlugin>();
|
||||||
private readonly PluginUpdater _updater;
|
|
||||||
public CommandManager Commands { get; private set; }
|
public CommandManager Commands { get; private set; }
|
||||||
|
|
||||||
public float LastUpdateMs => _lastUpdateMs;
|
public float LastUpdateMs => _lastUpdateMs;
|
||||||
@@ -37,7 +36,6 @@ namespace Torch.Managers
|
|||||||
public PluginManager(ITorchBase torch)
|
public PluginManager(ITorchBase torch)
|
||||||
{
|
{
|
||||||
_torch = torch;
|
_torch = torch;
|
||||||
_updater = new PluginUpdater(this);
|
|
||||||
|
|
||||||
if (!Directory.Exists(PluginDir))
|
if (!Directory.Exists(PluginDir))
|
||||||
Directory.CreateDirectory(PluginDir);
|
Directory.CreateDirectory(PluginDir);
|
||||||
@@ -46,7 +44,7 @@ namespace Torch.Managers
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds the plugin updater plugin to VRage's plugin system.
|
/// Adds the plugin manager "plugin" to VRage's plugin system.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void InitUpdater()
|
private void InitUpdater()
|
||||||
{
|
{
|
||||||
@@ -55,7 +53,7 @@ namespace Torch.Managers
|
|||||||
if (pluginList == null)
|
if (pluginList == null)
|
||||||
throw new TypeLoadException($"{fieldName} field not found in {nameof(MyPlugins)}");
|
throw new TypeLoadException($"{fieldName} field not found in {nameof(MyPlugins)}");
|
||||||
|
|
||||||
pluginList.Add(_updater);
|
pluginList.Add(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -85,7 +83,8 @@ namespace Torch.Managers
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
var network = NetworkManager.Instance;
|
((TorchBase)_torch).Network.Init();
|
||||||
|
ChatManager.Instance.Init();
|
||||||
Commands = new CommandManager(_torch);
|
Commands = new CommandManager(_torch);
|
||||||
|
|
||||||
_log.Info("Loading plugins");
|
_log.Info("Loading plugins");
|
||||||
@@ -93,8 +92,7 @@ namespace Torch.Managers
|
|||||||
var dlls = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);
|
var dlls = Directory.GetFiles(pluginsPath, "*.dll", SearchOption.AllDirectories);
|
||||||
foreach (var dllPath in dlls)
|
foreach (var dllPath in dlls)
|
||||||
{
|
{
|
||||||
UnblockDll(dllPath);
|
var asm = Assembly.UnsafeLoadFrom(dllPath);
|
||||||
var asm = Assembly.LoadFrom(dllPath);
|
|
||||||
|
|
||||||
foreach (var type in asm.GetExportedTypes())
|
foreach (var type in asm.GetExportedTypes())
|
||||||
{
|
{
|
||||||
@@ -134,45 +132,19 @@ namespace Torch.Managers
|
|||||||
return GetEnumerator();
|
return GetEnumerator();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
void IPlugin.Init(object obj)
|
||||||
/// Removes the lock on a DLL downloaded from the internet.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool UnblockDll(string fileName)
|
|
||||||
{
|
{
|
||||||
return DeleteFile(fileName + ":Zone.Identifier");
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
[DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
void IPlugin.Update()
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
|
||||||
private static extern bool DeleteFile(string name);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Tiny "plugin" to call <see cref="PluginManager"/>'s update method after each game tick.
|
|
||||||
/// </summary>
|
|
||||||
private class PluginUpdater : IPlugin
|
|
||||||
{
|
{
|
||||||
private readonly IPluginManager _manager;
|
UpdatePlugins();
|
||||||
|
|
||||||
public PluginUpdater(IPluginManager manager)
|
|
||||||
{
|
|
||||||
_manager = manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Init(object obj)
|
|
||||||
{
|
|
||||||
_manager.Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update()
|
|
||||||
{
|
|
||||||
_manager.UpdatePlugins();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_manager.DisposePlugins();
|
DisposePlugins();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,55 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using Sandbox.Engine.Multiplayer;
|
|
||||||
using Torch.API;
|
|
||||||
|
|
||||||
namespace Torch
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Stores player information in an observable format.
|
|
||||||
/// </summary>
|
|
||||||
public class Player : ViewModel, IPlayer
|
|
||||||
{
|
|
||||||
private ulong _steamId;
|
|
||||||
private string _name;
|
|
||||||
private ConnectionState _state;
|
|
||||||
|
|
||||||
public ulong SteamId
|
|
||||||
{
|
|
||||||
get { return _steamId; }
|
|
||||||
set { _steamId = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return _name; }
|
|
||||||
set { _name = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: track identity history
|
|
||||||
public List<ulong> IdentityIds { get; } = new List<ulong>();
|
|
||||||
|
|
||||||
public DateTime LastConnected { get; private set; }
|
|
||||||
|
|
||||||
public ConnectionState State
|
|
||||||
{
|
|
||||||
get { return _state; }
|
|
||||||
set { _state = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public Player(ulong steamId)
|
|
||||||
{
|
|
||||||
_steamId = steamId;
|
|
||||||
_name = MyMultiplayer.Static.GetMemberName(steamId);
|
|
||||||
_state = ConnectionState.Unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetConnectionState(ConnectionState state)
|
|
||||||
{
|
|
||||||
if (state == ConnectionState.Connected)
|
|
||||||
LastConnected = DateTime.Now;
|
|
||||||
|
|
||||||
State = state;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,9 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Win32;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Sandbox;
|
using Sandbox;
|
||||||
using Sandbox.Engine.Networking;
|
using Sandbox.Engine.Networking;
|
||||||
@@ -19,9 +22,13 @@ namespace Torch
|
|||||||
private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
|
private static CancellationTokenSource _tokenSource = new CancellationTokenSource();
|
||||||
private static CancellationToken _cancelToken;
|
private static CancellationToken _cancelToken;
|
||||||
private static Logger _log = LogManager.GetLogger(nameof(SteamHelper));
|
private static Logger _log = LogManager.GetLogger(nameof(SteamHelper));
|
||||||
|
public static string BasePath { get; private set; }
|
||||||
|
private static string _libraryFolders;
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
|
BasePath = Registry.GetValue(@"HKEY_CURRENT_USER\Software\Valve\Steam", "SteamPath", null) as string;
|
||||||
|
_libraryFolders = File.ReadAllText(Path.Combine(BasePath, @"steamapps\libraryfolders.vdf"));
|
||||||
_cancelToken = _tokenSource.Token;
|
_cancelToken = _tokenSource.Token;
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
@@ -106,5 +113,20 @@ namespace Torch
|
|||||||
{
|
{
|
||||||
return new MyObjectBuilder_Checkpoint.ModItem(null, details.PublishedFileId, details.Title);
|
return new MyObjectBuilder_Checkpoint.ModItem(null, details.PublishedFileId, details.Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetInstallFolder(string subfolderName)
|
||||||
|
{
|
||||||
|
var basePaths = new List<string>();
|
||||||
|
var matches = Regex.Matches(_libraryFolders, @"""\d+""[ \t]+""([^""]+)""", RegexOptions.Singleline);
|
||||||
|
foreach (Match match in matches)
|
||||||
|
{
|
||||||
|
basePaths.Add(match.Groups[1].Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
var path = basePaths.Select(p => Path.Combine(p, "SteamApps", "common", subfolderName)).FirstOrDefault(Directory.Exists);
|
||||||
|
if (path != null && !path.EndsWith("\\"))
|
||||||
|
path += "\\";
|
||||||
|
return path;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -145,6 +145,7 @@
|
|||||||
<Reference Include="WindowsBase" />
|
<Reference Include="WindowsBase" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="ChatMessage.cs" />
|
||||||
<Compile Include="Collections\KeyTree.cs" />
|
<Compile Include="Collections\KeyTree.cs" />
|
||||||
<Compile Include="Commands\CategoryAttribute.cs" />
|
<Compile Include="Commands\CategoryAttribute.cs" />
|
||||||
<Compile Include="Commands\Command.cs" />
|
<Compile Include="Commands\Command.cs" />
|
||||||
@@ -153,22 +154,20 @@
|
|||||||
<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\PermissionAttribute.cs" />
|
<Compile Include="Commands\Permissions\PermissionAttribute.cs" />
|
||||||
<Compile Include="Commands\Permissions\PermissonsSystem.cs" />
|
<Compile Include="Commands\Permissions\PermissonsSystem.cs" />
|
||||||
<Compile Include="Commands\TorchCommands.cs" />
|
<Compile Include="Commands\TorchCommands.cs" />
|
||||||
<Compile Include="Managers\ChatManager.cs" />
|
<Compile Include="Managers\ChatManager.cs" />
|
||||||
|
<Compile Include="Managers\EntityManager.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="Managers\MultiplayerManager.cs" />
|
<Compile Include="Managers\MultiplayerManager.cs" />
|
||||||
<Compile Include="Reflection.cs" />
|
<Compile Include="Reflection.cs" />
|
||||||
<Compile Include="Managers\ScriptingManager.cs" />
|
<Compile Include="Managers\ScriptingManager.cs" />
|
||||||
<Compile Include="TorchBase.cs" />
|
<Compile Include="TorchBase.cs" />
|
||||||
<Compile Include="Player.cs" />
|
|
||||||
<Compile Include="Collections\PlayerInfoCache.cs" />
|
|
||||||
<Compile Include="SteamService.cs" />
|
<Compile Include="SteamService.cs" />
|
||||||
|
<Compile Include="TorchConfig.cs" />
|
||||||
<Compile Include="TorchPluginBase.cs" />
|
<Compile Include="TorchPluginBase.cs" />
|
||||||
<Compile Include="ViewModels\ChatItem.cs" />
|
|
||||||
<Compile Include="ViewModels\ModViewModel.cs" />
|
<Compile Include="ViewModels\ModViewModel.cs" />
|
||||||
<Compile Include="Collections\MTObservableCollection.cs" />
|
<Compile Include="Collections\MTObservableCollection.cs" />
|
||||||
<Compile Include="Extensions\MyPlayerCollectionExtensions.cs" />
|
<Compile Include="Extensions\MyPlayerCollectionExtensions.cs" />
|
||||||
|
@@ -17,6 +17,7 @@ using Sandbox.ModAPI;
|
|||||||
using SpaceEngineers.Game;
|
using SpaceEngineers.Game;
|
||||||
using Torch.API;
|
using Torch.API;
|
||||||
using Torch.Managers;
|
using Torch.Managers;
|
||||||
|
using VRage.FileSystem;
|
||||||
using VRage.Scripting;
|
using VRage.Scripting;
|
||||||
using VRage.Utils;
|
using VRage.Utils;
|
||||||
|
|
||||||
@@ -35,6 +36,8 @@ namespace Torch
|
|||||||
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; }
|
||||||
|
public EntityManager Entities { get; protected set; }
|
||||||
|
public NetworkManager Network { get; protected set; }
|
||||||
public event Action SessionLoading;
|
public event Action SessionLoading;
|
||||||
public event Action SessionLoaded;
|
public event Action SessionLoaded;
|
||||||
public event Action SessionUnloading;
|
public event Action SessionUnloading;
|
||||||
@@ -53,6 +56,13 @@ namespace Torch
|
|||||||
RunArgs = new string[0];
|
RunArgs = new string[0];
|
||||||
Plugins = new PluginManager(this);
|
Plugins = new PluginManager(this);
|
||||||
Multiplayer = new MultiplayerManager(this);
|
Multiplayer = new MultiplayerManager(this);
|
||||||
|
Entities = new EntityManager(this);
|
||||||
|
Network = NetworkManager.Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsOnGameThread()
|
||||||
|
{
|
||||||
|
return Thread.CurrentThread.ManagedThreadId == MySandboxGame.Static.UpdateThread.ManagedThreadId;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task SaveGameAsync()
|
public async Task SaveGameAsync()
|
||||||
|
69
Torch/TorchConfig.cs
Normal file
69
Torch/TorchConfig.cs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
|
namespace Torch
|
||||||
|
{
|
||||||
|
public class TorchConfig
|
||||||
|
{
|
||||||
|
private static Logger _log = LogManager.GetLogger("Config");
|
||||||
|
|
||||||
|
public string InstancePath { get; set; }
|
||||||
|
public string InstanceName { get; set; }
|
||||||
|
public int Autosave { get; set; }
|
||||||
|
public bool AutoRestart { get; set; }
|
||||||
|
public bool LogChat { get; set; }
|
||||||
|
|
||||||
|
public TorchConfig() : this("Torch") { }
|
||||||
|
|
||||||
|
public TorchConfig(string instanceName = "Torch", string instancePath = null, int autosaveInterval = 5, bool autoRestart = false)
|
||||||
|
{
|
||||||
|
InstanceName = instanceName;
|
||||||
|
InstancePath = instancePath ?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Torch", InstanceName);
|
||||||
|
Autosave = autosaveInterval;
|
||||||
|
AutoRestart = autoRestart;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TorchConfig LoadFrom(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var serializer = new XmlSerializer(typeof(TorchConfig));
|
||||||
|
TorchConfig config;
|
||||||
|
using (var f = File.OpenRead(path))
|
||||||
|
{
|
||||||
|
config = (TorchConfig)serializer.Deserialize(f);
|
||||||
|
}
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_log.Error(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SaveTo(string path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var serializer = new XmlSerializer(typeof(TorchConfig));
|
||||||
|
using (var f = File.OpenWrite(path))
|
||||||
|
{
|
||||||
|
serializer.Serialize(f, this);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_log.Error(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,43 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Torch.API;
|
|
||||||
|
|
||||||
namespace Torch.ViewModels
|
|
||||||
{
|
|
||||||
public class ChatItem : ViewModel, IChatItem
|
|
||||||
{
|
|
||||||
private IPlayer _sender;
|
|
||||||
private string _message;
|
|
||||||
private DateTime _timestamp;
|
|
||||||
|
|
||||||
public IPlayer Player
|
|
||||||
{
|
|
||||||
get { return _sender; }
|
|
||||||
set { _sender = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Message
|
|
||||||
{
|
|
||||||
get { return _message; }
|
|
||||||
set { _message = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTime Time
|
|
||||||
{
|
|
||||||
get { return _timestamp; }
|
|
||||||
set { _timestamp = value; OnPropertyChanged(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
public string TimeString => Time.ToShortTimeString();
|
|
||||||
|
|
||||||
public ChatItem(IPlayer sender, string message, DateTime timestamp = default(DateTime))
|
|
||||||
{
|
|
||||||
_sender = sender;
|
|
||||||
_message = message;
|
|
||||||
|
|
||||||
if (timestamp == default(DateTime))
|
|
||||||
_timestamp = DateTime.Now;
|
|
||||||
else
|
|
||||||
_timestamp = timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Reference in New Issue
Block a user