diff --git a/Torch.Server/Torch.Server.csproj b/Torch.Server/Torch.Server.csproj index d970c467..f33fad8e 100644 --- a/Torch.Server/Torch.Server.csproj +++ b/Torch.Server/Torch.Server.csproj @@ -277,7 +277,9 @@ + + @@ -291,9 +293,15 @@ CharacterView.xaml + + FactionView.xaml + FloatingObjectsView.xaml + + PlayerView.xaml + LogEventViewer.xaml @@ -470,11 +478,13 @@ MSBuild:Compile Designer + Designer MSBuild:Compile + diff --git a/Torch.Server/ViewModels/Entities/FactionViewModel.cs b/Torch.Server/ViewModels/Entities/FactionViewModel.cs new file mode 100644 index 00000000..7ea66fed --- /dev/null +++ b/Torch.Server/ViewModels/Entities/FactionViewModel.cs @@ -0,0 +1,65 @@ +using System.Collections.ObjectModel; +using Sandbox.Game.World; +using VRage.Game; + +namespace Torch.Server.ViewModels.Entities +{ + public class FactionViewModel : ViewModel + { + public FactionViewModel() + { } + + public MyFaction Faction { get; } + + public FactionViewModel(MyFaction faction) + { + Faction = faction; + GenerateMembers(); + } + + public string Name => Faction.Name; + public string Description => Faction.Description; + public string Tag => Faction.Tag; + public long ID => Faction.FactionId; + + public MemberData Founder { get; private set; } + public ObservableCollection Leaders { get; } = new ObservableCollection(); + public ObservableCollection Members { get; } = new ObservableCollection(); + + public void GenerateMembers() + { + Leaders.Clear(); + Members.Clear(); + foreach (MyFactionMember factionMember in Faction.Members.Values) + { + var playerIdent = MySession.Static.Players.TryGetIdentity(factionMember.PlayerId); + MySession.Static.Players.TryGetPlayerId(factionMember.PlayerId, out MyPlayer.PlayerId playerId); + MemberData md = new MemberData + { + PlayerIdent = playerIdent, + PlayerId = playerId + }; + + if (factionMember.IsFounder) + { + Founder = md; + continue; + } + + if (factionMember.IsLeader) + { + Leaders.Add(md); + continue; + } + + Members.Add(md); + } + } + } + + public sealed class MemberData + { + public MyIdentity PlayerIdent { get; set; } + public MyPlayer.PlayerId PlayerId { get; set; } + } +} diff --git a/Torch.Server/ViewModels/Entities/PlayerViewModel.cs b/Torch.Server/ViewModels/Entities/PlayerViewModel.cs new file mode 100644 index 00000000..858b671a --- /dev/null +++ b/Torch.Server/ViewModels/Entities/PlayerViewModel.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using Sandbox.Game.World; + +namespace Torch.Server.ViewModels.Entities +{ + public class PlayerViewModel : ViewModel + { + private readonly MyIdentity _backing; + private readonly MyPlayer.PlayerId _backingPlayer; + + public PlayerViewModel() + { } + + public MyIdentity Player => _backing; + + public PlayerViewModel(MyIdentity player, MyPlayer.PlayerId playerId) + { + _backing = player; + _backingPlayer = playerId; + } + + public string Name => Player.DisplayName; + public long ID => Player.IdentityId; + public ulong SteamID => _backingPlayer.SteamId; + + public string FactionTag + { + get + { + var faction = MySession.Static.Factions.GetPlayerFaction(ID); + return faction is null ? string.Empty : faction.Tag; + } + } + + public string FactionName + { + get + { + var faction = MySession.Static.Factions.GetPlayerFaction(ID); + return faction is null ? string.Empty : faction.Name; + } + } + public DateTime LastLogin => Player.LastLoginTime; + public DateTime LastLogout => Player.LastLogoutTime; + public string LastDeathLocation => Player.LastDeathPosition.ToString(); + public int BlocksBuilt => Player.BlockLimits.BlocksBuilt; + public int PCU => Player.BlockLimits.PCUBuilt; + public bool OverLimits => Player.BlockLimits.IsOverLimits; + } +} \ No newline at end of file diff --git a/Torch.Server/ViewModels/EntityTreeViewModel.cs b/Torch.Server/ViewModels/EntityTreeViewModel.cs index a39129c4..e4731915 100644 --- a/Torch.Server/ViewModels/EntityTreeViewModel.cs +++ b/Torch.Server/ViewModels/EntityTreeViewModel.cs @@ -1,18 +1,19 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows.Controls; using Sandbox.Game.Entities; using Sandbox.Game.Entities.Character; using Torch.Server.ViewModels.Entities; -using VRage.Game.ModAPI; -using VRage.ModAPI; using System.Windows.Threading; using NLog; +using Sandbox.Game.Multiplayer; +using Sandbox.Game.World; +using Torch.API; +using Torch.API.Managers; +using Torch.API.Session; using Torch.Collections; -using Torch.Server.Views.Entities; +using VRage.Game.ModAPI; +using PlayerViewModel = Torch.Server.ViewModels.Entities.PlayerViewModel; namespace Torch.Server.ViewModels { @@ -34,6 +35,8 @@ public enum SortEnum public MtObservableSortedDictionary Characters { get; set; } = new MtObservableSortedDictionary(); public MtObservableSortedDictionary FloatingObjects { get; set; } = new MtObservableSortedDictionary(); public MtObservableSortedDictionary VoxelMaps { get; set; } = new MtObservableSortedDictionary(); + public MtObservableSortedDictionary Players { get; set; } = new MtObservableSortedDictionary(); + public MtObservableSortedDictionary Factions { get; set; } = new MtObservableSortedDictionary(); public Dispatcher ControlDispatcher => _control.Dispatcher; public SortedView SortedGrids { get; } @@ -41,6 +44,8 @@ public enum SortEnum public SortedView SortedCharacters { get; } public SortedView SortedFloatingObjects { get; } public SortedView SortedVoxelMaps { get; } + public SortedView SortedPlayers { get; } + public SortedView SortedFactions { get; } private EntityViewModel _currentEntity; private SortEnum _currentSort; @@ -58,20 +63,105 @@ public SortEnum CurrentSort set => SetValue(ref _currentSort, value); } - // I hate you today WPF - public EntityTreeViewModel() : this(null) + // Westin miller still hates you today WPF + public EntityTreeViewModel() : this(null, null) { } - public EntityTreeViewModel(UserControl control) + public EntityTreeViewModel(UserControl control, ITorchServer server) { _control = control; - var comparer = new EntityViewModel.Comparer(_currentSort); - SortedGrids = new SortedView(Grids.Values, comparer); - FilteredSortedGrids = new SortedView(Grids.Values, comparer); - SortedCharacters = new SortedView(Characters.Values, comparer); - SortedFloatingObjects = new SortedView(FloatingObjects.Values, comparer); - SortedVoxelMaps = new SortedView(VoxelMaps.Values, comparer); + var entityComparer = new EntityViewModel.Comparer(_currentSort); + SortedGrids = new SortedView(Grids.Values, entityComparer); + FilteredSortedGrids = new SortedView(Grids.Values, entityComparer); + SortedCharacters = new SortedView(Characters.Values, entityComparer); + SortedFloatingObjects = new SortedView(FloatingObjects.Values, entityComparer); + SortedVoxelMaps = new SortedView(VoxelMaps.Values, entityComparer); + SortedPlayers = new SortedView(Players.Values, Comparer + .Create((x, y) => + string.Compare(x?.Name, y?.Name, StringComparison.InvariantCultureIgnoreCase)) + ); + SortedFactions = new SortedView(Factions.Values, Comparer + .Create((x, y) => + string.Compare(x?.Name, y?.Name, StringComparison.InvariantCultureIgnoreCase)) + ); + + if (server != null) + { + var sessionManager = server.Managers.GetManager(); + sessionManager.SessionStateChanged += RegisterLiveNonEntities; + } + } + + private void RegisterLiveNonEntities(ITorchSession session, TorchSessionState newState) + { + switch (newState) + { + case TorchSessionState.Loaded: + foreach (var identity in MySession.Static.Players.GetAllPlayers()) + { + if (identity.SteamId == 0) continue; + var player = MySession.Static.Players.TryGetPlayerIdentity(identity.SteamId); + if (player is null) continue; + Players.Add(new KeyValuePair(player.IdentityId, new PlayerViewModel(player, identity))); + } + + foreach (MyFaction faction in MySession.Static.Factions.GetAllFactions()) + { + Factions.Add(new KeyValuePair(faction.FactionId, new FactionViewModel(faction))); + } + + Sync.Players.RealPlayerIdentityCreated += NewPlayerCreated; + MySession.Static.Factions.FactionCreated += NewFactionCreated; + MySession.Static.Factions.FactionStateChanged += FactionChanged; + break; + + case TorchSessionState.Unloading: + Sync.Players.RealPlayerIdentityCreated -= NewPlayerCreated; + MySession.Static.Factions.FactionCreated -= NewFactionCreated; + Players.Clear(); + break; + } + } + + // These might be off, but I only need the reason and main faction id. + private void FactionChanged(MyFactionStateChange reason, long FactionId, long ToFactionId, long PlayerId, long SenderId) + { + switch (reason) + { + case MyFactionStateChange.RemoveFaction: + ControlDispatcher.Invoke(() => { Factions.Remove(FactionId);}); + + break; + case MyFactionStateChange.FactionMemberAcceptJoin: + case MyFactionStateChange.FactionMemberPromote: + case MyFactionStateChange.FactionMemberKick: + case MyFactionStateChange.FactionMemberDemote: + case MyFactionStateChange.FactionMemberLeave: + ControlDispatcher.Invoke(() => + { + if (Factions.TryGetValue(FactionId, out FactionViewModel faction)) + faction.GenerateMembers(); + }); + break; + } + } + + private void NewFactionCreated(long id) + { + ControlDispatcher.Invoke(() => + { + var faction = MySession.Static.Factions.GetPlayerFaction(id); + if (faction is null) return; + Factions.Add(new KeyValuePair(faction.FactionId, new FactionViewModel(faction))); + }); + } + + private void NewPlayerCreated(long identityId) + { + var player = MySession.Static.Players.TryGetPlayer(identityId); + if (player is null) return; + Players.Add(new KeyValuePair(player.Identity.IdentityId, new PlayerViewModel(player.Identity, new MyPlayer.PlayerId()))); } public void Init() diff --git a/Torch.Server/Views/Entities/FactionView.xaml b/Torch.Server/Views/Entities/FactionView.xaml new file mode 100644 index 00000000..efa1ff17 --- /dev/null +++ b/Torch.Server/Views/Entities/FactionView.xaml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +