24 Commits

Author SHA1 Message Date
Yue-bin
8b5e3c33d2 chore(PlayerManager): 更新版本号从4.0.7到4.0.8
All checks were successful
Publish Release / build (push) Successful in 36s
- 将项目版本号从4.0.7升级至4.0.8
- 保持其他配置不变
2026-06-22 05:44:30 +08:00
Yue-bin
079716cc85 docs: 添加4.0.8更新说明 2026-06-22 05:44:17 +08:00
Yue-bin
04337028b3 fix(PlayerManagerGUI): 修复空SteamId导致的异常
当玩家列表中的成员SteamId无效时跳过绘制,
避免因空值引起的运行时错误。
2026-06-22 05:41:14 +08:00
Yue-bin
6b9910486b feat(Gui): 添加玩家管理界面的widget绘制优化功能
- 引入HashSet来记录需要忽略的widget,避免不必要的绘制操作
- 实现widget可见性检查逻辑,当widget对所有玩家都不需要绘制时将其加入忽略列表
- 修改玩家行绘制循环,跳过被标记为忽略的widget以提升性能
- 优化列位置推进逻辑,仅在widget未被忽略时才进行占位推进
2026-06-22 05:36:59 +08:00
Yue-bin
c320a07370 fix(PlayerManager): 修复大厅成员变更时未触发更新的问题
当请求大厅列表后,添加调用OnLobbyMembersChanged()方法来确保
大厅成员信息能够正确更新和显示。
2026-06-22 05:26:30 +08:00
Yue-bin
a0d1386712 feat(PlayerManager): 添加房间所有权转让功能
添加了转让房主按钮,允许房主将房间所有权转移给其他玩家。
- 在GUI中新增TransButton组件,用于转让房主功能
- 添加ShowTransButton配置项控制按钮显示
- 实现TransferLobbyOwnership方法处理房主转让逻辑
- 默认启用转让按钮显示
2026-06-22 05:02:26 +08:00
Yue-bin
ab960fc38b chore(PlayerManager): 更新版本号至4.0.7
All checks were successful
Publish Release / build (push) Successful in 1m38s
- 将项目版本从4.0.6升级到4.0.7
- 保持其他配置不变
2026-06-19 20:41:59 +08:00
Yue-bin
a40a605c37 docs(readme): 添加作者信息并更新v4.0.7版本日志
- 添加项目作者信息到README文档
- 新增v4.0.7版本更新内容
- 包含大厅列表按钮点击状态标识功能说明
- 优化LocalPlayer初始化逻辑相关说明
2026-06-19 20:41:47 +08:00
Yue-bin
b19f906216 fix(PlayerManagerGUI): 修复大厅加入逻辑中的条件判断错误
修改了玩家管理GUI中大厅加入的条件判断逻辑,将内部的条件判断移到外部,
确保只有当不在大厅内时才能加入新的大厅,修复了可能的重复加入问题。

adhd???
2026-06-19 20:30:37 +08:00
Yue-bin
3ecb7fb78b fix(PlayerManager): 修复本地玩家初始化逻辑
当SteamManager已初始化但LocalPlayer为空时才创建新的LocalPlayer实例,
避免重复初始化问题。
2026-06-19 20:25:15 +08:00
Yue-bin
4e8931caba feat(gui): 添加已访问大厅的视觉标识功能
添加了ButtonPressed样式用于标识已进入过的大厅,
使用户能够直观区分未访问和已访问的大厅。

在PlayerManager中新增enteredLobbyList集合来跟踪已访问的大厅,
并在界面中根据访问状态显示不同的按钮颜色。
2026-06-19 20:24:29 +08:00
Yue-bin
3adcdc46ba Merge branch 'master' of 172.16.29.13:Stick_Mods/stick.plugins.playermanager
All checks were successful
Publish Release / build (push) Successful in 31s
2026-06-11 02:13:25 +08:00
Yue-bin
b6edc70594 chore(ci): 为.NET构建流程添加代理配置
在Gitea工作流中添加HTTP/HTTPS代理环境变量配置,
以解决网络访问问题并提高依赖包恢复速度。
2026-06-11 02:13:09 +08:00
9e7fb4d443 doc: 大厅搜索范围按钮现在可同步修改快速匹配的搜索范围
Some checks failed
Publish Release / build (push) Failing after 4m9s
2026-06-10 19:09:02 +08:00
6ab8c38109 feat(matchmaking): 大厅搜索范围按钮现在可同步修改快速匹配的搜索范围 2026-06-10 18:55:01 +08:00
9a5d149241 fix(playermanager): 应用静音Patch 2026-06-10 18:54:41 +08:00
Yue-bin
f193d8a805 fix(playermanager): 修复加好友按钮显示问题并更新版本号至4.0.5
Some checks failed
Publish Release / build (push) Failing after 3s
- 在readme.md中添加v4.0.5更新日志,记录修复了加好友按钮始终不显示的问题
- 更新stick.plugins.playermanager.csproj中的版本号从4.0.4到4.0.5
2026-05-31 01:59:19 +08:00
Yue-bin
00960eb3f7 fix(Gui): 修复添加好友按钮的本地玩家检查逻辑
- 将 PlayerManager.IsLocalPlayer(PlayerManager.LocalPlayer)
  修改为 PlayerManager.IsLocalPlayer(player)
- 确保正确检查目标玩家是否为本地玩家,而非始终检查本地玩家自己
- 避免好友列表中出现本地玩家的错误情况
2026-05-31 01:58:30 +08:00
Yue-bin
bc2d44f5cd docs(readme): 更新文档添加新功能说明
Some checks failed
Publish Release / build (push) Failing after 4m0s
- 移除了重复的玩家名称颜色显示说明
- 添加了一键加好友功能描述
- 更新了更新日志,包含v4.0.4版本的新功能:
  1. 房间列表现在在房间内也显示,但是点击无效
  2. 添加了加好友按钮
  3. 修复了禁音功能
- 调整了v4.0.3版本更新内容的序号格式
2026-05-28 17:02:17 +08:00
Yue-bin
c065b14f9d chore(PlayerManager): 更新版本号到4.0.4
- 将项目版本从4.0.3更新至4.0.4
2026-05-28 16:58:42 +08:00
Yue-bin
46f05b5489 🐞 fix(mute): 修复了禁音无效的问题
难道他真的是猪?
2026-05-28 16:58:06 +08:00
Yue-bin
3a9e903044 feat(gui): 添加加好友按钮功能
新增了加好友按钮组件,允许玩家通过Steam界面添加其他玩家为好友。
该功能包含一个可配置的按钮,点击后会复制玩家信息到剪贴板并打开Steam好友添加界面。
同时增加了相应的配置选项来控制按钮的显示。

需要配置项ShowAddFriendButton来控制加好友按钮的显示状态,
默认设置为显示(true)。
2026-05-28 16:24:23 +08:00
Yue-bin
ca331d4ac8 feat(Gui): 添加大厅搜索信息显示功能
添加了大厅搜索信息的绘制功能,并优化了服务器加入逻辑,
避免在已有大厅的情况下重复加入服务器。
2026-05-28 16:09:47 +08:00
Yue-bin
692fc25d42 fix(Gui): 修改静音按钮逻辑
- 移除主机玩家的条件限制,仅保留本地玩家检查
- 将"禁音"/"取消禁音"文本改为更标准的"静音"/"取消静音"
2026-05-08 17:42:15 +08:00
13 changed files with 262 additions and 25 deletions

View File

@@ -21,6 +21,11 @@ jobs:
- name: Restore dependencies
run: dotnet restore
# 直接加代理得了
env:
http_proxy: "http://172.17.0.1:7890"
https_proxy: "http://172.17.0.1:7890"
no_proxy: "localhost,127.0.0.1,*.lan"
- name: Build
run: dotnet build --no-restore --configuration Release

View File

@@ -41,7 +41,12 @@ public static class DefaultWidgets
if (PlayerManager.ShowNameToggleButton.Value)
RegisterManager.RegisterPlayerRow(InternalWidgets.NameToggleButton.Create());
if (PlayerManager.ShowTransButton.Value)
RegisterManager.RegisterPlayerRow(InternalWidgets.TransButton.Create());
if (PlayerManager.ShowMuteButton.Value)
RegisterManager.RegisterPlayerRow(InternalWidgets.MuteButton.Create());
if (PlayerManager.ShowAddFriendButton.Value)
RegisterManager.RegisterPlayerRow(InternalWidgets.AddFriendButton.Create());
}
}

View File

@@ -15,6 +15,9 @@ public static class GUIStyles
/// <summary>普通按钮样式fontSize=22, richText=false</summary>
public static GUIStyle Button;
/// <summary>被按过的按钮样式用于标识已经进入过的房间fontSize=22</summary>
public static GUIStyle ButtonPressed;
/// <summary>黄色按钮样式(已记录玩家)</summary>
public static GUIStyle YellowButton;
@@ -35,6 +38,8 @@ public static class GUIStyles
Label = new GUIStyle(GUI.skin.label) { fontSize = 22 };
Button = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
ButtonPressed = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
ButtonPressed.normal.textColor = Color.grey;
YellowButton = new GUIStyle(GUI.skin.button) { fontSize = 22, richText = false };
YellowButton.normal.textColor = Color.yellow;

View 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,
};
}
}

View File

@@ -9,11 +9,9 @@ public static class MuteButton
return new PlayerRowButtonWidget
{
Name = "mute",
Condition = player =>
!PlayerManager.IsHost(player)
&& !PlayerManager.IsLocalPlayer(player),
Condition = player => !PlayerManager.IsLocalPlayer(player),
GetText = player =>
PlayerManager.IsMuted(player) ? "取消音" : "音",
PlayerManager.IsMuted(player) ? "取消音" : "音",
OnClick = player =>
{
if (PlayerManager.IsMuted(player))

View File

@@ -0,0 +1,21 @@
using MultiplayerBasicExample;
namespace stick.plugins.playermanager.Gui.InternalWidgets;
public static class TransButton
{
public static IPlayerRowWidget Create()
{
return new PlayerRowButtonWidget
{
Name = "Trans Host",
Condition = player =>
PlayerManager.IsHost(PlayerManager.LocalPlayer)
&& !PlayerManager.IsLocalPlayer(player),
GetText = _ => "转让",
OnClick = player =>
PlayerManager.TransferLobbyOwnership(player),
Width = 100f,
};
}
}

View File

@@ -3,6 +3,7 @@ using MultiplayerBasicExample;
using Steamworks;
using UnityEngine;
using stick.plugins.playermanager.Recorder;
using System.Collections.Generic;
namespace stick.plugins.playermanager.Gui;
@@ -30,6 +31,11 @@ public static class PlayerManagerGUI
/// </summary>
private static readonly LayoutCursor Cursor = new();
/// <summary>
/// 记录该行widget是否该绘制
/// </summary>
private static readonly HashSet<IPlayerRowWidget> IgnoreWidgets = [];
#endregion
#region
@@ -45,6 +51,7 @@ public static class PlayerManagerGUI
if (PlayerManager.MatchmakingHandler.IsInsideLobby)
{
DrawCurrentLobbyInfo();
DrawLobbySearchInfo();
}
else
{
@@ -88,10 +95,29 @@ public static class PlayerManagerGUI
Cursor.EndRow();
}
// 玩家行区域:每玩家一行,行内横向迭代注册的 PlayerRowWidget
for (int i = 0; i < PlayerManager.lobbyMemberList.Count; i++)
IgnoreWidgets.Clear();
// 如果一个widget对所有玩家都不需要绘制则忽略
foreach (var widget in RegisterManager.PlayerRowWidgets)
{
bool shouldDraw = false;
foreach (var member in PlayerManager.lobbyMemberList)
{
if (!member.SteamId.IsValid()) continue;
if (widget.ShouldDraw(member))
{
shouldDraw = true;
break;
}
}
if (!shouldDraw)
IgnoreWidgets.Add(widget);
}
// 玩家行区域:每玩家一行,行内横向迭代注册的 PlayerRowWidget
foreach (var member in PlayerManager.lobbyMemberList)
{
PlayerInfo member = PlayerManager.lobbyMemberList[i];
if (!member.SteamId.IsValid()) continue;
Cursor.BeginRow();
@@ -100,7 +126,8 @@ public static class PlayerManagerGUI
if (widget.ShouldDraw(member))
widget.Draw(Cursor.NextColumn(widget.Width, 40f), member);
else
Cursor.NextColumn(widget.Width, 40f); // 占位推进列位置
if (!IgnoreWidgets.Contains(widget))
Cursor.NextColumn(widget.Width, 40f); // 占位推进列位置对齐
}
Cursor.EndRow();
}
@@ -189,13 +216,21 @@ public static class PlayerManagerGUI
for (int i = 0; i < PlayerManager.lobbyDataList.Count; i++)
{
CSteamID lobbyId = PlayerManager.lobbyDataList[i];
var style = PlayerManager.enteredLobbyList.Contains(lobbyId) ? GUIStyles.ButtonPressed : GUIStyles.Button;
if (GUI.Button(
new Rect(Cursor.OffsetX, Cursor.LineHeight * i, 500f, 40f),
$"{lobbyId} 人数{SteamMatchmaking.GetNumLobbyMembers(lobbyId)}",
GUIStyles.Button
style
))
{
PlayerManager.JoinSpecificServer(lobbyId);
// 在大厅中则不加入
if (!PlayerManager.MatchmakingHandler.IsInsideLobby)
{
// 记录一下加入过的状态
PlayerManager.enteredLobbyList.Add(lobbyId);
PlayerManager.JoinSpecificServer(lobbyId);
}
}
}

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

15
Patches/MutePatch.cs Normal file
View 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;
}
}

View File

@@ -39,6 +39,11 @@ public class PlayerManager : BaseUnityPlugin
/// </summary>
internal static ConfigEntry<bool> ShowKickButton;
/// <summary>
/// 是否显示转让按钮
/// </summary>
internal static ConfigEntry<bool> ShowTransButton;
/// <summary>
/// 是否显示记录/拉黑按钮
/// </summary>
@@ -64,6 +69,11 @@ public class PlayerManager : BaseUnityPlugin
/// </summary>
internal static ConfigEntry<bool> ShowMuteButton;
/// <summary>
/// 是否显示加好友按钮
/// </summary>
internal static ConfigEntry<bool> ShowAddFriendButton;
#endregion
#region Steam回调
@@ -97,6 +107,11 @@ public class PlayerManager : BaseUnityPlugin
/// </summary>
public static List<CSteamID> lobbyDataList = [];
/// <summary>
/// 进入过的大厅列表
/// </summary>
public static HashSet<CSteamID> enteredLobbyList = [];
/// <summary>
/// 大厅距离过滤设置
/// </summary>
@@ -111,6 +126,11 @@ public class PlayerManager : BaseUnityPlugin
#region 访
/// <summary>
/// 多人管理器实例
/// </summary>
public static MultiplayerManager MultiplayerManager => FindObjectOfType<MultiplayerManager>();
/// <summary>
/// 大厅管理器实例
/// </summary>
@@ -164,7 +184,7 @@ public class PlayerManager : BaseUnityPlugin
/// <summary>
/// 禁音玩家列表
/// </summary>
public static HashSet<PlayerInfo> MutedPlayers = [];
public static HashSet<ushort> MutedPlayers = [];
#endregion
@@ -185,7 +205,7 @@ public class PlayerManager : BaseUnityPlugin
private void Update()
{
HandleInput();
if (SteamManager.Initialized)
if (SteamManager.Initialized && LocalPlayer is null)
{
LocalPlayer = new(SteamUser.GetSteamID());
}
@@ -229,6 +249,13 @@ public class PlayerManager : BaseUnityPlugin
"是否显示踢人按钮"
);
ShowTransButton = Config.Bind(
"GUI",
"ShowTransButton",
true,
"是否显示转让按钮"
);
ShowRecordButton = Config.Bind(
"GUI",
"ShowRecordButton",
@@ -263,6 +290,13 @@ public class PlayerManager : BaseUnityPlugin
true,
"是否显示切换公开性按钮"
);
ShowAddFriendButton = Config.Bind(
"GUI",
"ShowAddFriendButton",
true,
"是否显示加好友按钮"
);
}
/// <summary>
@@ -276,6 +310,8 @@ public class PlayerManager : BaseUnityPlugin
}
Harmony.CreateAndPatchAll(typeof(ApplyBlacklist));
Harmony.CreateAndPatchAll(typeof(ListenForChange));
Harmony.CreateAndPatchAll(typeof(MutePatch));
Harmony.CreateAndPatchAll(typeof(DistanceFilterPatch));
}
/// <summary>
@@ -302,6 +338,7 @@ public class PlayerManager : BaseUnityPlugin
else
{
RequestLobbyList();
OnLobbyMembersChanged();
PlayerManagerGUI.ShowLobbyInfo = true;
Debug.Log("大厅信息界面已打开");
}
@@ -310,6 +347,37 @@ public class PlayerManager : BaseUnityPlugin
#region
/// <summary>
/// 转让房主
/// </summary>
/// <param name="targetPlayer">目标玩家</param>
/// <returns></returns>
public static void TransferLobbyOwnership(PlayerInfo targetPlayer)
{
if (targetPlayer != null && targetPlayer != LocalPlayer)
{
SteamMatchmaking.SetLobbyOwner(CurrentLobbyID, targetPlayer.SteamId);
}
}
/// <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>
@@ -317,7 +385,7 @@ public class PlayerManager : BaseUnityPlugin
/// <returns>如果被静音返回true</returns>
public static bool IsMuted(PlayerInfo player)
{
return player != null && MutedPlayers.Contains(player);
return player != null && MutedPlayers.Contains(player.NetworkSpawnID);
}
/// <summary>
@@ -328,7 +396,7 @@ public class PlayerManager : BaseUnityPlugin
{
if (player != null)
{
MutedPlayers.Add(player);
MutedPlayers.Add(player.NetworkSpawnID);
Debug.Log($"玩家 {player} 已被静音");
}
}
@@ -339,9 +407,9 @@ public class PlayerManager : BaseUnityPlugin
/// <param name="player">要取消静音的玩家</param>
public static void UnmutePlayer(PlayerInfo player)
{
if (player != null && MutedPlayers.Contains(player))
if (player != null && MutedPlayers.Contains(player.NetworkSpawnID))
{
MutedPlayers.Remove(player);
MutedPlayers.Remove(player.NetworkSpawnID);
Debug.Log($"玩家 {player} 已被取消静音");
}
}
@@ -397,6 +465,7 @@ public class PlayerManager : BaseUnityPlugin
{
Debug.Log("大厅列表请求完成: " + result.m_nLobbiesMatching + " 个大厅");
lobbyDataList = [];
enteredLobbyList = [];
uint lobbyCount = result.m_nLobbiesMatching;
for (uint i = 0; i < lobbyCount; i++)

View File

@@ -43,6 +43,12 @@ public class PlayerInfo : IEquatable<PlayerInfo>
/// </summary>
public PlayerRecordStatus RecordStatus { get; set; }
/// <summary>
/// 柴自己的NetworkSpawnID
/// </summary>
public ushort NetworkSpawnID => PlayerManager.GetNetworkSpawnIDBySteamID(SteamId);
/// <summary>
/// 当前玩家名称(实时获取)
/// </summary>

View File

@@ -5,8 +5,8 @@
## 功能
- 房间查找
- 转让房主
- 玩家记录
- 被记录的玩家显示为黄名
- 是steam好友的玩家显示为绿名优先级更高
- 被拉黑的玩家显示为红名(优先级最高)
@@ -16,16 +16,46 @@
- 可配置的界面开启按键默认为F2
- 可以随时切换房间的公开性
- 静音单个玩家
- 一键加好友
## 作者
老狼老狼几点钟、Moncak、z7572
## 更新日志
### v4.0.8
1. 添加了转让房主功能
2. 现在如果某个按钮(行组件)对所有人都不显示,则不留空
### v4.0.7
1. 现在点击大厅列表中的按钮进入大厅会在列表中将该大厅用灰色样式标识,标记已进入过
2. 现在不会在每帧都初始化一遍LocalPlayer *难道他真的是猪??*
### v4.0.6
1. 大厅搜索范围按钮现在可同步修改快速匹配的搜索范围
2. 修复了禁音功能 *难道他真的是猪??*
### v4.0.5
1. 修复了加好友按钮始终不显示的问题 *难道他真的是猪??*
### v4.0.4
1. 房间列表现在在房间内也显示,但是点击无效
2. 添加了加好友按钮
3. 修复了禁音功能 *难道他真的是猪??*
### v4.0.3
1. 静音单个玩家
1. 性能优化
1. 提供了更多可选是否开启功能显示的配置项
1. 提供按钮组件注册入口
1. 更好的房间公开性切换
2. 性能优化
3. 提供了更多可选是否开启功能显示的配置项
4. 提供按钮组件注册入口
5. 更好的房间公开性切换
### v3.1.1

View File

@@ -4,7 +4,7 @@
<TargetFramework>net35</TargetFramework>
<AssemblyName>stick.plugins.playermanager</AssemblyName>
<Product>PlayerManager</Product>
<Version>4.0.3</Version>
<Version>4.0.8</Version>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>latest</LangVersion>
<RestoreAdditionalProjectSources>