Compare commits
19 Commits
v4.0.2
...
9e7fb4d443
| Author | SHA1 | Date | |
|---|---|---|---|
| 9e7fb4d443 | |||
| 6ab8c38109 | |||
| 9a5d149241 | |||
|
|
f193d8a805 | ||
|
|
00960eb3f7 | ||
|
|
bc2d44f5cd | ||
|
|
c065b14f9d | ||
|
|
46f05b5489 | ||
|
|
3a9e903044 | ||
|
|
ca331d4ac8 | ||
|
|
692fc25d42 | ||
|
|
bec55e4ecc | ||
|
|
8a36e74c4b | ||
|
|
4b9c831c73 | ||
|
|
910c407e3d | ||
|
|
56caddcb65 | ||
|
|
c8abc7c265 | ||
|
|
1dc30bdabd | ||
|
|
14db933880 |
@@ -40,5 +40,10 @@ public static class DefaultWidgets
|
|||||||
|
|
||||||
if (PlayerManager.ShowNameToggleButton.Value)
|
if (PlayerManager.ShowNameToggleButton.Value)
|
||||||
RegisterManager.RegisterPlayerRow(InternalWidgets.NameToggleButton.Create());
|
RegisterManager.RegisterPlayerRow(InternalWidgets.NameToggleButton.Create());
|
||||||
|
|
||||||
|
if (PlayerManager.ShowMuteButton.Value)
|
||||||
|
RegisterManager.RegisterPlayerRow(InternalWidgets.MuteButton.Create());
|
||||||
|
if (PlayerManager.ShowAddFriendButton.Value)
|
||||||
|
RegisterManager.RegisterPlayerRow(InternalWidgets.AddFriendButton.Create());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
50
Gui/GUIStyles.cs
Normal file
50
Gui/GUIStyles.cs
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace stick.plugins.playermanager.Gui;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 集中管理所有 GUIStyle 的静态类。
|
||||||
|
/// 必须在 OnGUI 上下文中调用 Initialize() 初始化(依赖 GUI.skin)。
|
||||||
|
/// 所有 GUI 组件通过此类的静态字段获取样式,避免重复创建。
|
||||||
|
/// </summary>
|
||||||
|
public static class GUIStyles
|
||||||
|
{
|
||||||
|
/// <summary>标签样式(fontSize=22)</summary>
|
||||||
|
public static GUIStyle Label;
|
||||||
|
|
||||||
|
/// <summary>普通按钮样式(fontSize=22, richText=false)</summary>
|
||||||
|
public static GUIStyle Button;
|
||||||
|
|
||||||
|
/// <summary>黄色按钮样式(已记录玩家)</summary>
|
||||||
|
public static GUIStyle YellowButton;
|
||||||
|
|
||||||
|
/// <summary>红色按钮样式(黑名单玩家)</summary>
|
||||||
|
public static GUIStyle RedButton;
|
||||||
|
|
||||||
|
/// <summary>绿色按钮样式(好友玩家)</summary>
|
||||||
|
public static GUIStyle GreenButton;
|
||||||
|
|
||||||
|
private static bool _initialized;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化所有样式。必须在 OnGUI 上下文中调用,允许多次调用(仅首次生效)。
|
||||||
|
/// </summary>
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
if (_initialized) return;
|
||||||
|
|
||||||
|
Label = new GUIStyle(GUI.skin.label) { fontSize = 22 };
|
||||||
|
Button = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
||||||
|
|
||||||
|
YellowButton = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
||||||
|
YellowButton.normal.textColor = Color.yellow;
|
||||||
|
|
||||||
|
RedButton = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
||||||
|
RedButton.normal.textColor = Color.red;
|
||||||
|
|
||||||
|
GreenButton = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
||||||
|
GreenButton.normal.textColor = Color.green;
|
||||||
|
|
||||||
|
_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Gui/InternalWidgets/AddFriendButton.cs
Normal file
26
Gui/InternalWidgets/AddFriendButton.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using Steamworks;
|
||||||
|
using UnityEngine;
|
||||||
|
using stick.plugins.playermanager.Recorder;
|
||||||
|
|
||||||
|
namespace stick.plugins.playermanager.Gui.InternalWidgets;
|
||||||
|
|
||||||
|
public static class AddFriendButton
|
||||||
|
{
|
||||||
|
public static IPlayerRowWidget Create()
|
||||||
|
{
|
||||||
|
return new PlayerRowButtonWidget
|
||||||
|
{
|
||||||
|
Name = "Add Friend",
|
||||||
|
GetText = player => "加好友",
|
||||||
|
Condition = player =>
|
||||||
|
!PlayerManager.IsLocalPlayer(player)
|
||||||
|
&& !player.IsFriend,
|
||||||
|
OnClick = player =>
|
||||||
|
{
|
||||||
|
GUIUtility.systemCopyBuffer = player.ToString();
|
||||||
|
SteamFriends.ActivateGameOverlayToUser("friendadd", player.SteamId);
|
||||||
|
},
|
||||||
|
Width = 100f,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
29
Gui/InternalWidgets/MuteButton.cs
Normal file
29
Gui/InternalWidgets/MuteButton.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using MultiplayerBasicExample;
|
||||||
|
|
||||||
|
namespace stick.plugins.playermanager.Gui.InternalWidgets;
|
||||||
|
|
||||||
|
public static class MuteButton
|
||||||
|
{
|
||||||
|
public static IPlayerRowWidget Create()
|
||||||
|
{
|
||||||
|
return new PlayerRowButtonWidget
|
||||||
|
{
|
||||||
|
Name = "mute",
|
||||||
|
Condition = player => !PlayerManager.IsLocalPlayer(player),
|
||||||
|
GetText = player =>
|
||||||
|
PlayerManager.IsMuted(player) ? "取消静音" : "静音",
|
||||||
|
OnClick = player =>
|
||||||
|
{
|
||||||
|
if (PlayerManager.IsMuted(player))
|
||||||
|
{
|
||||||
|
PlayerManager.UnmutePlayer(player);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlayerManager.MutePlayer(player);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Width = 100f,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,23 +6,6 @@ namespace stick.plugins.playermanager.Gui.InternalWidgets;
|
|||||||
|
|
||||||
public static class PlayerInfoButton
|
public static class PlayerInfoButton
|
||||||
{
|
{
|
||||||
private static GUIStyle _redStyle;
|
|
||||||
private static GUIStyle _yellowStyle;
|
|
||||||
private static GUIStyle _greenStyle;
|
|
||||||
private static GUIStyle _normalStyle;
|
|
||||||
|
|
||||||
private static void EnsureStyles()
|
|
||||||
{
|
|
||||||
if (_normalStyle != null) return;
|
|
||||||
_normalStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
_yellowStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
_yellowStyle.normal.textColor = Color.yellow;
|
|
||||||
_redStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
_redStyle.normal.textColor = Color.red;
|
|
||||||
_greenStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
_greenStyle.normal.textColor = Color.green;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IPlayerRowWidget Create()
|
public static IPlayerRowWidget Create()
|
||||||
{
|
{
|
||||||
return new PlayerRowButtonWidget
|
return new PlayerRowButtonWidget
|
||||||
@@ -37,12 +20,11 @@ public static class PlayerInfoButton
|
|||||||
Width = 500f,
|
Width = 500f,
|
||||||
GetStyle = player =>
|
GetStyle = player =>
|
||||||
{
|
{
|
||||||
EnsureStyles();
|
|
||||||
return player.RecordStatus switch
|
return player.RecordStatus switch
|
||||||
{
|
{
|
||||||
PlayerRecordStatus.Blacklisted => _redStyle,
|
PlayerRecordStatus.Blacklisted => GUIStyles.RedButton,
|
||||||
PlayerRecordStatus.Recorded => _yellowStyle,
|
PlayerRecordStatus.Recorded => GUIStyles.YellowButton,
|
||||||
_ => player.IsFriend ? _greenStyle : _normalStyle,
|
_ => player.IsFriend ? GUIStyles.GreenButton : GUIStyles.Button,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -32,63 +32,6 @@ public static class PlayerManagerGUI
|
|||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region GUIStyle缓存(internal 供 DefaultWidgets 引用)
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 标题样式
|
|
||||||
/// </summary>
|
|
||||||
private static GUIStyle TitleStyle;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 普通按钮样式
|
|
||||||
/// </summary>
|
|
||||||
private static GUIStyle CommonButtonStyle;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 黄色按钮样式(已记录玩家)
|
|
||||||
/// </summary>
|
|
||||||
private static GUIStyle YellowButtonStyle;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 红色按钮样式(黑名单玩家)
|
|
||||||
/// </summary>
|
|
||||||
private static GUIStyle RedButtonStyle;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 绿色按钮样式(好友)
|
|
||||||
/// </summary>
|
|
||||||
private static GUIStyle GreenButtonStyle;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 样式是否已初始化
|
|
||||||
/// </summary>
|
|
||||||
private static bool StylesInitialized;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 样式初始化
|
|
||||||
|
|
||||||
private static void InitializeStyles()
|
|
||||||
{
|
|
||||||
if (StylesInitialized) return;
|
|
||||||
|
|
||||||
TitleStyle = new GUIStyle(GUI.skin.label) { fontSize = 22 };
|
|
||||||
CommonButtonStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
|
|
||||||
YellowButtonStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
YellowButtonStyle.normal.textColor = Color.yellow;
|
|
||||||
|
|
||||||
RedButtonStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
RedButtonStyle.normal.textColor = Color.red;
|
|
||||||
|
|
||||||
GreenButtonStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
GreenButtonStyle.normal.textColor = Color.green;
|
|
||||||
|
|
||||||
StylesInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 主绘制方法
|
#region 主绘制方法
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -96,19 +39,20 @@ public static class PlayerManagerGUI
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public static void DrawLobbyInfoGUI()
|
public static void DrawLobbyInfoGUI()
|
||||||
{
|
{
|
||||||
InitializeStyles();
|
GUIStyles.Initialize();
|
||||||
Cursor.Reset();
|
Cursor.Reset();
|
||||||
|
|
||||||
if (PlayerManager.MatchmakingHandler.IsInsideLobby)
|
if (PlayerManager.MatchmakingHandler.IsInsideLobby)
|
||||||
{
|
{
|
||||||
DrawCurrentLobbyInfo();
|
DrawCurrentLobbyInfo();
|
||||||
|
DrawLobbySearchInfo();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUI.Label(
|
GUI.Label(
|
||||||
Cursor.NextLine(500f, 40f),
|
Cursor.NextLine(500f, 40f),
|
||||||
"当前不在大厅中",
|
"当前不在大厅中",
|
||||||
TitleStyle
|
GUIStyles.Label
|
||||||
);
|
);
|
||||||
DrawLobbySearchInfo();
|
DrawLobbySearchInfo();
|
||||||
}
|
}
|
||||||
@@ -128,7 +72,7 @@ public static class PlayerManagerGUI
|
|||||||
GUI.Label(
|
GUI.Label(
|
||||||
Cursor.NextLine(2000f, 40f),
|
Cursor.NextLine(2000f, 40f),
|
||||||
$"当前大厅: {PlayerManager.CurrentLobbyID} 房主: {PlayerManager.LobbyOwner.CurrentName}",
|
$"当前大厅: {PlayerManager.CurrentLobbyID} 房主: {PlayerManager.LobbyOwner.CurrentName}",
|
||||||
TitleStyle
|
GUIStyles.Label
|
||||||
);
|
);
|
||||||
|
|
||||||
// HeaderRow 区域:纵向迭代每一行,行内横向迭代 Children
|
// HeaderRow 区域:纵向迭代每一行,行内横向迭代 Children
|
||||||
@@ -156,6 +100,8 @@ public static class PlayerManagerGUI
|
|||||||
{
|
{
|
||||||
if (widget.ShouldDraw(member))
|
if (widget.ShouldDraw(member))
|
||||||
widget.Draw(Cursor.NextColumn(widget.Width, 40f), member);
|
widget.Draw(Cursor.NextColumn(widget.Width, 40f), member);
|
||||||
|
else
|
||||||
|
Cursor.NextColumn(widget.Width, 40f); // 占位推进列位置
|
||||||
}
|
}
|
||||||
Cursor.EndRow();
|
Cursor.EndRow();
|
||||||
}
|
}
|
||||||
@@ -175,7 +121,7 @@ public static class PlayerManagerGUI
|
|||||||
if (GUI.Button(
|
if (GUI.Button(
|
||||||
Cursor.NextLine(400f, 40f),
|
Cursor.NextLine(400f, 40f),
|
||||||
$"搜索范围 {areaText}",
|
$"搜索范围 {areaText}",
|
||||||
CommonButtonStyle
|
GUIStyles.Button
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
CycleLobbyDistanceFilter();
|
CycleLobbyDistanceFilter();
|
||||||
@@ -186,7 +132,7 @@ public static class PlayerManagerGUI
|
|||||||
if (GUI.Button(
|
if (GUI.Button(
|
||||||
new Rect(Cursor.OffsetX + 420f, Cursor.CurrentY, 100f, 40f),
|
new Rect(Cursor.OffsetX + 420f, Cursor.CurrentY, 100f, 40f),
|
||||||
"刷新",
|
"刷新",
|
||||||
CommonButtonStyle
|
GUIStyles.Button
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
PlayerManager.RequestLobbyList();
|
PlayerManager.RequestLobbyList();
|
||||||
@@ -196,7 +142,7 @@ public static class PlayerManagerGUI
|
|||||||
GUI.Label(
|
GUI.Label(
|
||||||
Cursor.NextLine(500f, 40f),
|
Cursor.NextLine(500f, 40f),
|
||||||
$"搜索到大厅数量: {PlayerManager.lobbyDataList.Count}",
|
$"搜索到大厅数量: {PlayerManager.lobbyDataList.Count}",
|
||||||
TitleStyle
|
GUIStyles.Label
|
||||||
);
|
);
|
||||||
|
|
||||||
// 大厅列表滚动视图
|
// 大厅列表滚动视图
|
||||||
@@ -247,10 +193,12 @@ public static class PlayerManagerGUI
|
|||||||
if (GUI.Button(
|
if (GUI.Button(
|
||||||
new Rect(Cursor.OffsetX, Cursor.LineHeight * i, 500f, 40f),
|
new Rect(Cursor.OffsetX, Cursor.LineHeight * i, 500f, 40f),
|
||||||
$"{lobbyId} 人数{SteamMatchmaking.GetNumLobbyMembers(lobbyId)}",
|
$"{lobbyId} 人数{SteamMatchmaking.GetNumLobbyMembers(lobbyId)}",
|
||||||
CommonButtonStyle
|
GUIStyles.Button
|
||||||
))
|
))
|
||||||
{
|
{
|
||||||
PlayerManager.JoinSpecificServer(lobbyId);
|
// 在大厅中则不加入
|
||||||
|
if (!PlayerManager.MatchmakingHandler.IsInsideLobby)
|
||||||
|
PlayerManager.JoinSpecificServer(lobbyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,17 +96,6 @@ public interface IPlayerRowWidget
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class HeaderLabelWidget : IHeaderWidget
|
public class HeaderLabelWidget : IHeaderWidget
|
||||||
{
|
{
|
||||||
private static GUIStyle _defaultStyle;
|
|
||||||
private static GUIStyle DefaultStyle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_defaultStyle == null)
|
|
||||||
_defaultStyle = new GUIStyle(GUI.skin.label) { fontSize = 22 };
|
|
||||||
return _defaultStyle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public Func<bool> Condition { get; set; }
|
public Func<bool> Condition { get; set; }
|
||||||
public Func<string> Content { get; set; }
|
public Func<string> Content { get; set; }
|
||||||
@@ -117,7 +106,7 @@ public class HeaderLabelWidget : IHeaderWidget
|
|||||||
|
|
||||||
public void Draw(Rect rect)
|
public void Draw(Rect rect)
|
||||||
{
|
{
|
||||||
GUI.Label(rect, Content?.Invoke() ?? string.Empty, Style ?? DefaultStyle);
|
GUI.Label(rect, Content?.Invoke() ?? string.Empty, Style ?? GUIStyles.Label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,17 +115,6 @@ public class HeaderLabelWidget : IHeaderWidget
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class HeaderButtonWidget : IHeaderWidget
|
public class HeaderButtonWidget : IHeaderWidget
|
||||||
{
|
{
|
||||||
private static GUIStyle _defaultStyle;
|
|
||||||
private static GUIStyle DefaultStyle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_defaultStyle == null)
|
|
||||||
_defaultStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
return _defaultStyle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public Func<bool> Condition { get; set; }
|
public Func<bool> Condition { get; set; }
|
||||||
public string Text { get; set; }
|
public string Text { get; set; }
|
||||||
@@ -148,7 +126,7 @@ public class HeaderButtonWidget : IHeaderWidget
|
|||||||
|
|
||||||
public void Draw(Rect rect)
|
public void Draw(Rect rect)
|
||||||
{
|
{
|
||||||
if (GUI.Button(rect, Text ?? string.Empty, Style ?? DefaultStyle))
|
if (GUI.Button(rect, Text ?? string.Empty, Style ?? GUIStyles.Button))
|
||||||
Action?.Invoke();
|
Action?.Invoke();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,17 +159,6 @@ public class HeaderRow : IHeaderRow
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PlayerRowButtonWidget : IPlayerRowWidget
|
public class PlayerRowButtonWidget : IPlayerRowWidget
|
||||||
{
|
{
|
||||||
private static GUIStyle _defaultStyle;
|
|
||||||
private static GUIStyle DefaultStyle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_defaultStyle == null)
|
|
||||||
_defaultStyle = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
|
|
||||||
return _defaultStyle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public Func<PlayerInfo, bool> Condition { get; set; }
|
public Func<PlayerInfo, bool> Condition { get; set; }
|
||||||
public Func<PlayerInfo, string> GetText { get; set; }
|
public Func<PlayerInfo, string> GetText { get; set; }
|
||||||
@@ -212,7 +179,7 @@ public class PlayerRowButtonWidget : IPlayerRowWidget
|
|||||||
|
|
||||||
public void Draw(Rect rect, PlayerInfo player)
|
public void Draw(Rect rect, PlayerInfo player)
|
||||||
{
|
{
|
||||||
GUIStyle style = GetStyle?.Invoke(player) ?? Style ?? DefaultStyle;
|
GUIStyle style = GetStyle?.Invoke(player) ?? Style ?? GUIStyles.Button;
|
||||||
if (GUI.Button(rect, GetText?.Invoke(player) ?? string.Empty, style))
|
if (GUI.Button(rect, GetText?.Invoke(player) ?? string.Empty, style))
|
||||||
OnClick?.Invoke(player);
|
OnClick?.Invoke(player);
|
||||||
}
|
}
|
||||||
@@ -223,17 +190,6 @@ public class PlayerRowButtonWidget : IPlayerRowWidget
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class PlayerRowLabelWidget : IPlayerRowWidget
|
public class PlayerRowLabelWidget : IPlayerRowWidget
|
||||||
{
|
{
|
||||||
private static GUIStyle _defaultStyle;
|
|
||||||
private static GUIStyle DefaultStyle
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_defaultStyle == null)
|
|
||||||
_defaultStyle = new GUIStyle(GUI.skin.label) { fontSize = 22 };
|
|
||||||
return _defaultStyle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public Func<PlayerInfo, bool> Condition { get; set; }
|
public Func<PlayerInfo, bool> Condition { get; set; }
|
||||||
public Func<PlayerInfo, string> GetText { get; set; }
|
public Func<PlayerInfo, string> GetText { get; set; }
|
||||||
@@ -244,7 +200,7 @@ public class PlayerRowLabelWidget : IPlayerRowWidget
|
|||||||
|
|
||||||
public void Draw(Rect rect, PlayerInfo player)
|
public void Draw(Rect rect, PlayerInfo player)
|
||||||
{
|
{
|
||||||
GUI.Label(rect, GetText?.Invoke(player) ?? string.Empty, Style ?? DefaultStyle);
|
GUI.Label(rect, GetText?.Invoke(player) ?? string.Empty, Style ?? GUIStyles.Label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
22
Patches/DistanceFilterPatch.cs
Normal file
22
Patches/DistanceFilterPatch.cs
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
using System.Reflection.Emit;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using HarmonyLib;
|
||||||
|
using stick.plugins.playermanager;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(MatchmakingHandler), "OnRandomServerJoinFailed")]
|
||||||
|
class DistanceFilterPatch
|
||||||
|
{
|
||||||
|
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
|
||||||
|
{
|
||||||
|
return new CodeMatcher(instructions)
|
||||||
|
.MatchForward(false,
|
||||||
|
new CodeMatch(OpCodes.Ldc_I4_1),
|
||||||
|
new CodeMatch(OpCodes.Stloc_0)
|
||||||
|
)
|
||||||
|
.SetInstruction(
|
||||||
|
new CodeInstruction(OpCodes.Ldsfld,
|
||||||
|
AccessTools.Field(typeof(PlayerManager), nameof(PlayerManager.lobbyDistanceFilter))))
|
||||||
|
.InstructionEnumeration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
using HarmonyLib;
|
|
||||||
using stick.plugins.playermanager;
|
|
||||||
|
|
||||||
using Steamworks;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(HostLeverHandler), "Update")]
|
|
||||||
class LogLeverAngle
|
|
||||||
{
|
|
||||||
static Vector3 lastForward = Vector3.zero;
|
|
||||||
public static void PostFix()
|
|
||||||
{
|
|
||||||
Vector3 currentForward = PlayerManager.HostLeverHandler.lever.transform.forward;
|
|
||||||
if (currentForward != lastForward)
|
|
||||||
{
|
|
||||||
Debug.Log("Current Lever Angle: " + currentForward);
|
|
||||||
lastForward = currentForward;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
15
Patches/MutePatch.cs
Normal file
15
Patches/MutePatch.cs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
using HarmonyLib;
|
||||||
|
using stick.plugins.playermanager;
|
||||||
|
|
||||||
|
[HarmonyPatch(typeof(NetworkPlayer), "SyncClientChat")]
|
||||||
|
class MutePatch
|
||||||
|
{
|
||||||
|
public static bool Prefix(NetworkPlayer __instance)
|
||||||
|
{
|
||||||
|
if (PlayerManager.MutedPlayers.Contains(__instance.NetworkSpawnID))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
125
Plugin.cs
125
Plugin.cs
@@ -9,6 +9,8 @@ using System.Data;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using stick.plugins.playermanager.Recorder;
|
using stick.plugins.playermanager.Recorder;
|
||||||
using stick.plugins.playermanager.Gui;
|
using stick.plugins.playermanager.Gui;
|
||||||
|
using System.Collections;
|
||||||
|
using MultiplayerBasicExample;
|
||||||
|
|
||||||
namespace stick.plugins.playermanager;
|
namespace stick.plugins.playermanager;
|
||||||
|
|
||||||
@@ -57,6 +59,16 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static ConfigEntry<bool> ShowRoomPublicityButton;
|
internal static ConfigEntry<bool> ShowRoomPublicityButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否显示禁音按钮
|
||||||
|
/// </summary>
|
||||||
|
internal static ConfigEntry<bool> ShowMuteButton;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否显示加好友按钮
|
||||||
|
/// </summary>
|
||||||
|
internal static ConfigEntry<bool> ShowAddFriendButton;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Steam回调
|
#region Steam回调
|
||||||
@@ -104,6 +116,11 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
|
|
||||||
#region 快捷访问属性
|
#region 快捷访问属性
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 多人管理器实例
|
||||||
|
/// </summary>
|
||||||
|
public static MultiplayerManager MultiplayerManager => FindObjectOfType<MultiplayerManager>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 大厅管理器实例
|
/// 大厅管理器实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -117,11 +134,6 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
"ChangeLobbyType"
|
"ChangeLobbyType"
|
||||||
);
|
);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// leverhandler实例
|
|
||||||
/// </summary>
|
|
||||||
public static HostLeverHandler HostLeverHandler => UnityEngine.Object.FindObjectOfType<HostLeverHandler>();
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 房间公开性
|
/// 房间公开性
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -140,7 +152,29 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 本地玩家信息
|
/// 本地玩家信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static PlayerInfo LocalPlayer => new(SteamUser.GetSteamID());
|
public static PlayerInfo LocalPlayer;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化localPlayer和只需要初始化一次的steam相关的协程
|
||||||
|
/// </summary>
|
||||||
|
IEnumerator InitAfterSteam()
|
||||||
|
{
|
||||||
|
// 等待 Steam 初始化(给游戏一点初始化时间)
|
||||||
|
yield return new WaitForSeconds(2f);
|
||||||
|
|
||||||
|
// 或者轮询检查 Steam 是否就绪
|
||||||
|
while (!SteamManager.Initialized) // 如果游戏有 SteamManager
|
||||||
|
{
|
||||||
|
yield return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalPlayer = new(SteamUser.GetSteamID());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 禁音玩家列表
|
||||||
|
/// </summary>
|
||||||
|
public static HashSet<ushort> MutedPlayers = [];
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -153,9 +187,18 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
DefaultWidgets.RegisterAll();
|
DefaultWidgets.RegisterAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Start()
|
||||||
|
{
|
||||||
|
StartCoroutine(InitAfterSteam());
|
||||||
|
}
|
||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
HandleInput();
|
HandleInput();
|
||||||
|
if (SteamManager.Initialized)
|
||||||
|
{
|
||||||
|
LocalPlayer = new(SteamUser.GetSteamID());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnGUI()
|
private void OnGUI()
|
||||||
@@ -210,6 +253,13 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
"是否显示曾用名切换按钮"
|
"是否显示曾用名切换按钮"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ShowMuteButton = Config.Bind(
|
||||||
|
"GUI",
|
||||||
|
"ShowMuteButton",
|
||||||
|
true,
|
||||||
|
"是否显示禁音按钮"
|
||||||
|
);
|
||||||
|
|
||||||
ShowRoomPublicityLabel = Config.Bind(
|
ShowRoomPublicityLabel = Config.Bind(
|
||||||
"GUI",
|
"GUI",
|
||||||
"ShowRoomPublicityLabel",
|
"ShowRoomPublicityLabel",
|
||||||
@@ -223,6 +273,13 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
true,
|
true,
|
||||||
"是否显示切换公开性按钮"
|
"是否显示切换公开性按钮"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ShowAddFriendButton = Config.Bind(
|
||||||
|
"GUI",
|
||||||
|
"ShowAddFriendButton",
|
||||||
|
true,
|
||||||
|
"是否显示加好友按钮"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -236,6 +293,8 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
}
|
}
|
||||||
Harmony.CreateAndPatchAll(typeof(ApplyBlacklist));
|
Harmony.CreateAndPatchAll(typeof(ApplyBlacklist));
|
||||||
Harmony.CreateAndPatchAll(typeof(ListenForChange));
|
Harmony.CreateAndPatchAll(typeof(ListenForChange));
|
||||||
|
Harmony.CreateAndPatchAll(typeof(MutePatch));
|
||||||
|
Harmony.CreateAndPatchAll(typeof(DistanceFilterPatch));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -270,6 +329,60 @@ public class PlayerManager : BaseUnityPlugin
|
|||||||
|
|
||||||
#region 公共方法
|
#region 公共方法
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 通过SteamID获取NetworkSpawnID
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetSteamID"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public static ushort GetNetworkSpawnIDBySteamID(CSteamID targetSteamID)
|
||||||
|
{
|
||||||
|
ConnectedClientData[] clients = MultiplayerManager.ConnectedClients;
|
||||||
|
for (ushort i = 0; i < clients.Length; i++)
|
||||||
|
{
|
||||||
|
if (clients[i] != null && clients[i].ClientID == targetSteamID)
|
||||||
|
{
|
||||||
|
return i; // i 就是 NetworkSpawnID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 65535; // ushort.MaxValue,表示未找到(与默认值一致)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断指定玩家是否被静音
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">要检查的玩家</param>
|
||||||
|
/// <returns>如果被静音返回true</returns>
|
||||||
|
public static bool IsMuted(PlayerInfo player)
|
||||||
|
{
|
||||||
|
return player != null && MutedPlayers.Contains(player.NetworkSpawnID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 静音指定玩家
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">被静音的玩家</param>
|
||||||
|
public static void MutePlayer(PlayerInfo player)
|
||||||
|
{
|
||||||
|
if (player != null)
|
||||||
|
{
|
||||||
|
MutedPlayers.Add(player.NetworkSpawnID);
|
||||||
|
Debug.Log($"玩家 {player} 已被静音");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 取消静音指定玩家
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="player">要取消静音的玩家</param>
|
||||||
|
public static void UnmutePlayer(PlayerInfo player)
|
||||||
|
{
|
||||||
|
if (player != null && MutedPlayers.Contains(player.NetworkSpawnID))
|
||||||
|
{
|
||||||
|
MutedPlayers.Remove(player.NetworkSpawnID);
|
||||||
|
Debug.Log($"玩家 {player} 已被取消静音");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 判断指定玩家是否为房主
|
/// 判断指定玩家是否为房主
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ public class PlayerInfo : IEquatable<PlayerInfo>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public PlayerRecordStatus RecordStatus { get; set; }
|
public PlayerRecordStatus RecordStatus { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 柴自己的NetworkSpawnID
|
||||||
|
/// </summary>
|
||||||
|
public ushort NetworkSpawnID => PlayerManager.GetNetworkSpawnIDBySteamID(SteamId);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 当前玩家名称(实时获取)
|
/// 当前玩家名称(实时获取)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -9,20 +9,16 @@ namespace stick.plugins.playermanager.Recorder;
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 记录器基类
|
/// 记录器基类
|
||||||
/// 提供玩家记录和黑名单功能的通用实现
|
/// 提供玩家记录和黑名单功能的通用实现
|
||||||
|
/// 使用 Dictionary<CSteamID, PlayerInfo> 实现 O(1) 查找
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class RecorderBase
|
public abstract class RecorderBase
|
||||||
{
|
{
|
||||||
#region 字段
|
#region 字段
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 玩家信息集合(用于快速查找)
|
/// 玩家信息字典(以 SteamID 为键,O(1) 查找)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected HashSet<PlayerInfo> playerSet = new HashSet<PlayerInfo>();
|
protected Dictionary<CSteamID, PlayerInfo> playerDict = new Dictionary<CSteamID, PlayerInfo>();
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 玩家信息列表(用于有序遍历和文件写入)
|
|
||||||
/// </summary>
|
|
||||||
protected List<PlayerInfo> playerList = new List<PlayerInfo>();
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -68,7 +64,7 @@ public abstract class RecorderBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPlayerRecorded(PlayerInfo playerInfo)
|
public bool IsPlayerRecorded(PlayerInfo playerInfo)
|
||||||
{
|
{
|
||||||
return playerInfo != null && playerSet.Contains(playerInfo);
|
return playerInfo != null && playerDict.ContainsKey(playerInfo.SteamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -76,8 +72,7 @@ public abstract class RecorderBase
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsPlayerRecorded(CSteamID playerId)
|
public bool IsPlayerRecorded(CSteamID playerId)
|
||||||
{
|
{
|
||||||
PlayerInfo playerInfo = new PlayerInfo(playerId);
|
return playerDict.ContainsKey(playerId);
|
||||||
return playerSet.Contains(playerInfo);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -89,9 +84,9 @@ public abstract class RecorderBase
|
|||||||
|
|
||||||
playerInfo.RecordStatus = RecordStatus;
|
playerInfo.RecordStatus = RecordStatus;
|
||||||
|
|
||||||
if (playerSet.Add(playerInfo))
|
if (!playerDict.ContainsKey(playerInfo.SteamId))
|
||||||
{
|
{
|
||||||
playerList.Add(playerInfo);
|
playerDict.Add(playerInfo.SteamId, playerInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
AppendToFile(playerInfo);
|
AppendToFile(playerInfo);
|
||||||
@@ -104,27 +99,22 @@ public abstract class RecorderBase
|
|||||||
{
|
{
|
||||||
if (playerInfo == null) return;
|
if (playerInfo == null) return;
|
||||||
|
|
||||||
if (playerSet.Remove(playerInfo))
|
if (playerDict.Remove(playerInfo.SteamId))
|
||||||
{
|
{
|
||||||
playerList.Remove(playerInfo);
|
|
||||||
WriteBackToFile();
|
WriteBackToFile();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 检查并合并玩家记录信息
|
/// 检查并合并玩家记录信息(O(1) 字典查找)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void CheckAndMerge(PlayerInfo playerInfo)
|
public void CheckAndMerge(PlayerInfo playerInfo)
|
||||||
{
|
{
|
||||||
if (playerInfo == null) return;
|
if (playerInfo == null) return;
|
||||||
|
|
||||||
foreach (PlayerInfo existingInfo in playerSet)
|
if (playerDict.TryGetValue(playerInfo.SteamId, out PlayerInfo existingInfo))
|
||||||
{
|
{
|
||||||
if (existingInfo.Equals(playerInfo))
|
playerInfo.MergeWith(existingInfo);
|
||||||
{
|
|
||||||
playerInfo.MergeWith(existingInfo);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,8 +132,7 @@ public abstract class RecorderBase
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
playerSet.Clear();
|
playerDict.Clear();
|
||||||
playerList.Clear();
|
|
||||||
|
|
||||||
using (StreamReader reader = new StreamReader(FilePath))
|
using (StreamReader reader = new StreamReader(FilePath))
|
||||||
{
|
{
|
||||||
@@ -157,9 +146,9 @@ public abstract class RecorderBase
|
|||||||
RecordStatus = RecordStatus
|
RecordStatus = RecordStatus
|
||||||
};
|
};
|
||||||
|
|
||||||
if (playerSet.Add(playerInfo))
|
if (!playerDict.ContainsKey(playerInfo.SteamId))
|
||||||
{
|
{
|
||||||
playerList.Add(playerInfo);
|
playerDict.Add(playerInfo.SteamId, playerInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,7 +161,7 @@ public abstract class RecorderBase
|
|||||||
{
|
{
|
||||||
using (StreamWriter writer = new StreamWriter(FilePath, false))
|
using (StreamWriter writer = new StreamWriter(FilePath, false))
|
||||||
{
|
{
|
||||||
foreach (PlayerInfo info in playerList)
|
foreach (PlayerInfo info in playerDict.Values)
|
||||||
{
|
{
|
||||||
writer.WriteLine(info.ToInfoString());
|
writer.WriteLine(info.ToInfoString());
|
||||||
}
|
}
|
||||||
|
|||||||
165
readme.md
165
readme.md
@@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
- 房间查找
|
- 房间查找
|
||||||
- 玩家记录
|
- 玩家记录
|
||||||
|
|
||||||
- 被记录的玩家显示为黄名
|
- 被记录的玩家显示为黄名
|
||||||
- 是steam好友的玩家显示为绿名(优先级更高)
|
- 是steam好友的玩家显示为绿名(优先级更高)
|
||||||
- 被拉黑的玩家显示为红名(优先级最高)
|
- 被拉黑的玩家显示为红名(优先级最高)
|
||||||
@@ -15,9 +14,33 @@
|
|||||||
- 可选择开启,默认开启的防踢
|
- 可选择开启,默认开启的防踢
|
||||||
- 可配置的界面开启按键,默认为F2
|
- 可配置的界面开启按键,默认为F2
|
||||||
- 可以随时切换房间的公开性
|
- 可以随时切换房间的公开性
|
||||||
|
- 静音单个玩家
|
||||||
|
- 一键加好友
|
||||||
|
|
||||||
## 更新日志
|
## 更新日志
|
||||||
|
|
||||||
|
### v4.0.6
|
||||||
|
1. 大厅搜索范围按钮现在可同步修改快速匹配的搜索范围
|
||||||
|
2. 修复了禁音功能 *难道他真的是猪??*
|
||||||
|
|
||||||
|
### v4.0.5
|
||||||
|
|
||||||
|
1. 修复了加好友按钮始终不显示的问题 *难道他真的是猪??*
|
||||||
|
|
||||||
|
### v4.0.4
|
||||||
|
|
||||||
|
1. 房间列表现在在房间内也显示,但是点击无效
|
||||||
|
2. 添加了加好友按钮
|
||||||
|
3. 修复了禁音功能 *难道他真的是猪??*
|
||||||
|
|
||||||
|
### v4.0.3
|
||||||
|
|
||||||
|
1. 静音单个玩家
|
||||||
|
2. 性能优化
|
||||||
|
3. 提供了更多可选是否开启功能显示的配置项
|
||||||
|
4. 提供按钮组件注册入口
|
||||||
|
5. 更好的房间公开性切换
|
||||||
|
|
||||||
### v3.1.1
|
### v3.1.1
|
||||||
|
|
||||||
1. 添加了房间公开性切换功能
|
1. 添加了房间公开性切换功能
|
||||||
@@ -72,3 +95,143 @@
|
|||||||
感谢老狼的原版插件
|
感谢老狼的原版插件
|
||||||
|
|
||||||
旧版插件用户可以通过把 `...\StickFightTheGame\StickFight_Data`下的 `CustomPlayerRecord.txt`文件移动到 `...\StickFightTheGame\BepInEx\config\`目录来保留以前的记录
|
旧版插件用户可以通过把 `...\StickFightTheGame\StickFight_Data`下的 `CustomPlayerRecord.txt`文件移动到 `...\StickFightTheGame\BepInEx\config\`目录来保留以前的记录
|
||||||
|
|
||||||
|
## 接口文档
|
||||||
|
|
||||||
|
### 组件注册
|
||||||
|
|
||||||
|
v4.0.3 起开放 GUI 组件注册,允许其他插件向界面的 Header 区或玩家行插入自定义控件。
|
||||||
|
|
||||||
|
命名空间:`stick.plugins.playermanager.Gui`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### `RegisterManager` — 注册/反注册 API
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// 注册一个 Header 行(纵向排列,行内子组件横向排列)
|
||||||
|
static void RegisterHeaderRow(IHeaderRow row);
|
||||||
|
|
||||||
|
// 注册一个玩家行组件(每个玩家行中横向排列)
|
||||||
|
static void RegisterPlayerRow(IPlayerRowWidget widget);
|
||||||
|
|
||||||
|
// 按 Name 反注册
|
||||||
|
static bool UnregisterHeaderRow(string name);
|
||||||
|
static bool UnregisterPlayerRow(string name);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 玩家行组件
|
||||||
|
|
||||||
|
每个大厅成员对应一行,注册的组件在行内从左到右排列。两种组件:
|
||||||
|
|
||||||
|
**`PlayerRowButtonWidget`** — 可点击按钮
|
||||||
|
|
||||||
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|
| ----------- | ---------------------------- | ---- | ------------------------------- |
|
||||||
|
| `Name` | `string` | ✓ | 唯一标识,用于反注册 |
|
||||||
|
| `Width` | `float` | ✓ | 组件宽度(像素) |
|
||||||
|
| `GetText` | `Func<PlayerInfo, string>` | ✓ | 按钮文字,`player` 为当前行玩家 |
|
||||||
|
| `OnClick` | `Action<PlayerInfo>` | ✓ | 点击回调 |
|
||||||
|
| `Condition` | `Func<PlayerInfo, bool>` | | 返回 `false` 时对该玩家隐藏 |
|
||||||
|
| `Style` | `GUIStyle` | | 静态样式 |
|
||||||
|
| `GetStyle` | `Func<PlayerInfo, GUIStyle>` | | 动态样式,优先于 `Style` |
|
||||||
|
|
||||||
|
**`PlayerRowLabelWidget`** — 只读文本
|
||||||
|
|
||||||
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|
| ----------- | -------------------------- | ---- | ------------------- |
|
||||||
|
| `Name` | `string` | ✓ | 唯一标识 |
|
||||||
|
| `Width` | `float` | ✓ | 组件宽度(像素) |
|
||||||
|
| `GetText` | `Func<PlayerInfo, string>` | ✓ | 显示文本 |
|
||||||
|
| `Condition` | `Func<PlayerInfo, bool>` | | 返回 `false` 时隐藏 |
|
||||||
|
| `Style` | `GUIStyle` | | 自定义样式 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### Header 组件
|
||||||
|
|
||||||
|
Header 区位于标题下方,每行可含多个子组件。两种子组件:
|
||||||
|
|
||||||
|
**`HeaderRow`** — 一个 Header 行
|
||||||
|
|
||||||
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|
| ----------- | --------------------- | ---- | ----------------------- |
|
||||||
|
| `Name` | `string` | ✓ | 唯一标识 |
|
||||||
|
| `Children` | `List<IHeaderWidget>` | ✓ | 行内子组件列表 |
|
||||||
|
| `Condition` | `Func<bool>` | | 返回 `false` 时整行隐藏 |
|
||||||
|
|
||||||
|
**`HeaderLabelWidget`** — 行内文本
|
||||||
|
|
||||||
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|
| ----------- | -------------- | ---- | ------------------- |
|
||||||
|
| `Name` | `string` | ✓ | 唯一标识 |
|
||||||
|
| `Width` | `float` | ✓ | 组件宽度(像素) |
|
||||||
|
| `Content` | `Func<string>` | ✓ | 显示文本 |
|
||||||
|
| `Condition` | `Func<bool>` | | 返回 `false` 时隐藏 |
|
||||||
|
| `Style` | `GUIStyle` | | 自定义样式 |
|
||||||
|
|
||||||
|
**`HeaderButtonWidget`** — 行内按钮
|
||||||
|
|
||||||
|
| 参数 | 类型 | 必填 | 说明 |
|
||||||
|
| ----------- | ------------ | ---- | ------------------- |
|
||||||
|
| `Name` | `string` | ✓ | 唯一标识 |
|
||||||
|
| `Width` | `float` | ✓ | 组件宽度(像素) |
|
||||||
|
| `Text` | `string` | ✓ | 按钮文字 |
|
||||||
|
| `Action` | `Action` | ✓ | 点击回调 |
|
||||||
|
| `Condition` | `Func<bool>` | | 返回 `false` 时隐藏 |
|
||||||
|
| `Style` | `GUIStyle` | | 自定义样式 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 示例
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
using stick.plugins.playermanager.Gui;
|
||||||
|
using stick.plugins.playermanager.Recorder;
|
||||||
|
|
||||||
|
// 玩家行按钮
|
||||||
|
RegisterManager.RegisterPlayerRow(new PlayerRowButtonWidget
|
||||||
|
{
|
||||||
|
Name = "MyButton",
|
||||||
|
GetText = player => "打招呼",
|
||||||
|
OnClick = player => Debug.Log($"你好 {player}"),
|
||||||
|
Width = 100f,
|
||||||
|
Condition = player => !PlayerManager.IsLocalPlayer(player),
|
||||||
|
});
|
||||||
|
|
||||||
|
// 玩家行标签
|
||||||
|
RegisterManager.RegisterPlayerRow(new PlayerRowLabelWidget
|
||||||
|
{
|
||||||
|
Name = "MyLabel",
|
||||||
|
GetText = player => $"#{player.SteamId}",
|
||||||
|
Width = 150f,
|
||||||
|
Style = GUIStyles.Label,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Header 行(含标签 + 按钮)
|
||||||
|
RegisterManager.RegisterHeaderRow(new HeaderRow
|
||||||
|
{
|
||||||
|
Name = "MyHeader",
|
||||||
|
Condition = () => PlayerManager.IsHost(PlayerManager.LocalPlayer),
|
||||||
|
Children = new List<IHeaderWidget>
|
||||||
|
{
|
||||||
|
new HeaderLabelWidget
|
||||||
|
{
|
||||||
|
Name = "Status",
|
||||||
|
Content = () => "状态: 运行中",
|
||||||
|
Width = 150f,
|
||||||
|
},
|
||||||
|
new HeaderButtonWidget
|
||||||
|
{
|
||||||
|
Name = "Action",
|
||||||
|
Text = "执行",
|
||||||
|
Action = () => Debug.Log("点击"),
|
||||||
|
Width = 100f,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 反注册
|
||||||
|
RegisterManager.UnregisterPlayerRow("MyButton");
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<TargetFramework>net35</TargetFramework>
|
<TargetFramework>net35</TargetFramework>
|
||||||
<AssemblyName>stick.plugins.playermanager</AssemblyName>
|
<AssemblyName>stick.plugins.playermanager</AssemblyName>
|
||||||
<Product>PlayerManager</Product>
|
<Product>PlayerManager</Product>
|
||||||
<Version>4.0.2</Version>
|
<Version>4.0.6</Version>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<RestoreAdditionalProjectSources>
|
<RestoreAdditionalProjectSources>
|
||||||
|
|||||||
Reference in New Issue
Block a user