UI联机
This commit is contained in:
parent
57abeb5c05
commit
bee4e7d48f
@ -1,5 +1,5 @@
|
||||
{
|
||||
"nextId": 258,
|
||||
"nextId": 263,
|
||||
"bugs": [
|
||||
{
|
||||
"id": 2,
|
||||
@ -2550,6 +2550,56 @@
|
||||
"module": "",
|
||||
"createdAt": 1779506906721,
|
||||
"updatedAt": 1779506906721
|
||||
},
|
||||
{
|
||||
"id": 258,
|
||||
"title": "我联机打的时候,楼陀罗火车打守矢的那个大白蛇会有bug",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"createdAt": 1779523517289,
|
||||
"updatedAt": 1779523517289
|
||||
},
|
||||
{
|
||||
"id": 259,
|
||||
"title": "所有巨人单位应该是LV6以上升级可选",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"createdAt": 1779537607662,
|
||||
"updatedAt": 1779537607662
|
||||
},
|
||||
{
|
||||
"id": 260,
|
||||
"title": "间谍攻城的时候城里也有间谍怎么办?",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"createdAt": 1779538468082,
|
||||
"updatedAt": 1779538468082
|
||||
},
|
||||
{
|
||||
"id": 261,
|
||||
"title": "玩其他游戏时好像邀请不了",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"createdAt": 1779539073924,
|
||||
"updatedAt": 1779539073924
|
||||
},
|
||||
{
|
||||
"id": 262,
|
||||
"title": "话说什么时候恋升级不可视 升个级还能被人看到(",
|
||||
"description": "",
|
||||
"status": "open",
|
||||
"priority": "medium",
|
||||
"module": "",
|
||||
"createdAt": 1779539151076,
|
||||
"updatedAt": 1779539151076
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -32,6 +32,11 @@ MonoBehaviour:
|
||||
OutsideMultiplayIncludeAIPlayerHint: "(\u5305\u542BAI\u73A9\u5BB6)"
|
||||
OutsideMultiplayNoRoomHint: "\u6682\u65E0\u8054\u673A\u623F\u95F4"
|
||||
OutsideMultiplayRoomNameSuffix: "\u7684\u623F\u95F4"
|
||||
OutsideMultiplayTeamTitle: "\u961F\u4F0D"
|
||||
OutsideMultiplayAIPlayerTitle: "AI\u73A9\u5BB6"
|
||||
OutsideMultiplayOpenTitle: "\u5F85\u52A0\u5165"
|
||||
OutsideMultiplayReadyTitle: "\u5DF2\u51C6\u5907"
|
||||
OutsideMultiplayOpenHint: "\u73A9\u5BB6\u5E2D\u4F4D\u672A\u6EE1\uFF0C\u8BF7\u8C03\u6574\u5E2D\u4F4D"
|
||||
OutsideHistoryDropListNoLimitP: "\u4E0D\u9650"
|
||||
OutsideHistoryDropList2P: "2\u4EBA"
|
||||
OutsideHistoryDropList3P: "3\u4EBA"
|
||||
|
||||
File diff suppressed because one or more lines are too long
136
Unity/Assets/Resources/Export/NetworkPlayerTipDataAssets.asset
Normal file
136
Unity/Assets/Resources/Export/NetworkPlayerTipDataAssets.asset
Normal file
@ -0,0 +1,136 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 3ebbbbba88fe43409c16e83b934b878c, type: 3}
|
||||
m_Name: NetworkPlayerTipDataAssets
|
||||
m_EditorClassIdentifier:
|
||||
DefaultCooldownSeconds: 3
|
||||
NetworkPlayerTipInfoList:
|
||||
- TipType: 1
|
||||
Title: 20000
|
||||
Message: 20001
|
||||
CooldownSeconds: 5
|
||||
- TipType: 2
|
||||
Title: 20002
|
||||
Message: 20003
|
||||
CooldownSeconds: 5
|
||||
- TipType: 3
|
||||
Title: 20004
|
||||
Message: 20005
|
||||
CooldownSeconds: 10
|
||||
- TipType: 4
|
||||
Title: 20006
|
||||
Message: 20007
|
||||
CooldownSeconds: 5
|
||||
- TipType: 5
|
||||
Title: 20008
|
||||
Message: 20009
|
||||
CooldownSeconds: 3
|
||||
- TipType: 6
|
||||
Title: 20010
|
||||
Message: 20011
|
||||
CooldownSeconds: 3
|
||||
- TipType: 7
|
||||
Title: 20012
|
||||
Message: 20013
|
||||
CooldownSeconds: 2
|
||||
- TipType: 8
|
||||
Title: 20014
|
||||
Message: 20015
|
||||
CooldownSeconds: 2
|
||||
- TipType: 9
|
||||
Title: 20016
|
||||
Message: 20017
|
||||
CooldownSeconds: 3
|
||||
- TipType: 10
|
||||
Title: 20018
|
||||
Message: 20019
|
||||
CooldownSeconds: 3
|
||||
- TipType: 11
|
||||
Title: 20020
|
||||
Message: 20021
|
||||
CooldownSeconds: 5
|
||||
- TipType: 12
|
||||
Title: 20022
|
||||
Message: 20023
|
||||
CooldownSeconds: 3
|
||||
- TipType: 13
|
||||
Title: 20024
|
||||
Message: 20025
|
||||
CooldownSeconds: 5
|
||||
- TipType: 14
|
||||
Title: 20026
|
||||
Message: 20027
|
||||
CooldownSeconds: 3
|
||||
- TipType: 15
|
||||
Title: 20028
|
||||
Message: 20029
|
||||
CooldownSeconds: 3
|
||||
- TipType: 16
|
||||
Title: 20030
|
||||
Message: 20031
|
||||
CooldownSeconds: 5
|
||||
- TipType: 17
|
||||
Title: 20032
|
||||
Message: 20033
|
||||
CooldownSeconds: 3
|
||||
- TipType: 18
|
||||
Title: 20034
|
||||
Message: 20035
|
||||
CooldownSeconds: 5
|
||||
- TipType: 19
|
||||
Title: 20036
|
||||
Message: 20037
|
||||
CooldownSeconds: 5
|
||||
- TipType: 20
|
||||
Title: 20038
|
||||
Message: 20039
|
||||
CooldownSeconds: 5
|
||||
- TipType: 21
|
||||
Title: 20040
|
||||
Message: 20041
|
||||
CooldownSeconds: 3
|
||||
- TipType: 22
|
||||
Title: 20042
|
||||
Message: 20043
|
||||
CooldownSeconds: 5
|
||||
- TipType: 23
|
||||
Title: 20044
|
||||
Message: 20045
|
||||
CooldownSeconds: 5
|
||||
- TipType: 24
|
||||
Title: 20046
|
||||
Message: 20047
|
||||
CooldownSeconds: 5
|
||||
- TipType: 25
|
||||
Title: 20048
|
||||
Message: 20049
|
||||
CooldownSeconds: 5
|
||||
- TipType: 26
|
||||
Title: 20050
|
||||
Message: 20051
|
||||
CooldownSeconds: 3
|
||||
- TipType: 27
|
||||
Title: 20052
|
||||
Message: 20053
|
||||
CooldownSeconds: 3
|
||||
- TipType: 28
|
||||
Title: 20054
|
||||
Message: 20055
|
||||
CooldownSeconds: 2
|
||||
- TipType: 29
|
||||
Title: 20056
|
||||
Message: 20057
|
||||
CooldownSeconds: 3
|
||||
- TipType: 30
|
||||
Title: 20058
|
||||
Message: 20059
|
||||
CooldownSeconds: 5
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e8a9f8a49839186478275813e5fe3dc1
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -32,6 +32,11 @@ MonoBehaviour:
|
||||
OutsideMultiplayIncludeAIPlayerHint: 2405
|
||||
OutsideMultiplayNoRoomHint: 17453
|
||||
OutsideMultiplayRoomNameSuffix: 17705
|
||||
OutsideMultiplayTeamTitle:
|
||||
OutsideMultiplayAIPlayerTitle:
|
||||
OutsideMultiplayOpenTitle:
|
||||
OutsideMultiplayReadyTitle:
|
||||
OutsideMultiplayOpenHint:
|
||||
OutsideHistoryDropListNoLimitP: 17352
|
||||
OutsideHistoryDropList2P: 17353
|
||||
OutsideHistoryDropList3P: 17354
|
||||
|
||||
Binary file not shown.
@ -3404,7 +3404,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 147, y: -23}
|
||||
m_SizeDelta: {x: 120.01, y: 32.0265}
|
||||
m_SizeDelta: {x: 0, y: 32.0265}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5182836495056545005
|
||||
CanvasRenderer:
|
||||
@ -4348,7 +4348,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 250, y: -550.093}
|
||||
m_AnchoredPosition: {x: 250, y: -480.093}
|
||||
m_SizeDelta: {x: 500, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &4676610239985244751
|
||||
@ -5247,7 +5247,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 250, y: -785.093}
|
||||
m_AnchoredPosition: {x: 250, y: -550.093}
|
||||
m_SizeDelta: {x: 500, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1555931548957767936
|
||||
|
||||
@ -1587,7 +1587,7 @@ MonoBehaviour:
|
||||
NoExport: 0
|
||||
FontBan: 0
|
||||
Preset: 0
|
||||
ID: 1401
|
||||
ID: 19977
|
||||
FontID: 1
|
||||
TextCfg:
|
||||
- Type: 1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -828,6 +828,7 @@ GameObject:
|
||||
- component: {fileID: 4071889833013536115}
|
||||
- component: {fileID: 3511343210454506103}
|
||||
- component: {fileID: 7865469868100666246}
|
||||
- component: {fileID: 8973491618798335770}
|
||||
m_Layer: 5
|
||||
m_Name: Placeholder
|
||||
m_TagString: Untagged
|
||||
@ -971,6 +972,25 @@ MonoBehaviour:
|
||||
m_FlexibleWidth: -1
|
||||
m_FlexibleHeight: -1
|
||||
m_LayoutPriority: 1
|
||||
--- !u!114 &8973491618798335770
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4045480400424864957}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6b27f832d22e4a8d916272b644937774, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
Ban: 0
|
||||
NoExport: 0
|
||||
FontBan: 0
|
||||
Preset: 0
|
||||
ID: 19647
|
||||
FontID: 0
|
||||
TextCfg: []
|
||||
--- !u!1 &5471446911446404968
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -1617,7 +1637,7 @@ MonoBehaviour:
|
||||
NoExport: 0
|
||||
FontBan: 0
|
||||
Preset: 0
|
||||
ID: 17557
|
||||
ID: 19999
|
||||
FontID: 1
|
||||
TextCfg:
|
||||
- Type: 1
|
||||
@ -2758,6 +2778,7 @@ GameObject:
|
||||
- component: {fileID: 334792629644883303}
|
||||
- component: {fileID: 4652138525967637174}
|
||||
- component: {fileID: 8169390067649257082}
|
||||
- component: {fileID: 9058535840347886198}
|
||||
m_Layer: 5
|
||||
m_Name: RoomName
|
||||
m_TagString: Untagged
|
||||
@ -2881,6 +2902,25 @@ MonoBehaviour:
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!114 &9058535840347886198
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8171858811077351841}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 6b27f832d22e4a8d916272b644937774, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
Ban: 0
|
||||
NoExport: 0
|
||||
FontBan: 0
|
||||
Preset: 0
|
||||
ID: 19979
|
||||
FontID: 0
|
||||
TextCfg: []
|
||||
--- !u!1 &8438381095895913330
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@ -86,9 +86,8 @@ GameObject:
|
||||
- component: {fileID: 2438225421395076648}
|
||||
- component: {fileID: 591212338599555894}
|
||||
- component: {fileID: 7030574526118729750}
|
||||
- component: {fileID: 959187344526487202}
|
||||
m_Layer: 5
|
||||
m_Name: UIOutsideMultiplayRoomMemberButtonRow
|
||||
m_Name: UIOutsideMultiplayRoomMemberLineRow
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
@ -152,23 +151,3 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1.25
|
||||
--- !u!114 &959187344526487202
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 7377647467463133788}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: b944c6e03ad742440a76463c2ecf000a, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
AvatarImage: {fileID: 0}
|
||||
LeaderImage: {fileID: 0}
|
||||
NameText: {fileID: 0}
|
||||
StatusText: {fileID: 0}
|
||||
ForcesText: {fileID: 0}
|
||||
ForcesButton: {fileID: 0}
|
||||
RefreshButton: {fileID: 0}
|
||||
QuitButton: {fileID: 0}
|
||||
@ -1935,7 +1935,7 @@ MonoBehaviour:
|
||||
NoExport: 0
|
||||
FontBan: 0
|
||||
Preset: 0
|
||||
ID: 1635
|
||||
ID: 19995
|
||||
FontID: 2
|
||||
TextCfg:
|
||||
- Type: 1
|
||||
@ -2505,7 +2505,7 @@ MonoBehaviour:
|
||||
NoExport: 0
|
||||
FontBan: 0
|
||||
Preset: 0
|
||||
ID: 2225
|
||||
ID: 2231
|
||||
FontID: 1
|
||||
TextCfg:
|
||||
- Type: 1
|
||||
@ -3192,3 +3192,8 @@ MonoBehaviour:
|
||||
ForcesButton: {fileID: 8612292243586636816}
|
||||
RefreshButton: {fileID: 8612292243586636816}
|
||||
QuitButton: {fileID: 8717023295481533829}
|
||||
ForceLeftButton: {fileID: 8612292243586636816}
|
||||
ForceRightButton: {fileID: 6556385597021353403}
|
||||
TeamText: {fileID: 3332880645268972119}
|
||||
TeamLeftButton: {fileID: 8962252367205184452}
|
||||
TeamRightButton: {fileID: 2906850645216239320}
|
||||
|
||||
@ -38,6 +38,9 @@ public class TextDataAssets : ScriptableObject
|
||||
[MultilingualField]public string OutsideMultiplayRoomNameSuffix;
|
||||
[MultilingualField]public string OutsideMultiplayTeamTitle;
|
||||
[MultilingualField]public string OutsideMultiplayAIPlayerTitle;
|
||||
[MultilingualField]public string OutsideMultiplayOpenTitle;
|
||||
[MultilingualField]public string OutsideMultiplayReadyTitle;
|
||||
[MultilingualField]public string OutsideMultiplayOpenHint;
|
||||
|
||||
[MultilingualField]public string OutsideHistoryDropListNoLimitP;
|
||||
[MultilingualField]public string OutsideHistoryDropList2P;
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Logic.Multilingual;
|
||||
using RuntimeData;
|
||||
using TH1_Logic.Core;
|
||||
@ -17,84 +16,118 @@ public class UIOutsideMultiplayMemberRowMono : MonoBehaviour
|
||||
public TextMeshProUGUI NameText;
|
||||
public TextMeshProUGUI StatusText;
|
||||
public TextMeshProUGUI ForcesText;
|
||||
//public TextMeshProUGUI CivButtonText;
|
||||
//public Button CivButton;
|
||||
public Button ForcesButton;
|
||||
public Button RefreshButton;
|
||||
public Button QuitButton;
|
||||
public Button ForceLeftButton;
|
||||
public Button ForceRightButton;
|
||||
public TextMeshProUGUI TeamText;
|
||||
public Button TeamLeftButton;
|
||||
public Button TeamRightButton;
|
||||
|
||||
private SteamLobbyManager _lobby;
|
||||
// Start is called before the first frame update
|
||||
private CivEnum _civ;
|
||||
private ForceEnum _force;
|
||||
private int _teamId;
|
||||
private int _maxTeamId;
|
||||
private string _forceNameOverride;
|
||||
private Action<int> _onForceChanged;
|
||||
private Action<int> _onTeamChanged;
|
||||
|
||||
private static readonly (CivEnum Civ, ForceEnum Force)[] ForceOptions =
|
||||
{
|
||||
(CivEnum.Egyptian, ForceEnum.Remilia),
|
||||
(CivEnum.French, ForceEnum.Kaguya),
|
||||
(CivEnum.Germany, ForceEnum.Kanako),
|
||||
(CivEnum.Indian, ForceEnum.Satori),
|
||||
};
|
||||
|
||||
public bool CheckParam()
|
||||
{
|
||||
return AvatarImage != null && NameText != null &&
|
||||
ForcesText != null && StatusText != null; // && CivButton != null && ForcesButton != null;*/
|
||||
ForcesText != null && StatusText != null;
|
||||
}
|
||||
|
||||
public void SetContent(MemberInfo info,string status,CivEnum civ,SteamLobbyManager lobby, string forceNameOverride = null)
|
||||
|
||||
public void SetContent(MemberInfo info, string status, CivEnum civ, SteamLobbyManager lobby, string forceNameOverride = null)
|
||||
{
|
||||
SetHumanContent(info, status, civ, GetDefaultForce(civ), 1, 1, lobby, true, forceNameOverride, null, null);
|
||||
}
|
||||
|
||||
public void SetHumanContent(
|
||||
MemberInfo info,
|
||||
string status,
|
||||
CivEnum civ,
|
||||
ForceEnum force,
|
||||
int teamId,
|
||||
int maxTeamId,
|
||||
SteamLobbyManager lobby,
|
||||
bool canEdit,
|
||||
string forceNameOverride,
|
||||
Action<int> onForceChanged,
|
||||
Action<int> onTeamChanged)
|
||||
{
|
||||
if (!CheckParam()) return;
|
||||
_forceNameOverride = forceNameOverride;
|
||||
NameText.text = info.Name;
|
||||
var texture = info.Texture;
|
||||
ResetButtons();
|
||||
_lobby = lobby;
|
||||
if(lobby.GetLobbyOwnerId() == info.Id)
|
||||
MultilingualManager.Instance.SetUIText(StatusText,Table.Instance.TextDataAssets.MultiplayRoomOwnerTitle);
|
||||
else
|
||||
MultilingualManager.Instance.SetUIText(StatusText,Table.Instance.TextDataAssets.MultiplayRoomGuestTitle);
|
||||
if (texture != null)
|
||||
{
|
||||
// 使用整个纹理区域创建一个矩形
|
||||
Rect rect = new Rect(0, 0, texture.width, texture.height);
|
||||
// 创建Sprite,轴心点在中心
|
||||
Vector2 pivot = new Vector2(0.5f, 0.5f);
|
||||
|
||||
// Sprite.Create(源纹理, 纹理内的矩形区域, 轴心点)
|
||||
AvatarImage.sprite = Sprite.Create(texture, rect, pivot);
|
||||
AvatarImage.rectTransform.localScale = new Vector3(1, -1, 1);
|
||||
}
|
||||
|
||||
ForcesButton.onClick.RemoveAllListeners();
|
||||
RefreshButton.gameObject.SetActive(false);
|
||||
if (info.Id == lobby.GetSelfMemberId())
|
||||
{
|
||||
ForcesButton?.onClick.AddListener(OnClickForces);
|
||||
RefreshButton.gameObject.SetActive(true);
|
||||
}
|
||||
_forceNameOverride = forceNameOverride;
|
||||
_teamId = Mathf.Max(1, teamId);
|
||||
_maxTeamId = Mathf.Max(1, maxTeamId);
|
||||
_onForceChanged = onForceChanged;
|
||||
_onTeamChanged = onTeamChanged;
|
||||
|
||||
// 踢人按钮:仅"自己是房主 + 该行不是自己"时显示并绑定,否则隐藏
|
||||
if (QuitButton != null)
|
||||
{
|
||||
QuitButton.onClick.RemoveAllListeners();
|
||||
bool selfIsOwner = lobby.GetLobbyOwnerId() == lobby.GetSelfMemberId();
|
||||
bool rowIsSelf = info.Id == lobby.GetSelfMemberId();
|
||||
bool showQuit = selfIsOwner && !rowIsSelf;
|
||||
QuitButton.gameObject.SetActive(showQuit);
|
||||
if (showQuit)
|
||||
{
|
||||
// 闭包捕获本地变量,避免行复用时把上一行的 memberId 带进来
|
||||
var targetMemberId = info.Id;
|
||||
QuitButton.onClick.AddListener(() => lobby.KickMember(targetMemberId));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ForceEnum force = civ switch
|
||||
{
|
||||
CivEnum.Egyptian => ForceEnum.Remilia,
|
||||
CivEnum.French => ForceEnum.Kaguya,
|
||||
CivEnum.Germany => ForceEnum.Kanako,
|
||||
CivEnum.Indian => ForceEnum.Satori,
|
||||
_ => ForceEnum.Kanako
|
||||
};
|
||||
SetAvatarVisible(true);
|
||||
NameText.text = info.Name;
|
||||
SetAvatar(info.Texture);
|
||||
UpdatePlayerInfoView(civ, force);
|
||||
MultilingualManager.Instance.SetUIText(StatusText, status);
|
||||
SetStatus(status);
|
||||
SetTeamText(_teamId);
|
||||
SetEditButtonsVisible(canEdit);
|
||||
BindEditButtons(canEdit);
|
||||
BindQuitButton(info, lobby);
|
||||
}
|
||||
|
||||
public void UpdatePlayerInfoView(CivEnum civ,ForceEnum force)
|
||||
public void SetOpenContent()
|
||||
{
|
||||
if (!CheckParam()) return;
|
||||
ResetButtons();
|
||||
SetAvatarVisible(false);
|
||||
MultilingualManager.Instance.SetUIText(NameText, Table.Instance.TextDataAssets.OutsideMultiplayOpenTitle);
|
||||
StatusText.text = string.Empty;
|
||||
ForcesText.text = string.Empty;
|
||||
SetTeamText(0);
|
||||
SetEditButtonsVisible(false);
|
||||
if (QuitButton != null) QuitButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void SetAIContent(
|
||||
CivEnum civ,
|
||||
ForceEnum force,
|
||||
int teamId,
|
||||
int maxTeamId,
|
||||
bool canEdit,
|
||||
string forceNameOverride,
|
||||
Action<int> onForceChanged,
|
||||
Action<int> onTeamChanged)
|
||||
{
|
||||
if (!CheckParam()) return;
|
||||
ResetButtons();
|
||||
_forceNameOverride = forceNameOverride;
|
||||
_teamId = Mathf.Max(1, teamId);
|
||||
_maxTeamId = Mathf.Max(1, maxTeamId);
|
||||
_onForceChanged = onForceChanged;
|
||||
_onTeamChanged = onTeamChanged;
|
||||
|
||||
SetAvatarVisible(false);
|
||||
MultilingualManager.Instance.SetUIText(NameText, Table.Instance.TextDataAssets.OutsideMultiplayAIPlayerTitle);
|
||||
StatusText.text = string.Empty;
|
||||
UpdatePlayerInfoView(civ, force);
|
||||
SetTeamText(_teamId);
|
||||
SetEditButtonsVisible(canEdit);
|
||||
BindEditButtons(canEdit);
|
||||
if (QuitButton != null) QuitButton.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
public void UpdatePlayerInfoView(CivEnum civ, ForceEnum force)
|
||||
{
|
||||
_civ = civ;
|
||||
_force = force;
|
||||
@ -102,19 +135,11 @@ public class UIOutsideMultiplayMemberRowMono : MonoBehaviour
|
||||
if (!string.IsNullOrEmpty(_forceNameOverride))
|
||||
ForcesText.text = _forceNameOverride;
|
||||
else
|
||||
MultilingualManager.Instance.SetUIText(ForcesText,playerInfo.ForceName);
|
||||
LeaderImage.sprite = playerInfo.LeaderIllustration;
|
||||
//MultilingualManager.Instance.SetUIText(CivButtonText,playerInfo.CivName);
|
||||
//设置按钮颜色(和阵营一致)
|
||||
//if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(_civ, _force, out var info)) return;
|
||||
//var civButtonSprite = CivButton?.GetComponent<Image>();
|
||||
var forceButtonSprite = ForcesButton?.GetComponent<Image>();
|
||||
//if (civButtonSprite != null) civButtonSprite.color = info.Color;
|
||||
//if (forceButtonSprite != null) forceButtonSprite.color = info.Color;
|
||||
|
||||
MultilingualManager.Instance.SetUIText(ForcesText, playerInfo.ForceName);
|
||||
if (LeaderImage != null) LeaderImage.sprite = playerInfo.LeaderIllustration;
|
||||
}
|
||||
|
||||
public bool UpdatePlayerInfoData(CivEnum civ,ForceEnum force)
|
||||
public bool UpdatePlayerInfoData(CivEnum civ, ForceEnum force)
|
||||
{
|
||||
var accepted = Main.Instance.MapConfig.UpdateSelfMemberCiv(
|
||||
Table.Instance.TransCivEnumToCivId(civ),
|
||||
@ -125,38 +150,131 @@ public class UIOutsideMultiplayMemberRowMono : MonoBehaviour
|
||||
|
||||
public void OnClickForces()
|
||||
{
|
||||
// 切换阵营时清掉旧的覆盖文本,避免在服务端 UpdateUIOutsideMultiplayRoomSetting 回流前
|
||||
// 本地 UI 残留上一阵营的 "xx nP" 字样;最终 nP 是否需要由 View 重画时统一计算。
|
||||
_forceNameOverride = null;
|
||||
if (_civ == CivEnum.Egyptian)
|
||||
{
|
||||
if (UpdatePlayerInfoData(CivEnum.French,ForceEnum.Kaguya))
|
||||
UpdatePlayerInfoView(CivEnum.French,ForceEnum.Kaguya);
|
||||
}
|
||||
else if (_civ == CivEnum.French)
|
||||
{
|
||||
if (UpdatePlayerInfoData(CivEnum.Germany,ForceEnum.Kanako))
|
||||
UpdatePlayerInfoView(CivEnum.Germany,ForceEnum.Kanako);
|
||||
}
|
||||
else if (_civ == CivEnum.Germany)
|
||||
{
|
||||
if (UpdatePlayerInfoData(CivEnum.Indian,ForceEnum.Satori))
|
||||
UpdatePlayerInfoView(CivEnum.Indian,ForceEnum.Satori);
|
||||
}
|
||||
else if (_civ == CivEnum.Indian)
|
||||
{
|
||||
if (UpdatePlayerInfoData(CivEnum.Egyptian,ForceEnum.Remilia))
|
||||
UpdatePlayerInfoView(CivEnum.Egyptian,ForceEnum.Remilia);
|
||||
}
|
||||
}
|
||||
void Start()
|
||||
{
|
||||
|
||||
ChangeForce(1);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
private void ResetButtons()
|
||||
{
|
||||
|
||||
ForcesButton?.onClick.RemoveAllListeners();
|
||||
RefreshButton?.onClick.RemoveAllListeners();
|
||||
QuitButton?.onClick.RemoveAllListeners();
|
||||
ForceLeftButton?.onClick.RemoveAllListeners();
|
||||
ForceRightButton?.onClick.RemoveAllListeners();
|
||||
TeamLeftButton?.onClick.RemoveAllListeners();
|
||||
TeamRightButton?.onClick.RemoveAllListeners();
|
||||
}
|
||||
|
||||
private void SetAvatar(Texture2D texture)
|
||||
{
|
||||
if (AvatarImage == null || texture == null) return;
|
||||
var rect = new Rect(0, 0, texture.width, texture.height);
|
||||
var pivot = new Vector2(0.5f, 0.5f);
|
||||
AvatarImage.sprite = Sprite.Create(texture, rect, pivot);
|
||||
AvatarImage.rectTransform.localScale = new Vector3(1, -1, 1);
|
||||
}
|
||||
|
||||
private void SetAvatarVisible(bool visible)
|
||||
{
|
||||
if (AvatarImage != null) AvatarImage.gameObject.SetActive(visible);
|
||||
if (LeaderImage != null) LeaderImage.gameObject.SetActive(visible);
|
||||
}
|
||||
|
||||
private void SetStatus(string status)
|
||||
{
|
||||
if (string.IsNullOrEmpty(status))
|
||||
{
|
||||
StatusText.text = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
MultilingualManager.Instance.SetUIText(StatusText, status);
|
||||
}
|
||||
|
||||
private void SetTeamText(int teamId)
|
||||
{
|
||||
if (TeamText == null) return;
|
||||
if (teamId <= 0)
|
||||
{
|
||||
TeamText.text = string.Empty;
|
||||
return;
|
||||
}
|
||||
|
||||
var title = MultilingualManager.Instance.GetMultilingualText(Table.Instance.TextDataAssets.OutsideMultiplayTeamTitle);
|
||||
TeamText.text = $"{title}{teamId}";
|
||||
}
|
||||
|
||||
private void SetEditButtonsVisible(bool visible)
|
||||
{
|
||||
if (ForcesButton != null) ForcesButton.gameObject.SetActive(visible);
|
||||
if (RefreshButton != null && RefreshButton != ForcesButton) RefreshButton.gameObject.SetActive(visible);
|
||||
if (ForceLeftButton != null) ForceLeftButton.gameObject.SetActive(visible);
|
||||
if (ForceRightButton != null) ForceRightButton.gameObject.SetActive(visible);
|
||||
if (TeamLeftButton != null) TeamLeftButton.gameObject.SetActive(visible);
|
||||
if (TeamRightButton != null) TeamRightButton.gameObject.SetActive(visible);
|
||||
if (TeamText != null) TeamText.gameObject.SetActive(visible || !string.IsNullOrEmpty(TeamText.text));
|
||||
if (ForcesText != null) ForcesText.gameObject.SetActive(visible || !string.IsNullOrEmpty(ForcesText.text));
|
||||
}
|
||||
|
||||
private void BindEditButtons(bool canEdit)
|
||||
{
|
||||
if (!canEdit) return;
|
||||
if (ForceLeftButton != null) ForceLeftButton.onClick.AddListener(() => ChangeForce(-1));
|
||||
if (ForceRightButton != null) ForceRightButton.onClick.AddListener(() => ChangeForce(1));
|
||||
if (ForcesButton != null && ForceLeftButton == null && ForceRightButton == null) ForcesButton.onClick.AddListener(OnClickForces);
|
||||
if (TeamLeftButton != null) TeamLeftButton.onClick.AddListener(() => ChangeTeam(-1));
|
||||
if (TeamRightButton != null) TeamRightButton.onClick.AddListener(() => ChangeTeam(1));
|
||||
}
|
||||
|
||||
private void BindQuitButton(MemberInfo info, SteamLobbyManager lobby)
|
||||
{
|
||||
if (QuitButton == null) return;
|
||||
bool selfIsOwner = lobby.GetLobbyOwnerId() == lobby.GetSelfMemberId();
|
||||
bool rowIsSelf = info.Id == lobby.GetSelfMemberId();
|
||||
bool showQuit = selfIsOwner && !rowIsSelf;
|
||||
QuitButton.gameObject.SetActive(showQuit);
|
||||
if (!showQuit) return;
|
||||
var targetMemberId = info.Id;
|
||||
QuitButton.onClick.AddListener(() => lobby.KickMember(targetMemberId));
|
||||
}
|
||||
|
||||
private void ChangeForce(int direction)
|
||||
{
|
||||
_forceNameOverride = null;
|
||||
int index = GetForceIndex(_civ, _force);
|
||||
index = (index + direction + ForceOptions.Length) % ForceOptions.Length;
|
||||
var next = ForceOptions[index];
|
||||
_onForceChanged?.Invoke(direction);
|
||||
UpdatePlayerInfoView(next.Civ, next.Force);
|
||||
}
|
||||
|
||||
private void ChangeTeam(int direction)
|
||||
{
|
||||
_teamId += direction;
|
||||
if (_teamId < 1) _teamId = _maxTeamId;
|
||||
if (_teamId > _maxTeamId) _teamId = 1;
|
||||
_onTeamChanged?.Invoke(direction);
|
||||
SetTeamText(_teamId);
|
||||
}
|
||||
|
||||
private static int GetForceIndex(CivEnum civ, ForceEnum force)
|
||||
{
|
||||
for (int i = 0; i < ForceOptions.Length; i++)
|
||||
{
|
||||
if (ForceOptions[i].Civ == civ && ForceOptions[i].Force == force) return i;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static ForceEnum GetDefaultForce(CivEnum civ)
|
||||
{
|
||||
return civ switch
|
||||
{
|
||||
CivEnum.Egyptian => ForceEnum.Remilia,
|
||||
CivEnum.French => ForceEnum.Kaguya,
|
||||
CivEnum.Germany => ForceEnum.Kanako,
|
||||
CivEnum.Indian => ForceEnum.Satori,
|
||||
_ => ForceEnum.Kanako
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,8 @@ namespace TH1_UI.View.Outside
|
||||
public Button CreateRoomButton;
|
||||
public Button LeaveRoomButton;
|
||||
public Button StartGameButton;
|
||||
public Button ReadyButton;
|
||||
public Button CancelReadyButton;
|
||||
public Toggle ResumeToggle;
|
||||
|
||||
[Header("相关提示对象")]
|
||||
@ -61,6 +63,7 @@ namespace TH1_UI.View.Outside
|
||||
public GameObject FriendList;
|
||||
|
||||
public GameObject MemberRowPrefab;
|
||||
public GameObject MemberLineRowPrefab;
|
||||
public GameObject MemberList;
|
||||
|
||||
[Header("联机大厅")]
|
||||
@ -82,9 +85,13 @@ namespace TH1_UI.View.Outside
|
||||
|
||||
private List<UIOutsideMultiplayFriendRowMono> _friendRowList;
|
||||
private List<UIOutsideMultiplayMemberRowMono> _memberRowList;
|
||||
private List<GameObject> _memberLineRowList;
|
||||
private List<RoomMemberRowData> _roomMemberRows;
|
||||
private List<UIOutsideMultiplayLobbyRowMono> _lobbyRowList;
|
||||
|
||||
|
||||
private SteamLobbyManager _lobby;
|
||||
private int _roomSeatCount = 4;
|
||||
private int _openMemberRowCount = 0;
|
||||
//关闭时执行的委托
|
||||
public ViDelegateAssisstant.Dele OnBtnCloseClick;
|
||||
|
||||
@ -101,6 +108,30 @@ namespace TH1_UI.View.Outside
|
||||
private bool _isSearchingLobby = false;
|
||||
private bool _hasLobbySearchResult = false;
|
||||
|
||||
private enum RoomMemberRowType
|
||||
{
|
||||
Human,
|
||||
Open,
|
||||
Line,
|
||||
AI
|
||||
}
|
||||
|
||||
private class RoomMemberRowData
|
||||
{
|
||||
public RoomMemberRowType Type;
|
||||
public MemberCiv MemberCiv;
|
||||
public MemberInfo MemberInfo;
|
||||
public int SlotIndex;
|
||||
}
|
||||
|
||||
private static readonly (CivEnum Civ, ForceEnum Force)[] RoomForceOptions =
|
||||
{
|
||||
(CivEnum.Egyptian, ForceEnum.Remilia),
|
||||
(CivEnum.French, ForceEnum.Kaguya),
|
||||
(CivEnum.Germany, ForceEnum.Kanako),
|
||||
(CivEnum.Indian, ForceEnum.Satori),
|
||||
};
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
base.OnInit();
|
||||
@ -139,8 +170,24 @@ namespace TH1_UI.View.Outside
|
||||
LeaveRoomButton.onClick.RemoveAllListeners();
|
||||
LeaveRoomButton.onClick.AddListener(LeaveRoom);
|
||||
|
||||
if (ReadyButton != null)
|
||||
{
|
||||
SetButtonText(ReadyButton, MultilingualManager.Instance.GetMultilingualText(Table.Instance.TextDataAssets.OutsideMultiplayReadyTitle));
|
||||
ReadyButton.onClick.RemoveAllListeners();
|
||||
ReadyButton.onClick.AddListener(() => SetSelfReadyState(true));
|
||||
}
|
||||
|
||||
if (CancelReadyButton != null)
|
||||
{
|
||||
SetButtonText(CancelReadyButton, "取消准备");
|
||||
CancelReadyButton.onClick.RemoveAllListeners();
|
||||
CancelReadyButton.onClick.AddListener(() => SetSelfReadyState(false));
|
||||
}
|
||||
|
||||
_friendRowList = new List<UIOutsideMultiplayFriendRowMono>();
|
||||
_memberRowList = new List<UIOutsideMultiplayMemberRowMono>();
|
||||
_memberLineRowList = new List<GameObject>();
|
||||
_roomMemberRows = new List<RoomMemberRowData>();
|
||||
_lobbyRowList = new List<UIOutsideMultiplayLobbyRowMono>();
|
||||
_lobby = LobbyManager.Instance.Lobby as SteamLobbyManager;
|
||||
|
||||
@ -292,7 +339,6 @@ namespace TH1_UI.View.Outside
|
||||
|
||||
private void SetRoomInfoMember()
|
||||
{
|
||||
//显示房间区域,隐藏联机大厅
|
||||
RoomArea?.SetActive(true);
|
||||
HallArea?.SetActive(false);
|
||||
|
||||
@ -304,108 +350,352 @@ namespace TH1_UI.View.Outside
|
||||
|
||||
CreateRoomButton.gameObject.SetActive(false);
|
||||
NoRoomHint.gameObject.SetActive(false);
|
||||
|
||||
|
||||
|
||||
var memberList = _lobby.GetAllMemberInfo();
|
||||
Main.Instance.MapConfig.EnsurePlayerSlots(NetMode.Multi);
|
||||
ReconcileRoomMembers();
|
||||
var multiCivs = Main.Instance.MapConfig.MultiCivs;
|
||||
// 按 MultiCivs 顺序渲染(与游戏内 PlayerDataList 中真人玩家顺序一致),
|
||||
// 这样大厅显示的全局位置与进入游戏后的 nP 编号对齐。
|
||||
// 不在 memberList 中的 MultiCiv 视为离线,跳过。
|
||||
var orderedMemberCivs = new List<MemberCiv>();
|
||||
foreach (var mc in multiCivs)
|
||||
BuildRoomMemberRows(memberList, multiCivs);
|
||||
RenderRoomMemberRows(multiCivs);
|
||||
RefreshRoomButtons();
|
||||
}
|
||||
|
||||
private void BuildRoomMemberRows(Dictionary<ulong, MemberInfo> memberList, List<MemberCiv> multiCivs)
|
||||
{
|
||||
_roomMemberRows.Clear();
|
||||
var humanRows = new List<RoomMemberRowData>();
|
||||
var emptyAiRows = new List<RoomMemberRowData>();
|
||||
|
||||
for (int i = 0; i < multiCivs.Count; i++)
|
||||
{
|
||||
if (memberList.ContainsKey(mc.MemberId)) orderedMemberCivs.Add(mc);
|
||||
var mc = multiCivs[i];
|
||||
if (mc == null) continue;
|
||||
if (mc.MemberId != 0 && memberList.TryGetValue(mc.MemberId, out var info))
|
||||
{
|
||||
humanRows.Add(new RoomMemberRowData { Type = RoomMemberRowType.Human, MemberCiv = mc, MemberInfo = info, SlotIndex = i });
|
||||
}
|
||||
else if (mc.MemberId == 0 && mc.IsAI)
|
||||
{
|
||||
emptyAiRows.Add(new RoomMemberRowData { Type = RoomMemberRowType.AI, MemberCiv = mc, SlotIndex = i });
|
||||
}
|
||||
}
|
||||
|
||||
//如果目前的list内对象不够,补足
|
||||
while (_memberRowList.Count < orderedMemberCivs.Count)
|
||||
{
|
||||
var item = Instantiate(MemberRowPrefab,MemberList.transform);
|
||||
//item.transform.localPosition = Vector3.zero;
|
||||
var cpn = item.GetComponent<UIOutsideMultiplayMemberRowMono>();
|
||||
_memberRowList.Add(cpn);
|
||||
}
|
||||
for (int i = 0; i < _memberRowList.Count; i++)
|
||||
_memberRowList[i].gameObject.SetActive(i < orderedMemberCivs.Count);
|
||||
int totalPlayerCount = Mathf.Max(0, (int)Main.Instance.MapConfig.PlayerCount);
|
||||
int roomSeatCount = Mathf.Clamp(_roomSeatCount, humanRows.Count, totalPlayerCount);
|
||||
_openMemberRowCount = Mathf.Max(0, roomSeatCount - humanRows.Count);
|
||||
int aiCount = Mathf.Max(0, totalPlayerCount - roomSeatCount);
|
||||
|
||||
// 统计每个"显示用 (CivEnum,ForceEnum)"在成员中的出现次数;
|
||||
// 仅当 ≥2 时该位置的成员需要显示 nP 后缀。
|
||||
// 注意:CivId==0 表示玩家尚未主动选择阵营,但 TransCivIdToCivEnum(0) 会兜底到默认阵营,
|
||||
// 显示上仍然会落到一个真实阵营(通常是埃及/Remilia),因此必须按"显示阵营"统计才能与玩家
|
||||
// 在 UI 上看到的重复情况一致——直接用 raw CivId 跳过 0 会漏掉"两个人都没选、显示同一默认阵营"的场景。
|
||||
_roomMemberRows.AddRange(humanRows);
|
||||
for (int i = 0; i < _openMemberRowCount; i++)
|
||||
_roomMemberRows.Add(new RoomMemberRowData { Type = RoomMemberRowType.Open });
|
||||
|
||||
_roomMemberRows.Add(new RoomMemberRowData { Type = RoomMemberRowType.Line });
|
||||
int aiStart = Mathf.Max(0, emptyAiRows.Count - aiCount);
|
||||
for (int i = aiStart; i < emptyAiRows.Count; i++)
|
||||
_roomMemberRows.Add(emptyAiRows[i]);
|
||||
}
|
||||
|
||||
private void RenderRoomMemberRows(List<MemberCiv> multiCivs)
|
||||
{
|
||||
var sameCountDict = BuildForceSameCountDict(_roomMemberRows);
|
||||
int memberRowIndex = 0;
|
||||
int lineRowIndex = 0;
|
||||
for (int i = 0; i < _roomMemberRows.Count; i++)
|
||||
{
|
||||
var row = _roomMemberRows[i];
|
||||
if (row.Type == RoomMemberRowType.Line)
|
||||
{
|
||||
var line = GetLineRow(lineRowIndex++);
|
||||
if (line != null) line.transform.SetSiblingIndex(i);
|
||||
continue;
|
||||
}
|
||||
|
||||
var memberRow = GetMemberRow(memberRowIndex++);
|
||||
if (memberRow == null) continue;
|
||||
memberRow.transform.SetSiblingIndex(i);
|
||||
RenderMemberRow(memberRow, row, multiCivs, sameCountDict);
|
||||
}
|
||||
|
||||
for (int i = memberRowIndex; i < _memberRowList.Count; i++)
|
||||
_memberRowList[i].gameObject.SetActive(false);
|
||||
for (int i = lineRowIndex; i < _memberLineRowList.Count; i++)
|
||||
_memberLineRowList[i].SetActive(false);
|
||||
}
|
||||
|
||||
private Dictionary<(CivEnum, ForceEnum), int> BuildForceSameCountDict(List<RoomMemberRowData> rows)
|
||||
{
|
||||
var sameCountDict = new Dictionary<(CivEnum, ForceEnum), int>();
|
||||
foreach (var mc in orderedMemberCivs)
|
||||
foreach (var row in rows)
|
||||
{
|
||||
var dispCiv = Table.Instance.TransCivIdToCivEnum(mc.CivId);
|
||||
var dispForce = Table.Instance.TransForceIdToForceEnum(mc.ForceId);
|
||||
if (row.MemberCiv == null || row.Type == RoomMemberRowType.Open || row.Type == RoomMemberRowType.Line) continue;
|
||||
var dispCiv = Table.Instance.TransCivIdToCivEnum(row.MemberCiv.CivId);
|
||||
var dispForce = Table.Instance.TransForceIdToForceEnum(row.MemberCiv.ForceId);
|
||||
var key = (dispCiv, dispForce);
|
||||
sameCountDict.TryGetValue(key, out var prevCnt);
|
||||
sameCountDict[key] = prevCnt + 1;
|
||||
}
|
||||
|
||||
//设置真人玩家行
|
||||
for (int idx = 0; idx < orderedMemberCivs.Count; idx++)
|
||||
return sameCountDict;
|
||||
}
|
||||
|
||||
private void RenderMemberRow(UIOutsideMultiplayMemberRowMono memberRow, RoomMemberRowData row, List<MemberCiv> multiCivs, Dictionary<(CivEnum, ForceEnum), int> sameCountDict)
|
||||
{
|
||||
memberRow.gameObject.SetActive(true);
|
||||
if (row.Type == RoomMemberRowType.Open)
|
||||
{
|
||||
var mc = orderedMemberCivs[idx];
|
||||
var info = memberList[mc.MemberId];
|
||||
var status = _lobby.GetLobbyOwnerId() == mc.MemberId
|
||||
? Table.Instance.TextDataAssets.OutsideMultiplayTitleHost
|
||||
: Table.Instance.TextDataAssets.OutsideMultiplayTitleGuest;
|
||||
var civ = Table.Instance.TransCivIdToCivEnum(mc.CivId);
|
||||
var force = Table.Instance.TransForceIdToForceEnum(mc.ForceId);
|
||||
|
||||
string forceNameOverride = null;
|
||||
if (sameCountDict.TryGetValue((civ, force), out var sameCnt) && sameCnt >= 2)
|
||||
{
|
||||
if (Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out var pi))
|
||||
{
|
||||
var raw = MultilingualManager.Instance.GetMultilingualTextSafe(pi.ForceName);
|
||||
// 全局位置 = 该成员在 PlayerDataList 中的 1-based index = MultiCivs 中的 1-based index
|
||||
int globalIdx = multiCivs.IndexOf(mc) + 1;
|
||||
forceNameOverride = $"{raw} {globalIdx}P";
|
||||
}
|
||||
}
|
||||
|
||||
_memberRowList[idx].SetContent(info, status, civ, _lobby, forceNameOverride);
|
||||
memberRow.SetOpenContent();
|
||||
return;
|
||||
}
|
||||
|
||||
//Step #3 设置 是否继续上一个存档的toggle
|
||||
|
||||
var mc = row.MemberCiv;
|
||||
var civ = Table.Instance.TransCivIdToCivEnum(mc.CivId);
|
||||
var force = Table.Instance.TransForceIdToForceEnum(mc.ForceId);
|
||||
var teamId = GetValidTeamId(mc);
|
||||
var forceNameOverride = GetForceNameOverride(mc, civ, force, multiCivs, sameCountDict);
|
||||
int maxTeamId = Mathf.Max(1, (int)Main.Instance.MapConfig.PlayerCount);
|
||||
if (row.Type == RoomMemberRowType.AI)
|
||||
{
|
||||
memberRow.SetAIContent(civ, force, teamId, maxTeamId, _lobby.IsLobbyOwner(), forceNameOverride,
|
||||
direction => OnAIRowForceChanged(row.SlotIndex, direction),
|
||||
direction => OnAIRowTeamChanged(row.SlotIndex, direction));
|
||||
return;
|
||||
}
|
||||
|
||||
var status = GetHumanStatus(mc);
|
||||
bool canEditHuman = mc.MemberId == _lobby.GetSelfMemberId();
|
||||
memberRow.SetHumanContent(row.MemberInfo, status, civ, force, teamId, maxTeamId, _lobby, canEditHuman, forceNameOverride,
|
||||
direction => OnHumanRowForceChanged(mc.Index, direction),
|
||||
direction => OnHumanRowTeamChanged(mc.Index, direction));
|
||||
}
|
||||
|
||||
private UIOutsideMultiplayMemberRowMono GetMemberRow(int index)
|
||||
{
|
||||
while (_memberRowList.Count <= index)
|
||||
{
|
||||
var item = Instantiate(MemberRowPrefab, MemberList.transform);
|
||||
var cpn = item.GetComponent<UIOutsideMultiplayMemberRowMono>();
|
||||
_memberRowList.Add(cpn);
|
||||
}
|
||||
|
||||
return _memberRowList[index];
|
||||
}
|
||||
|
||||
private GameObject GetLineRow(int index)
|
||||
{
|
||||
if (MemberLineRowPrefab == null) return null;
|
||||
while (_memberLineRowList.Count <= index)
|
||||
_memberLineRowList.Add(Instantiate(MemberLineRowPrefab, MemberList.transform));
|
||||
|
||||
var line = _memberLineRowList[index];
|
||||
line.SetActive(true);
|
||||
return line;
|
||||
}
|
||||
|
||||
private string GetHumanStatus(MemberCiv mc)
|
||||
{
|
||||
if (mc.MemberId == _lobby.GetLobbyOwnerId()) return Table.Instance.TextDataAssets.OutsideMultiplayTitleHost;
|
||||
return mc.IsReady ? Table.Instance.TextDataAssets.OutsideMultiplayReadyTitle : null;
|
||||
}
|
||||
|
||||
private string GetForceNameOverride(MemberCiv mc, CivEnum civ, ForceEnum force, List<MemberCiv> multiCivs, Dictionary<(CivEnum, ForceEnum), int> sameCountDict)
|
||||
{
|
||||
if (!sameCountDict.TryGetValue((civ, force), out var sameCnt) || sameCnt < 2) return null;
|
||||
if (!Table.Instance.PlayerDataAssets.GetPlayerInfo(civ, force, out var pi)) return null;
|
||||
var raw = MultilingualManager.Instance.GetMultilingualTextSafe(pi.ForceName);
|
||||
int globalIdx = multiCivs.IndexOf(mc) + 1;
|
||||
return $"{raw} {globalIdx}P";
|
||||
}
|
||||
|
||||
private void RefreshRoomButtons()
|
||||
{
|
||||
ResumeToggle.SetIsOnWithoutNotify(false);
|
||||
ResumeToggle.interactable = false;
|
||||
if (_lobby.IsLobbyOwner())
|
||||
{
|
||||
if(Main.Instance.HasMultiArchive())
|
||||
ResumeToggle.interactable = true;
|
||||
}
|
||||
|
||||
//Step #4 设置开始按钮
|
||||
ResumeToggle.interactable = _lobby.IsLobbyOwner() && Main.Instance.HasMultiArchive();
|
||||
StartGameButton.onClick.RemoveAllListeners();
|
||||
StartGameButton.interactable = false;
|
||||
StartGameButton.gameObject.SetActive(_lobby.IsLobbyOwner());
|
||||
var img = StartGameButton.transform.Find("Color")?.GetComponent<Image>();
|
||||
var c = (img != null)?img.color : Color.white;
|
||||
var c = img != null ? img.color : Color.white;
|
||||
c.a = 0.5f;
|
||||
if (img != null) img.color = c;
|
||||
if(_lobby.IsLobbyOwner())
|
||||
if (_lobby.IsLobbyOwner())
|
||||
{
|
||||
var cpn = StartGameButton.GetComponent<ButtonHoverEffect>();
|
||||
if(cpn != null) cpn.enabled = true;
|
||||
if (cpn != null) cpn.enabled = true;
|
||||
var simg = StartGameButton.GetComponent<Image>();
|
||||
if (simg != null) simg.color = Color.white;
|
||||
StartGameButton.interactable = true;
|
||||
c.a = 1f;
|
||||
if (img != null) img.color = c;
|
||||
StartGameButton.onClick.AddListener(StartGame);
|
||||
SetReadyButtonsVisible(false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var cpn = StartGameButton.GetComponent<ButtonHoverEffect>();
|
||||
if(cpn != null) cpn.enabled = false;
|
||||
if (cpn != null) cpn.enabled = false;
|
||||
var simg = StartGameButton.GetComponent<Image>();
|
||||
if (simg != null) simg.color = new Color(0.5f,0.5f,0.5f,0.5f);
|
||||
|
||||
if (simg != null) simg.color = new Color(0.5f, 0.5f, 0.5f, 0.5f);
|
||||
bool isReady = Main.Instance.MapConfig.IsMemberReady(_lobby.GetSelfMemberId());
|
||||
SetReadyButtonsVisible(!isReady, isReady);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void SetButtonText(Button button, string text)
|
||||
{
|
||||
var label = button.GetComponentInChildren<TextMeshProUGUI>(true);
|
||||
if (label != null) label.text = text;
|
||||
}
|
||||
|
||||
private void SetReadyButtonsVisible(bool showReady, bool showCancelReady)
|
||||
{
|
||||
if (ReadyButton != null) ReadyButton.gameObject.SetActive(showReady);
|
||||
if (CancelReadyButton != null) CancelReadyButton.gameObject.SetActive(showCancelReady);
|
||||
}
|
||||
|
||||
private void SetSelfReadyState(bool isReady)
|
||||
{
|
||||
if (Main.Instance.MapConfig.SetSelfReady(isReady))
|
||||
{
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
RefreshRoomInfo();
|
||||
}
|
||||
}
|
||||
|
||||
private void ReconcileRoomMembers()
|
||||
{
|
||||
Main.Instance.MapConfig.SetPlayerCount(Main.Instance.MapConfig.PlayerCount, NetMode.Multi);
|
||||
var multiCivs = Main.Instance.MapConfig.MultiCivs;
|
||||
int totalPlayerCount = Mathf.Max(0, (int)Main.Instance.MapConfig.PlayerCount);
|
||||
_roomSeatCount = Mathf.Clamp(_roomSeatCount, _lobby.GetMemberCount(), totalPlayerCount);
|
||||
int lobbyMemberLimit = _lobby.GetMemberLimit();
|
||||
if (lobbyMemberLimit > 0) _roomSeatCount = Mathf.Clamp(lobbyMemberLimit, _lobby.GetMemberCount(), totalPlayerCount);
|
||||
var usedCivs = new HashSet<uint>();
|
||||
var usedTeams = new HashSet<int>();
|
||||
for (int i = 0; i < multiCivs.Count; i++)
|
||||
{
|
||||
var mc = multiCivs[i];
|
||||
if (mc == null) continue;
|
||||
if (mc.TeamId <= 0 || mc.TeamId > totalPlayerCount) mc.TeamId = PickDefaultTeamId(i, totalPlayerCount, usedTeams);
|
||||
if (!mc.IsCivFixed)
|
||||
{
|
||||
var civId = PickDefaultCivId(i, usedCivs);
|
||||
mc.CivId = civId;
|
||||
mc.ForceId = civId;
|
||||
mc.IsCivFixed = true;
|
||||
}
|
||||
usedTeams.Add(mc.TeamId);
|
||||
usedCivs.Add(mc.CivId);
|
||||
}
|
||||
}
|
||||
|
||||
private int GetValidTeamId(MemberCiv mc)
|
||||
{
|
||||
int maxTeamId = Mathf.Max(1, (int)Main.Instance.MapConfig.PlayerCount);
|
||||
if (mc.TeamId >= 1 && mc.TeamId <= maxTeamId) return mc.TeamId;
|
||||
return Mathf.Clamp(mc.Index + 1, 1, maxTeamId);
|
||||
}
|
||||
|
||||
private int PickDefaultTeamId(int preferredIndex, int maxTeamId, HashSet<int> usedTeams)
|
||||
{
|
||||
maxTeamId = Mathf.Max(1, maxTeamId);
|
||||
for (int offset = 0; offset < maxTeamId; offset++)
|
||||
{
|
||||
int teamId = (preferredIndex + offset) % maxTeamId + 1;
|
||||
if (!usedTeams.Contains(teamId)) return teamId;
|
||||
}
|
||||
|
||||
return preferredIndex % maxTeamId + 1;
|
||||
}
|
||||
|
||||
private uint PickDefaultCivId(int preferredIndex, HashSet<uint> usedCivs)
|
||||
{
|
||||
const int defaultCivCount = 17;
|
||||
for (int offset = 0; offset < defaultCivCount; offset++)
|
||||
{
|
||||
var civId = (uint)((preferredIndex + offset) % defaultCivCount);
|
||||
if (!usedCivs.Contains(civId)) return civId;
|
||||
}
|
||||
|
||||
return (uint)preferredIndex;
|
||||
}
|
||||
|
||||
private void OnHumanRowForceChanged(int slotIndex, int direction)
|
||||
{
|
||||
var slot = Main.Instance.MapConfig.GetPlayerSlot(slotIndex, NetMode.Multi);
|
||||
if (slot == null) return;
|
||||
var next = GetNextForce(slot.CivId, slot.ForceId, direction);
|
||||
if (Main.Instance.MapConfig.UpdateSelfMemberConfig(slotIndex,
|
||||
Table.Instance.TransCivEnumToCivId(next.Civ),
|
||||
Table.Instance.TransForceEnumToForceId(next.Force),
|
||||
GetValidTeamId(slot)))
|
||||
{
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnHumanRowTeamChanged(int slotIndex, int direction)
|
||||
{
|
||||
var slot = Main.Instance.MapConfig.GetPlayerSlot(slotIndex, NetMode.Multi);
|
||||
if (slot == null) return;
|
||||
int nextTeamId = GetNextTeamId(GetValidTeamId(slot), direction);
|
||||
if (Main.Instance.MapConfig.UpdateSelfMemberTeam(nextTeamId))
|
||||
{
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAIRowForceChanged(int slotIndex, int direction)
|
||||
{
|
||||
if (!_lobby.IsLobbyOwner()) return;
|
||||
var slot = Main.Instance.MapConfig.GetPlayerSlot(slotIndex, NetMode.Multi);
|
||||
if (slot == null) return;
|
||||
var next = GetNextForce(slot.CivId, slot.ForceId, direction);
|
||||
if (Main.Instance.MapConfig.SetPlayerSlotCiv(slotIndex,
|
||||
Table.Instance.TransCivEnumToCivId(next.Civ),
|
||||
Table.Instance.TransForceEnumToForceId(next.Force)))
|
||||
{
|
||||
Main.Instance.MapConfig.ResetGuestReadyStates();
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAIRowTeamChanged(int slotIndex, int direction)
|
||||
{
|
||||
if (!_lobby.IsLobbyOwner()) return;
|
||||
var slot = Main.Instance.MapConfig.GetPlayerSlot(slotIndex, NetMode.Multi);
|
||||
if (slot == null) return;
|
||||
int nextTeamId = GetNextTeamId(GetValidTeamId(slot), direction);
|
||||
if (Main.Instance.MapConfig.SetPlayerSlotTeam(slotIndex, nextTeamId))
|
||||
{
|
||||
Main.Instance.MapConfig.ResetGuestReadyStates();
|
||||
Main.Instance.MapConfig.CheckMapConfigChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private int GetNextTeamId(int teamId, int direction)
|
||||
{
|
||||
int maxTeamId = Mathf.Max(1, (int)Main.Instance.MapConfig.PlayerCount);
|
||||
teamId += direction;
|
||||
if (teamId < 1) return maxTeamId;
|
||||
if (teamId > maxTeamId) return 1;
|
||||
return teamId;
|
||||
}
|
||||
|
||||
private (CivEnum Civ, ForceEnum Force) GetNextForce(uint civId, uint forceId, int direction)
|
||||
{
|
||||
var civ = Table.Instance.TransCivIdToCivEnum(civId);
|
||||
var force = Table.Instance.TransForceIdToForceEnum(forceId);
|
||||
int index = 0;
|
||||
for (int i = 0; i < RoomForceOptions.Length; i++)
|
||||
{
|
||||
if (RoomForceOptions[i].Civ == civ && RoomForceOptions[i].Force == force)
|
||||
{
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
index = (index + direction + RoomForceOptions.Length) % RoomForceOptions.Length;
|
||||
return RoomForceOptions[index];
|
||||
}
|
||||
|
||||
private void SetRoomInfoSetting()
|
||||
@ -527,6 +817,7 @@ namespace TH1_UI.View.Outside
|
||||
public void SetNoRoom()
|
||||
{
|
||||
StartGameButton.gameObject.SetActive(false);
|
||||
SetReadyButtonsVisible(false, false);
|
||||
LeaveRoomButton.gameObject.SetActive(false);
|
||||
RoomSettingArea.gameObject.SetActive(false);
|
||||
RoomMemberArea.gameObject.SetActive(false);
|
||||
@ -618,7 +909,8 @@ namespace TH1_UI.View.Outside
|
||||
|
||||
//获取房间类型:0=公开,1=私密
|
||||
bool isPublic = RoomType?.SelectedIndex == 0;
|
||||
_lobby.CreateLobby(4, isPublic);
|
||||
_roomSeatCount = Mathf.Max(1, (int)Main.Instance.MapConfig.PlayerCount);
|
||||
_lobby.CreateLobby(_roomSeatCount, isPublic);
|
||||
}
|
||||
|
||||
public void LeaveRoom()
|
||||
@ -640,6 +932,14 @@ namespace TH1_UI.View.Outside
|
||||
return;
|
||||
|
||||
SetMapConfig();
|
||||
ReconcileRoomMembers();
|
||||
BuildRoomMemberRows(_lobby.GetAllMemberInfo(), Main.Instance.MapConfig.MultiCivs);
|
||||
|
||||
if (_openMemberRowCount > 0)
|
||||
{
|
||||
ShowCantStartHint(Table.Instance.TextDataAssets.OutsideMultiplayOpenHint);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Main.Instance.MapConfig.AreAllLobbyMembersReady())
|
||||
{
|
||||
@ -662,23 +962,28 @@ namespace TH1_UI.View.Outside
|
||||
if (members.Count > playerCount)
|
||||
{
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyMembersNotSynced);
|
||||
CantStartHint.SetActive(true);
|
||||
CantStartHintText.text = MultilingualManager.Instance.GetMultilingualText(Table.Instance.TextDataAssets.OutsideMultiplayCantStartCount);
|
||||
CantStartHintAnimancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeIn);
|
||||
Timer.Instance.TimerRegister(this, () =>
|
||||
{
|
||||
CantStartHintAnimancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeOut);
|
||||
},1f,"MultiplayStartGame");
|
||||
Timer.Instance.TimerRegister(this, () =>
|
||||
{
|
||||
CantStartHint.SetActive(false);
|
||||
},1f + ResourceCache.Instance.AnimCache.UICommonPanelFadeOut.length,"MultiplayStartGame");
|
||||
ShowCantStartHint(Table.Instance.TextDataAssets.OutsideMultiplayCantStartCount);
|
||||
return;
|
||||
}
|
||||
|
||||
ShowLoadingAndStartGame(false);
|
||||
}
|
||||
|
||||
private void ShowCantStartHint(string textKey)
|
||||
{
|
||||
CantStartHint.SetActive(true);
|
||||
CantStartHintText.text = MultilingualManager.Instance.GetMultilingualText(textKey);
|
||||
CantStartHintAnimancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeIn);
|
||||
Timer.Instance.TimerRegister(this, () =>
|
||||
{
|
||||
CantStartHintAnimancer.Play(ResourceCache.Instance.AnimCache.UICommonPanelFadeOut);
|
||||
},1f,"MultiplayStartGame");
|
||||
Timer.Instance.TimerRegister(this, () =>
|
||||
{
|
||||
CantStartHint.SetActive(false);
|
||||
},1f + ResourceCache.Instance.AnimCache.UICommonPanelFadeOut.length,"MultiplayStartGame");
|
||||
}
|
||||
|
||||
private void SetMapConfig(bool resetGuestReady = false)
|
||||
{
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user