Merge remote-tracking branch 'origin/PreRelease'
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
@@ -12,7 +13,8 @@ namespace Torch
|
|||||||
string InstancePath { get; set; }
|
string InstancePath { get; set; }
|
||||||
bool NoGui { get; set; }
|
bool NoGui { get; set; }
|
||||||
bool NoUpdate { get; set; }
|
bool NoUpdate { get; set; }
|
||||||
List<string> Plugins { get; set; }
|
List<Guid> Plugins { get; set; }
|
||||||
|
bool LocalPlugins { get; set; }
|
||||||
bool RestartOnCrash { get; set; }
|
bool RestartOnCrash { get; set; }
|
||||||
bool ShouldUpdatePlugins { get; }
|
bool ShouldUpdatePlugins { get; }
|
||||||
bool ShouldUpdateTorch { get; }
|
bool ShouldUpdateTorch { get; }
|
||||||
|
@@ -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.Collections;
|
||||||
using VRage.Network;
|
using VRage.Network;
|
||||||
|
|
||||||
namespace Torch.API.Managers
|
namespace Torch.API.Managers
|
||||||
@@ -41,5 +42,24 @@ namespace Torch.API.Managers
|
|||||||
/// <param name="font">Font to use</param>
|
/// <param name="font">Font to use</param>
|
||||||
/// <param name="targetSteamId">Player to send the message to, or everyone by default</param>
|
/// <param name="targetSteamId">Player to send the message to, or everyone by default</param>
|
||||||
void SendMessageAsOther(string author, string message, string font, ulong targetSteamId = 0);
|
void SendMessageAsOther(string author, string message, string font, ulong targetSteamId = 0);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mute user from global chat.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="steamId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool MuteUser(ulong steamId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unmute user from global chat.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="steamId"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
bool UnmuteUser(ulong steamId);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Users which are not allowed to chat.
|
||||||
|
/// </summary>
|
||||||
|
HashSetReader<ulong> MutedUsers { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -283,12 +283,16 @@
|
|||||||
<Compile Include="Views\Entities\CharacterView.xaml.cs">
|
<Compile Include="Views\Entities\CharacterView.xaml.cs">
|
||||||
<DependentUpon>CharacterView.xaml</DependentUpon>
|
<DependentUpon>CharacterView.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Views\Extensions.cs" />
|
||||||
<Compile Include="Views\ModListControl.xaml.cs">
|
<Compile Include="Views\ModListControl.xaml.cs">
|
||||||
<DependentUpon>ModListControl.xaml</DependentUpon>
|
<DependentUpon>ModListControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Views\PluginBrowser.xaml.cs">
|
<Compile Include="Views\PluginBrowser.xaml.cs">
|
||||||
<DependentUpon>PluginBrowser.xaml</DependentUpon>
|
<DependentUpon>PluginBrowser.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
|
<Compile Include="Views\RoleEditor.xaml.cs">
|
||||||
|
<DependentUpon>RoleEditor.xaml</DependentUpon>
|
||||||
|
</Compile>
|
||||||
<Compile Include="Views\ThemeControl.xaml.cs">
|
<Compile Include="Views\ThemeControl.xaml.cs">
|
||||||
<DependentUpon>ThemeControl.xaml</DependentUpon>
|
<DependentUpon>ThemeControl.xaml</DependentUpon>
|
||||||
</Compile>
|
</Compile>
|
||||||
@@ -473,6 +477,10 @@
|
|||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
</Page>
|
</Page>
|
||||||
|
<Page Include="Views\RoleEditor.xaml">
|
||||||
|
<SubType>Designer</SubType>
|
||||||
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
</Page>
|
||||||
<Page Include="Views\SessionSettingsView.xaml">
|
<Page Include="Views\SessionSettingsView.xaml">
|
||||||
<SubType>Designer</SubType>
|
<SubType>Designer</SubType>
|
||||||
<Generator>MSBuild:Compile</Generator>
|
<Generator>MSBuild:Compile</Generator>
|
||||||
|
@@ -59,7 +59,11 @@ namespace Torch.Server
|
|||||||
public int TickTimeout { get; set; } = 60;
|
public int TickTimeout { get; set; } = 60;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public List<string> Plugins { get; set; } = new List<string>();
|
[Arg("plugins", "Starts Torch with the given plugin GUIDs (space delimited).")]
|
||||||
|
public List<Guid> Plugins { get; set; } = new List<Guid>();
|
||||||
|
|
||||||
|
[Arg("localplugins", "Loads all pluhins from disk, ignores the plugins defined in config.")]
|
||||||
|
public bool LocalPlugins { get; set; }
|
||||||
|
|
||||||
public string ChatName { get; set; } = "Server";
|
public string ChatName { get; set; } = "Server";
|
||||||
|
|
||||||
|
@@ -45,6 +45,8 @@ namespace Torch.Server
|
|||||||
private ServerState _state;
|
private ServerState _state;
|
||||||
private Stopwatch _uptime;
|
private Stopwatch _uptime;
|
||||||
private Timer _watchdog;
|
private Timer _watchdog;
|
||||||
|
private int _players;
|
||||||
|
private MultiplayerManagerDedicated _multiplayerManagerDedicated;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public TorchServer(TorchConfig config = null)
|
public TorchServer(TorchConfig config = null)
|
||||||
@@ -92,6 +94,8 @@ namespace Torch.Server
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string InstancePath => Config?.InstancePath;
|
public string InstancePath => Config?.InstancePath;
|
||||||
|
|
||||||
|
public int OnlinePlayers { get => _players; private set => SetValue(ref _players, value); }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Init()
|
public override void Init()
|
||||||
{
|
{
|
||||||
@@ -188,6 +192,7 @@ namespace Torch.Server
|
|||||||
|
|
||||||
if (newState == TorchSessionState.Loaded)
|
if (newState == TorchSessionState.Loaded)
|
||||||
{
|
{
|
||||||
|
_multiplayerManagerDedicated = CurrentSession.Managers.GetManager<MultiplayerManagerDedicated>();
|
||||||
CurrentSession.Managers.GetManager<CommandManager>().RegisterCommandModule(typeof(WhitelistCommands));
|
CurrentSession.Managers.GetManager<CommandManager>().RegisterCommandModule(typeof(WhitelistCommands));
|
||||||
ModCommunication.Register();
|
ModCommunication.Register();
|
||||||
}
|
}
|
||||||
@@ -211,6 +216,7 @@ namespace Torch.Server
|
|||||||
SimulationRatio = Math.Min(Sync.ServerSimulationRatio, 1);
|
SimulationRatio = Math.Min(Sync.ServerSimulationRatio, 1);
|
||||||
var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
|
var elapsed = TimeSpan.FromSeconds(Math.Floor(_uptime.Elapsed.TotalSeconds));
|
||||||
ElapsedPlayTime = elapsed;
|
ElapsedPlayTime = elapsed;
|
||||||
|
OnlinePlayers = _multiplayerManagerDedicated?.Players.Count ?? 0;
|
||||||
|
|
||||||
if (_watchdog == null && Config.TickTimeout > 0)
|
if (_watchdog == null && Config.TickTimeout > 0)
|
||||||
{
|
{
|
||||||
|
@@ -58,7 +58,7 @@
|
|||||||
<RowDefinition />
|
<RowDefinition />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<ScrollViewer VerticalScrollBarVisibility="Disabled">
|
<ScrollViewer VerticalScrollBarVisibility="Auto">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@@ -99,6 +99,7 @@
|
|||||||
<TextBox Text="{Binding Administrators, Converter={StaticResource ListConverterString}}"
|
<TextBox Text="{Binding Administrators, Converter={StaticResource ListConverterString}}"
|
||||||
Margin="3"
|
Margin="3"
|
||||||
Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto" />
|
Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto" />
|
||||||
|
<Button Content="Edit Roles" Click="RoleEdit_Onlick" Margin="3"/>
|
||||||
<Label Content="Reserved Players" />
|
<Label Content="Reserved Players" />
|
||||||
<TextBox Margin="3" Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"
|
<TextBox Margin="3" Height="100" AcceptsReturn="true" VerticalScrollBarVisibility="Auto"
|
||||||
Style="{StaticResource ValidatedTextBox}">
|
Style="{StaticResource ValidatedTextBox}">
|
||||||
|
@@ -12,6 +12,7 @@ using Torch.API.Managers;
|
|||||||
using Torch.Server.Annotations;
|
using Torch.Server.Annotations;
|
||||||
using Torch.Server.Managers;
|
using Torch.Server.Managers;
|
||||||
using Torch.Server.ViewModels;
|
using Torch.Server.ViewModels;
|
||||||
|
using Torch.Views;
|
||||||
|
|
||||||
namespace Torch.Server.Views
|
namespace Torch.Server.Views
|
||||||
{
|
{
|
||||||
@@ -122,5 +123,13 @@ namespace Torch.Server.Views
|
|||||||
var c = new WorldGeneratorDialog(_instanceManager);
|
var c = new WorldGeneratorDialog(_instanceManager);
|
||||||
c.Show();
|
c.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RoleEdit_Onlick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
//var w = new RoleEditor(_instanceManager.DedicatedConfig.SelectedWorld);
|
||||||
|
//w.Show();
|
||||||
|
var d = new RoleEditor();
|
||||||
|
d.Edit(_instanceManager.DedicatedConfig.SelectedWorld.Checkpoint.PromotedUsers.Dictionary);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
24
Torch.Server/Views/Extensions.cs
Normal file
24
Torch.Server/Views/Extensions.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views
|
||||||
|
{
|
||||||
|
public static class Extensions
|
||||||
|
{
|
||||||
|
public static readonly DependencyProperty ScrollContainerProperty = DependencyProperty.RegisterAttached("ScrollContainer", typeof(bool), typeof(Extensions), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
public static bool GetScrollContainer(this UIElement ui)
|
||||||
|
{
|
||||||
|
return (bool)ui.GetValue(ScrollContainerProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void SetScrollContainer(this UIElement ui, bool value)
|
||||||
|
{
|
||||||
|
ui.SetValue(ScrollContainerProperty, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -90,6 +90,7 @@ namespace Torch.Server.Views
|
|||||||
private void DownloadButton_OnClick(object sender, RoutedEventArgs e)
|
private void DownloadButton_OnClick(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var item = CurrentItem;
|
var item = CurrentItem;
|
||||||
|
TorchBase.Instance.Config.Plugins.Add(new Guid(item.ID));
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var result = await PluginQuery.Instance.DownloadPlugin(item.ID);
|
var result = await PluginQuery.Instance.DownloadPlugin(item.ID);
|
||||||
|
@@ -41,7 +41,9 @@ namespace Torch.Server.Views
|
|||||||
{
|
{
|
||||||
if (propertyChangedEventArgs.PropertyName == nameof(PluginManagerViewModel.SelectedPlugin))
|
if (propertyChangedEventArgs.PropertyName == nameof(PluginManagerViewModel.SelectedPlugin))
|
||||||
{
|
{
|
||||||
if (((PluginManagerViewModel)DataContext).SelectedPlugin.Control is PropertyGrid)
|
var plugin = ((PluginManagerViewModel)DataContext).SelectedPlugin;
|
||||||
|
|
||||||
|
if (plugin.Control is PropertyGrid || !plugin.Control.GetScrollContainer())
|
||||||
PScroll.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
|
PScroll.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;
|
||||||
else
|
else
|
||||||
PScroll.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
PScroll.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;
|
||||||
|
52
Torch.Server/Views/RoleEditor.xaml
Normal file
52
Torch.Server/Views/RoleEditor.xaml
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
<Window x:Class="Torch.Server.Views.RoleEditor"
|
||||||
|
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"
|
||||||
|
xmlns:sys="clr-namespace:System;assembly=mscorlib"
|
||||||
|
xmlns:modApi="clr-namespace:VRage.Game.ModAPI;assembly=VRage.Game"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="RoleEditor" Height="300" Width="300">
|
||||||
|
<Window.Resources>
|
||||||
|
<ObjectDataProvider MethodName="GetValues" ObjectType="{x:Type sys:Enum}" x:Key="GetEnumValues">
|
||||||
|
<ObjectDataProvider.MethodParameters>
|
||||||
|
<x:Type TypeName="modApi:MyPromoteLevel"/>
|
||||||
|
</ObjectDataProvider.MethodParameters>
|
||||||
|
</ObjectDataProvider>
|
||||||
|
</Window.Resources>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition Height="Auto"/>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<DataGrid x:Name="ItemGrid" AutoGenerateColumns="false" CanUserAddRows="true" Grid.Row="0">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Width="5*" Header="Key" Binding="{Binding Key}"/>
|
||||||
|
<DataGridComboBoxColumn Width ="5*" Header="Value" ItemsSource="{Binding Source={StaticResource GetEnumValues}}" SelectedValueBinding="{Binding Value, Mode=TwoWay}"/>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
<Button Grid.Row="1" Content="Add New" Margin="5" Click="AddNew_OnClick"></Button>
|
||||||
|
<Grid Grid.Row="2">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button Grid.Column="0" Content="Cancel" Margin="5" Click="Cancel_OnClick" />
|
||||||
|
<Button Grid.Column="1" Content="OK" Margin="5" Click="Ok_OnClick" />
|
||||||
|
</Grid>
|
||||||
|
<Grid Grid.Row="3">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ComboBox Name="BulkSelect" ItemsSource="{Binding Source={StaticResource GetEnumValues}}" SelectedValue ="{Binding
|
||||||
|
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:RoleEditor}},
|
||||||
|
Path = BulkPromote, Mode=TwoWay}" Margin="5"/>
|
||||||
|
<Button Grid.Column="1" Content="Bulk edit" Margin ="5" Click="BulkEdit"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
||||||
|
|
123
Torch.Server/Views/RoleEditor.xaml.cs
Normal file
123
Torch.Server/Views/RoleEditor.xaml.cs
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
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.Shapes;
|
||||||
|
using Torch.Server.Managers;
|
||||||
|
using Torch.Views;
|
||||||
|
using VRage.Game.ModAPI;
|
||||||
|
|
||||||
|
namespace Torch.Server.Views
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for RoleEditor.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class RoleEditor : Window
|
||||||
|
{
|
||||||
|
public RoleEditor()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
DataContext = Items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<IDictionaryItem> Items { get; } = new ObservableCollection<IDictionaryItem>();
|
||||||
|
private Type _itemType;
|
||||||
|
|
||||||
|
private Action _commitChanges;
|
||||||
|
public MyPromoteLevel BulkPromote { get; set; } = MyPromoteLevel.Scripter;
|
||||||
|
|
||||||
|
public void Edit(IDictionary dict)
|
||||||
|
{
|
||||||
|
Items.Clear();
|
||||||
|
var dictType = dict.GetType();
|
||||||
|
_itemType = typeof(DictionaryItem<,>).MakeGenericType(dictType.GenericTypeArguments[0], dictType.GenericTypeArguments[1]);
|
||||||
|
|
||||||
|
foreach (var key in dict.Keys)
|
||||||
|
{
|
||||||
|
Items.Add((IDictionaryItem)Activator.CreateInstance(_itemType, key, dict[key]));
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemGrid.ItemsSource = Items;
|
||||||
|
|
||||||
|
_commitChanges = () =>
|
||||||
|
{
|
||||||
|
dict.Clear();
|
||||||
|
foreach (var item in Items)
|
||||||
|
{
|
||||||
|
dict[item.Key] = item.Value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Cancel_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Ok_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
_commitChanges?.Invoke();
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IDictionaryItem
|
||||||
|
{
|
||||||
|
object Key { get; set; }
|
||||||
|
object Value { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class DictionaryItem<TKey, TValue> : ViewModel, IDictionaryItem
|
||||||
|
{
|
||||||
|
private TKey _key;
|
||||||
|
private TValue _value;
|
||||||
|
|
||||||
|
object IDictionaryItem.Key { get => _key; set => SetValue(ref _key, (TKey)value); }
|
||||||
|
object IDictionaryItem.Value { get => _value; set => SetValue(ref _value, (TValue)value); }
|
||||||
|
|
||||||
|
public TKey Key { get => _key; set => SetValue(ref _key, value); }
|
||||||
|
public TValue Value { get => _value; set => SetValue(ref _value, value); }
|
||||||
|
|
||||||
|
public DictionaryItem()
|
||||||
|
{
|
||||||
|
_key = default(TKey);
|
||||||
|
_value = default(TValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
public DictionaryItem(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddNew_OnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Items.Add((IDictionaryItem)Activator.CreateInstance(_itemType));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void BulkEdit(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
List<ulong> l = Items.Where(i => i.Value.Equals(BulkPromote)).Select(i => (ulong)i.Key).ToList();
|
||||||
|
var w = new CollectionEditor();
|
||||||
|
w.Edit((ICollection<ulong>)l, "Bulk edit");
|
||||||
|
var r = Items.Where(j => j.Value.Equals(BulkPromote) || l.Contains((ulong)j.Key)).ToList();
|
||||||
|
foreach (var k in r)
|
||||||
|
Items.Remove(k);
|
||||||
|
foreach (var m in l)
|
||||||
|
Items.Add(new DictionaryItem<ulong, MyPromoteLevel>(m, BulkPromote));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -57,7 +57,7 @@
|
|||||||
</Label>
|
</Label>
|
||||||
<Label x:Name="LabelPlayers">
|
<Label x:Name="LabelPlayers">
|
||||||
<Label.Content>
|
<Label.Content>
|
||||||
<TextBlock ></TextBlock>
|
<TextBlock Text="{Binding OnlinePlayers, StringFormat=Players: {0}}"/>
|
||||||
</Label.Content>
|
</Label.Content>
|
||||||
</Label>
|
</Label>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
@@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
namespace Torch
|
namespace Torch
|
||||||
{
|
{
|
||||||
@@ -12,6 +13,7 @@ namespace Torch
|
|||||||
{
|
{
|
||||||
private readonly string _argPrefix;
|
private readonly string _argPrefix;
|
||||||
private readonly Dictionary<ArgAttribute, PropertyInfo> _args = new Dictionary<ArgAttribute, PropertyInfo>();
|
private readonly Dictionary<ArgAttribute, PropertyInfo> _args = new Dictionary<ArgAttribute, PropertyInfo>();
|
||||||
|
private readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
protected CommandLine(string argPrefix = "-")
|
protected CommandLine(string argPrefix = "-")
|
||||||
{
|
{
|
||||||
@@ -89,6 +91,24 @@ namespace Torch
|
|||||||
|
|
||||||
if (property.Value.PropertyType == typeof(string))
|
if (property.Value.PropertyType == typeof(string))
|
||||||
property.Value.SetValue(this, args[++i]);
|
property.Value.SetValue(this, args[++i]);
|
||||||
|
|
||||||
|
if (property.Value.PropertyType == typeof(List<Guid>))
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
var l = new List<Guid>(16);
|
||||||
|
while (i < args.Length && !args[i].StartsWith(_argPrefix))
|
||||||
|
{
|
||||||
|
if (Guid.TryParse(args[i], out Guid g))
|
||||||
|
{
|
||||||
|
l.Add(g);
|
||||||
|
_log.Info($"added plugin {g}");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_log.Warn($"Failed to parse GUID {args[i]}");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
property.Value.SetValue(this, l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
@@ -57,10 +57,16 @@ namespace Torch.Commands
|
|||||||
if (node != null)
|
if (node != null)
|
||||||
{
|
{
|
||||||
var command = node.Command;
|
var command = node.Command;
|
||||||
var children = node.Subcommands.Select(x => x.Key);
|
var children = node.Subcommands.Where(e => Context.Player == null || e.Value.Command?.MinimumPromoteLevel <= Context.Player.PromoteLevel).Select(x => x.Key);
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
|
if (command?.MinimumPromoteLevel > Context.Player.PromoteLevel)
|
||||||
|
{
|
||||||
|
Context.Respond("You are not authorized to use this command.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (command != null)
|
if (command != null)
|
||||||
{
|
{
|
||||||
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
|
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
|
||||||
@@ -94,11 +100,11 @@ namespace Torch.Commands
|
|||||||
if (node != null)
|
if (node != null)
|
||||||
{
|
{
|
||||||
var command = node.Command;
|
var command = node.Command;
|
||||||
var children = node.Subcommands.Select(x => x.Key);
|
var children = node.Subcommands.Where(e => e.Value.Command?.MinimumPromoteLevel <= Context.Player.PromoteLevel).Select(x => x.Key);
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
if (command != null)
|
if (command != null && (Context.Player == null || command.MinimumPromoteLevel <= Context.Player.PromoteLevel))
|
||||||
{
|
{
|
||||||
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
|
sb.AppendLine($"Syntax: {command.SyntaxHelp}");
|
||||||
sb.Append(command.HelpText);
|
sb.Append(command.HelpText);
|
||||||
@@ -114,7 +120,7 @@ namespace Torch.Commands
|
|||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
foreach (var command in commandManager.Commands.WalkTree())
|
foreach (var command in commandManager.Commands.WalkTree())
|
||||||
{
|
{
|
||||||
if (command.IsCommand)
|
if (command.IsCommand && (Context.Player == null || command.Command.MinimumPromoteLevel <= Context.Player.PromoteLevel))
|
||||||
sb.AppendLine($"{command.Command.SyntaxHelp}\n {command.Command.HelpText}");
|
sb.AppendLine($"{command.Command.SyntaxHelp}\n {command.Command.HelpText}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,6 +16,7 @@ using Torch.API.Managers;
|
|||||||
using Torch.Managers.PatchManager;
|
using Torch.Managers.PatchManager;
|
||||||
using Torch.Utils;
|
using Torch.Utils;
|
||||||
using VRage;
|
using VRage;
|
||||||
|
using VRage.Collections;
|
||||||
using VRage.Library.Collections;
|
using VRage.Library.Collections;
|
||||||
using VRage.Network;
|
using VRage.Network;
|
||||||
|
|
||||||
@@ -47,6 +48,10 @@ namespace Torch.Managers.ChatManager
|
|||||||
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
private static readonly Logger _chatLog = LogManager.GetLogger("Chat");
|
private static readonly Logger _chatLog = LogManager.GetLogger("Chat");
|
||||||
|
|
||||||
|
private readonly HashSet<ulong> _muted = new HashSet<ulong>();
|
||||||
|
/// <inheritdoc />
|
||||||
|
public HashSetReader<ulong> MutedUsers => _muted;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ChatManagerServer(ITorchBase torchInstance) : base(torchInstance)
|
public ChatManagerServer(ITorchBase torchInstance) : base(torchInstance)
|
||||||
{
|
{
|
||||||
@@ -56,6 +61,18 @@ namespace Torch.Managers.ChatManager
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public event MessageProcessingDel MessageProcessing;
|
public event MessageProcessingDel MessageProcessing;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool MuteUser(ulong steamId)
|
||||||
|
{
|
||||||
|
return _muted.Add(steamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool UnmuteUser(ulong steamId)
|
||||||
|
{
|
||||||
|
return _muted.Remove(steamId);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SendMessageAsOther(ulong authorId, string message, ulong targetSteamId = 0)
|
public void SendMessageAsOther(ulong authorId, string message, ulong targetSteamId = 0)
|
||||||
{
|
{
|
||||||
@@ -128,6 +145,13 @@ namespace Torch.Managers.ChatManager
|
|||||||
internal void RaiseMessageRecieved(ChatMsg message, ref bool consumed)
|
internal void RaiseMessageRecieved(ChatMsg message, ref bool consumed)
|
||||||
{
|
{
|
||||||
var torchMsg = new TorchChatMessage(GetMemberName(message.Author), message.Author, message.Text, (ChatChannel)message.Channel, message.TargetId);
|
var torchMsg = new TorchChatMessage(GetMemberName(message.Author), message.Author, message.Text, (ChatChannel)message.Channel, message.TargetId);
|
||||||
|
if (_muted.Contains(message.Author))
|
||||||
|
{
|
||||||
|
consumed = true;
|
||||||
|
_chatLog.Warn($"MUTED USER: [{torchMsg.Channel}:{torchMsg.Target}] {torchMsg.Author}: {torchMsg.Message}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
MessageProcessing?.Invoke(torchMsg, ref consumed);
|
MessageProcessing?.Invoke(torchMsg, ref consumed);
|
||||||
|
|
||||||
if (!consumed)
|
if (!consumed)
|
||||||
|
@@ -96,6 +96,8 @@ namespace Torch.Managers
|
|||||||
|
|
||||||
public void LoadPlugins()
|
public void LoadPlugins()
|
||||||
{
|
{
|
||||||
|
bool firstLoad = Torch.Config.Plugins.Count == 0;
|
||||||
|
List<Guid> foundPlugins = new List<Guid>();
|
||||||
if (Torch.Config.ShouldUpdatePlugins)
|
if (Torch.Config.ShouldUpdatePlugins)
|
||||||
DownloadPluginUpdates();
|
DownloadPluginUpdates();
|
||||||
|
|
||||||
@@ -106,22 +108,56 @@ namespace Torch.Managers
|
|||||||
var path = Path.Combine(PluginDir, item);
|
var path = Path.Combine(PluginDir, item);
|
||||||
var isZip = item.EndsWith(".zip", StringComparison.CurrentCultureIgnoreCase);
|
var isZip = item.EndsWith(".zip", StringComparison.CurrentCultureIgnoreCase);
|
||||||
var manifest = isZip ? GetManifestFromZip(path) : GetManifestFromDirectory(path);
|
var manifest = isZip ? GetManifestFromZip(path) : GetManifestFromDirectory(path);
|
||||||
if (manifest == null)
|
if (!Torch.Config.LocalPlugins)
|
||||||
{
|
{
|
||||||
_log.Warn($"Item '{item}' is missing a manifest, skipping.");
|
if (isZip && !Torch.Config.Plugins.Contains(manifest.Guid))
|
||||||
continue;
|
{
|
||||||
|
if (!firstLoad)
|
||||||
|
{
|
||||||
|
_log.Warn($"Plugin {manifest.Name} ({item}) exists in the plugin directory, but is not listed in torch.cfg. Skipping load!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_log.Info($"First-time load: Plugin {manifest.Name} added to torch.cfg.");
|
||||||
|
Torch.Config.Plugins.Add(manifest.Guid);
|
||||||
|
}
|
||||||
|
if(isZip)
|
||||||
|
foundPlugins.Add(manifest.Guid);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_plugins.ContainsKey(manifest.Guid))
|
LoadPlugin(item);
|
||||||
{
|
}
|
||||||
_log.Error($"The GUID provided by {manifest.Name} ({item}) is already in use by {_plugins[manifest.Guid].Name}");
|
if (!Torch.Config.LocalPlugins && firstLoad)
|
||||||
continue;
|
Torch.Config.Save();
|
||||||
}
|
|
||||||
|
|
||||||
if (isZip)
|
if (!Torch.Config.LocalPlugins)
|
||||||
LoadPluginFromZip(path);
|
{
|
||||||
else
|
List<string> toLoad = new List<string>();
|
||||||
LoadPluginFromFolder(path);
|
|
||||||
|
//This is actually the easiest way to batch process async tasks and block until completion (????)
|
||||||
|
Task.WhenAll(Torch.Config.Plugins.Select(async g =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (foundPlugins.Contains(g))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var item = await PluginQuery.Instance.QueryOne(g);
|
||||||
|
string s = Path.Combine(PluginDir, item.Name + ".zip");
|
||||||
|
await PluginQuery.Instance.DownloadPlugin(item, s);
|
||||||
|
lock (toLoad)
|
||||||
|
toLoad.Add(s);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Error(ex);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
foreach (var l in toLoad)
|
||||||
|
{
|
||||||
|
LoadPlugin(l);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var plugin in _plugins.Values)
|
foreach (var plugin in _plugins.Values)
|
||||||
@@ -132,11 +168,34 @@ namespace Torch.Managers
|
|||||||
PluginsLoaded?.Invoke(_plugins.Values.AsReadOnly());
|
PluginsLoaded?.Invoke(_plugins.Values.AsReadOnly());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadPlugin(string item)
|
||||||
|
{
|
||||||
|
var path = Path.Combine(PluginDir, item);
|
||||||
|
var isZip = item.EndsWith(".zip", StringComparison.CurrentCultureIgnoreCase);
|
||||||
|
var manifest = isZip ? GetManifestFromZip(path) : GetManifestFromDirectory(path);
|
||||||
|
if (manifest == null)
|
||||||
|
{
|
||||||
|
_log.Warn($"Item '{item}' is missing a manifest, skipping.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_plugins.ContainsKey(manifest.Guid))
|
||||||
|
{
|
||||||
|
_log.Error($"The GUID provided by {manifest.Name} ({item}) is already in use by {_plugins[manifest.Guid].Name}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isZip)
|
||||||
|
LoadPluginFromZip(path);
|
||||||
|
else
|
||||||
|
LoadPluginFromFolder(path);
|
||||||
|
}
|
||||||
|
|
||||||
private void DownloadPluginUpdates()
|
private void DownloadPluginUpdates()
|
||||||
{
|
{
|
||||||
_log.Info("Checking for plugin updates...");
|
_log.Info("Checking for plugin updates...");
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var pluginItems = Directory.EnumerateFiles(PluginDir, "*.zip").Union(Directory.EnumerateDirectories(PluginDir));
|
var pluginItems = Directory.EnumerateFiles(PluginDir, "*.zip");
|
||||||
Parallel.ForEach(pluginItems, async item =>
|
Parallel.ForEach(pluginItems, async item =>
|
||||||
{
|
{
|
||||||
PluginManifest manifest = null;
|
PluginManifest manifest = null;
|
||||||
@@ -144,7 +203,12 @@ namespace Torch.Managers
|
|||||||
{
|
{
|
||||||
var path = Path.Combine(PluginDir, item);
|
var path = Path.Combine(PluginDir, item);
|
||||||
var isZip = item.EndsWith(".zip", StringComparison.CurrentCultureIgnoreCase);
|
var isZip = item.EndsWith(".zip", StringComparison.CurrentCultureIgnoreCase);
|
||||||
manifest = isZip ? GetManifestFromZip(path) : GetManifestFromDirectory(path);
|
if (!isZip)
|
||||||
|
{
|
||||||
|
_log.Warn($"Unzipped plugins cannot be auto-updated. Skipping plugin {item}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manifest = GetManifestFromZip(path);
|
||||||
if (manifest == null)
|
if (manifest == null)
|
||||||
{
|
{
|
||||||
_log.Warn($"Item '{item}' is missing a manifest, skipping update check.");
|
_log.Warn($"Item '{item}' is missing a manifest, skipping update check.");
|
||||||
@@ -188,48 +252,6 @@ namespace Torch.Managers
|
|||||||
_log.Info($"Updated {count} plugins.");
|
_log.Info($"Updated {count} plugins.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<Tuple<Version, string>> GetLatestArchiveAsync(string repository)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//var split = repository.Split('/');
|
|
||||||
//var latest = await _gitClient.Repository.Release.GetLatest(split[0], split[1]).ConfigureAwait(false);
|
|
||||||
//if (!latest.TagName.TryExtractVersion(out Version latestVersion))
|
|
||||||
//{
|
|
||||||
// _log.Error($"Unable to parse version tag for the latest release of '{repository}.'");
|
|
||||||
//}
|
|
||||||
|
|
||||||
//var zipAsset = latest.Assets.FirstOrDefault(x => x.Name.Contains(".zip", StringComparison.CurrentCultureIgnoreCase));
|
|
||||||
//if (zipAsset == null)
|
|
||||||
//{
|
|
||||||
// _log.Error($"Unable to find archive for the latest release of '{repository}.'");
|
|
||||||
//}
|
|
||||||
|
|
||||||
//return new Tuple<Version, string>(latestVersion, zipAsset?.BrowserDownloadUrl);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
_log.Error($"Unable to get the latest release of '{repository}.'");
|
|
||||||
_log.Error(e);
|
|
||||||
return default(Tuple<Version, string>);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task UpdatePluginAsync(string localPath, string downloadUrl)
|
|
||||||
{
|
|
||||||
if (File.Exists(localPath))
|
|
||||||
File.Delete(localPath);
|
|
||||||
|
|
||||||
if (Directory.Exists(localPath))
|
|
||||||
Directory.Delete(localPath, true);
|
|
||||||
|
|
||||||
var fileName = downloadUrl.Split('/').Last();
|
|
||||||
var filePath = Path.Combine(PluginDir, fileName);
|
|
||||||
|
|
||||||
return new WebClient().DownloadFileTaskAsync(downloadUrl, filePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadPluginFromFolder(string directory)
|
private void LoadPluginFromFolder(string directory)
|
||||||
{
|
{
|
||||||
var assemblies = new List<Assembly>();
|
var assemblies = new List<Assembly>();
|
||||||
|
Reference in New Issue
Block a user