Finish chat/players functionality, refactor logic to non-static classes with a single static entry point, add data binding
This commit is contained in:
@@ -5,11 +5,11 @@ VisualStudioVersion = 15.0.25618.0
|
|||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Piston", "Piston\Piston.csproj", "{7E01635C-3B67-472E-BCD6-C5539564F214}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Piston", "Piston\Piston.csproj", "{7E01635C-3B67-472E-BCD6-C5539564F214}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PistonAPI", "PistonAPI\PistonAPI.csproj", "{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Piston.API", "PistonAPI\Piston.API.csproj", "{FBA5D932-6254-4A1E-BAF4-E229FA94E3C2}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PistonClient", "PistonClient\PistonClient.csproj", "{E36DF745-260B-4956-A2E8-09F08B2E7161}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Piston.Client", "PistonClient\Piston.Client.csproj", "{E36DF745-260B-4956-A2E8-09F08B2E7161}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PistonServer", "PistonServer\PistonServer.csproj", "{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Piston.Server", "PistonServer\Piston.Server.csproj", "{CA50886B-7B22-4CD8-93A0-C06F38D4F77D}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
37
Piston/MTObservableCollection.cs
Normal file
37
Piston/MTObservableCollection.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
|
||||||
|
namespace Piston
|
||||||
|
{
|
||||||
|
public class MTObservableCollection<T> : ObservableCollection<T>
|
||||||
|
{
|
||||||
|
public override event NotifyCollectionChangedEventHandler CollectionChanged;
|
||||||
|
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
NotifyCollectionChangedEventHandler collectionChanged = CollectionChanged;
|
||||||
|
if (collectionChanged != null)
|
||||||
|
foreach (NotifyCollectionChangedEventHandler nh in collectionChanged.GetInvocationList())
|
||||||
|
{
|
||||||
|
var dispObj = nh.Target as DispatcherObject;
|
||||||
|
|
||||||
|
Dispatcher dispatcher = dispObj?.Dispatcher;
|
||||||
|
if (dispatcher != null && !dispatcher.CheckAccess())
|
||||||
|
{
|
||||||
|
dispatcher.BeginInvoke(
|
||||||
|
(Action)(() => nh.Invoke(this,
|
||||||
|
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
|
||||||
|
DispatcherPriority.DataBind);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
nh.Invoke(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
Piston/ObservableType.cs
Normal file
20
Piston/ObservableType.cs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Piston
|
||||||
|
{
|
||||||
|
public class ObservableType : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
protected void OnPropertyChanged([CallerMemberName] string propName = "")
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -111,17 +111,20 @@
|
|||||||
<Reference Include="VRage.Scripting">
|
<Reference Include="VRage.Scripting">
|
||||||
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Scripting.dll</HintPath>
|
<HintPath>C:\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\Bin64\VRage.Scripting.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="Logger.cs" />
|
<Compile Include="Logger.cs" />
|
||||||
|
<Compile Include="MTObservableCollection.cs" />
|
||||||
<Compile Include="MyPlayerCollectionExtensions.cs" />
|
<Compile Include="MyPlayerCollectionExtensions.cs" />
|
||||||
|
<Compile Include="ObservableType.cs" />
|
||||||
<Compile Include="PluginManager.cs" />
|
<Compile Include="PluginManager.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\PistonAPI\PistonAPI.csproj">
|
<ProjectReference Include="..\PistonAPI\Piston.API.csproj">
|
||||||
<Project>{fba5d932-6254-4a1e-baf4-e229fa94e3c2}</Project>
|
<Project>{fba5d932-6254-4a1e-baf4-e229fa94e3c2}</Project>
|
||||||
<Name>PistonAPI</Name>
|
<Name>Piston.API</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
@@ -5,7 +5,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 PistonAPI;
|
using Piston.API;
|
||||||
using Sandbox;
|
using Sandbox;
|
||||||
using VRage.Plugins;
|
using VRage.Plugins;
|
||||||
using VRage.Collections;
|
using VRage.Collections;
|
||||||
@@ -17,13 +17,12 @@ namespace Piston
|
|||||||
{
|
{
|
||||||
//TODO: Disable reloading if the plugin has static elements because they prevent a full reload.
|
//TODO: Disable reloading if the plugin has static elements because they prevent a full reload.
|
||||||
|
|
||||||
public static PluginManager Static { get; } = new PluginManager();
|
|
||||||
public ListReader<IPlugin> Plugins => MyPlugins.Plugins;
|
public ListReader<IPlugin> Plugins => MyPlugins.Plugins;
|
||||||
|
|
||||||
private List<IPlugin> _plugins;
|
private List<IPlugin> _plugins;
|
||||||
public const string PluginDir = "Plugins";
|
public const string PluginDir = "Plugins";
|
||||||
|
|
||||||
private PluginManager()
|
public PluginManager()
|
||||||
{
|
{
|
||||||
if (!Directory.Exists(PluginDir))
|
if (!Directory.Exists(PluginDir))
|
||||||
Directory.CreateDirectory(PluginDir);
|
Directory.CreateDirectory(PluginDir);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
namespace PistonAPI
|
namespace Piston.API
|
||||||
{
|
{
|
||||||
public interface IEnvironmentInfo
|
public interface IEnvironmentInfo
|
||||||
{
|
{
|
||||||
|
@@ -6,7 +6,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using VRage.Plugins;
|
using VRage.Plugins;
|
||||||
|
|
||||||
namespace PistonAPI
|
namespace Piston.API
|
||||||
{
|
{
|
||||||
public interface IPistonPlugin : IPlugin
|
public interface IPistonPlugin : IPlugin
|
||||||
{
|
{
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
|
||||||
namespace PistonAPI
|
namespace Piston.API
|
||||||
{
|
{
|
||||||
public interface IServerControls
|
public interface IServerControls
|
||||||
{
|
{
|
||||||
|
@@ -5,7 +5,7 @@ using System.Text;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
|
||||||
namespace PistonAPI
|
namespace Piston.API
|
||||||
{
|
{
|
||||||
public static class PistonAPI
|
public static class PistonAPI
|
||||||
{
|
{
|
||||||
|
@@ -1,15 +1,27 @@
|
|||||||
<UserControl x:Class="PistonServer.ChatControl"
|
<UserControl x:Class="Piston.Server.ChatControl"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:PistonServer"
|
xmlns:local="clr-namespace:Piston.Server"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<DockPanel DockPanel.Dock="Bottom">
|
<DockPanel DockPanel.Dock="Bottom">
|
||||||
<Button x:Name="Send" Content="Send" DockPanel.Dock="Right" Width="50" Margin="5,5,5,5" Click="SendButton_Click"></Button>
|
<Button x:Name="Send" Content="Send" DockPanel.Dock="Right" Width="50" Margin="5,5,5,5" Click="SendButton_Click"></Button>
|
||||||
<TextBox x:Name="Message" DockPanel.Dock="Left" Margin="5,5,5,5" KeyDown="Message_OnKeyDown"></TextBox>
|
<TextBox x:Name="Message" DockPanel.Dock="Left" Margin="5,5,5,5" KeyDown="Message_OnKeyDown"></TextBox>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
<TextBox x:Name="Chat" IsReadOnly="True" Margin="5,5,5,5"/>
|
<ListView x:Name="ChatItems" Margin="5,5,5,5">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<WrapPanel>
|
||||||
|
<TextBlock Text="{Binding Time}"/>
|
||||||
|
<TextBlock Text=" "/>
|
||||||
|
<TextBlock Text="{Binding Sender.Name}" FontWeight="Bold"/>
|
||||||
|
<TextBlock Text=": "/>
|
||||||
|
<TextBlock Text="{Binding Message}"/>
|
||||||
|
</WrapPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
@@ -19,45 +19,17 @@ using Sandbox.Engine.Multiplayer;
|
|||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using SteamSDK;
|
using SteamSDK;
|
||||||
|
|
||||||
namespace PistonServer
|
namespace Piston.Server
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for ChatControl.xaml
|
/// Interaction logic for ChatControl.xaml
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class ChatControl : UserControl
|
public partial class ChatControl : UserControl
|
||||||
{
|
{
|
||||||
public event Action<string> MessageEntered;
|
|
||||||
public ChatControl()
|
public ChatControl()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
ServerManager.Static.SessionReady += InitChatHandler;
|
ChatItems.ItemsSource = PistonServer.Multiplayer.ChatView;
|
||||||
}
|
|
||||||
|
|
||||||
public void InitChatHandler()
|
|
||||||
{
|
|
||||||
MyMultiplayer.Static.ChatMessageReceived += MessageReceived;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MessageReceived(ulong steamId, string message, ChatEntryTypeEnum chatType)
|
|
||||||
{
|
|
||||||
//Messages sent from server loop back around.
|
|
||||||
if (steamId == MyMultiplayer.Static.ServerId)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var name = MyMultiplayer.Static.GetMemberName(steamId);
|
|
||||||
Dispatcher.Invoke(() => AddMessage(name, message), DispatcherPriority.Normal);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddMessage(string sender, string message)
|
|
||||||
{
|
|
||||||
Chat.Text += $"{DateTime.Now.ToLongTimeString()} | {sender}: {message}\n";
|
|
||||||
Program.UserInterface.Players.RefreshNames();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SendMessage(string message)
|
|
||||||
{
|
|
||||||
MyMultiplayer.Static.SendChatMessage(message);
|
|
||||||
Dispatcher.Invoke(() => AddMessage("Server", message));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SendButton_Click(object sender, RoutedEventArgs e)
|
private void SendButton_Click(object sender, RoutedEventArgs e)
|
||||||
@@ -65,18 +37,18 @@ namespace PistonServer
|
|||||||
OnMessageEntered();
|
OnMessageEntered();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnMessageEntered()
|
|
||||||
{
|
|
||||||
var text = Message.Text;
|
|
||||||
SendMessage(text);
|
|
||||||
MessageEntered?.Invoke(Message.Text);
|
|
||||||
Message.Text = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Message_OnKeyDown(object sender, KeyEventArgs e)
|
private void Message_OnKeyDown(object sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.Key == Key.Enter)
|
if (e.Key == Key.Enter)
|
||||||
OnMessageEntered();
|
OnMessageEntered();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnMessageEntered()
|
||||||
|
{
|
||||||
|
//Can't use Message.Text directly because of object ownership in WPF.
|
||||||
|
var text = Message.Text;
|
||||||
|
PistonServer.Multiplayer.SendMessage(text);
|
||||||
|
Message.Text = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,25 +1,25 @@
|
|||||||
<Window x:Class="PistonServer.MainWindow"
|
<Window x:Class="Piston.Server.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:PistonServer"
|
xmlns:local="clr-namespace:Piston.Server"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="Piston" Height="600" Width="900">
|
Title="Piston" Height="600" Width="900">
|
||||||
<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"/>
|
||||||
<Button x:Name="BtnStop" Content="Stop" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left" Click="BtnStop_Click" IsEnabled="False"/>
|
<Button x:Name="BtnStop" Content="Stop" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left" Click="BtnStop_Click" IsEnabled="False"/>
|
||||||
<Button x:Name="BtnRestart" Content="Restart" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left"/>
|
<Button x:Name="BtnRestart" Content="Restart" Height="24" Width="75" Margin="5,0,5,0" HorizontalAlignment="Left" Click="BtnRestart_Click"/>
|
||||||
<Label x:Name="LabelSimulation" Content="Sim Ratio: 0.00"/>
|
<Label x:Name="LabelSimulation" Content="Sim Ratio: 0.00"/>
|
||||||
<Label x:Name="LabelUptime" Content="Uptime: 0d 0h 0m"/>
|
<Label x:Name="LabelUptime" Content="Uptime: 0d 0h 0m"/>
|
||||||
</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">
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem Header="Chat/Players">
|
<TabItem Header="Chat/PlayerList">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<local:PlayersControl x:Name="Players" DockPanel.Dock="Right" Width="250" IsEnabled="False"></local:PlayersControl>
|
<local:PlayerListControl x:Name="PlayerList" DockPanel.Dock="Right" Width="250" IsEnabled="False"/>
|
||||||
<local:ChatControl x:Name="Chat" IsEnabled="False"/>
|
<local:ChatControl x:Name="Chat" IsEnabled="False"/>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</TabItem>
|
</TabItem>
|
||||||
@@ -30,3 +30,4 @@
|
|||||||
</TabControl>
|
</TabControl>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
||||||
|
@@ -17,7 +17,7 @@ using System.Windows.Media.Imaging;
|
|||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
namespace PistonServer
|
namespace Piston.Server
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for MainWindow.xaml
|
/// Interaction logic for MainWindow.xaml
|
||||||
@@ -57,27 +57,32 @@ namespace PistonServer
|
|||||||
{
|
{
|
||||||
startTime = DateTime.Now;
|
startTime = DateTime.Now;
|
||||||
Chat.IsEnabled = true;
|
Chat.IsEnabled = true;
|
||||||
Players.IsEnabled = true;
|
PlayerList.IsEnabled = true;
|
||||||
((Button) sender).IsEnabled = false;
|
((Button) sender).IsEnabled = false;
|
||||||
BtnStop.IsEnabled = true;
|
BtnStop.IsEnabled = true;
|
||||||
uiUpdate.Start();
|
uiUpdate.Start();
|
||||||
ServerManager.Static.StartServerThread();
|
PistonServer.Server.StartServerThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
private void BtnStop_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
Chat.IsEnabled = false;
|
Chat.IsEnabled = false;
|
||||||
Players.IsEnabled = false;
|
PlayerList.IsEnabled = false;
|
||||||
((Button) sender).IsEnabled = false;
|
((Button) sender).IsEnabled = false;
|
||||||
//HACK: Uncomment when restarting is possible.
|
//HACK: Uncomment when restarting is possible.
|
||||||
//BtnStart.IsEnabled = true;
|
//BtnStart.IsEnabled = true;
|
||||||
uiUpdate.Stop();
|
uiUpdate.Stop();
|
||||||
ServerManager.Static.StopServer();
|
PistonServer.Server.StopServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClosing(CancelEventArgs e)
|
protected override void OnClosing(CancelEventArgs e)
|
||||||
{
|
{
|
||||||
ServerManager.Static.StopServer();
|
PistonServer.Server.StopServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BtnRestart_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Program.FullRestart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
187
PistonServer/MultiplayerManager.cs
Normal file
187
PistonServer/MultiplayerManager.cs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Threading;
|
||||||
|
using Piston;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using SteamSDK;
|
||||||
|
using VRage.Library.Collections;
|
||||||
|
|
||||||
|
namespace Piston.Server
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a proxy to the game's multiplayer-related functions.
|
||||||
|
/// </summary>
|
||||||
|
public class MultiplayerManager
|
||||||
|
{
|
||||||
|
public event Action<PlayerInfo> PlayerJoined;
|
||||||
|
public event Action<PlayerInfo> PlayerLeft;
|
||||||
|
public event Action<ChatItemInfo> ChatMessageReceived;
|
||||||
|
|
||||||
|
public MTObservableCollection<PlayerInfo> PlayersView { get; } = new MTObservableCollection<PlayerInfo>();
|
||||||
|
public MTObservableCollection<ChatItemInfo> ChatView { get; } = new MTObservableCollection<ChatItemInfo>();
|
||||||
|
public PlayerInfo LocalPlayer { get; private set; }
|
||||||
|
|
||||||
|
internal MultiplayerManager(ServerManager serverManager)
|
||||||
|
{
|
||||||
|
serverManager.SessionLoaded += OnSessionLoaded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void KickPlayer(ulong steamId) => MyMultiplayer.Static.KickClient(steamId);
|
||||||
|
|
||||||
|
public void BanPlayer(ulong steamId, bool banned = true) => MyMultiplayer.Static.BanClient(steamId, banned);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send a message in chat.
|
||||||
|
/// </summary>
|
||||||
|
public void SendMessage(string message)
|
||||||
|
{
|
||||||
|
MyMultiplayer.Static.SendChatMessage(message);
|
||||||
|
ChatView.Add(new ChatItemInfo(LocalPlayer, message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSessionLoaded()
|
||||||
|
{
|
||||||
|
LocalPlayer = new PlayerInfo(MyMultiplayer.Static.ServerId) { Name = "Server", State = ConnectionState.Connected };
|
||||||
|
|
||||||
|
MyMultiplayer.Static.ChatMessageReceived += OnChatMessage;
|
||||||
|
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
||||||
|
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
||||||
|
MySession.Static.Players.PlayerRequesting += OnPlayerRequesting;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChatMessage(ulong steamId, string message, ChatEntryTypeEnum chatType)
|
||||||
|
{
|
||||||
|
var player = PlayersView.FirstOrDefault(p => p.SteamId == steamId);
|
||||||
|
if (player == null || player == LocalPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var info = new ChatItemInfo(player, message);
|
||||||
|
ChatView.Add(info);
|
||||||
|
ChatMessageReceived?.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;
|
||||||
|
var player = new PlayerInfo(steamId) {State = ConnectionState.Connected};
|
||||||
|
PlayersView.Add(player);
|
||||||
|
PlayerJoined?.Invoke(player);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClientKicked(ulong steamId)
|
||||||
|
{
|
||||||
|
OnClientLeft(steamId, ChatMemberStateChangeEnum.Kicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnClientLeft(ulong steamId, ChatMemberStateChangeEnum stateChange)
|
||||||
|
{
|
||||||
|
var player = PlayersView.FirstOrDefault(p => p.SteamId == steamId);
|
||||||
|
|
||||||
|
if (player == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
player.State = (ConnectionState)stateChange;
|
||||||
|
PlayersView.Remove(player);
|
||||||
|
PlayerLeft?.Invoke(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Stores player information in an observable format.
|
||||||
|
/// </summary>
|
||||||
|
public class PlayerInfo : ObservableType
|
||||||
|
{
|
||||||
|
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(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public ConnectionState State
|
||||||
|
{
|
||||||
|
get { return _state; }
|
||||||
|
set { _state = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerInfo(ulong steamId)
|
||||||
|
{
|
||||||
|
_steamId = steamId;
|
||||||
|
_name = MyMultiplayer.Static.GetMemberName(steamId);
|
||||||
|
_state = ConnectionState.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChatItemInfo : ObservableType
|
||||||
|
{
|
||||||
|
private PlayerInfo _sender;
|
||||||
|
private string _message;
|
||||||
|
private DateTime _timestamp;
|
||||||
|
|
||||||
|
public PlayerInfo Sender
|
||||||
|
{
|
||||||
|
get { return _sender; }
|
||||||
|
set { _sender = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Message
|
||||||
|
{
|
||||||
|
get { return _message; }
|
||||||
|
set { _message = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public DateTime Timestamp
|
||||||
|
{
|
||||||
|
get { return _timestamp; }
|
||||||
|
set { _timestamp = value; OnPropertyChanged(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Time => Timestamp.ToShortTimeString();
|
||||||
|
|
||||||
|
public ChatItemInfo(PlayerInfo sender, string message)
|
||||||
|
{
|
||||||
|
_sender = sender;
|
||||||
|
_message = message;
|
||||||
|
_timestamp = DateTime.Now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Identifies a player's current connection state.
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum ConnectionState
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Connected = 1,
|
||||||
|
Left = 2,
|
||||||
|
Disconnected = 4,
|
||||||
|
Kicked = 8,
|
||||||
|
Banned = 16,
|
||||||
|
}
|
||||||
|
}
|
@@ -112,8 +112,10 @@
|
|||||||
<Compile Include="MainWindow.xaml.cs">
|
<Compile Include="MainWindow.xaml.cs">
|
||||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="PlayersControl.xaml.cs">
|
<Compile Include="MultiplayerManager.cs" />
|
||||||
<DependentUpon>PlayersControl.xaml</DependentUpon>
|
<Compile Include="PistonServer.cs" />
|
||||||
|
<Compile Include="PlayerListControl.xaml.cs">
|
||||||
|
<DependentUpon>PlayerListControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="ServerManager.cs" />
|
<Compile Include="ServerManager.cs" />
|
||||||
@@ -157,7 +159,7 @@
|
|||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
||||||
<Page Include="PlayersControl.xaml">
|
<Page Include="PlayerListControl.xaml">
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
</Page>
|
</Page>
|
42
PistonServer/PistonServer.cs
Normal file
42
PistonServer/PistonServer.cs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Piston;
|
||||||
|
|
||||||
|
namespace Piston.Server
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Entry point for all Piston server functionality.
|
||||||
|
/// </summary>
|
||||||
|
public static class PistonServer
|
||||||
|
{
|
||||||
|
public static ServerManager Server;
|
||||||
|
public static MultiplayerManager Multiplayer;
|
||||||
|
public static PluginManager Plugins;
|
||||||
|
|
||||||
|
private static bool _init;
|
||||||
|
|
||||||
|
public static void Init()
|
||||||
|
{
|
||||||
|
if (!_init)
|
||||||
|
{
|
||||||
|
Logger.Write("Initializing Piston");
|
||||||
|
_init = true;
|
||||||
|
Server = new ServerManager();
|
||||||
|
Multiplayer = new MultiplayerManager(Server);
|
||||||
|
Plugins = new PluginManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Reset()
|
||||||
|
{
|
||||||
|
Logger.Write("Resetting Piston");
|
||||||
|
Server = null;
|
||||||
|
Multiplayer = null;
|
||||||
|
Plugins = null;
|
||||||
|
_init = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,15 +1,26 @@
|
|||||||
<UserControl x:Class="PistonServer.PlayersControl"
|
<UserControl x:Class="Piston.Server.PlayerListControl"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:PistonServer"
|
xmlns:local="clr-namespace:Piston.Server"
|
||||||
mc:Ignorable="d">
|
mc:Ignorable="d">
|
||||||
<DockPanel>
|
<DockPanel>
|
||||||
<StackPanel DockPanel.Dock="Bottom">
|
<StackPanel DockPanel.Dock="Bottom">
|
||||||
<Button x:Name="KickButton" Content="Kick" Margin="5,5,5,5" Click="KickButton_Click"/>
|
<Button x:Name="KickButton" Content="Kick" Margin="5,5,5,5" Click="KickButton_Click"/>
|
||||||
<Button x:Name="BanButton" Content="Ban" Margin="5,5,5,5" Click="BanButton_Click"/>
|
<Button x:Name="BanButton" Content="Ban" Margin="5,5,5,5" Click="BanButton_Click"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ListBox x:Name="PlayerList" DockPanel.Dock="Top" Margin="5,5,5,5"/>
|
<ListView x:Name="PlayerList" DockPanel.Dock="Top" Margin="5,5,5,5">
|
||||||
|
<ListView.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<WrapPanel>
|
||||||
|
<TextBlock Text="{Binding Name}" FontWeight="Bold"/>
|
||||||
|
<TextBlock Text=" ("/>
|
||||||
|
<TextBlock Text="{Binding State}"/>
|
||||||
|
<TextBlock Text=")"/>
|
||||||
|
</WrapPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ListView.ItemTemplate>
|
||||||
|
</ListView>
|
||||||
</DockPanel>
|
</DockPanel>
|
||||||
</UserControl>
|
</UserControl>
|
53
PistonServer/PlayerListControl.xaml.cs
Normal file
53
PistonServer/PlayerListControl.xaml.cs
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
using System;
|
||||||
|
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;
|
||||||
|
using Piston;
|
||||||
|
using Sandbox;
|
||||||
|
using Sandbox.Engine.Multiplayer;
|
||||||
|
using Sandbox.Game.Multiplayer;
|
||||||
|
using Sandbox.Game.World;
|
||||||
|
using SteamSDK;
|
||||||
|
|
||||||
|
namespace Piston.Server
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for PlayerListControl.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class PlayerListControl : UserControl
|
||||||
|
{
|
||||||
|
public PlayerListControl()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
PlayerList.ItemsSource = PistonServer.Multiplayer.PlayersView;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void KickButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var player = PlayerList.SelectedItem as PlayerInfo;
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
PistonServer.Multiplayer.KickPlayer(player.SteamId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BanButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
var player = PlayerList.SelectedItem as PlayerInfo;
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
PistonServer.Multiplayer.BanPlayer(player.SteamId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,114 +0,0 @@
|
|||||||
using System;
|
|
||||||
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;
|
|
||||||
using Piston;
|
|
||||||
using Sandbox;
|
|
||||||
using Sandbox.Engine.Multiplayer;
|
|
||||||
using Sandbox.Game.Multiplayer;
|
|
||||||
using Sandbox.Game.World;
|
|
||||||
using SteamSDK;
|
|
||||||
|
|
||||||
namespace PistonServer
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for PlayersControl.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class PlayersControl : UserControl
|
|
||||||
{
|
|
||||||
public PlayersControl()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
ServerManager.Static.SessionReady += Static_SessionReady;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RefreshNames()
|
|
||||||
{
|
|
||||||
Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
foreach (var player in PlayerList.Items)
|
|
||||||
{
|
|
||||||
var p = (PlayerItem)player;
|
|
||||||
p.Name = MyMultiplayer.Static.GetMemberName(p.SteamId);
|
|
||||||
}
|
|
||||||
|
|
||||||
PlayerList.Items.Refresh();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Static_SessionReady()
|
|
||||||
{
|
|
||||||
MyMultiplayer.Static.ClientKicked += OnClientKicked;
|
|
||||||
MyMultiplayer.Static.ClientLeft += OnClientLeft;
|
|
||||||
MySession.Static.Players.PlayerRequesting += OnPlayerRequesting;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invoked when a client logs in and hits the respawn screen.
|
|
||||||
/// </summary>
|
|
||||||
private void OnPlayerRequesting(PlayerRequestArgs args)
|
|
||||||
{
|
|
||||||
var steamId = args.PlayerId.SteamId;
|
|
||||||
var player = new PlayerItem { Name = MyMultiplayer.Static.GetMemberName(steamId), SteamId = steamId };
|
|
||||||
Program.UserInterface.Chat.SendMessage($"{player.Name} connected.");
|
|
||||||
Dispatcher.Invoke(() => PlayerList.Items.Add(player));
|
|
||||||
}
|
|
||||||
private void OnClientKicked(ulong steamId)
|
|
||||||
{
|
|
||||||
OnClientLeft(steamId, ChatMemberStateChangeEnum.Kicked);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnClientLeft(ulong steamId, ChatMemberStateChangeEnum stateChange)
|
|
||||||
{
|
|
||||||
Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
var player = PlayerList.Items.Cast<PlayerItem>().FirstOrDefault(x => x.SteamId == steamId);
|
|
||||||
|
|
||||||
if (player == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Program.UserInterface.Chat.SendMessage($"{player.Name} {stateChange.ToString().ToLower()}.");
|
|
||||||
PlayerList.Items.Remove(player);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public class PlayerItem
|
|
||||||
{
|
|
||||||
public ulong SteamId;
|
|
||||||
public string Name;
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{Name} ({SteamId})";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void KickButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (PlayerList.SelectedItem == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var player = (PlayerItem)PlayerList.SelectedItem;
|
|
||||||
MyMultiplayer.Static.KickClient(player.SteamId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BanButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (PlayerList.SelectedItem == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var player = (PlayerItem)PlayerList.SelectedItem;
|
|
||||||
MyMultiplayer.Static.BanClient(player.SteamId, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -9,7 +10,7 @@ using System.Windows;
|
|||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
using Piston;
|
using Piston;
|
||||||
|
|
||||||
namespace PistonServer
|
namespace Piston.Server
|
||||||
{
|
{
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
@@ -19,18 +20,19 @@ namespace PistonServer
|
|||||||
[STAThread]
|
[STAThread]
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
ServerManager.Static.RunArgs = new[] { "-console" };
|
Logger.Write("Initializing");
|
||||||
|
PistonServer.Server.RunArgs = new[] { "-console" };
|
||||||
MainDispatcher = Dispatcher.CurrentDispatcher;
|
MainDispatcher = Dispatcher.CurrentDispatcher;
|
||||||
Console.WriteLine(MainDispatcher.Thread.ManagedThreadId);
|
|
||||||
#if DEBUG
|
|
||||||
Directory.SetCurrentDirectory(@"C:\Program Files (x86)\Steam\steamapps\common\SpaceEngineers\DedicatedServer64");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (args.Contains("-nogui"))
|
if (args.Contains("-nogui"))
|
||||||
ServerManager.Static.StartServer();
|
|
||||||
|
PistonServer.Server.StartServer();
|
||||||
else
|
else
|
||||||
StartUI();
|
StartUI();
|
||||||
|
|
||||||
|
if (args.Contains("-autostart") && !PistonServer.Server.Running)
|
||||||
|
PistonServer.Server.StartServerThread();
|
||||||
|
|
||||||
Dispatcher.Run();
|
Dispatcher.Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,5 +41,12 @@ namespace PistonServer
|
|||||||
Thread.CurrentThread.Name = "UI Thread";
|
Thread.CurrentThread.Name = "UI Thread";
|
||||||
UserInterface.Show();
|
UserInterface.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void FullRestart()
|
||||||
|
{
|
||||||
|
PistonServer.Server.StopServer();
|
||||||
|
Process.Start("PistonServer.exe", "-autostart");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
2
PistonServer/Properties/Resources.Designer.cs
generated
2
PistonServer/Properties/Resources.Designer.cs
generated
@@ -8,7 +8,7 @@
|
|||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace PistonServer.Properties {
|
namespace Piston.Server.Properties {
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
2
PistonServer/Properties/Settings.Designer.cs
generated
2
PistonServer/Properties/Settings.Designer.cs
generated
@@ -8,7 +8,7 @@
|
|||||||
// </auto-generated>
|
// </auto-generated>
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
namespace PistonServer.Properties {
|
namespace Piston.Server.Properties {
|
||||||
|
|
||||||
|
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
@@ -13,20 +13,21 @@ using Sandbox.Engine.Multiplayer;
|
|||||||
using Sandbox.Game.World;
|
using Sandbox.Game.World;
|
||||||
using VRage.Profiler;
|
using VRage.Profiler;
|
||||||
|
|
||||||
namespace PistonServer
|
namespace Piston.Server
|
||||||
{
|
{
|
||||||
public class ServerManager
|
public class ServerManager
|
||||||
{
|
{
|
||||||
public static ServerManager Static { get; } = new ServerManager();
|
|
||||||
public Thread ServerThread { get; private set; }
|
public Thread ServerThread { get; private set; }
|
||||||
public string[] RunArgs { get; set; } = new string[0];
|
public string[] RunArgs { get; set; } = new string[0];
|
||||||
|
public bool Running { get; private set; }
|
||||||
|
|
||||||
public event Action SessionLoading;
|
public event Action SessionLoading;
|
||||||
public event Action SessionReady;
|
public event Action SessionLoaded;
|
||||||
|
|
||||||
private readonly Assembly _dsAssembly;
|
private readonly Assembly _dsAssembly;
|
||||||
|
private readonly ManualResetEvent _stopHandle = new ManualResetEvent(false);
|
||||||
|
|
||||||
private ServerManager()
|
internal ServerManager()
|
||||||
{
|
{
|
||||||
using (var f = File.OpenRead("SpaceEngineersDedicated.exe"))
|
using (var f = File.OpenRead("SpaceEngineersDedicated.exe"))
|
||||||
{
|
{
|
||||||
@@ -47,7 +48,7 @@ namespace PistonServer
|
|||||||
|
|
||||||
private void OnSessionReady()
|
private void OnSessionReady()
|
||||||
{
|
{
|
||||||
SessionReady?.Invoke();
|
SessionLoaded?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -69,6 +70,7 @@ namespace PistonServer
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void StartServer()
|
public void StartServer()
|
||||||
{
|
{
|
||||||
|
Running = true;
|
||||||
Logger.Write("Starting server.");
|
Logger.Write("Starting server.");
|
||||||
|
|
||||||
if (MySandboxGame.Log.LogEnabled)
|
if (MySandboxGame.Log.LogEnabled)
|
||||||
@@ -89,15 +91,19 @@ namespace PistonServer
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stop the server.
|
/// Stop the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="abortThread"></param>
|
public void StopServer()
|
||||||
public void StopServer(bool abortThread = false)
|
|
||||||
{
|
{
|
||||||
if (Thread.CurrentThread != ServerThread)
|
if (Thread.CurrentThread.ManagedThreadId != ServerThread.ManagedThreadId)
|
||||||
{
|
{
|
||||||
MySandboxGame.Static?.Invoke(() => StopServer(true));
|
Logger.Write("Requesting server stop.");
|
||||||
|
MySandboxGame.Static.Invoke(StopServer);
|
||||||
|
_stopHandle.WaitOne();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Logger.Write("Stopping server.");
|
||||||
|
MySession.Static.Save();
|
||||||
|
MySession.Static.Unload();
|
||||||
MySandboxGame.Static.Exit();
|
MySandboxGame.Static.Exit();
|
||||||
|
|
||||||
//Unload all the static junk.
|
//Unload all the static junk.
|
||||||
@@ -106,18 +112,10 @@ namespace PistonServer
|
|||||||
VRage.Input.MyGuiGameControlsHelpers.Reset();
|
VRage.Input.MyGuiGameControlsHelpers.Reset();
|
||||||
VRage.Input.MyInput.UnloadData();
|
VRage.Input.MyInput.UnloadData();
|
||||||
CleanupProfilers();
|
CleanupProfilers();
|
||||||
GC.Collect(2);
|
|
||||||
|
|
||||||
Logger.Write("Server stopped.");
|
Logger.Write("Server stopped.");
|
||||||
if (abortThread)
|
_stopHandle.Set();
|
||||||
{
|
Running = false;
|
||||||
try { ServerThread.Abort(); }
|
|
||||||
catch (ThreadAbortException)
|
|
||||||
{
|
|
||||||
Logger.Write("Server thread aborted.");
|
|
||||||
}
|
|
||||||
ServerThread = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CleanupProfilers()
|
private void CleanupProfilers()
|
||||||
|
Reference in New Issue
Block a user