463 lines
20 KiB
C#
463 lines
20 KiB
C#
using System.Reflection;
|
|
using System.Text;
|
|
using HarmonyLib;
|
|
using Sandbox.Engine.Multiplayer;
|
|
using Sandbox.Game;
|
|
using Sandbox.Game.Gui;
|
|
using Sandbox.Game.GUI;
|
|
using Sandbox.Game.Localization;
|
|
using Sandbox.Game.Multiplayer;
|
|
using Sandbox.Game.SessionComponents;
|
|
using Sandbox.Game.World;
|
|
using Sandbox.Graphics.GUI;
|
|
using SeamlessClientPlugin.Messages;
|
|
using VRage;
|
|
using VRage.Audio;
|
|
using VRage.Game;
|
|
using VRage.Utils;
|
|
using VRageMath;
|
|
|
|
namespace SeamlessClientPlugin.Utilities;
|
|
|
|
public class OnlinePlayers
|
|
{
|
|
private static readonly Harmony Patcher = new("OnlinePlayersPatcher");
|
|
public static List<OnlineServer> AllServers = [];
|
|
public static int CurrentServer;
|
|
private static string _currentServerName;
|
|
|
|
public static int TotalPlayerCount;
|
|
public static int CurrentPlayerCount;
|
|
|
|
public static void Patch()
|
|
{
|
|
var recreateControls =
|
|
typeof(MyGuiScreenPlayers).GetMethod("RecreateControls", BindingFlags.Instance | BindingFlags.Public);
|
|
var updateCaption =
|
|
typeof(MyGuiScreenPlayers).GetMethod("UpdateCaption", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
|
|
|
|
Patcher.Patch(recreateControls, new HarmonyMethod(GetPatchMethod(nameof(RecreateControlsPrefix))));
|
|
Patcher.Patch(updateCaption, new HarmonyMethod(GetPatchMethod(nameof(UpdateCaption))));
|
|
//Patcher.Patch(recreateControls, postfix: new HarmonyMethod(GetPatchMethod(nameof(RecreateControlsSuffix))));
|
|
}
|
|
|
|
|
|
public static bool RecreateControlsPrefix(MyGuiScreenPlayers __instance, bool constructor)
|
|
{
|
|
if (MyMultiplayer.Static != null && MyMultiplayer.Static.IsLobby) return true;
|
|
|
|
try
|
|
{
|
|
__instance.Controls.Clear();
|
|
__instance.Elements.Clear();
|
|
//__instance.Elements.Add(m_cl);
|
|
__instance.FocusedControl = null;
|
|
//__instance.m_firstUpdateServed = false;
|
|
//__instance.m_screenCreation = DateTime.UtcNow;
|
|
//__instance.m_gamepadHelpInitialized = false;
|
|
//__instance.m_gamepadHelpLabel = null;
|
|
|
|
|
|
//SeamlessClient.TryShow("A");
|
|
|
|
|
|
//__instance.RecreateControls(constructor);
|
|
__instance.Size = new Vector2(0.937f, 0.913f);
|
|
__instance.CloseButtonEnabled = true;
|
|
|
|
|
|
//SeamlessClient.TryShow("A2");
|
|
//MyCommonTexts.ScreenCaptionPlayers
|
|
|
|
//MyStringId ID = MyStringId.GetOrCompute("Test Caption");
|
|
__instance.m_caption =
|
|
__instance.AddCaption(MyCommonTexts.ScreenCaptionPlayers, null, new Vector2(0f, 0.003f));
|
|
|
|
|
|
const float startX = -0.435f;
|
|
const float startY = -0.36f;
|
|
|
|
var myGuiControlSeparatorList = new MyGuiControlSeparatorList();
|
|
myGuiControlSeparatorList.AddHorizontal(new Vector2(startX, startY), .83f);
|
|
|
|
|
|
var start = new Vector2(startX, 0.358f);
|
|
myGuiControlSeparatorList.AddHorizontal(start, 0.728f);
|
|
myGuiControlSeparatorList.AddHorizontal(new Vector2(startX, 0.05f), 0.17f);
|
|
__instance.Controls.Add(myGuiControlSeparatorList);
|
|
|
|
|
|
var spacing = new Vector2(0f, 0.057f);
|
|
var vector3 = new Vector2(startX, startY + 0.035f);
|
|
|
|
//SeamlessClient.TryShow("B");
|
|
|
|
var mProfileButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
|
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
|
MyTexts.Get(MyCommonTexts.ScreenPlayers_Profile));
|
|
mProfileButton.ButtonClicked += __instance.profileButton_ButtonClicked;
|
|
__instance.Controls.Add(mProfileButton);
|
|
vector3 += spacing;
|
|
__instance.m_profileButton = mProfileButton;
|
|
|
|
|
|
var mPromoteButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
|
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
|
MyTexts.Get(MyCommonTexts.ScreenPlayers_Promote));
|
|
mPromoteButton.ButtonClicked += __instance.promoteButton_ButtonClicked;
|
|
__instance.Controls.Add(mPromoteButton);
|
|
vector3 += spacing;
|
|
__instance.m_promoteButton = mPromoteButton;
|
|
|
|
var mDemoteButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
|
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
|
MyTexts.Get(MyCommonTexts.ScreenPlayers_Demote));
|
|
mDemoteButton.ButtonClicked += __instance.demoteButton_ButtonClicked;
|
|
__instance.Controls.Add(mDemoteButton);
|
|
vector3 += spacing;
|
|
__instance.m_demoteButton = mDemoteButton;
|
|
|
|
|
|
var mKickButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
|
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
|
MyTexts.Get(MyCommonTexts.ScreenPlayers_Kick));
|
|
mKickButton.ButtonClicked += __instance.kickButton_ButtonClicked;
|
|
__instance.Controls.Add(mKickButton);
|
|
vector3 += spacing;
|
|
__instance.m_kickButton = mKickButton;
|
|
|
|
var mBanButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
|
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
|
MyTexts.Get(MyCommonTexts.ScreenPlayers_Ban));
|
|
mBanButton.ButtonClicked += __instance.banButton_ButtonClicked;
|
|
__instance.Controls.Add(mBanButton);
|
|
vector3 += spacing;
|
|
__instance.m_banButton = mBanButton;
|
|
|
|
|
|
var mTradeButton = new MyGuiControlButton(vector3, MyGuiControlButtonStyleEnum.Default, null, null,
|
|
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP, null,
|
|
MyTexts.Get(MySpaceTexts.PlayersScreen_TradeBtn));
|
|
mTradeButton.SetTooltip(MyTexts.GetString(MySpaceTexts.PlayersScreen_TradeBtn_TTP));
|
|
mTradeButton.ButtonClicked += __instance.tradeButton_ButtonClicked;
|
|
__instance.Controls.Add(mTradeButton);
|
|
__instance.m_tradeButton = mTradeButton;
|
|
|
|
|
|
//SeamlessClient.TryShow("C");
|
|
|
|
var vector4 = vector3 + new Vector2(-0.002f, mTradeButton.Size.Y + 0.03f);
|
|
__instance.m_lobbyTypeCombo = new MyGuiControlCombobox(vector4, null, null, null, 3);
|
|
|
|
var vector5 = vector4 + new Vector2(0f, 0.05f);
|
|
vector5 += new Vector2(0f, 0.03f);
|
|
__instance.m_maxPlayers = Sync.IsServer ? MyMultiplayerLobby.MAX_PLAYERS : 16;
|
|
__instance.m_maxPlayersSlider = new MyGuiControlSlider(vector5, 2f, Math.Max(__instance.m_maxPlayers, 3), 0.177f,
|
|
Sync.IsServer ? MySession.Static.MaxPlayers : MyMultiplayer.Static.MemberLimit, null, null, 1, 0.8f, 0f,
|
|
"White", null, MyGuiControlSliderStyleEnum.Default, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP,
|
|
true);
|
|
|
|
|
|
var mInviteButton = new MyGuiControlButton(new Vector2(startX, 0.25000026f),
|
|
MyGuiControlButtonStyleEnum.Default, null, null, MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_TOP,
|
|
null, MyTexts.Get(MyCommonTexts.ScreenPlayers_Invite));
|
|
mInviteButton.ButtonClicked += __instance.inviteButton_ButtonClicked;
|
|
__instance.Controls.Add(mInviteButton);
|
|
__instance.m_inviteButton = mInviteButton;
|
|
|
|
var vector6 = new Vector2(-startX - 0.034f, startY + 0.033f);
|
|
var size = new Vector2(0.66f, 1.2f);
|
|
var num2 = 18;
|
|
var num3 = 0f;
|
|
|
|
|
|
//SeamlessClient.TryShow("D");
|
|
var component = MySession.Static.GetComponent<MySessionComponentMatch>();
|
|
if (component.IsEnabled)
|
|
{
|
|
var vector7 = __instance.GetPositionAbsolute() + vector6 + new Vector2(0f - size.X, 0f);
|
|
var mWarfareTimeRemaintingLabel = new MyGuiControlLabel(vector6 - new Vector2(size.X, 0f))
|
|
{
|
|
Text = $"{MyTexts.GetString(MySpaceTexts.WarfareCounter_TimeRemaining)}: "
|
|
};
|
|
__instance.Controls.Add(mWarfareTimeRemaintingLabel);
|
|
__instance.m_warfare_timeRemainting_label = mWarfareTimeRemaintingLabel;
|
|
|
|
|
|
var timeSpan = TimeSpan.FromMinutes(component.RemainingMinutes);
|
|
var mWarfareTimeRemaintingTime = new MyGuiControlLabel(vector6 - new Vector2(size.X, 0f) +
|
|
new Vector2(
|
|
mWarfareTimeRemaintingLabel.Size.X,
|
|
0f))
|
|
{
|
|
Text = timeSpan.ToString(timeSpan.TotalHours >= 1.0 ? @"hh\:mm\:ss" : "mm\\:ss")
|
|
};
|
|
__instance.Controls.Add(mWarfareTimeRemaintingTime);
|
|
__instance.m_warfare_timeRemainting_time = mWarfareTimeRemaintingTime;
|
|
|
|
var num4 = 0.09f;
|
|
var num5 = size.X / 3f - 2f * num3;
|
|
var num6 = 0;
|
|
var allFactions = MySession.Static.Factions.GetAllFactions();
|
|
foreach (var myFaction in allFactions)
|
|
if ((myFaction.Name.StartsWith("Red") || myFaction.Name.StartsWith("Green") ||
|
|
myFaction.Name.StartsWith("Blue")) && myFaction.Name.EndsWith("Faction"))
|
|
{
|
|
__instance.Controls.Add(new MyGuiScreenPlayersWarfareTeamScoreTable(
|
|
vector7 + new Vector2(num6 * (num5 + num3), mWarfareTimeRemaintingLabel.Size.Y + num3),
|
|
num5, num4, myFaction.Name, myFaction.FactionIcon.Value.String,
|
|
MyTexts.GetString(MySpaceTexts.WarfareCounter_EscapePod), myFaction.FactionId, false, true,
|
|
myFaction.IsMember(MySession.Static.LocalHumanPlayer.Identity.IdentityId)));
|
|
num6++;
|
|
}
|
|
|
|
vector6.Y += mWarfareTimeRemaintingLabel.Size.Y + num4 + num3 * 2f;
|
|
num2 -= 3;
|
|
}
|
|
//SeamlessClient.TryShow("E");
|
|
|
|
__instance.m_playersTable = new MyGuiControlTable
|
|
{
|
|
Position = vector6,
|
|
Size = size,
|
|
OriginAlign = MyGuiDrawAlignEnum.HORISONTAL_RIGHT_AND_VERTICAL_TOP,
|
|
ColumnsCount = 7,
|
|
//SeamlessClient.TryShow("F");
|
|
GamepadHelpTextId = MySpaceTexts.PlayersScreen_Help_PlayersList,
|
|
VisibleRowsCount = num2
|
|
};
|
|
|
|
const float playerNameWidth = 0.2f;
|
|
const float rankWidth = 0.1f;
|
|
const float pingWidth = 0.08f;
|
|
const float mutedWidth = 0.1f;
|
|
const float steamIconWidth = 0.04f;
|
|
const float serverWidth = 0.20f;
|
|
const float factionNameWidth = 1f - playerNameWidth - rankWidth - mutedWidth - pingWidth - steamIconWidth - serverWidth;
|
|
|
|
__instance.m_playersTable.SetCustomColumnWidths([
|
|
steamIconWidth,
|
|
playerNameWidth,
|
|
factionNameWidth,
|
|
rankWidth,
|
|
pingWidth,
|
|
mutedWidth,
|
|
serverWidth
|
|
]);
|
|
|
|
//SeamlessClient.TryShow("G");
|
|
|
|
__instance.m_playersTable.SetColumnComparison(1, (a, b) => a.Text.CompareToIgnoreCase(b.Text));
|
|
__instance.m_playersTable.SetColumnName(1, MyTexts.Get(MyCommonTexts.ScreenPlayers_PlayerName));
|
|
__instance.m_playersTable.SetColumnComparison(2, (a, b) => a.Text.CompareToIgnoreCase(b.Text));
|
|
__instance.m_playersTable.SetColumnName(2, MyTexts.Get(MyCommonTexts.ScreenPlayers_FactionName));
|
|
__instance.m_playersTable.SetColumnName(5, new StringBuilder(MyTexts.GetString(MyCommonTexts.ScreenPlayers_Muted)));
|
|
__instance.m_playersTable.SetColumnComparison(3, GameAdminCompare);
|
|
__instance.m_playersTable.SetColumnName(3, MyTexts.Get(MyCommonTexts.ScreenPlayers_Rank));
|
|
__instance.m_playersTable.SetColumnComparison(4, GamePingCompare);
|
|
__instance.m_playersTable.SetColumnName(4, MyTexts.Get(MyCommonTexts.ScreenPlayers_Ping));
|
|
|
|
|
|
var colName = new StringBuilder("Server");
|
|
__instance.m_playersTable.SetColumnName(6, colName);
|
|
__instance.m_playersTable.SetColumnComparison(6, (a, b) => a.Text.CompareToIgnoreCase(b.Text));
|
|
|
|
//SeamlessClient.TryShow("H");
|
|
|
|
|
|
//m_PlayersTable_ItemSelected
|
|
__instance.m_playersTable.ItemSelected += __instance.playersTable_ItemSelected;
|
|
__instance.m_playersTable.UpdateTableSortHelpText();
|
|
__instance.Controls.Add(__instance.m_playersTable);
|
|
|
|
|
|
var thisServerName = "<this>";
|
|
TotalPlayerCount = 0;
|
|
foreach (var server in AllServers)
|
|
{
|
|
var servername = server.ServerName;
|
|
if (server.ServerId == CurrentServer)
|
|
{
|
|
thisServerName = servername;
|
|
_currentServerName = servername;
|
|
continue;
|
|
}
|
|
|
|
foreach (var player in server.Players)
|
|
{
|
|
AddPlayer(__instance, player.SteamId, servername, player.PlayerName, player.IdentityId);
|
|
TotalPlayerCount++;
|
|
}
|
|
}
|
|
|
|
|
|
CurrentPlayerCount = 0;
|
|
foreach (var onlinePlayer in Sync.Players.GetOnlinePlayers())
|
|
{
|
|
if (onlinePlayer.Id.SerialId != 0) continue;
|
|
|
|
CurrentPlayerCount++;
|
|
TotalPlayerCount++;
|
|
AddPlayer(__instance, onlinePlayer.Id.SteamId, thisServerName);
|
|
}
|
|
|
|
//SeamlessClient.TryShow("I");
|
|
|
|
if (__instance.m_lastSelected != 0L)
|
|
{
|
|
var row2 = __instance.m_playersTable.Find(r => (ulong)r.UserData == __instance.m_lastSelected);
|
|
if (row2 != null) __instance.m_playersTable.SelectedRow = row2;
|
|
}
|
|
|
|
__instance.UpdateButtonsEnabledState();
|
|
//UpdateButtonsEnabledState();
|
|
|
|
__instance.UpdateCaption();
|
|
|
|
|
|
var minSizeGui = MyGuiControlButton.GetVisualStyle(MyGuiControlButtonStyleEnum.Default).NormalTexture
|
|
.MinSizeGui;
|
|
var myGuiControlLabel = new MyGuiControlLabel(new Vector2(start.X, start.Y + minSizeGui.Y / 2f))
|
|
{
|
|
Name = MyGuiScreenBase.GAMEPAD_HELP_LABEL_NAME
|
|
};
|
|
__instance.Controls.Add(myGuiControlLabel);
|
|
__instance.GamepadHelpTextId = MySpaceTexts.PlayersScreen_Help_Screen;
|
|
__instance.FocusedControl = __instance.m_playersTable;
|
|
|
|
//SeamlessClient.TryShow("J");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
SeamlessClient.TryShow(ex.ToString());
|
|
__instance.Controls.Clear();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool AddPlayer(MyGuiScreenPlayers instance, ulong userId, string server, string playerName = null,
|
|
long playerId = 0)
|
|
{
|
|
var table = instance.m_playersTable;
|
|
var pings = instance.pings;
|
|
|
|
playerName ??= MyMultiplayer.Static.GetMemberName(userId);
|
|
|
|
if (string.IsNullOrEmpty(playerName)) return false;
|
|
|
|
|
|
var row = new MyGuiControlTable.Row(userId);
|
|
var memberServiceName = MyMultiplayer.Static.GetMemberServiceName(userId);
|
|
var text = new StringBuilder();
|
|
|
|
|
|
MyGuiHighlightTexture? icon = new MyGuiHighlightTexture
|
|
{
|
|
Normal = $@"Textures\GUI\Icons\Services\{memberServiceName}.png",
|
|
Highlight = $@"Textures\GUI\Icons\Services\{memberServiceName}.png",
|
|
SizePx = new Vector2(24f, 24f)
|
|
};
|
|
row.AddCell(new MyGuiControlTable.Cell(text, null, memberServiceName, Color.White, icon,
|
|
MyGuiDrawAlignEnum.HORISONTAL_LEFT_AND_VERTICAL_CENTER));
|
|
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(playerName), playerName));
|
|
|
|
|
|
if (playerId == 0)
|
|
playerId = Sync.Players.TryGetIdentityId(userId);
|
|
|
|
|
|
var playerFaction = MySession.Static.Factions.GetPlayerFaction(playerId);
|
|
var text2 = "";
|
|
var stringBuilder = new StringBuilder();
|
|
if (playerFaction != null)
|
|
{
|
|
text2 += playerFaction.Name;
|
|
text2 = $"{text2} | {playerName}";
|
|
foreach (var member in playerFaction.Members)
|
|
if ((member.Value.IsLeader || member.Value.IsFounder) &&
|
|
MySession.Static.Players.TryGetPlayerId(member.Value.PlayerId, out var result) &&
|
|
MySession.Static.Players.TryGetPlayerById(result, out var player))
|
|
{
|
|
text2 = $"{text2} | {player.DisplayName}";
|
|
break;
|
|
}
|
|
|
|
stringBuilder.Append(MyStatControlText.SubstituteTexts(playerFaction.Name));
|
|
if (playerFaction.IsLeader(playerId))
|
|
stringBuilder.Append(" (").Append((object)MyTexts.Get(MyCommonTexts.Leader)).Append(")");
|
|
if (!string.IsNullOrEmpty(playerFaction.Tag)) stringBuilder.Insert(0, $"[{playerFaction.Tag}] ");
|
|
}
|
|
|
|
row.AddCell(new MyGuiControlTable.Cell(stringBuilder, null, text2));
|
|
var stringBuilder2 = new StringBuilder();
|
|
var userPromoteLevel = MySession.Static.GetUserPromoteLevel(userId);
|
|
for (var i = 0; i < (int)userPromoteLevel; i++) stringBuilder2.Append('*');
|
|
row.AddCell(new MyGuiControlTable.Cell(stringBuilder2));
|
|
if (pings.TryGetValue(userId, out var ping))
|
|
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(ping.ToString())));
|
|
else
|
|
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder("----")));
|
|
var cell = new MyGuiControlTable.Cell(new StringBuilder(""));
|
|
row.AddCell(cell);
|
|
if (userId != Sync.MyId)
|
|
{
|
|
var myGuiControlButton = new MyGuiControlButton
|
|
{
|
|
CustomStyle = instance.m_buttonSizeStyleSilent,
|
|
Size = new Vector2(0.03f, 0.04f),
|
|
CueEnum = GuiSounds.None
|
|
};
|
|
|
|
myGuiControlButton.ButtonClicked += instance.OnToggleMutePressed;
|
|
myGuiControlButton.UserData = userId;
|
|
cell.Control = myGuiControlButton;
|
|
table.Controls.Add(myGuiControlButton);
|
|
instance.RefreshMuteIcons();
|
|
//RefreshMuteIcons();
|
|
}
|
|
|
|
table.Add(row);
|
|
instance.UpdateCaption();
|
|
|
|
row.AddCell(new MyGuiControlTable.Cell(new StringBuilder(server), "Server Name"));
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool UpdateCaption(MyGuiScreenPlayers __instance)
|
|
{
|
|
if (MyMultiplayer.Static != null && MyMultiplayer.Static.IsLobby) return true;
|
|
|
|
//string s = $"{MyTexts.Get(MyCommonTexts.ScreenCaptionServerName).ToString()} - SectorPlayers: ({ mm_playersTable.RowsCount} / {MySession.Static.MaxPlayers}) TotalPlayers: ( {5} / 200 )";
|
|
|
|
__instance.m_caption.Text =
|
|
$"Server: {_currentServerName} - Innstance Players ({CurrentPlayerCount} / {MySession.Static.MaxPlayers}) TotalPlayers: ({TotalPlayerCount})";
|
|
|
|
|
|
return false;
|
|
}
|
|
|
|
private static int GamePingCompare(MyGuiControlTable.Cell a, MyGuiControlTable.Cell b)
|
|
{
|
|
if (!int.TryParse(a.Text.ToString(), out var result)) result = -1;
|
|
if (!int.TryParse(b.Text.ToString(), out var result2)) result2 = -1;
|
|
return result.CompareTo(result2);
|
|
}
|
|
|
|
private static int GameAdminCompare(MyGuiControlTable.Cell a, MyGuiControlTable.Cell b)
|
|
{
|
|
var steamId = (ulong)a.Row.UserData;
|
|
var steamId2 = (ulong)b.Row.UserData;
|
|
var userPromoteLevel = (int)MySession.Static.GetUserPromoteLevel(steamId);
|
|
var userPromoteLevel2 = (int)MySession.Static.GetUserPromoteLevel(steamId2);
|
|
return userPromoteLevel.CompareTo(userPromoteLevel2);
|
|
}
|
|
|
|
private static MethodInfo GetPatchMethod(string v)
|
|
{
|
|
return typeof(OnlinePlayers).GetMethod(v, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic);
|
|
}
|
|
} |