Skip to content

Commit

Permalink
Merge pull request NebulaModTeam#697 from AlienXAXS/player_score_board
Browse files Browse the repository at this point in the history
Implemented a graphical player list
  • Loading branch information
starfi5h authored Jul 25, 2024
2 parents ae72e9e + 595bb19 commit 11f92ca
Show file tree
Hide file tree
Showing 8 changed files with 314 additions and 4 deletions.
4 changes: 4 additions & 0 deletions NebulaModel/MultiplayerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ public bool StreamerMode
[Description("Keyboard shortcut to toggle the chat window")]
public KeyboardShortcut ChatHotkey { get; set; } = new(KeyCode.BackQuote, KeyCode.LeftAlt);

[DisplayName("Player List Hotkey")]
[Description("Keyboard shortcut to display the Connected Players Window")]
public KeyboardShortcut PlayerListHotkey { get; set; } = new(KeyCode.BackQuote);

[DisplayName("Auto Open Chat")]
[Category("Chat")]
[Description("Auto open chat window when receiving message from other players")]
Expand Down
1 change: 0 additions & 1 deletion NebulaNetwork/Messaging/WebSocketService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ protected override void OnError(ErrorEventArgs e)
}
connections.Remove(Context.UserEndPoint.GetHashCode());


Log.Info($"Client disconnected because of an error: {ID}, reason: {e.Exception}");
UnityDispatchQueue.RunOnMainThread(() =>
{
Expand Down
6 changes: 3 additions & 3 deletions NebulaWorld/NebulaWorld.csproj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk">
<ItemGroup>
<ProjectReference Include="..\dep\discord_game_sdk\discord_game_sdk_dotnet.csproj"/>
<ProjectReference Include="..\NebulaModel\NebulaModel.csproj" SpecificVersion="true"/>
<ProjectReference Include="..\NebulaAPI\NebulaAPI.csproj" Private="false"/>
<ProjectReference Include="..\dep\discord_game_sdk\discord_game_sdk_dotnet.csproj" />
<ProjectReference Include="..\NebulaModel\NebulaModel.csproj" SpecificVersion="true" />
<ProjectReference Include="..\NebulaAPI\NebulaAPI.csproj" Private="false" />
</ItemGroup>
</Project>
3 changes: 3 additions & 0 deletions NebulaWorld/SimulatedWorld.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
using NebulaWorld.MonoBehaviours;
using NebulaWorld.MonoBehaviours.Local;
using NebulaWorld.MonoBehaviours.Local.Chat;
using NebulaWorld.UIPlayerList;
using UnityEngine;
using UnityEngine.UI;
using Object = UnityEngine.Object;
Expand Down Expand Up @@ -189,6 +190,8 @@ public void SetupInitialPlayerState()
localPlayerMovement = GameMain.mainPlayer.gameObject.AddComponentIfMissing<LocalPlayerMovement>();
// ChatManager should exist continuously until the game is closed
GameMain.mainPlayer.gameObject.AddComponentIfMissing<ChatManager>();
// Load the Player List Window
GameMain.mainPlayer.gameObject.AddComponentIfMissing<UIPlayerWindow>();
}

public static void FixPlayerAfterImport()
Expand Down
216 changes: 216 additions & 0 deletions NebulaWorld/UIPlayerList/UIPlayerWindow.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
using System;
using System.Linq;
using NebulaModel;
using NebulaModel.Logger;
using NebulaWorld.Combat;
using NebulaWorld.MonoBehaviours.Local.Chat;
using UnityEngine;
using Object = System.Object;

namespace NebulaWorld.UIPlayerList
{
public class UIPlayerWindow : MonoBehaviour
{
private const string WindowName = "";

private Rect windowSize = new Rect(10f, 10f, 1100f, 600f);
private Vector2 playerListScrollPosition = Vector2.zero;

private readonly Object _lockable = new Object();

private bool _windowVisible;
private ChatWindow _chatWindow;

public void OnInit()
{
var parent = UIRoot.instance.uiGame.inventoryWindow.transform.parent;
var chatGo = parent.Find("Chat Window") ? parent.Find("Chat Window").gameObject : null;

if (chatGo != null)
{
_chatWindow = chatGo.transform.GetComponentInChildren<ChatWindow>();
}
}

public void Update()
{
var hasModifier = Config.Options.PlayerListHotkey.Modifiers.Any();

_windowVisible = false;
if (Input.GetKey(Config.Options.PlayerListHotkey.MainKey))
{
if (Config.Options.PlayerListHotkey.Modifiers.All(Input.GetKey))
{
// If we have no modifier but a modifier is pressed, do not progress
if (!hasModifier && Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.LeftControl) ||
Input.GetKey(KeyCode.RightAlt) || Input.GetKey(KeyCode.RightControl)) return;

_windowVisible = true;
}
}
}

public void OnGUI()
{
if (!Multiplayer.IsActive) return;
if (Multiplayer.Session.IsDedicated) return;

try
{
if (!_windowVisible ||
IsChatWindowActive() ||
UIRoot.instance.uiGame.techTree.active ||
UIRoot.instance.uiGame.escMenu.active ||

Check warning on line 63 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)

Check warning on line 63 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)

Check warning on line 63 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Release)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)
UIRoot.instance.uiGame.dysonEditor.active)
return;

windowSize = GUI.Window(6245814, windowSize, WindowHandler, WindowName, UIStyles.DialogStyles.WindowBackgroundStyle());
windowSize.x = (int)(Screen.width * 0.5f - windowSize.width * 0.5f);
windowSize.y = (int)(Screen.height * 0.5f - windowSize.height * 0.5f);
}
catch (Exception ex)
{
Log.Error("Error in UIPlayerWindow OnGUI");
Log.Error(ex);
}
}

Check warning on line 77 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)

Check warning on line 77 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)

Check warning on line 77 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Release)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)
public void WindowHandler(int id)
{
//used to track how many times a GUI element needs to be recycled in the event
// that an exception is caught
var areaBegins = 0;
var horizontalBegins = 0;
var verticalBegins = 0;
var scrollViewBegins = 0;

var localPlayer = GameMain.mainPlayer;

try
{
GUILayout.BeginArea(new Rect(5f, 20f, windowSize.width - 10f, windowSize.height - 55f)); areaBegins++;
GUILayout.BeginHorizontal(); horizontalBegins++;
GUILayout.Space(2);
GUILayout.Label("Online Players", UIStyles.LabelStyles.HeaderLabelStyle, new GUILayoutOption[] { GUILayout.ExpandHeight(false), GUILayout.ExpandWidth(true) });
GUILayout.EndHorizontal(); horizontalBegins--;


// If the player is alone in their save, then do not draw the scoreboard proper
if (AmIAlone())
{
GUILayout.Label("It's Just You", UIStyles.LabelStyles.CenterLabelLarge, new GUILayoutOption[] { GUILayout.ExpandHeight(true), GUILayout.ExpandWidth(true) });
GUILayout.EndArea();
return;
}

GUILayout.Space(20f);
GUILayout.BeginVertical(); verticalBegins++;

// Headers
GUILayout.BeginHorizontal(); horizontalBegins++;
GUILayout.Label("Name", UIStyles.LabelStyles.RowHeaderLabelsStyle, GUILayout.Width(300));
GUILayout.Label("Location", UIStyles.LabelStyles.RowHeaderLabelsStyle, GUILayout.Width(600));
GUILayout.Label("Distance", UIStyles.LabelStyles.RowHeaderLabelsStyle, GUILayout.Width(100));
GUILayout.EndHorizontal(); horizontalBegins--;

// Horizontal bar
GUILayout.BeginHorizontal(); horizontalBegins++;
GUILayout.Box("", GUI.skin.horizontalSlider, UIStyles.BoxStyles.HorizontalSliderStyle);
GUILayout.EndHorizontal(); horizontalBegins--;

GUILayout.Space(10f);

playerListScrollPosition = GUILayout.BeginScrollView(playerListScrollPosition,
GUILayout.Width(windowSize.width - 10), GUILayout.ExpandHeight(true)); scrollViewBegins++;

lock (_lockable)
{
using (Multiplayer.Session.World.GetRemotePlayersModels(out var remotePlayersModels))
{
foreach (var entry in remotePlayersModels)
{
var player = entry.Value;
var pName = player.Username;
var pDistanceFromLocalPlayer = "";
var pLocation = "";

Check warning on line 136 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)

Check warning on line 136 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Debug)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)

Check warning on line 136 in NebulaWorld/UIPlayerList/UIPlayerWindow.cs

View workflow job for this annotation

GitHub Actions / build (Release)

Fix formatting (https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0055)
PlanetData pPlanet = null;
if (Multiplayer.Session.Combat.IndexByPlayerId.TryGetValue(player.PlayerId, out var index))
{
pPlanet = GameMain.galaxy.PlanetById(Multiplayer.Session.Combat.Players[index].planetId);
}

if (pPlanet != null)
pLocation = $"{pPlanet.displayName}";

if (pPlanet == null)
pLocation = "In Space";

var pPosition = player.PlayerTransform.position;
var distance = Vector3.Distance(localPlayer.position, pPosition);

if (distance < 10000)
{
pDistanceFromLocalPlayer = $"{distance:0.00} m";
}
else if (distance < 600000.0)
{
pDistanceFromLocalPlayer = $"{(distance / 40000):0.00} AU";
}
else
{
pDistanceFromLocalPlayer = $"{(distance / 2400000.0):0.00} LY";
}

GUILayout.BeginHorizontal(); horizontalBegins++;
GUILayout.Label(pName, UIStyles.LabelStyles.RowLabelStyle, GUILayout.Width(300));
GUILayout.Label(pLocation, UIStyles.LabelStyles.RowLabelStyle, GUILayout.Width(600));
GUILayout.Label(pDistanceFromLocalPlayer, UIStyles.LabelStyles.RowLabelStyle,
GUILayout.Width(100));
GUILayout.EndHorizontal(); horizontalBegins--;
GUILayout.Space(10f);
}
}
}
GUILayout.EndScrollView(); scrollViewBegins--;
GUILayout.EndVertical(); verticalBegins--;
GUILayout.EndArea(); areaBegins--;
}
catch (Exception e)
{
Log.Error("Error in UIPlayerWindow OnGUI while building the UI");
Log.Error(e);

for (var i = 1; i <= areaBegins; i++)
GUILayout.EndArea();

for (var i = 1; i <= horizontalBegins; i++)
GUILayout.EndHorizontal();

for (var i = 1; i <= verticalBegins; i++)
GUILayout.EndVertical();

for (var i = 1; i <= scrollViewBegins; i++)
GUILayout.EndScrollView();
}

}

private bool AmIAlone()
{
var connectedPlayerCount = 0;

using (Multiplayer.Session.World.GetRemotePlayersModels(out var remotePlayersModels))
{
connectedPlayerCount = remotePlayersModels.Count;
}

return connectedPlayerCount == 0;
}

private bool IsChatWindowActive()
{
return _chatWindow != null && _chatWindow.IsActive;
}
}
}
12 changes: 12 additions & 0 deletions NebulaWorld/UIPlayerList/UIStyles/BoxStyles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using UnityEngine;

namespace NebulaWorld.UIPlayerList.UIStyles
{
internal class BoxStyles
{
public static GUILayoutOption[] HorizontalSliderStyle => new GUILayoutOption[]
{
GUILayout.ExpandWidth(true), GUILayout.Height(1), GUILayout.MaxHeight(1)
};
}
}
42 changes: 42 additions & 0 deletions NebulaWorld/UIPlayerList/UIStyles/DialogStyles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using UnityEngine;

namespace NebulaWorld.UIPlayerList.UIStyles
{
internal class DialogStyles
{
// ReSharper disable once InconsistentNaming
private static Texture2D _textureMemory = null;

public static GUIStyle WindowBackgroundStyle()
{
var width = 32;
var height = 32;

if (_textureMemory == null)
_textureMemory = MakeTex(width, height, new Color32(36, 67, 76, 200));

var style = new GUIStyle(GUI.skin.box)
{
normal = new GUIStyleState()
{
background = _textureMemory
},
};

return style;
}

private static Texture2D MakeTex(int width, int height, Color col)
{
Color[] pixels = new Color[width * height];
for (int i = 0; i < pixels.Length; ++i)
{
pixels[i] = col;
}
Texture2D result = new Texture2D(width, height);
result.SetPixels(pixels);
result.Apply();
return result;
}
}
}
34 changes: 34 additions & 0 deletions NebulaWorld/UIPlayerList/UIStyles/LabelStyles.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using UnityEngine;

namespace NebulaWorld.UIPlayerList.UIStyles
{
internal class LabelStyles
{
public static GUIStyle HeaderLabelStyle = new GUIStyle(UnityEngine.GUI.skin.label)
{
alignment = TextAnchor.MiddleCenter,
fontSize = 24,
fontStyle = FontStyle.Bold
};

public static GUIStyle CenterLabelLarge = new GUIStyle(UnityEngine.GUI.skin.label)
{
alignment = TextAnchor.MiddleCenter,
fontSize = 42,
fontStyle = FontStyle.Bold
};

public static GUIStyle RowHeaderLabelsStyle = new GUIStyle(UnityEngine.GUI.skin.label)
{
alignment = TextAnchor.MiddleLeft,
fontSize = 18,
fontStyle = FontStyle.Bold
};

public static GUIStyle RowLabelStyle = new GUIStyle(UnityEngine.GUI.skin.label)
{
alignment = TextAnchor.MiddleLeft,
fontSize = 18
};
}
}

0 comments on commit 11f92ca

Please sign in to comment.