Files
SeamlessClient/Utilities/OnlinePlayers.cs
zznty aa323f1ff6
Some checks failed
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (push) Failing after 6s
fixes for nexus v3
2025-07-28 03:58:25 +07:00

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);
}
}