Merge branch 'develop' of ssh://git.pthub.vn:3222/Unity/perfect-world-unity into fix-ui

This commit is contained in:
Chomper9981
2026-04-08 13:47:00 +07:00
17 changed files with 7795 additions and 23875 deletions
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3218176555537563708}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.235, y: 0.001, z: 0.015}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &4570469791566163120
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4720678646282004868}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.061, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &2558500868448674905
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2916308637203925776}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.061, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &2359515785900208490
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4858308094309864508}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.84, y: -0.064, z: -0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &5945091725935784906
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7515438785474843149}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &4684279536110930119
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6015463627169791726}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &5659237752439739352
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1197563511380039097}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &133678441249318870
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,13 +26,13 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6982793425996143688}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0.564, y: -0.013, z: -0.005}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
--- !u!33 &1783189990820706467
MeshFilter:
m_ObjectHideFlags: 0
@@ -26,6 +26,7 @@ namespace BrewMonster
private float _lastPinchDistance;
private bool _pinchZoomActive;
private int _touchCount = 0;
public CinemachineOrbitalFollow Orbital { get => orbital;}
@@ -63,11 +64,19 @@ namespace BrewMonster
public void OnPointerDown(PointerEventData eventData)
{
fingerDown = true;
if(_touchCount < 2)
{
_touchCount++;
}
}
public void OnPointerUp(PointerEventData eventData)
{
fingerDown = false;
if(_touchCount > 0)
{
_touchCount--;
}
}
private void OnValidate()
@@ -133,7 +142,7 @@ namespace BrewMonster
return;
}
if (Input.touchCount == 2)
if (_touchCount == 2)
{
Touch t0 = Input.GetTouch(0);
Touch t1 = Input.GetTouch(1);
@@ -2,12 +2,13 @@
// Creator : Converted from C++ EC_Shop
// Date : 2024
using BrewMonster.Network;
using BrewMonster.Scripts;
using CSNetwork.C2SCommand;
using System.Text.RegularExpressions;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using BrewMonster.Scripts;
using BrewMonster.Network;
using CSNetwork.C2SCommand;
public class NPCShopDetailPanel : MonoBehaviour
{
@@ -47,7 +48,7 @@ public class NPCShopDetailPanel : MonoBehaviour
UpdateDisplay();
}
void UpdateDisplay()
public void UpdateDisplay()
{
if (currentItem.id == 0)
{
@@ -59,6 +60,9 @@ public class NPCShopDetailPanel : MonoBehaviour
if (itemDescriptionText != null)
{
string description = GetItemDescription((int)currentItem.id);
Debug.Log("[NPCShopDetail] RAW:\n" + description);
description = SanitizeDescription(description);
Debug.Log("[NPCShopDetail] Sanitized:\n" + description);
itemDescriptionText.Set(description);
}
@@ -85,7 +89,57 @@ public class NPCShopDetailPanel : MonoBehaviour
LoadItemIcon(itemIconImage, (int)currentItem.id);
}
}
private string SanitizeDescription(string desc)
{
if (string.IsNullOrWhiteSpace(desc))
return string.Empty;
// Normalize escaped + real line breaks (including unicode line separators)
desc = Regex.Replace(
desc,
@"\\r\\n|\\n|\\r|\r\n|\r|\u2028|\u2029",
"\n",
RegexOptions.CultureInvariant);
desc = Regex.Replace(
desc,
@"\^[0-9A-Fa-f]{6}",
string.Empty,
RegexOptions.CultureInvariant);
string[] lines = desc.Split('\n');
var sb = new System.Text.StringBuilder();
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
if (string.IsNullOrWhiteSpace(line))
continue;
line = Regex.Replace(line, @"[\u200B-\u200D\uFEFF]", string.Empty, RegexOptions.CultureInvariant);
string plain = Regex.Replace(line, @"<[^>]*>", string.Empty, RegexOptions.CultureInvariant)
.Replace('', ':')
.Trim();
if (Regex.IsMatch(plain, @"^(?:ID|Price)\s*:", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
continue;
line = Regex.Replace(
line,
@"(?i)\b(?:ID|Price)\b\s*[:]\s*\d+\b",
string.Empty,
RegexOptions.CultureInvariant).Trim();
if (string.IsNullOrWhiteSpace(line))
continue;
if (sb.Length > 0)
sb.AppendLine();
sb.Append(line);
}
return sb.ToString().Trim();
}
void LoadItemIcon(Image iconImage, int itemId)
{
if (itemId <= 0 || iconImage == null)
@@ -161,6 +215,12 @@ public class NPCShopDetailPanel : MonoBehaviour
return "No description available.";
}
public void ClearText()
{
if(itemDescriptionText != null)
itemDescriptionText.Set(string.Empty);
}
void OnCloseClicked()
{
@@ -223,6 +283,7 @@ public class NPCShopDetailPanel : MonoBehaviour
{
[SerializeField] public Text legacy;
[SerializeField] public TMPro.TextMeshProUGUI tmp;
Color myColorDecimal = new Color(1f, 0.816f, 0.365f, 1f);
public void Set(string value)
{
@@ -233,6 +294,7 @@ public class NPCShopDetailPanel : MonoBehaviour
if (tmp != null)
{
tmp.text = EC_Utility.FormatForTextMeshPro(value ?? string.Empty);
Debug.Log($"[TextOutlet] Set text: {tmp.text}");
}
}
}
@@ -26,13 +26,16 @@ public class NPCShopUIManager : AUIDialog
public GameObject contentRight;
public GameObject contentMidSell;
public GameObject item_info;
public ScrollRect scrollDetailItem;
public ScrollRect scrollListItem;
[Header("Texts")]
public TextMeshProUGUI itemDetailNameText;
public TextMeshProUGUI itemMoneyText;
public TextOutlet itemDescriptionText;
public NPCShopDetailPanel itemDescriptionText;
public TextMeshProUGUI itemsBuyAmountText;
public TextMeshProUGUI itemsBuyTotalMoneyText;
public TextMeshProUGUI itemsSellTotalMoneyText;
[Header("Tabs")]
public Transform tabButtonContainer;
@@ -82,7 +85,6 @@ public class NPCShopUIManager : AUIDialog
/// <summary>Current NPC id for this shop session. Send SEVNPC_HELLO with this before buy.</summary>
public uint CurrentNPCID => currentNPCID;
private NPCShopDetailPanel detailPanelScript;
public override void OnEnable()
{
@@ -392,45 +394,47 @@ public class NPCShopUIManager : AUIDialog
// Initialize buy array with at least one option
shopItem.buy = new GShopBuyOption[4]; // GShopItem supports up to 4 buy options
// Resolve display name/price in a type-agnostic way.
// Some element types come back as DATA_TYPE values we don't special-case here (arrows, flyswords, fashion, etc).
string itemName = EC_IvtrItemUtils.Instance.ResolveItemName(unchecked((int)good.id));
if (string.IsNullOrWhiteSpace(itemName))
itemName = $"Item_{good.id}";
static int ExtractInt(object data, params string[] fieldOrPropNames)
// Get item name and price based on type
string itemName = "Unknown";
int shopPrice = 0;
switch (itemDataType)
{
if (data == null || fieldOrPropNames == null || fieldOrPropNames.Length == 0)
return 0;
var t = data.GetType();
for (int i = 0; i < fieldOrPropNames.Length; i++)
{
string name = fieldOrPropNames[i];
if (string.IsNullOrEmpty(name))
continue;
var field = t.GetField(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
if (field != null && field.FieldType == typeof(int))
{
try { return (int)field.GetValue(data); } catch { }
}
var prop = t.GetProperty(name, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.IgnoreCase);
if (prop != null && prop.PropertyType == typeof(int) && prop.CanRead)
{
try { return (int)prop.GetValue(data); } catch { }
}
}
return 0;
case DATA_TYPE.DT_WEAPON_ESSENCE:
var weaponEssence = (WEAPON_ESSENCE)itemData;
itemName = weaponEssence.Name;
shopPrice = weaponEssence.shop_price;
break;
case DATA_TYPE.DT_ARMOR_ESSENCE:
var armorEssence = (ARMOR_ESSENCE)itemData;
itemName = armorEssence.Name;
shopPrice = armorEssence.shop_price;
break;
case DATA_TYPE.DT_MEDICINE_ESSENCE:
var medicineEssence = (MEDICINE_ESSENCE)itemData;
itemName = ByteToStringUtils.UshortArrayToUnicodeString(medicineEssence.name);
shopPrice = medicineEssence.shop_price;
break;
case DATA_TYPE.DT_DECORATION_ESSENCE:
var decorationEssence = (DECORATION_ESSENCE)itemData;
itemName = ByteToStringUtils.UshortArrayToUnicodeString(decorationEssence.name);
shopPrice = decorationEssence.shop_price;
break;
case DATA_TYPE.DT_STONE_ESSENCE:
var stoneEssence = (STONE_ESSENCE)itemData;
itemName = ByteToStringUtils.UshortArrayToUnicodeString(stoneEssence.name);
shopPrice = stoneEssence.shop_price;
break;
case DATA_TYPE.DT_MATERIAL_ESSENCE:
var materialEssence = (MATERIAL_ESSENCE)itemData;
itemName = ByteToStringUtils.UshortArrayToUnicodeString(materialEssence.name);
shopPrice = materialEssence.shop_price;
break;
default:
itemName = $"Item_{good.id}";
break;
}
// Prefer shop_price; fall back to base price if that's all we have.
int shopPrice = ExtractInt(itemData, "shop_price");
if (shopPrice <= 0)
shopPrice = ExtractInt(itemData, "price");
shopItem.name = itemName;
// Set price from contribution cost or shop price
@@ -458,7 +462,42 @@ public class NPCShopUIManager : AUIDialog
{
if (itemPanelPrefab == null || itemContainer == null)
return;
if(scrollListItem != null)
{
scrollListItem.verticalNormalizedPosition = 1f;
}
if (scrollDetailItem != null)
{
scrollDetailItem.verticalNormalizedPosition = 1f;
}
if (itemDetailNameText != null)
{
itemDetailNameText.text = string.Empty;
}
if (itemMoneyText != null)
{
itemMoneyText.text = string.Empty;
}
if (itemDescriptionText != null)
{
itemDescriptionText.ClearText();
}
if (itemIconImage != null)
{
itemIconImage.sprite = khung_item;
}
if (itemsBuyTotalMoneyText != null)
{
itemsBuyTotalMoneyText.text = string.Empty;
}
GameObject itemPanel = Instantiate(itemPanelPrefab, itemContainer);
itemPanel.SetActive(true);
@@ -494,27 +533,37 @@ public class NPCShopUIManager : AUIDialog
return;
SetupDetailPanel(item, this, shopItemIndex);
// Ensure detail panel script is available
if (detailPanelScript == null)
{
}
if (detailPanelScript != null)
{
}
else
{
Debug.LogError("[NPCShopUIManager] NPCShopDetailPanel component not found on npcShopDetailPanel GameObject!");
}
}
public override void CloseDialogue()
{
base.CloseDialogue();
if (itemDetailNameText != null)
{
itemDetailNameText.text = string.Empty;
}
if (itemMoneyText != null)
{
itemMoneyText.text = string.Empty;
}
if (itemDescriptionText != null)
{
itemDescriptionText.ClearText();
}
if (itemIconImage != null)
{
itemIconImage.sprite = khung_item;
}
if(itemsBuyTotalMoneyText != null)
{
itemsBuyTotalMoneyText.text = string.Empty;
}
EC_Game.GetGameRun().GetUIManager().GetInGameUIMan().EndNPCService();
}
@@ -590,14 +639,18 @@ public class NPCShopUIManager : AUIDialog
itemMoneyText.text = BuyUiEmptyValue;
}
if (scrollDetailItem != null)
{
scrollDetailItem.verticalNormalizedPosition = 1f;
}
buyCount = BuyCountMin;
UpdateBuyPriceTexts();
// Set item description
if (itemDescriptionText != null)
{
string description = GetItemDescription((int)currentItem.id);
itemDescriptionText.Set(description);
itemDescriptionText.SetupDetailPanel(currentItem, this, shopItemIndex);
}
// if (itemPriceText != null)
@@ -708,7 +761,26 @@ public class NPCShopUIManager : AUIDialog
if (itemsBuyTotalMoneyText != null)
{
itemsBuyTotalMoneyText.text = total.ToString();
uint playerMoney = 0;
try
{
var host = CECGameRun.Instance?.GetHostPlayer();
if (host != null)
{
playerMoney = host.GetMoneyAmount();
}
}
catch
{
playerMoney = 0;
}
string totalText = total.ToString();
string playerMoneyStr = playerMoney.ToString();
itemsBuyTotalMoneyText.text = total > playerMoney
? $"<color=red>{total}</color>/{playerMoney}"
: $"{total}/{playerMoney}";
}
if (m_btn_buy != null)
@@ -1138,28 +1210,6 @@ public class NPCShopUIManager : AUIDialog
m_use_Item.onClick.RemoveListener(OnUseItemClicked);
}
// === Text Outlet Helper ===
[System.Serializable]
public class TextOutlet
{
[SerializeField] public Text legacy;
[SerializeField] public TMPro.TextMeshProUGUI tmp;
public void Set(string value)
{
if (legacy != null)
{
legacy.text = EC_Utility.FormatForLegacyText(value ?? string.Empty);
}
if (tmp != null)
{
string formatTextDeail = EC_Utility.FormatForTextMeshPro(value ?? string.Empty);
formatTextDeail.Replace("<color=#FFFFFF>", "<color=#FFD05D>");
tmp.text = formatTextDeail;
}
}
}
private void SetupSellReadySlotListeners()
{
if (itemReadySell == null)
@@ -1237,7 +1287,75 @@ public class NPCShopUIManager : AUIDialog
private void UpdateSellTotalPriceText()
{
// Sell total text removed from this manager.
return;
long totalSellValue = 0;
int stageCount = 0;
try
{
var host = CECGameRun.Instance?.GetHostPlayer();
var inv = host?.GetInventory(0);
if (inv == null || sellSlotToSourceSlot == null)
{
if (itemsSellTotalMoneyText != null)
itemsSellTotalMoneyText.text = BuyUiEmptyValue;
if (m_btn_sell != null)
m_btn_sell.interactable = false;
return;
}
foreach (var pair in sellSlotToSourceSlot)
{
int sourceSlot = pair.Value;
if (sourceSlot < 0 || sourceSlot >= inv.GetSize())
continue;
var item = inv.GetItem(sourceSlot, false);
if (item == null || item.m_iCount <= 0)
continue;
if (!item.IsSellable())
continue;
try
{
item.GetDetailDataFromLocal();
}
catch
{
}
int unitPrice = item.GetScaledPrice();
long itemTotal = (long)unitPrice * item.m_iCount;
if (itemTotal > 0)
{
totalSellValue += itemTotal;
stageCount++;
}
}
}
catch(Exception ex)
{
}
if (itemsSellTotalMoneyText != null)
{
if(stageCount == 0 || totalSellValue <= 0)
{
itemsSellTotalMoneyText.text = BuyUiEmptyValue;
}
else
{
itemsSellTotalMoneyText.text = totalSellValue.ToString();
}
}
if (m_btn_sell != null)
{
m_btn_sell.interactable = stageCount > 0 && totalSellValue > 0;
}
}
}
+47 -7
View File
@@ -1840,11 +1840,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_fontSize
value: 48.2
value: 36
objectReference: {fileID: 0}
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_fontSizeBase
value: 48.2
value: 36
objectReference: {fileID: 0}
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_enableAutoSizing
@@ -1934,25 +1934,49 @@ PrefabInstance:
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_SizeDelta.x
value: 200
value: 171
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_SizeDelta.y
value: 67.9
value: 56.91
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.x
value: 532
value: 85.5
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: -37
value: -28.455
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.x
value: 85.5
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: -152.91
objectReference: {fileID: 0}
- target: {fileID: 6102967088919909530, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: 10.8
value: 8
objectReference: {fileID: 0}
- target: {fileID: 6830833846243993097, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_Name
@@ -1962,6 +1986,22 @@ PrefabInstance:
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.x
value: 85.5
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: -88.91
objectReference: {fileID: 0}
- target: {fileID: 7209086543831860202, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+47 -7
View File
@@ -1980,11 +1980,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_fontSize
value: 48.2
value: 36
objectReference: {fileID: 0}
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_fontSizeBase
value: 48.2
value: 36
objectReference: {fileID: 0}
- target: {fileID: 777847736648841921, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_enableAutoSizing
@@ -2074,25 +2074,49 @@ PrefabInstance:
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_SizeDelta.x
value: 200
value: 171
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_SizeDelta.y
value: 67.9
value: 55.9082
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.x
value: 532
value: 85.5
objectReference: {fileID: 0}
- target: {fileID: 1900527214026617767, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: -37
value: -27.9541
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.x
value: 85.5
objectReference: {fileID: 0}
- target: {fileID: 4313766541946487796, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: -151.9082
objectReference: {fileID: 0}
- target: {fileID: 6102967088919909530, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: 10.8
value: 3.5
objectReference: {fileID: 0}
- target: {fileID: 6830833846243993097, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_Name
@@ -2102,6 +2126,22 @@ PrefabInstance:
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMin.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.x
value: 85.5
objectReference: {fileID: 0}
- target: {fileID: 6900679650323527362, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchoredPosition.y
value: -87.9082
objectReference: {fileID: 0}
- target: {fileID: 7209086543831860202, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
propertyPath: m_AnchorMax.y
value: 1
+28 -120
View File
@@ -2771,8 +2771,8 @@ namespace BrewMonster
return m_idSelTarget;
}
// Auto select a attackable target / 自动选择一个可攻击的目标
// Auto select a attackable target / 自动选择一个可攻击目标
// Auto select a attackable target — cycle by distance (nearest → farthest, then repeat)
// 自动选择可攻击目标 — 按距离循环(从近到远,再回到最近)
public int AutoSelectTarget()
{
if (!CanDo(ActionCanDo.CANDO_CHANGESELECT))
@@ -2780,145 +2780,53 @@ namespace BrewMonster
int idCurSel = (m_idSelTarget != 0 && m_idSelTarget != m_PlayerInfo.cid) ? m_idSelTarget : 0;
// Clean up invalid targets from tab selection array / 清理无效目标
if (idCurSel == 0)
{
// Rebuild selected table / 重建选中表
m_aTabSels.Clear();
}
else
{
// Remove targets that are too far / 移除距离过远的目标
for (int i = m_aTabSels.Count - 1; i >= 0; i--)
{
CECObject pObject = m_aTabSels[i];
if (pObject == null)
{
m_aTabSels.RemoveAt(i);
continue;
}
float fDistToHost = 0.0f;
if (pObject is EC_ElsePlayer pPlayer)
fDistToHost = pPlayer.GetDistToHost();
else if (pObject is CECNPC pNPC)
fDistToHost = pNPC.GetDistToHost();
if (fDistToHost > EC_RoleTypes.EC_TABSEL_DIST || !CanSafelySelectWith(fDistToHost))
{
m_aTabSels.RemoveAt(i);
}
}
}
float fMinDist = 10000.0f;
CECObject pCand = null;
int idCandidate = 0;
// Get player candidates / 获取玩家候选列表
// idCurSel == 0 so TabSelectCandidates includes current target for index-based cycling
List<EC_ElsePlayer> aCandPlayers = new List<EC_ElsePlayer>();
EC_ManMessageMono.Instance.EC_ManPlayer.TabSelectCandidates(idCurSel, aCandPlayers);
EC_ManMessageMono.Instance.EC_ManPlayer.TabSelectCandidates(0, aCandPlayers);
List<CECNPC> aCandNPCs = new List<CECNPC>();
EC_ManMessageMono.Instance.CECNPCMan.TabSelectCandidates(0, aCandNPCs);
var sorted = new List<(float dist, int id, CECObject obj)>();
foreach (var pPlayer in aCandPlayers)
{
if (pPlayer == null)
continue;
// Check whether this player is in selected array / 检查此玩家是否已在选中数组中
if (m_aTabSels.Contains(pPlayer))
continue; // This player has been in selected array / 此玩家已在选中数组中
// Record the nearest one as candidate / 记录最近的一个作为候选
float fDist = pPlayer.GetDistToHost();
if (fDist < fMinDist)
{
fMinDist = fDist;
pCand = pPlayer;
idCandidate = pPlayer.GetCharacterID();
}
sorted.Add((pPlayer.GetDistToHost(), pPlayer.GetCharacterID(), pPlayer));
}
// Get NPC candidates / 获取NPC候选列表
List<CECNPC> aCandNPCs = new List<CECNPC>();
EC_ManMessageMono.Instance.CECNPCMan.TabSelectCandidates(idCurSel, aCandNPCs);
foreach (var pNPC in aCandNPCs)
{
if (pNPC == null)
continue;
// Check whether this npc is in selected array / 检查此NPC是否已在选中数组中
if (m_aTabSels.Contains(pNPC))
continue; // This npc has been in selected array / 此NPC已在选中数组中
// Record the nearest one as candidate / 记录最近的一个作为候选
float fDist = pNPC.GetDistToHost();
if (fDist < fMinDist)
{
fMinDist = fDist;
pCand = pNPC;
idCandidate = pNPC.GetNPCID();
}
sorted.Add((pNPC.GetDistToHost(), pNPC.GetNPCID(), pNPC));
}
sorted.Sort((a, b) =>
{
int c = a.dist.CompareTo(b.dist);
return c != 0 ? c : a.id.CompareTo(b.id);
});
m_aTabSels.Clear();
for (int i = 0; i < sorted.Count; i++)
m_aTabSels.Add(sorted[i].obj);
// Maximum number of candidates in tab selection array / 标签选择数组中的最大候选数
// Increased from 9 to 20 to allow more targets / 从9增加到20以允许更多目标
const int iMaxCand = 9;
int idNewSel = 0;
if (pCand != null && idCandidate != 0)
if (sorted.Count == 0)
{
// Add candidate to tab selection array / 将候选添加到标签选择数组
if (m_aTabSels.Count >= iMaxCand)
{
m_aTabSels.RemoveAt(m_aTabSels.Count - 1);
m_aTabSels.Insert(0, pCand);
}
else
{
m_aTabSels.Add(pCand);
}
idNewSel = idCandidate;
idNewSel = idCurSel;
}
else // No proper candidate was found / 未找到合适的候选
else
{
if (m_aTabSels.Count == 0)
int idx = -1;
for (int i = 0; i < sorted.Count; i++)
{
idNewSel = idCurSel;
}
else // Try to select one which has been in selected array / 尝试选择已在选中数组中的一个
{
int iIndex = -1;
for (int i = 0; i < m_aTabSels.Count; i++)
if (sorted[i].id == idCurSel)
{
CECObject pObject = m_aTabSels[i];
if (pObject == null)
continue;
int objId = 0;
if (pObject is EC_ElsePlayer pElsePlayer)
objId = pElsePlayer.GetCharacterID();
else if (pObject is CECNPC pNPC)
objId = pNPC.GetNPCID();
if (objId == idCurSel)
{
iIndex = i;
break;
}
}
iIndex = (iIndex + 1) % m_aTabSels.Count;
CECObject pSelectedObj = m_aTabSels[iIndex];
if (pSelectedObj != null)
{
if (pSelectedObj is EC_ElsePlayer pSelPlayer)
idNewSel = pSelPlayer.GetCharacterID();
else if (pSelectedObj is CECNPC pSelNPC)
idNewSel = pSelNPC.GetNPCID();
idx = i;
break;
}
}
int nextIdx = idx < 0 ? 0 : (idx + 1) % sorted.Count;
idNewSel = sorted[nextIdx].id;
}
// Select the target if found / 如果找到目标则选择它