Merge branch 'develop' of https://git.pthub.vn/Unity/perfect-world-unity into fix-ui
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:329ce992197e8e90aa8ecc86ad5a2e9d0e4516ae41630b0e0fb4b68080d9ba75
|
||||
size 303602
|
||||
oid sha256:fdca6f6915cfc055b350581a53fbc4d2e19ab522da9eb954295d71d45d8aed58
|
||||
size 303299
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:08dd99327890c9a20d09b1faadef16ad55b5a276d5080d744bfdc2f4191dceac
|
||||
size 111628
|
||||
oid sha256:7bb8ce7140f7f3652a200d0393561498e3ecdd8f4425bd2248e1ff000f225e5e
|
||||
size 106979
|
||||
|
||||
@@ -15,6 +15,8 @@ using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
using BrewMonster.Scripts.UI.Inventory;
|
||||
using CSNetwork.Protocols.RPCData;
|
||||
|
||||
namespace BrewMonster.Scripts.Managers
|
||||
{
|
||||
@@ -166,6 +168,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
ShowDetailPanel(false);
|
||||
ShowSplitPanel(false);
|
||||
RefreshAll();
|
||||
RefreshCharacterModelPreview();
|
||||
}
|
||||
|
||||
private void WireSplitUI()
|
||||
@@ -688,6 +691,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
Debug.Log($"[InventoryUI] Equip request sent for item {currentSelectedItem.m_tid} from slot {currentSelectedSlot} to equip location {equipLocation}");
|
||||
// Refresh inventory after equip
|
||||
RefreshAll();
|
||||
RefreshCharacterModelPreview();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -713,6 +717,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
Debug.Log($"[InventoryUI] Unequip request sent for item {currentSelectedItem.m_tid} from equip location {equipLocation} to inventory slot {emptySlot}");
|
||||
// Refresh inventory after unequip
|
||||
RefreshAll();
|
||||
RefreshCharacterModelPreview();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -738,6 +743,7 @@ namespace BrewMonster.Scripts.Managers
|
||||
|
||||
// Refresh inventory after drop
|
||||
RefreshAll();
|
||||
RefreshCharacterModelPreview();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1617,6 +1623,61 @@ namespace BrewMonster.Scripts.Managers
|
||||
return false;
|
||||
}
|
||||
|
||||
public void RefreshCharacterModelPreview()
|
||||
{
|
||||
var preview = PlayerModelPreview.Instance;
|
||||
if (preview != null)
|
||||
{
|
||||
RoleInfo roleInfo = BuildCurrentPreviewRoleInfo();
|
||||
if (roleInfo != null)
|
||||
{
|
||||
preview.ReloadRoleModel(roleInfo);
|
||||
}
|
||||
}
|
||||
|
||||
var inventoryPreview = FindFirstObjectByType<InventoryCharacterPreview>();
|
||||
if (inventoryPreview != null)
|
||||
{
|
||||
inventoryPreview.QueueRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
private RoleInfo BuildCurrentPreviewRoleInfo()
|
||||
{
|
||||
RoleInfo roleInfo = UnityGameSession.Instance != null ? UnityGameSession.Instance.GetRoleInfo() : null;
|
||||
if (roleInfo == null)
|
||||
return null;
|
||||
|
||||
RoleInfo snapshot = roleInfo.Clone();
|
||||
if (snapshot.equipment == null)
|
||||
snapshot.equipment = new List<GRoleInventory>();
|
||||
else
|
||||
snapshot.equipment.Clear();
|
||||
|
||||
CECHostPlayer host = CECGameRun.Instance?.GetHostPlayer();
|
||||
var equipInv = host?.GetInventory(InventoryConst.IVTRTYPE_EQUIPPACK);
|
||||
if (equipInv == null)
|
||||
return snapshot;
|
||||
|
||||
int size = equipInv.GetSize();
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
EC_IvtrItem item = equipInv.GetItem(i, false);
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
snapshot.equipment.Add(new GRoleInventory
|
||||
{
|
||||
id = (uint)item.GetTemplateID(),
|
||||
pos = i,
|
||||
count = item.GetCount(),
|
||||
max_count = Math.Max(1, item.GetPileLimitInstance())
|
||||
});
|
||||
}
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private bool IsPointerOverDetailPanel(Vector2 screenPosition)
|
||||
{
|
||||
var panelRect = detailPanelRoot.transform as RectTransform;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using BrewMonster;
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts.World;
|
||||
using CSNetwork;
|
||||
using CSNetwork.GPDataType;
|
||||
@@ -260,7 +261,8 @@ namespace PerfectWorld.Scripts.Managers
|
||||
CECMatter pMatter = GetMatter(mid);
|
||||
if (pMatter != null)
|
||||
{
|
||||
UnityEngine.Object.Destroy(pMatter.gameObject);
|
||||
//UnityEngine.Object.Destroy(pMatter.gameObject);
|
||||
PoolManager.Instance.Despawn(pMatter.gameObject);
|
||||
m_MatterTab.Remove(mid);
|
||||
}
|
||||
//TODO: Might need to implement later
|
||||
@@ -345,4 +347,4 @@ namespace PerfectWorld.Scripts.Managers
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,6 +324,9 @@ namespace BrewMonster
|
||||
public const int EFF_FACEPILL = 1;
|
||||
}
|
||||
private BaseVfxObject _levelUpVfx;
|
||||
// [中文] 当前激活的状态效果 GFX,以 (路径+挂点) 为键
|
||||
// [English] Currently active state-effect GFX objects, keyed by (path + hook)
|
||||
private Dictionary<string, BaseVfxObject> _stateGfxObjects = new Dictionary<string, BaseVfxObject>();
|
||||
protected GameObject[] m_pModels = new GameObject[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX];
|
||||
protected int[] m_aShapeID = new int[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX];
|
||||
|
||||
@@ -895,91 +898,103 @@ namespace BrewMonster
|
||||
// !CECOptimize::Instance().GetGFX().CanShowState(GetCharacterID(), GetClassID()))
|
||||
// return;
|
||||
|
||||
//static const char* szBasePath = "������\\״̬Ч��\\";
|
||||
// [中文] 策划联入\状态效果\ (状态效果 GFX 的基础路径)
|
||||
// [English] Designer-integrated state effect GFX base path
|
||||
const string szBasePath = "策划联入/状态效果/";
|
||||
|
||||
const int bitSize = sizeof(uint) * 8;
|
||||
BMLogger.LogError($"[CECPlayer] ShowExtendStates: start: {start}, count: {count}, bitSize: {bitSize}");
|
||||
for (int index = 0; index<count; index++)
|
||||
for (int index = 0; index < count; index++)
|
||||
{
|
||||
int idState = index + start;
|
||||
for (int i=0; i < bitSize; i++)
|
||||
for (int i = 0; i < bitSize; i++)
|
||||
{
|
||||
int dwMask = 1 << i;
|
||||
int dwFlag1 = (int)(m_aExtStatesShown[idState] & dwMask);
|
||||
int dwFlag2 = (int)(pData[index] & dwMask);
|
||||
|
||||
// [中文] 两者相同(都激活或都未激活),跳过
|
||||
// [English] Both unchanged (both on or both off), skip
|
||||
if ((dwFlag1 == 0 && dwFlag2 == 0) || (dwFlag1 != 0 && dwFlag2 != 0))
|
||||
continue;
|
||||
|
||||
BMLogger.LogError($"[CECPlayer] ShowExtendStates: idState: {idState}, bitIndex: {i}, i + idState*bitSize: {i + idState * bitSize}");
|
||||
//TODO: Implement visible state
|
||||
// const GNET::VisibleState* pvs = GNET::VisibleState::Query(m_iProfession, i + idState*bitSize);
|
||||
// if (!pvs)
|
||||
// continue;
|
||||
// [中文] 查询可见状态(profession 参数被忽略,仅按 id 查找)
|
||||
// [English] Query visible state (profession is ignored; keyed by id only)
|
||||
VisibleState pvs = VisibleState.Query(m_iProfession, i + idState * bitSize);
|
||||
if (pvs == null)
|
||||
continue;
|
||||
|
||||
// AString strGFXFile = pvs->GetEffect();
|
||||
// if (!strGFXFile.GetLength())
|
||||
// continue;
|
||||
string strEffect = pvs.GetEffect();
|
||||
if (string.IsNullOrEmpty(strEffect))
|
||||
continue;
|
||||
|
||||
// strGFXFile = szBasePath + strGFXFile;
|
||||
string strGFXFile = szBasePath + strEffect;
|
||||
|
||||
// if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState*bitSize))
|
||||
// continue;
|
||||
// [中文] TestProcessPetCureGFX — 宠愈 GFX 系统尚未移植,跳过(等价于始终返回 false)
|
||||
// [English] TestProcessPetCureGFX — pet-cure GFX system not ported yet; skip (equivalent to always false)
|
||||
// if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState * bitSize)) continue;
|
||||
|
||||
if (dwFlag1 != 0)
|
||||
{
|
||||
// [中文] 移除旧状态效果
|
||||
// [English] Remove old state GFX
|
||||
if (SkillGfxMan.InstanceSub != null)
|
||||
{
|
||||
SkillGfxMan.InstanceSub.RemoveAllTraceTargetGfx();
|
||||
}
|
||||
// //TODO: Implement remove old state
|
||||
|
||||
// CECModel *pWeapon = NULL;
|
||||
// bool bLeft (false);
|
||||
// if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
|
||||
// {
|
||||
// // ��������Ч
|
||||
// if (pWeapon)
|
||||
// {
|
||||
// const char * gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
// pWeapon->RemoveGfx(strGFXFile, gfxHook);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
/*bool bLeft = false;
|
||||
CECModel pWeapon = null;
|
||||
if (IsWeaponHookPos(pvs.GetHH(), out bLeft, out pWeapon))
|
||||
{
|
||||
// ģ������Ч
|
||||
// RemoveGfx(strGFXFile, pvs->GetHH(), PLAYERMODEL_TYPEALL);
|
||||
// [中文] 武器上的效果
|
||||
// [English] GFX on weapon model
|
||||
if (pWeapon != null)
|
||||
{
|
||||
string gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
RemoveStateGfxFromModel(pWeapon, strGFXFile, gfxHook);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// [中文] 模型上的效果
|
||||
// [English] GFX on player model
|
||||
RemoveGfx(strGFXFile, pvs.GetHH(), (uint)PLAYERMODEL_TYPE.PLAYERMODEL_TYPEALL);
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// [中文] 添加新状态效果
|
||||
// [English] Add new state GFX
|
||||
string szHH = pvs.GetHH();
|
||||
float fScale;
|
||||
|
||||
// [中文] 根据挂点类型获取模型缩放数据
|
||||
// [English] Determine GFX scale from model outer data based on hook type
|
||||
CECModel majorModel = GetMajorModel()?.GetComponent<CECModel>();
|
||||
if (majorModel != null && szHH.Equals("HH_Head", StringComparison.OrdinalIgnoreCase))
|
||||
fScale = majorModel.GetOuterData()[0];
|
||||
else if (majorModel != null && szHH.Equals("HH_Spine", StringComparison.OrdinalIgnoreCase))
|
||||
fScale = majorModel.GetOuterData()[1];
|
||||
else
|
||||
fScale = 1.0f;
|
||||
|
||||
bool bLeft = false;
|
||||
CECModel pWeapon = null;
|
||||
if (IsWeaponHookPos(szHH, out bLeft, out pWeapon))
|
||||
{
|
||||
// [中文] 武器上的效果
|
||||
// [English] GFX on weapon model
|
||||
if (pWeapon != null)
|
||||
{
|
||||
string gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
PlayStateGfxOnModel(pWeapon, strGFXFile, gfxHook, fScale);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// [中文] 玩家模型上的效果
|
||||
// [English] GFX on player model
|
||||
PlayGfx(strGFXFile, pvs.GetHH(), fScale, (uint)PLAYERMODEL_TYPE.PLAYERMODEL_TYPEALL, true);
|
||||
}
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// // Add new state
|
||||
|
||||
// const char* szHH = pvs->GetHH();
|
||||
// float fScale;
|
||||
|
||||
// if (stricmp("HH_Head", szHH) == 0)
|
||||
// fScale = GetMajorModel()->GetOuterData()[0];
|
||||
// else if (stricmp("HH_Spine", szHH) == 0)
|
||||
// fScale = GetMajorModel()->GetOuterData()[1];
|
||||
// else
|
||||
// fScale = 1.0f;
|
||||
|
||||
// CECModel *pWeapon = NULL;
|
||||
// bool bLeft (false);
|
||||
// if (IsWeaponHookPos(pvs->GetHH(), &bLeft, &pWeapon))
|
||||
// {
|
||||
// if (pWeapon)
|
||||
// {
|
||||
// const char *gfxHook = GetWeaponGFXHookPos(pWeapon, bLeft);
|
||||
// pWeapon->PlayGfx(strGFXFile, gfxHook, fScale);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// PlayGfx(strGFXFile, pvs->GetHH(), fScale, PLAYERMODEL_TYPEALL, true);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,6 +1011,68 @@ namespace BrewMonster
|
||||
int bitOffset = n % bitSize;
|
||||
return (m_aExtStates[index] & (1 << bitOffset)) != 0;
|
||||
}
|
||||
|
||||
// [中文] 判断挂点是否为武器挂点,并返回对应武器模型和左右手标志
|
||||
// [English] Check if hook pos is a weapon hook; output the corresponding weapon model and left-hand flag
|
||||
protected bool IsWeaponHookPos(string szHH, out bool bLeft, out CECModel pWeapon)
|
||||
{
|
||||
bLeft = false;
|
||||
pWeapon = null;
|
||||
if (string.IsNullOrEmpty(szHH)) return false;
|
||||
|
||||
// [中文] 左手武器挂点(手持或肩部)
|
||||
// [English] Left-hand weapon hook positions (held or shoulder)
|
||||
if (szHH.Equals("HH_lefthandweapon", StringComparison.OrdinalIgnoreCase) ||
|
||||
szHH.Equals("HH_leftsword", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
bLeft = true;
|
||||
pWeapon = GetLeftHandWeapon();
|
||||
return true;
|
||||
}
|
||||
|
||||
// [中文] 右手武器挂点(手持、肩部或镰刀)
|
||||
// [English] Right-hand weapon hook positions (held, shoulder, or sickle/nickle)
|
||||
if (szHH.Equals("HH_righthandweapon", StringComparison.OrdinalIgnoreCase) ||
|
||||
szHH.Equals("HH_rightsword", StringComparison.OrdinalIgnoreCase) ||
|
||||
szHH.Equals("HH_weapon", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
pWeapon = GetRightHandWeapon();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// [中文] 获取左手武器模型(武器 CECModel 未接入时返回 null)
|
||||
// [English] Get left-hand weapon model (returns null until weapon CECModel tracking is wired)
|
||||
protected virtual CECModel GetLeftHandWeapon() => null;
|
||||
|
||||
// [中文] 获取右手武器模型(武器 CECModel 未接入时返回 null)
|
||||
// [English] Get right-hand weapon model (returns null until weapon CECModel tracking is wired)
|
||||
protected virtual CECModel GetRightHandWeapon() => null;
|
||||
|
||||
// [中文] 获取武器上用于挂载 GFX 的挂点名称
|
||||
// [English] Get the GFX hook position name on the weapon model
|
||||
protected string GetWeaponGFXHookPos(CECModel pModel, bool bLeft)
|
||||
{
|
||||
// [中文] 武器 CECModel 挂点逻辑未接入,暂时返回 null
|
||||
// [English] Weapon CECModel hook logic not wired yet; return null for now
|
||||
return null;
|
||||
}
|
||||
|
||||
// [中文] 从玩家模型上移除状态效果 GFX
|
||||
// [English] Remove a state-effect GFX from the player model
|
||||
protected void RemoveGfx(string szPath, string szHook, uint iShapeTypeMask)
|
||||
{
|
||||
string key = szPath + szHook;
|
||||
if (_stateGfxObjects.TryGetValue(key, out BaseVfxObject vfx) && vfx != null)
|
||||
{
|
||||
vfx.Stop();
|
||||
Destroy(vfx.gameObject);
|
||||
_stateGfxObjects.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetUpPlayer()
|
||||
{
|
||||
m_dwResFlags = 0;
|
||||
@@ -1708,15 +1785,15 @@ namespace BrewMonster
|
||||
//swing sfx
|
||||
//workaround for sound effect delay, it need to trigger via weapon combine action
|
||||
SFXManager.Instance.PlaySkillSfxAtPointAsync(soundPath, Vector3.zero,iTransTime/1000f).Forget();
|
||||
|
||||
|
||||
szAct = EC_Utility.BuildActionName(action, weapon_type, "落");
|
||||
m_pActionController.QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX);
|
||||
|
||||
|
||||
//hit sfx
|
||||
//workaround for sound effect delay, it need to trigger via weapon combine action
|
||||
//.1f is a magic number to make sure the sound effect is triggered after the action is finished
|
||||
SFXManager.Instance.PlaySkillSfxAtPointAsync(hitSoundPath, Vector3.zero,iTransTime/1000f+.1f).Forget();
|
||||
|
||||
|
||||
//PlayNonSkillActionWithName(iAction, szAct, true, 200, true, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);gagága
|
||||
/*
|
||||
if (pRightHandWeapon != null && IsUsingMagicWeapon())
|
||||
@@ -2832,10 +2909,53 @@ namespace BrewMonster
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
PlayLevelUpGfx(szPath);
|
||||
// [中文] 路由到状态 GFX 播放(支持多 GFX 同时激活)
|
||||
// [English] Route to state GFX playback (supports multiple concurrent GFX)
|
||||
_ = PlayStateGfxAsync(szPath, szHook, fScale);
|
||||
return false;
|
||||
}
|
||||
|
||||
// [中文] 异步加载并播放状态效果 GFX,以 (路径+挂点) 为键去重
|
||||
// [English] Asynchronously load and play a state-effect GFX; keyed by (path+hook) to deduplicate
|
||||
private async Task PlayStateGfxAsync(string path, string hook, float fScale)
|
||||
{
|
||||
if (string.IsNullOrEmpty(path)) return;
|
||||
string key = path + hook;
|
||||
if (_stateGfxObjects.ContainsKey(key)) return; // [中文] 已激活,跳过 / [English] Already active, skip
|
||||
|
||||
GameObject prefab = await AddressableManager.Instance.LoadPrefabAsync(path);
|
||||
if (prefab == null)
|
||||
{
|
||||
BMLogger.LogWarning($"[StateGFX] Failed to load prefab: {path}");
|
||||
return;
|
||||
}
|
||||
|
||||
// [中文] 实例化挂载在玩家 transform 下,初始位置归零
|
||||
// [English] Instantiate parented to player transform with zeroed local position
|
||||
BaseVfxObject vfx = Instantiate(prefab, transform).GetComponent<BaseVfxObject>();
|
||||
if (vfx == null) return;
|
||||
|
||||
vfx.transform.localPosition = Vector3.zero;
|
||||
vfx.SetScale(fScale);
|
||||
vfx.Play();
|
||||
_stateGfxObjects[key] = vfx;
|
||||
BMLogger.Log($"[StateGFX] Playing: {path}, hook: {hook}, scale: {fScale}");
|
||||
}
|
||||
|
||||
// [中文] 在武器 CECModel 上移除状态效果 GFX(武器挂点逻辑未接入,暂存桩)
|
||||
// [English] Remove state-effect GFX from weapon CECModel (weapon hook not wired yet; stub)
|
||||
private void RemoveStateGfxFromModel(CECModel model, string path, string hook)
|
||||
{
|
||||
// TODO: implement when weapon CECModel GFX tracking is available
|
||||
}
|
||||
|
||||
// [中文] 在武器 CECModel 上播放状态效果 GFX(武器挂点逻辑未接入,暂存桩)
|
||||
// [English] Play state-effect GFX on weapon CECModel (weapon hook not wired yet; stub)
|
||||
private void PlayStateGfxOnModel(CECModel model, string path, string hook, float fScale)
|
||||
{
|
||||
// TODO: implement when weapon CECModel GFX tracking is available
|
||||
}
|
||||
|
||||
private async void PlayLevelUpGfx(string path)
|
||||
{
|
||||
// Usage: Load the prefab asynchronously using AddressableManager
|
||||
|
||||
@@ -230,7 +230,7 @@ public class CECModelStaticData
|
||||
SrcBlend = A3DBLEND.A3DBLEND_SRCALPHA,
|
||||
DestBlend = A3DBLEND.A3DBLEND_INVSRCALPHA
|
||||
};
|
||||
private readonly float[] m_OuterData = new float[CECModelConstants.OUTER_DATA_COUNT];
|
||||
public float[] m_OuterData = new float[CECModelConstants.OUTER_DATA_COUNT];
|
||||
private bool m_bCanCastShadow = true;
|
||||
private bool m_bRenderSkinModel = true;
|
||||
private bool m_bRenderEdge = true;
|
||||
@@ -636,6 +636,7 @@ public class CECModel
|
||||
}
|
||||
return hook;
|
||||
}
|
||||
public float[] GetOuterData() { return m_pMapModel.m_OuterData; }
|
||||
|
||||
/// <summary>
|
||||
/// Invalidate hook cache (call when model reloads)
|
||||
|
||||
@@ -161,10 +161,11 @@ namespace PerfectWorld.Scripts
|
||||
var fileMatterValue = fileMatterField.GetValue(matterData);
|
||||
string filePath = ByteToStringUtils.ByteArrayToCP936String((byte[])fileMatterValue);
|
||||
|
||||
var matterPrefab = await AddressableManager.Instance.LoadPrefabAsync(AFile.NormalizePath(filePath.ToLower(), true));
|
||||
if (matterPrefab != null)
|
||||
//var matterPrefab = await AddressableManager.Instance.LoadPrefabAsync(AFile.NormalizePath(filePath.ToLower(), true));
|
||||
var matterObject = await PoolManager.Instance.SpawnAsync(AFile.NormalizePath(filePath.ToLower(), true), Vector3.zero, Quaternion.identity, 15f);
|
||||
if (matterObject != null)
|
||||
{
|
||||
var matterObject = Instantiate(matterPrefab);
|
||||
//var matterObject = Instantiate(matterPrefab);
|
||||
matterObject.name = $"Matter {matterObject.name} {matterInfo.tid} {matterInfo.mid}";
|
||||
matterObject.transform.position = new Vector3(Info.pos.x, Info.pos.y, Info.pos.z);
|
||||
matterObject.transform.localScale = new Vector3(1f, 1f, 1f);
|
||||
|
||||
@@ -6,7 +6,7 @@ using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
public class PlayerModelPreview : MonoBehaviour
|
||||
public class PlayerModelPreview : MonoSingleton<PlayerModelPreview>
|
||||
{
|
||||
[SerializeField] private Transform modelRoot;
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace BrewMonster.Scripts
|
||||
|
||||
private int _loadVersion;
|
||||
|
||||
private bool _hasRequestedPlayerModelId;
|
||||
private int _requestedPlayerModelId;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (modelRoot == null)
|
||||
@@ -36,10 +39,15 @@ namespace BrewMonster.Scripts
|
||||
_loadVersion++;
|
||||
int version = _loadVersion;
|
||||
|
||||
ClearModels();
|
||||
|
||||
if (roleInfos == null || roleInfos.Count == 0 || NPCManager.Instance == null)
|
||||
{
|
||||
ClearModels();
|
||||
return;
|
||||
}
|
||||
|
||||
List<GameObject> oldModels = new List<GameObject>(playerModels);
|
||||
playerModels.Clear();
|
||||
playerModelIds.Clear();
|
||||
|
||||
for (int i = 0; i < roleInfos.Count; i++)
|
||||
{
|
||||
@@ -51,20 +59,27 @@ namespace BrewMonster.Scripts
|
||||
|
||||
if (version != _loadVersion)
|
||||
{
|
||||
if (model != null)
|
||||
Destroy(model);
|
||||
Destroy(model);
|
||||
return;
|
||||
}
|
||||
|
||||
if (model == null)
|
||||
continue;
|
||||
|
||||
model.transform.SetParent(modelRoot, false);
|
||||
model.transform.localPosition = Vector3.zero;
|
||||
model.transform.localRotation = Quaternion.identity;
|
||||
model.SetActive(false);
|
||||
|
||||
playerModels.Add(model);
|
||||
playerModelIds.Add(role.roleid);
|
||||
|
||||
ApplyRequestedModelVisibility();
|
||||
}
|
||||
|
||||
for(int i=0; i < oldModels.Count; i++)
|
||||
{
|
||||
if (oldModels[i] != null)
|
||||
{
|
||||
Destroy(oldModels[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,23 +88,69 @@ namespace BrewMonster.Scripts
|
||||
/// </summary>
|
||||
public void ShowPlayerModel(int playerModelId)
|
||||
{
|
||||
//int n = Mathf.Min(playerModels.Count, playerModelIds.Count);
|
||||
//for (int i = 0; i < n; i++)
|
||||
//{
|
||||
// GameObject go = playerModels[i];
|
||||
// if (go == null)
|
||||
// continue;
|
||||
// go.SetActive(playerModelIds[i] == playerModelId);
|
||||
//}
|
||||
_hasRequestedPlayerModelId = true;
|
||||
_requestedPlayerModelId = playerModelId;
|
||||
|
||||
ApplyRequestedModelVisibility();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the visibility of player models based on the requested player model id.
|
||||
/// </summary>
|
||||
private void ApplyRequestedModelVisibility()
|
||||
{
|
||||
if(!_hasRequestedPlayerModelId)
|
||||
return;
|
||||
|
||||
int n = Mathf.Min(playerModels.Count, playerModelIds.Count);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
GameObject go = playerModels[i];
|
||||
if (go == null)
|
||||
if(go == null)
|
||||
continue;
|
||||
go.SetActive(playerModelIds[i] == playerModelId);
|
||||
|
||||
go.SetActive(playerModelIds[i] == _requestedPlayerModelId);
|
||||
}
|
||||
}
|
||||
|
||||
public void HideAllPlayerModels()
|
||||
{
|
||||
_hasRequestedPlayerModelId = false;
|
||||
for (int i = 0; i < playerModels.Count; i++)
|
||||
{
|
||||
if (playerModels[i] != null)
|
||||
{
|
||||
playerModels[i].SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearModels()
|
||||
{
|
||||
//for (int i = 0; i < playerModels.Count; i++)
|
||||
//{
|
||||
// if (playerModels[i] != null)
|
||||
// {
|
||||
// Destroy(playerModels[i]);
|
||||
// }
|
||||
//}
|
||||
|
||||
for (int i = 0; i < playerModels.Count; i++)
|
||||
{
|
||||
if (playerModels[i] != null)
|
||||
{
|
||||
Destroy(playerModels[i]);
|
||||
}
|
||||
}
|
||||
|
||||
playerModels.Clear();
|
||||
playerModelIds.Clear();
|
||||
}
|
||||
@@ -98,14 +159,18 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
for (int i = 0; i < playerModels.Count; i++)
|
||||
{
|
||||
if (playerModels[i] != null)
|
||||
if (modelRoot != null)
|
||||
{
|
||||
if (Application.isPlaying)
|
||||
Destroy(playerModels[i]);
|
||||
else
|
||||
DestroyImmediate(playerModels[i]);
|
||||
if(playerModels[i] != null)
|
||||
{
|
||||
if(Application.isPlaying)
|
||||
Destroy(playerModels[i]);
|
||||
else
|
||||
DestroyImmediate(playerModels[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playerModels.Clear();
|
||||
playerModelIds.Clear();
|
||||
}
|
||||
@@ -114,13 +179,17 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
BMLogger.Log($"LoadPlayerModel: {role.roleid}");
|
||||
var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan();
|
||||
GameObject prefab = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender);
|
||||
if (prefab == null)
|
||||
{
|
||||
GameObject model = await NPCManager.Instance.GetModelPlayer(role.occupation, role.gender);
|
||||
if(model == null)
|
||||
return null;
|
||||
}
|
||||
|
||||
model.SetActive(false);
|
||||
BMLogger.Log($"LoadPlayerModel: {role.roleid} - prefab loaded");
|
||||
GameObject model = Instantiate(prefab);
|
||||
if (modelRoot != null)
|
||||
{
|
||||
model.transform.SetParent(modelRoot, false);
|
||||
}
|
||||
|
||||
var playerDefaultEquipments = model.GetComponentInChildren<PlayerDefaultEquipments>();
|
||||
if (playerDefaultEquipments == null)
|
||||
{
|
||||
@@ -310,5 +379,14 @@ namespace BrewMonster.Scripts
|
||||
}
|
||||
return skeletonBuilder;
|
||||
}
|
||||
|
||||
public void ReloadRoleModel(RoleInfo roleInfo)
|
||||
{
|
||||
if (roleInfo == null)
|
||||
return;
|
||||
|
||||
ShowAllPlayerModels(new List<RoleInfo> { roleInfo });
|
||||
ShowPlayerModel(roleInfo.roleid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a86dd2e474fb3c34cb8214c766f0b941
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
/// <summary>
|
||||
/// Implement this on pooled prefab components that need to reset state between uses.
|
||||
/// </summary>
|
||||
public interface IPoolable
|
||||
{
|
||||
void OnSpawn();
|
||||
void OnDespawn();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c09b2b8b565f2946bb4e9f09e2966af
|
||||
@@ -0,0 +1,270 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
internal sealed class ObjectPool
|
||||
{
|
||||
private readonly string _addressableKey;
|
||||
private readonly PoolManager _owner;
|
||||
private readonly AddressableManager _addressableManager;
|
||||
private readonly Transform _poolRoot;
|
||||
private readonly Stack<GameObject> _idleInstances = new();
|
||||
private readonly HashSet<GameObject> _activeInstances = new();
|
||||
private readonly HashSet<GameObject> _knownInstances = new();
|
||||
private readonly Dictionary<GameObject, int> _spawnVersions = new();
|
||||
|
||||
private GameObject _prefab;
|
||||
private Task<GameObject> _loadTask;
|
||||
private Coroutine _releaseCoroutine;
|
||||
private float _memoryReleaseTTL;
|
||||
|
||||
public ObjectPool(
|
||||
string addressableKey,
|
||||
PoolManager owner,
|
||||
AddressableManager addressableManager,
|
||||
Transform poolRoot,
|
||||
float memoryReleaseTTL)
|
||||
{
|
||||
_addressableKey = addressableKey;
|
||||
_owner = owner;
|
||||
_addressableManager = addressableManager;
|
||||
_poolRoot = poolRoot;
|
||||
_memoryReleaseTTL = Mathf.Max(0f, memoryReleaseTTL);
|
||||
}
|
||||
|
||||
public string AddressableKey => _addressableKey;
|
||||
public int ActiveCount => _activeInstances.Count;
|
||||
public int IdleCount => _idleInstances.Count;
|
||||
|
||||
public void UpdateMemoryReleaseTTL(float memoryReleaseTTL)
|
||||
{
|
||||
_memoryReleaseTTL = Mathf.Max(0f, memoryReleaseTTL);
|
||||
}
|
||||
|
||||
public async Task<GameObject> SpawnAsync(Vector3 position, Quaternion rotation, Transform parent)
|
||||
{
|
||||
CancelReleaseCountdown();
|
||||
|
||||
GameObject instance = GetIdleInstance();
|
||||
if (instance == null)
|
||||
{
|
||||
GameObject prefab = await LoadPrefabAsync();
|
||||
if (prefab == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
instance = Object.Instantiate(prefab);
|
||||
_knownInstances.Add(instance);
|
||||
_spawnVersions[instance] = 0;
|
||||
}
|
||||
|
||||
_activeInstances.Add(instance);
|
||||
_spawnVersions[instance]++;
|
||||
instance.transform.SetParent(parent, true);
|
||||
instance.transform.SetPositionAndRotation(position, rotation);
|
||||
instance.SetActive(true);
|
||||
NotifyPoolablesSpawned(instance);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public bool Despawn(GameObject instance)
|
||||
{
|
||||
if (instance == null || !_activeInstances.Remove(instance))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
NotifyPoolablesDespawned(instance);
|
||||
_spawnVersions[instance]++;
|
||||
instance.SetActive(false);
|
||||
instance.transform.SetParent(_poolRoot, false);
|
||||
_idleInstances.Push(instance);
|
||||
|
||||
if (_activeInstances.Count == 0)
|
||||
{
|
||||
StartReleaseCountdown();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsActiveInstance(GameObject instance, int spawnVersion)
|
||||
{
|
||||
return instance != null
|
||||
&& _activeInstances.Contains(instance)
|
||||
&& _spawnVersions.TryGetValue(instance, out int currentVersion)
|
||||
&& currentVersion == spawnVersion;
|
||||
}
|
||||
|
||||
public int GetSpawnVersion(GameObject instance)
|
||||
{
|
||||
return instance != null && _spawnVersions.TryGetValue(instance, out int version) ? version : -1;
|
||||
}
|
||||
|
||||
public IEnumerable<GameObject> GetKnownInstances()
|
||||
{
|
||||
return _knownInstances;
|
||||
}
|
||||
|
||||
public void ReleaseNow()
|
||||
{
|
||||
CancelReleaseCountdown();
|
||||
DestroyAllInstances();
|
||||
ReleasePrefabAsset();
|
||||
}
|
||||
|
||||
private GameObject GetIdleInstance()
|
||||
{
|
||||
while (_idleInstances.Count > 0)
|
||||
{
|
||||
GameObject instance = _idleInstances.Pop();
|
||||
if (instance != null)
|
||||
{
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private async Task<GameObject> LoadPrefabAsync()
|
||||
{
|
||||
if (_prefab != null)
|
||||
{
|
||||
return _prefab;
|
||||
}
|
||||
|
||||
if (_loadTask != null)
|
||||
{
|
||||
return await _loadTask;
|
||||
}
|
||||
|
||||
_loadTask = LoadPrefabInternalAsync();
|
||||
GameObject prefab = await _loadTask;
|
||||
if (prefab == null)
|
||||
{
|
||||
_loadTask = null;
|
||||
}
|
||||
|
||||
return prefab;
|
||||
}
|
||||
|
||||
private async Task<GameObject> LoadPrefabInternalAsync()
|
||||
{
|
||||
if (_addressableManager == null)
|
||||
{
|
||||
BMLogger.LogError($"ObjectPool: AddressableManager is not available for '{_addressableKey}'.");
|
||||
return null;
|
||||
}
|
||||
|
||||
await _addressableManager.WaitUntilInitializedAsync();
|
||||
|
||||
GameObject prefab = await _addressableManager.LoadPrefabAsync(_addressableKey);
|
||||
if (prefab == null)
|
||||
{
|
||||
BMLogger.LogError($"ObjectPool: Failed to load Addressable prefab '{_addressableKey}'.");
|
||||
return null;
|
||||
}
|
||||
|
||||
_prefab = prefab;
|
||||
return _prefab;
|
||||
}
|
||||
|
||||
private void StartReleaseCountdown()
|
||||
{
|
||||
CancelReleaseCountdown();
|
||||
_releaseCoroutine = _owner.StartCoroutine(ReleaseMemoryCountdown());
|
||||
}
|
||||
|
||||
private void CancelReleaseCountdown()
|
||||
{
|
||||
if (_releaseCoroutine == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_owner.StopCoroutine(_releaseCoroutine);
|
||||
_releaseCoroutine = null;
|
||||
}
|
||||
|
||||
private IEnumerator ReleaseMemoryCountdown()
|
||||
{
|
||||
if (_memoryReleaseTTL > 0f)
|
||||
{
|
||||
yield return new WaitForSecondsRealtime(_memoryReleaseTTL);
|
||||
}
|
||||
|
||||
_releaseCoroutine = null;
|
||||
if (_activeInstances.Count > 0)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
_owner.RemovePool(this);
|
||||
DestroyAllInstances();
|
||||
ReleasePrefabAsset();
|
||||
}
|
||||
|
||||
private void DestroyAllInstances()
|
||||
{
|
||||
foreach (GameObject instance in _knownInstances)
|
||||
{
|
||||
if (instance == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_activeInstances.Contains(instance))
|
||||
{
|
||||
NotifyPoolablesDespawned(instance);
|
||||
}
|
||||
|
||||
Object.Destroy(instance);
|
||||
}
|
||||
|
||||
_idleInstances.Clear();
|
||||
_activeInstances.Clear();
|
||||
_knownInstances.Clear();
|
||||
_spawnVersions.Clear();
|
||||
|
||||
if (_poolRoot != null)
|
||||
{
|
||||
Object.Destroy(_poolRoot.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
private void ReleasePrefabAsset()
|
||||
{
|
||||
if (_prefab != null && _addressableManager != null)
|
||||
{
|
||||
_addressableManager.ReleaseAsset(_addressableKey);
|
||||
}
|
||||
|
||||
_prefab = null;
|
||||
_loadTask = null;
|
||||
}
|
||||
|
||||
private static void NotifyPoolablesSpawned(GameObject instance)
|
||||
{
|
||||
IPoolable[] poolables = instance.GetComponentsInChildren<IPoolable>(true);
|
||||
for (int i = 0; i < poolables.Length; i++)
|
||||
{
|
||||
poolables[i].OnSpawn();
|
||||
}
|
||||
}
|
||||
|
||||
private static void NotifyPoolablesDespawned(GameObject instance)
|
||||
{
|
||||
IPoolable[] poolables = instance.GetComponentsInChildren<IPoolable>(true);
|
||||
for (int i = 0; i < poolables.Length; i++)
|
||||
{
|
||||
poolables[i].OnDespawn();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fc34059fd203384d9c5aa022301e68f
|
||||
@@ -0,0 +1,244 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts
|
||||
{
|
||||
public sealed class PoolManager : MonoSingleton<PoolManager>
|
||||
{
|
||||
private readonly Dictionary<string, ObjectPool> _pools = new();
|
||||
private readonly Dictionary<GameObject, ObjectPool> _instanceToPool = new();
|
||||
|
||||
private AddressableManager _addressableManager;
|
||||
private Transform _poolContainer;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_addressableManager = AddressableManager.Instance;
|
||||
_addressableManager.OnDispose += ReleaseAllPools;
|
||||
|
||||
_poolContainer = new GameObject("Addressables Object Pools").transform;
|
||||
_poolContainer.SetParent(transform, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Spawns an Addressables prefab from its pool. The returned task completes after the prefab is loaded if needed.
|
||||
/// </summary>
|
||||
public async Task<GameObject> SpawnAsync(
|
||||
string addressableKey,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
float memoryReleaseTTL,
|
||||
float autoDespawnTime = 0f,
|
||||
Transform parent = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(addressableKey))
|
||||
{
|
||||
BMLogger.LogError("PoolManager: Cannot spawn with a null or empty Addressables key.");
|
||||
return null;
|
||||
}
|
||||
|
||||
ObjectPool pool = GetOrCreatePool(addressableKey, memoryReleaseTTL);
|
||||
pool.UpdateMemoryReleaseTTL(memoryReleaseTTL);
|
||||
|
||||
GameObject instance = await pool.SpawnAsync(position, rotation, parent);
|
||||
if (instance == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_instanceToPool[instance] = pool;
|
||||
|
||||
if (autoDespawnTime > 0f)
|
||||
{
|
||||
StartCoroutine(AutoDespawnAfter(pool, instance, pool.GetSpawnVersion(instance), autoDespawnTime));
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Coroutine-friendly spawn API for callers that do not use async/await.
|
||||
/// </summary>
|
||||
public void Spawn(
|
||||
string addressableKey,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
float memoryReleaseTTL,
|
||||
float autoDespawnTime,
|
||||
Action<GameObject> onComplete,
|
||||
Transform parent = null)
|
||||
{
|
||||
StartCoroutine(SpawnRoutine(addressableKey, position, rotation, memoryReleaseTTL, autoDespawnTime, onComplete, parent));
|
||||
}
|
||||
|
||||
public bool Despawn(string addressableKey, GameObject instance)
|
||||
{
|
||||
if (string.IsNullOrEmpty(addressableKey) || instance == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_pools.TryGetValue(addressableKey, out ObjectPool pool))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool despawned = pool.Despawn(instance);
|
||||
if (despawned)
|
||||
{
|
||||
_instanceToPool[instance] = pool;
|
||||
}
|
||||
|
||||
return despawned;
|
||||
}
|
||||
|
||||
public bool Despawn(GameObject instance)
|
||||
{
|
||||
if (instance == null || !_instanceToPool.TryGetValue(instance, out ObjectPool pool))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return pool.Despawn(instance);
|
||||
}
|
||||
|
||||
public bool TryGetPoolCounts(string addressableKey, out int activeCount, out int idleCount)
|
||||
{
|
||||
activeCount = 0;
|
||||
idleCount = 0;
|
||||
|
||||
if (!_pools.TryGetValue(addressableKey, out ObjectPool pool))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
activeCount = pool.ActiveCount;
|
||||
idleCount = pool.IdleCount;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ReleasePool(string addressableKey)
|
||||
{
|
||||
if (!_pools.TryGetValue(addressableKey, out ObjectPool pool))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UnregisterPoolInstances(pool);
|
||||
pool.ReleaseNow();
|
||||
_pools.Remove(addressableKey);
|
||||
}
|
||||
|
||||
public void ReleaseAllPools()
|
||||
{
|
||||
List<ObjectPool> pools = new(_pools.Values);
|
||||
for (int i = 0; i < pools.Count; i++)
|
||||
{
|
||||
pools[i].ReleaseNow();
|
||||
}
|
||||
|
||||
_pools.Clear();
|
||||
_instanceToPool.Clear();
|
||||
}
|
||||
|
||||
internal void RemovePool(ObjectPool pool)
|
||||
{
|
||||
if (pool == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UnregisterPoolInstances(pool);
|
||||
_pools.Remove(pool.AddressableKey);
|
||||
}
|
||||
|
||||
private IEnumerator SpawnRoutine(
|
||||
string addressableKey,
|
||||
Vector3 position,
|
||||
Quaternion rotation,
|
||||
float memoryReleaseTTL,
|
||||
float autoDespawnTime,
|
||||
Action<GameObject> onComplete,
|
||||
Transform parent)
|
||||
{
|
||||
Task<GameObject> spawnTask = SpawnAsync(addressableKey, position, rotation, memoryReleaseTTL, autoDespawnTime, parent);
|
||||
while (!spawnTask.IsCompleted)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (spawnTask.Exception != null)
|
||||
{
|
||||
BMLogger.LogError($"PoolManager: Spawn failed for '{addressableKey}': {spawnTask.Exception}");
|
||||
onComplete?.Invoke(null);
|
||||
yield break;
|
||||
}
|
||||
|
||||
onComplete?.Invoke(spawnTask.Result);
|
||||
}
|
||||
|
||||
private IEnumerator AutoDespawnAfter(ObjectPool pool, GameObject instance, int spawnVersion, float autoDespawnTime)
|
||||
{
|
||||
yield return new WaitForSeconds(autoDespawnTime);
|
||||
|
||||
if (pool != null && pool.IsActiveInstance(instance, spawnVersion))
|
||||
{
|
||||
Despawn(instance);
|
||||
}
|
||||
}
|
||||
|
||||
private ObjectPool GetOrCreatePool(string addressableKey, float memoryReleaseTTL)
|
||||
{
|
||||
if (_pools.TryGetValue(addressableKey, out ObjectPool pool))
|
||||
{
|
||||
return pool;
|
||||
}
|
||||
|
||||
Transform poolRoot = new GameObject(GetPoolRootName(addressableKey)).transform;
|
||||
poolRoot.SetParent(_poolContainer, false);
|
||||
|
||||
pool = new ObjectPool(addressableKey, this, _addressableManager, poolRoot, memoryReleaseTTL);
|
||||
_pools[addressableKey] = pool;
|
||||
return pool;
|
||||
}
|
||||
|
||||
private void UnregisterPoolInstances(ObjectPool pool)
|
||||
{
|
||||
foreach (GameObject instance in pool.GetKnownInstances())
|
||||
{
|
||||
if (instance != null)
|
||||
{
|
||||
_instanceToPool.Remove(instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetPoolRootName(string addressableKey)
|
||||
{
|
||||
string name = addressableKey.Replace('\\', '/');
|
||||
int lastSlash = name.LastIndexOf('/');
|
||||
if (lastSlash >= 0 && lastSlash < name.Length - 1)
|
||||
{
|
||||
name = name.Substring(lastSlash + 1);
|
||||
}
|
||||
|
||||
return $"Pool - {name}";
|
||||
}
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
if (_addressableManager != null)
|
||||
{
|
||||
_addressableManager.OnDispose -= ReleaseAllPools;
|
||||
}
|
||||
|
||||
ReleaseAllPools();
|
||||
base.OnDestroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b8e790a183861dd40bd580421c793038
|
||||
@@ -621,7 +621,13 @@ namespace BrewMonster.Scripts.Skills
|
||||
public virtual string GetName() { return null; }
|
||||
public virtual string GetHH() { return null; }
|
||||
public virtual string GetEffect() { return null; }
|
||||
public static VisibleState Query(int profession, int id) { return null; }
|
||||
public static VisibleState Query(int profession, int id)
|
||||
{
|
||||
// [中文] C++ 实现同样忽略 profession,只按 id 查找
|
||||
// [English] C++ impl also ignores profession; keyed by id only
|
||||
GNET.VisibleState.TryGetValue(id, out var result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
public class TeamState
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using BrewMonster.Network;
|
||||
using CSNetwork;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
@@ -20,6 +21,7 @@ namespace BrewMonster.UI
|
||||
private bool m_bUpdateRenderTarget = false;
|
||||
[SerializeField] TextMeshProUGUI skillNameText;
|
||||
[SerializeField] Image imageProgress;
|
||||
[SerializeField] Button btnCancel;
|
||||
|
||||
public virtual void Show(bool value)
|
||||
{
|
||||
@@ -313,6 +315,11 @@ namespace BrewMonster.UI
|
||||
public virtual void Awake()
|
||||
{
|
||||
m_szName = "Dialog_";
|
||||
if(btnCancel != null)
|
||||
{
|
||||
btnCancel.onClick.RemoveAllListeners();
|
||||
btnCancel.onClick.AddListener(OnClickBtnCancel);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Start()
|
||||
@@ -365,5 +372,10 @@ namespace BrewMonster.UI
|
||||
{
|
||||
CECUIManager.Instance.HideCurrentUIInStack();
|
||||
}
|
||||
|
||||
public void OnClickBtnCancel()
|
||||
{
|
||||
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_PRESSCANCEL, MANAGER_INDEX.MAN_PLAYER, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,64 +27,97 @@ namespace BrewMonster.Scripts.UI.Inventory
|
||||
[SerializeField] private Vector3 previewLocalPosition = Vector3.zero;
|
||||
[SerializeField] private Vector3 previewLocalEuler;
|
||||
[SerializeField] private Vector3 previewLocalScale = Vector3.one;
|
||||
[Tooltip("Copy the preview root layer onto the cloned hierarchy so the preview camera can isolate it.")]
|
||||
[SerializeField] private bool inheritPreviewLayer = true;
|
||||
|
||||
[Header("Camera Output")]
|
||||
[SerializeField] private Camera previewCamera;
|
||||
[SerializeField] private RawImage previewFrame;
|
||||
[SerializeField] private RenderTexture previewRenderTexture;
|
||||
[SerializeField] private bool autoFocusCamera = true;
|
||||
[SerializeField] private Vector3 cameraFocusOffset = new Vector3(0f, 1.5f, 0f);
|
||||
[SerializeField] private Vector3 cameraFocusOffset = new Vector3(0f, 0f, 0f);
|
||||
|
||||
[Header("Behaviour")]
|
||||
[Tooltip("Disable PlayerVisual/Animancer components on the clone so it stays in a frozen idle pose.")]
|
||||
[SerializeField] private bool freezeAnimation = true;
|
||||
[Header("Camera Framing")]
|
||||
[SerializeField] private float previewCameraDistance = 3.3f;
|
||||
[SerializeField] private Vector3 previewCameraOffset = new Vector3(0.15f, 0.8f, 0f);
|
||||
[SerializeField] private bool overrideFieldOfView = true;
|
||||
[SerializeField][Range(10f, 60f)] private float previewFieldOfView = 33f;
|
||||
|
||||
[SerializeField] private bool autoFrameByBounds = true;
|
||||
[SerializeField][Range(1f, 2f)] private float autoFramePadding = 1.15f;
|
||||
[SerializeField] private float minAutoCameraDistance = 1.25f;
|
||||
[SerializeField] private float maxAutoCameraDistance = 8f;
|
||||
|
||||
private bool _cameraStateCached;
|
||||
private Vector3 _cachedCameraPosition;
|
||||
private Quaternion _cachedCameraRotation;
|
||||
private float _cachedCameraFov;
|
||||
|
||||
//[Header("Behaviour")]
|
||||
//[Tooltip("Disable PlayerVisual/Animancer components on the clone so it stays in a frozen idle pose.")]
|
||||
//[SerializeField] private bool freezeAnimation = true;
|
||||
|
||||
private GameObject _previewInstance;
|
||||
private bool _refreshQueued;
|
||||
private int _lastOriginModelChildCount;
|
||||
private Transform _lastOriginModelRoot;
|
||||
private Camera _previewCamera;
|
||||
private PlayerModelPreview _playerModelPreview;
|
||||
private RenderTexture _cachedTargetTexture;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
|
||||
if (previewRoot == null)
|
||||
{
|
||||
previewRoot = transform;
|
||||
}
|
||||
|
||||
TryBindPreviewSystem();
|
||||
TryBindHostPlayer();
|
||||
EnsureCameraBindings();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
TryBindPreviewSystem();
|
||||
EnsureCameraBindings();
|
||||
QueueRefresh();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
DestroyPreviewInstance();
|
||||
RestoreCameraTargetTexture();
|
||||
RestoreSharedCameraState();
|
||||
ReleasePreviewReference();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
TryBindPreviewSystem();
|
||||
TryBindHostPlayer();
|
||||
|
||||
// Check if origin model structure has changed (equipment models are child objects)
|
||||
// This detects equipment changes in realtime since all equipment is attached as children
|
||||
var currentOriginRoot = ResolveSourceModelRoot();
|
||||
if (currentOriginRoot != null)
|
||||
Transform currentOriginRoot = ResolveSourceModelRoot();
|
||||
if (currentOriginRoot == null)
|
||||
{
|
||||
int currentChildCount = CountAllChildren(currentOriginRoot);
|
||||
|
||||
// Refresh if origin model changed or child count changed (equipment added/removed)
|
||||
if (_lastOriginModelRoot != currentOriginRoot || _lastOriginModelChildCount != currentChildCount)
|
||||
if (_previewInstance == null)
|
||||
{
|
||||
_lastOriginModelRoot = currentOriginRoot;
|
||||
_lastOriginModelChildCount = currentChildCount;
|
||||
QueueRefresh();
|
||||
}
|
||||
if(_refreshQueued)
|
||||
{
|
||||
_refreshQueued = false;
|
||||
BuildPreviewModel();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int currentChildCount = CountAllChildren(currentOriginRoot);
|
||||
|
||||
if (_lastOriginModelRoot != currentOriginRoot || _lastOriginModelChildCount != currentChildCount)
|
||||
{
|
||||
_lastOriginModelRoot = currentOriginRoot;
|
||||
_lastOriginModelChildCount = currentChildCount;
|
||||
QueueRefresh();
|
||||
}
|
||||
|
||||
if (_refreshQueued)
|
||||
@@ -92,6 +125,11 @@ namespace BrewMonster.Scripts.UI.Inventory
|
||||
_refreshQueued = false;
|
||||
BuildPreviewModel();
|
||||
}
|
||||
|
||||
if(_previewInstance != null)
|
||||
{
|
||||
EnsureCameraFocus(_previewInstance.transform);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Allows manual binding from external UI scripts.</summary>
|
||||
@@ -119,6 +157,23 @@ namespace BrewMonster.Scripts.UI.Inventory
|
||||
_refreshQueued = true;
|
||||
}
|
||||
|
||||
private void TryBindPreviewSystem()
|
||||
{
|
||||
if (_playerModelPreview == null)
|
||||
{
|
||||
_playerModelPreview = PlayerModelPreview.Instance;
|
||||
}
|
||||
|
||||
if (_playerModelPreview == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_previewCamera == null)
|
||||
{
|
||||
_previewCamera = _playerModelPreview.GetComponent<Camera>();
|
||||
}
|
||||
}
|
||||
|
||||
private void TryBindHostPlayer()
|
||||
{
|
||||
@@ -136,14 +191,40 @@ namespace BrewMonster.Scripts.UI.Inventory
|
||||
|
||||
private void EnsureCameraBindings()
|
||||
{
|
||||
if (previewCamera != null && previewRenderTexture != null)
|
||||
if (_previewCamera == null)
|
||||
{
|
||||
previewCamera.targetTexture = previewRenderTexture;
|
||||
TryBindPreviewSystem();
|
||||
}
|
||||
|
||||
if (previewFrame != null && previewCamera != null)
|
||||
if (_previewCamera == null || previewFrame == null)
|
||||
{
|
||||
previewFrame.texture = previewCamera.targetTexture;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cachedTargetTexture == null)
|
||||
{
|
||||
_cachedTargetTexture = _previewCamera.targetTexture;
|
||||
}
|
||||
|
||||
if (previewRenderTexture != null)
|
||||
{
|
||||
_previewCamera.targetTexture = previewRenderTexture;
|
||||
}
|
||||
|
||||
if(previewFrame != null)
|
||||
previewFrame.texture = _previewCamera.targetTexture;
|
||||
}
|
||||
|
||||
private void RestoreCameraTargetTexture()
|
||||
{
|
||||
if (_previewCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cachedTargetTexture != null)
|
||||
{
|
||||
_previewCamera.targetTexture = _cachedTargetTexture;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,64 +235,43 @@ namespace BrewMonster.Scripts.UI.Inventory
|
||||
return;
|
||||
}
|
||||
|
||||
var sourceRoot = ResolveSourceModelRoot();
|
||||
Transform sourceRoot = ResolveSourceModelRoot();
|
||||
if (sourceRoot == null)
|
||||
{
|
||||
_previewInstance = null;
|
||||
_lastOriginModelRoot = null;
|
||||
_lastOriginModelChildCount = 0;
|
||||
|
||||
QueueRefresh();
|
||||
return;
|
||||
}
|
||||
|
||||
DestroyPreviewInstance();
|
||||
if (_previewInstance != null && _previewInstance != sourceRoot.gameObject)
|
||||
{
|
||||
DestroyPreviewInstance();
|
||||
}
|
||||
|
||||
_previewInstance = Instantiate(sourceRoot.gameObject, previewRoot, false);
|
||||
_previewInstance.name = $"{sourceRoot.name}_Preview";
|
||||
if (!sourceRoot.gameObject.activeSelf)
|
||||
{
|
||||
sourceRoot.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
var instanceTransform = _previewInstance.transform;
|
||||
instanceTransform.localPosition = previewLocalPosition;
|
||||
// Use resolved source root, not sourceModelRoot field directly.
|
||||
_previewInstance = sourceRoot.gameObject;
|
||||
Transform instanceTransform = _previewInstance.transform;
|
||||
|
||||
if (instanceTransform.parent != previewRoot)
|
||||
{
|
||||
instanceTransform.SetParent(previewRoot, false);
|
||||
}
|
||||
|
||||
instanceTransform.localPosition = previewLocalPosition + Vector3.up;
|
||||
instanceTransform.localRotation = Quaternion.Euler(previewLocalEuler);
|
||||
instanceTransform.localScale = previewLocalScale;
|
||||
|
||||
if (inheritPreviewLayer)
|
||||
{
|
||||
ApplyLayerRecursive(instanceTransform, previewRoot.gameObject.layer);
|
||||
}
|
||||
|
||||
if (freezeAnimation)
|
||||
{
|
||||
DisableComponentInChildren<PlayerVisual>(_previewInstance);
|
||||
DisableComponentInChildren<AnimancerComponent>(_previewInstance);
|
||||
DisableComponentInChildren<Animator>(_previewInstance);
|
||||
FreezeAnimators(_previewInstance);
|
||||
}
|
||||
|
||||
if (cloneWholeHostHierarchy && stripRuntimeComponents)
|
||||
{
|
||||
StripRuntimeScripts(_previewInstance);
|
||||
}
|
||||
|
||||
ApplyLayerRecursive(instanceTransform, previewRoot.gameObject.layer);
|
||||
EnsureCameraFocus(instanceTransform);
|
||||
}
|
||||
|
||||
private Transform ResolveSourceModelRoot()
|
||||
{
|
||||
if (sourceModelRoot != null)
|
||||
{
|
||||
return sourceModelRoot;
|
||||
}
|
||||
|
||||
if (hostPlayer == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (cloneWholeHostHierarchy)
|
||||
{
|
||||
sourceModelRoot = hostPlayer.transform;
|
||||
return sourceModelRoot;
|
||||
}
|
||||
|
||||
var playerVisual = hostPlayer.GetComponentInChildren<PlayerVisual>(true);
|
||||
sourceModelRoot = playerVisual != null ? playerVisual.transform : hostPlayer.transform;
|
||||
return sourceModelRoot;
|
||||
EnsureCameraBindings();
|
||||
}
|
||||
|
||||
private void DestroyPreviewInstance()
|
||||
@@ -223,29 +283,79 @@ namespace BrewMonster.Scripts.UI.Inventory
|
||||
}
|
||||
}
|
||||
|
||||
private static void DisableComponentInChildren<T>(GameObject root) where T : Behaviour
|
||||
|
||||
private Transform ResolveSourceModelRoot()
|
||||
{
|
||||
if (root == null)
|
||||
if (sourceModelRoot != null)
|
||||
{
|
||||
return;
|
||||
return sourceModelRoot;
|
||||
}
|
||||
|
||||
var components = root.GetComponentsInChildren<T>(true);
|
||||
for (int i = 0; i < components.Length; i++)
|
||||
if (_playerModelPreview == null)
|
||||
{
|
||||
var component = components[i];
|
||||
if (component == null)
|
||||
continue;
|
||||
return null;
|
||||
}
|
||||
|
||||
component.enabled = false;
|
||||
|
||||
if (component is PlayerVisual)
|
||||
// Prefer active model.
|
||||
for (int i = 0; i < _playerModelPreview.playerModels.Count; i++)
|
||||
{
|
||||
GameObject model = _playerModelPreview.playerModels[i];
|
||||
if (model != null && model.activeSelf)
|
||||
{
|
||||
Destroy(component);
|
||||
return model.transform;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to first available model.
|
||||
for (int i = 0; i < _playerModelPreview.playerModels.Count; i++)
|
||||
{
|
||||
GameObject model = _playerModelPreview.playerModels[i];
|
||||
if (model != null)
|
||||
{
|
||||
return model.transform;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ReleasePreviewReference()
|
||||
{
|
||||
_previewInstance = null;
|
||||
}
|
||||
|
||||
//private void DestroyPreviewInstance()
|
||||
//{
|
||||
// if (_previewInstance != null)
|
||||
// {
|
||||
// Destroy(_previewInstance);
|
||||
// _previewInstance = null;
|
||||
// }
|
||||
//}
|
||||
|
||||
//private static void DisableComponentInChildren<T>(GameObject root) where T : Behaviour
|
||||
//{
|
||||
// if (root == null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var components = root.GetComponentsInChildren<T>(true);
|
||||
// for (int i = 0; i < components.Length; i++)
|
||||
// {
|
||||
// var component = components[i];
|
||||
// if (component == null)
|
||||
// continue;
|
||||
|
||||
// component.enabled = false;
|
||||
|
||||
// if (component is PlayerVisual)
|
||||
// {
|
||||
// Destroy(component);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
private void ApplyLayerRecursive(Transform root, int layer)
|
||||
{
|
||||
if (root == null)
|
||||
@@ -262,70 +372,113 @@ namespace BrewMonster.Scripts.UI.Inventory
|
||||
|
||||
private void EnsureCameraFocus(Transform modelRoot)
|
||||
{
|
||||
if (!autoFocusCamera || previewCamera == null || modelRoot == null)
|
||||
if (_previewCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var focusPoint = modelRoot.TransformPoint(cameraFocusOffset);
|
||||
|
||||
if (!_cameraStateCached)
|
||||
{
|
||||
_cachedCameraPosition = _previewCamera.transform.position;
|
||||
_cachedCameraRotation = _previewCamera.transform.rotation;
|
||||
_cachedCameraFov = _previewCamera.fieldOfView;
|
||||
_cameraStateCached = true;
|
||||
}
|
||||
|
||||
// Apply FOV override independently from auto focus.
|
||||
if (overrideFieldOfView)
|
||||
{
|
||||
_previewCamera.fieldOfView = previewFieldOfView;
|
||||
}
|
||||
|
||||
if (!autoFocusCamera || modelRoot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector3 focusPoint = modelRoot.TransformPoint(cameraFocusOffset) + previewCameraOffset;
|
||||
|
||||
Vector3 viewDirection = modelRoot.forward;
|
||||
viewDirection.y = 0f;
|
||||
if (viewDirection.sqrMagnitude < 0.0001f)
|
||||
{
|
||||
viewDirection = Vector3.back;
|
||||
}
|
||||
|
||||
viewDirection.Normalize();
|
||||
|
||||
_previewCamera.transform.position = focusPoint + viewDirection * previewCameraDistance;
|
||||
_previewCamera.transform.LookAt(focusPoint);
|
||||
}
|
||||
|
||||
private void StripRuntimeScripts(GameObject cloneRoot)
|
||||
//private void StripRuntimeScripts(GameObject cloneRoot)
|
||||
//{
|
||||
// if (cloneRoot == null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// var monoBehaviours = cloneRoot.GetComponentsInChildren<MonoBehaviour>(true);
|
||||
// for (int i = 0; i < monoBehaviours.Length; i++)
|
||||
// {
|
||||
// var behaviour = monoBehaviours[i];
|
||||
// if (behaviour == null)
|
||||
// continue;
|
||||
|
||||
// Destroy(behaviour);
|
||||
// }
|
||||
|
||||
// var colliders = cloneRoot.GetComponentsInChildren<Collider>(true);
|
||||
// for (int i = 0; i < colliders.Length; i++)
|
||||
// {
|
||||
// var collider = colliders[i];
|
||||
// if (collider == null)
|
||||
// continue;
|
||||
|
||||
// Destroy(collider);
|
||||
// }
|
||||
|
||||
// var rigidbodies = cloneRoot.GetComponentsInChildren<Rigidbody>(true);
|
||||
// for (int i = 0; i < rigidbodies.Length; i++)
|
||||
// {
|
||||
// var body = rigidbodies[i];
|
||||
// if (body == null)
|
||||
// continue;
|
||||
|
||||
// Destroy(body);
|
||||
// }
|
||||
//}
|
||||
|
||||
private void RestoreSharedCameraState()
|
||||
{
|
||||
if (cloneRoot == null)
|
||||
if (!_cameraStateCached || _previewCamera == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var monoBehaviours = cloneRoot.GetComponentsInChildren<MonoBehaviour>(true);
|
||||
for (int i = 0; i < monoBehaviours.Length; i++)
|
||||
{
|
||||
var behaviour = monoBehaviours[i];
|
||||
if (behaviour == null)
|
||||
continue;
|
||||
|
||||
Destroy(behaviour);
|
||||
}
|
||||
|
||||
var colliders = cloneRoot.GetComponentsInChildren<Collider>(true);
|
||||
for (int i = 0; i < colliders.Length; i++)
|
||||
{
|
||||
var collider = colliders[i];
|
||||
if (collider == null)
|
||||
continue;
|
||||
|
||||
Destroy(collider);
|
||||
}
|
||||
|
||||
var rigidbodies = cloneRoot.GetComponentsInChildren<Rigidbody>(true);
|
||||
for (int i = 0; i < rigidbodies.Length; i++)
|
||||
{
|
||||
var body = rigidbodies[i];
|
||||
if (body == null)
|
||||
continue;
|
||||
|
||||
Destroy(body);
|
||||
}
|
||||
_previewCamera.transform.position = _cachedCameraPosition;
|
||||
_previewCamera.transform.rotation = _cachedCameraRotation;
|
||||
_previewCamera.fieldOfView = _cachedCameraFov;
|
||||
_cameraStateCached = false;
|
||||
}
|
||||
|
||||
private void FreezeAnimators(GameObject cloneRoot)
|
||||
{
|
||||
if (cloneRoot == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//private void FreezeAnimators(GameObject cloneRoot)
|
||||
//{
|
||||
// if (cloneRoot == null)
|
||||
// {
|
||||
// return;
|
||||
// }
|
||||
|
||||
var animators = cloneRoot.GetComponentsInChildren<Animator>(true);
|
||||
for (int i = 0; i < animators.Length; i++)
|
||||
{
|
||||
var animator = animators[i];
|
||||
if (animator == null)
|
||||
continue;
|
||||
// var animators = cloneRoot.GetComponentsInChildren<Animator>(true);
|
||||
// for (int i = 0; i < animators.Length; i++)
|
||||
// {
|
||||
// var animator = animators[i];
|
||||
// if (animator == null)
|
||||
// continue;
|
||||
|
||||
animator.speed = 0f;
|
||||
}
|
||||
}
|
||||
// animator.speed = 0f;
|
||||
// }
|
||||
//}
|
||||
|
||||
/// <summary>
|
||||
/// Counts all children recursively in the transform hierarchy.
|
||||
|
||||
@@ -30,7 +30,6 @@ namespace BrewMonster.UI
|
||||
[SerializeField] private Button cancelButton;
|
||||
[SerializeField] private Button backButton;
|
||||
[SerializeField] private CDlgMessageBox messageBoxPrefab;
|
||||
[SerializeField] private PlayerModelPreview playerModelPreview;
|
||||
private CDlgMessageBox _messageBoxInstance;
|
||||
|
||||
private int _currentProfession = -1;
|
||||
@@ -403,12 +402,12 @@ namespace BrewMonster.UI
|
||||
}
|
||||
}
|
||||
|
||||
playerModelPreview.ShowAllPlayerModels(_roleInfos);
|
||||
PlayerModelPreview.Instance.ShowAllPlayerModels(_roleInfos);
|
||||
}
|
||||
|
||||
private void LoadShowModel(int prof, int gender)
|
||||
{
|
||||
playerModelPreview.ShowPlayerModel(prof * (int)Gender.NUM_GENDER + gender);
|
||||
PlayerModelPreview .Instance.ShowPlayerModel(prof * (int)Gender.NUM_GENDER + gender);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ namespace BrewMonster.UI
|
||||
{
|
||||
Tech3CSDKWrapper.Instance.SetLoginCallback(OnLoginCallback);
|
||||
Tech3CSDKWrapper.Instance.SetLogoutCallback(OnLogoutCallback);
|
||||
|
||||
if(PlayerModelPreview.Instance != null)
|
||||
{
|
||||
PlayerModelPreview.Instance.HideAllPlayerModels();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
@@ -102,7 +107,7 @@ namespace BrewMonster.UI
|
||||
{
|
||||
if (_roleInfos != null)
|
||||
{
|
||||
_selectCharacterScreen.InitScreen(_roleInfos, OnClickSelectCharacter, OnCreateCharacterComplete);
|
||||
_selectCharacterScreen.InitScreen(_roleInfos, OnClickSelectCharacter, OnCreateCharacterComplete, OnExitCharacterSelect);
|
||||
_roleInfos = null;
|
||||
}
|
||||
|
||||
@@ -422,6 +427,21 @@ namespace BrewMonster.UI
|
||||
{
|
||||
BMLogger.LogError($"Logout failed -- errorCode: {errorCode}: {errorMessage}");
|
||||
}
|
||||
|
||||
_loginInProgress = false;
|
||||
if (_loginButton != null)
|
||||
_loginButton.interactable = true;
|
||||
}
|
||||
|
||||
private void OnExitCharacterSelect()
|
||||
{
|
||||
BMLogger.Log("Exiting character select, returning to login screen.");
|
||||
if(_selectCharacterScreen != null)
|
||||
_selectCharacterScreen.gameObject.SetActive(false);
|
||||
|
||||
_loginInProgress = false;
|
||||
if(_loginButton != null)
|
||||
_loginButton.interactable = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
using BrewMonster.Assets.PerfectWorld.Scripts.UI;
|
||||
using BrewMonster.Common;
|
||||
using BrewMonster.Managers;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts.Managers;
|
||||
using BrewMonster.UI;
|
||||
using CSNetwork.GPDataType;
|
||||
using Cysharp.Threading.Tasks.Triggers;
|
||||
using PerfectWorld.Scripts.Managers;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace BrewMonster
|
||||
{
|
||||
public class TestEditBodyChar : AUIDialog
|
||||
{
|
||||
[Header("List Btn")]
|
||||
[SerializeField] private Button btn_dang_nguoi;
|
||||
[SerializeField] private Button btn_face;
|
||||
[SerializeField] private Button btn_eye;
|
||||
[SerializeField] private Button btn_nose_and_mouth;
|
||||
[SerializeField] private Button btn_hair;
|
||||
[SerializeField] private Button btn_cosplay;
|
||||
|
||||
[Header("List Box Of Edit")]
|
||||
[SerializeField] private GameObject box_dang_nguoi;
|
||||
[SerializeField] private GameObject box_face;
|
||||
[SerializeField] private GameObject box_eye;
|
||||
[SerializeField] private GameObject box_nose_and_mouth;
|
||||
[SerializeField] private GameObject box_hair;
|
||||
[SerializeField] private GameObject box_cosplay;
|
||||
|
||||
[Header("Box Dang Nguoi")]
|
||||
[SerializeField] private GameObject box_1;
|
||||
[SerializeField] private GameObject box_2;
|
||||
[SerializeField] private Button btn_save;
|
||||
[SerializeField] private Button btn_delete_and_setup;
|
||||
[SerializeField] private Button btn_random;
|
||||
[SerializeField] private Button btn_setting_advancde;
|
||||
[SerializeField] private Button btn_back;
|
||||
|
||||
[Header("Box Facae")]
|
||||
[SerializeField] private GameObject box_f_1;
|
||||
[SerializeField] private GameObject box_f_2;
|
||||
[SerializeField] private Button btn_setting_f_advancde;
|
||||
[SerializeField] private Button btn_back_f;
|
||||
|
||||
[Header("Box Eye")]
|
||||
[SerializeField] private GameObject box_e_1;
|
||||
[SerializeField] private GameObject box_e_2;
|
||||
[SerializeField] private Button btn_setting_e_advancde;
|
||||
[SerializeField] private Button btn_back_e;
|
||||
|
||||
[Header("Box Nose and Mouth")]
|
||||
[SerializeField] private GameObject box_n_1;
|
||||
[SerializeField] private GameObject box_n_2;
|
||||
[SerializeField] private Button btn_setting_n_advancde;
|
||||
[SerializeField] private Button btn_back_n;
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
btn_dang_nguoi.onClick.AddListener(OnClickBtnDangNguoi);
|
||||
btn_face.onClick.AddListener(OnClickBtnFace);
|
||||
btn_eye.onClick.AddListener(OnClickBtnEye);
|
||||
btn_nose_and_mouth.onClick.AddListener(OnClickBtnNoseAndMouth);
|
||||
btn_hair.onClick.AddListener(OnClickBtnHair);
|
||||
btn_cosplay.onClick.AddListener(OnClickBtnCosplay);
|
||||
|
||||
btn_setting_advancde.onClick.AddListener(OnClickAdvancedDangNguoi);
|
||||
btn_back.onClick.AddListener(OnClickBackDangNguoi);
|
||||
btn_setting_f_advancde.onClick.AddListener(OnClickAdvancedFace);
|
||||
btn_back_f.onClick.AddListener(OnClickBackFace);
|
||||
btn_setting_e_advancde.onClick.AddListener(OnClickAdvancedEye);
|
||||
btn_back_e.onClick.AddListener(OnClickBackEye);
|
||||
btn_setting_n_advancde.onClick.AddListener(OnClickAdvancedNoseAndMouth);
|
||||
btn_back_n.onClick.AddListener(OnClickBackNoseAndMouth);
|
||||
}
|
||||
|
||||
public override void OnDisable()
|
||||
{
|
||||
btn_dang_nguoi.onClick.RemoveListener(OnClickBtnDangNguoi);
|
||||
btn_face.onClick.RemoveListener(OnClickBtnFace);
|
||||
btn_eye.onClick.RemoveListener(OnClickBtnEye);
|
||||
btn_nose_and_mouth.onClick.RemoveListener(OnClickBtnNoseAndMouth);
|
||||
btn_hair.onClick.RemoveListener(OnClickBtnHair);
|
||||
btn_cosplay.onClick.RemoveListener(OnClickBtnCosplay);
|
||||
btn_setting_advancde.onClick.RemoveListener(OnClickAdvancedDangNguoi);
|
||||
btn_back.onClick.RemoveListener(OnClickBackDangNguoi);
|
||||
btn_setting_f_advancde.onClick.RemoveListener(OnClickAdvancedFace);
|
||||
btn_back_f.onClick.RemoveListener(OnClickBackFace);
|
||||
btn_setting_e_advancde.onClick.RemoveListener(OnClickAdvancedEye);
|
||||
btn_back_e.onClick.RemoveListener(OnClickBackEye);
|
||||
btn_setting_n_advancde.onClick.RemoveListener(OnClickAdvancedNoseAndMouth);
|
||||
btn_back_n.onClick.RemoveListener(OnClickBackNoseAndMouth);
|
||||
}
|
||||
|
||||
private void OnClickBtnDangNguoi()
|
||||
{
|
||||
box_dang_nguoi.SetActive(true);
|
||||
box_face.SetActive(false);
|
||||
box_eye.SetActive(false);
|
||||
box_nose_and_mouth.SetActive(false);
|
||||
box_hair.SetActive(false);
|
||||
box_cosplay.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickBtnFace()
|
||||
{
|
||||
box_dang_nguoi.SetActive(false);
|
||||
box_face.SetActive(true);
|
||||
box_eye.SetActive(false);
|
||||
box_nose_and_mouth.SetActive(false);
|
||||
box_hair.SetActive(false);
|
||||
box_cosplay.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickBtnEye()
|
||||
{
|
||||
box_dang_nguoi.SetActive(false);
|
||||
box_face.SetActive(false);
|
||||
box_eye.SetActive(true);
|
||||
box_nose_and_mouth.SetActive(false);
|
||||
box_hair.SetActive(false);
|
||||
box_cosplay.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickBtnNoseAndMouth()
|
||||
{
|
||||
box_dang_nguoi.SetActive(false);
|
||||
box_face.SetActive(false);
|
||||
box_eye.SetActive(false);
|
||||
box_nose_and_mouth.SetActive(true);
|
||||
box_hair.SetActive(false);
|
||||
box_cosplay.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickBtnHair()
|
||||
{
|
||||
box_dang_nguoi.SetActive(false);
|
||||
box_face.SetActive(false);
|
||||
box_eye.SetActive(false);
|
||||
box_nose_and_mouth.SetActive(false);
|
||||
box_hair.SetActive(true);
|
||||
box_cosplay.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickBtnCosplay()
|
||||
{
|
||||
box_dang_nguoi.SetActive(false);
|
||||
box_face.SetActive(false);
|
||||
box_eye.SetActive(false);
|
||||
box_nose_and_mouth.SetActive(false);
|
||||
box_hair.SetActive(false);
|
||||
box_cosplay.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnClickAdvancedDangNguoi()
|
||||
{
|
||||
box_1.SetActive(false);
|
||||
box_2.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnClickBackDangNguoi()
|
||||
{
|
||||
box_1.SetActive(true);
|
||||
box_2.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickAdvancedFace()
|
||||
{
|
||||
box_f_1.SetActive(false);
|
||||
box_f_2.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnClickBackFace()
|
||||
{
|
||||
box_f_1.SetActive(true);
|
||||
box_f_2.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickAdvancedEye()
|
||||
{
|
||||
box_e_1.SetActive(false);
|
||||
box_e_2.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnClickBackEye()
|
||||
{
|
||||
box_e_1.SetActive(true);
|
||||
box_e_2.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnClickAdvancedNoseAndMouth()
|
||||
{
|
||||
box_n_1.SetActive(false);
|
||||
box_n_2.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnClickBackNoseAndMouth()
|
||||
{
|
||||
box_n_1.SetActive(true);
|
||||
box_n_2.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ed6d61372d1789479a2ac3ad8eaf022
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 951489a2cb8c576469f156d0397b2811
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -500,10 +500,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 7166820878650541780}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 588.35, y: -59.5}
|
||||
m_SizeDelta: {x: 85, y: 85}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &9112205963990496432
|
||||
CanvasRenderer:
|
||||
@@ -907,10 +907,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 7166820878650541780}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 479.18, y: -59.5}
|
||||
m_SizeDelta: {x: 85, y: 85}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &3997873020355048166
|
||||
CanvasRenderer:
|
||||
@@ -1069,138 +1069,6 @@ MonoBehaviour:
|
||||
m_FillOrigin: 2
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &633515748786992396
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5275130098495308601}
|
||||
- component: {fileID: 7874153745862569389}
|
||||
- component: {fileID: 3332719603249310962}
|
||||
m_Layer: 5
|
||||
m_Name: PreviewCamera
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5275130098495308601
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 633515748786992396}
|
||||
m_LocalRotation: {x: 0, y: 1, z: 0, w: 0}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 103}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 6778274724352405780}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
|
||||
m_AnchorMin: {x: 1, y: 1}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 1}
|
||||
m_SizeDelta: {x: 100, y: 100}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!20 &7874153745862569389
|
||||
Camera:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 633515748786992396}
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_ClearFlags: 2
|
||||
m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
|
||||
m_projectionMatrixMode: 1
|
||||
m_GateFitMode: 2
|
||||
m_FOVAxisMode: 0
|
||||
m_Iso: 200
|
||||
m_ShutterSpeed: 0.005
|
||||
m_Aperture: 16
|
||||
m_FocusDistance: 10
|
||||
m_FocalLength: 50
|
||||
m_BladeCount: 5
|
||||
m_Curvature: {x: 2, y: 11}
|
||||
m_BarrelClipping: 0.25
|
||||
m_Anamorphism: 0
|
||||
m_SensorSize: {x: 36, y: 24}
|
||||
m_LensShift: {x: 0, y: 0}
|
||||
m_NormalizedViewPortRect:
|
||||
serializedVersion: 2
|
||||
x: 0
|
||||
y: 0
|
||||
width: 1
|
||||
height: 1
|
||||
near clip plane: 0.3
|
||||
far clip plane: 1000
|
||||
field of view: 38
|
||||
orthographic: 1
|
||||
orthographic size: 1
|
||||
m_Depth: 0
|
||||
m_CullingMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 4294967295
|
||||
m_RenderingPath: -1
|
||||
m_TargetTexture: {fileID: 8400000, guid: 42c3c43cd0c3b704cb6cf0dd1051d9ff, type: 2}
|
||||
m_TargetDisplay: 0
|
||||
m_TargetEye: 3
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
--- !u!114 &3332719603249310962
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 633515748786992396}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a79441f348de89743a2939f4d699eac1, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_RenderShadows: 1
|
||||
m_RequiresDepthTextureOption: 2
|
||||
m_RequiresOpaqueTextureOption: 2
|
||||
m_CameraType: 0
|
||||
m_Cameras: []
|
||||
m_RendererIndex: -1
|
||||
m_VolumeLayerMask:
|
||||
serializedVersion: 2
|
||||
m_Bits: 1
|
||||
m_VolumeTrigger: {fileID: 0}
|
||||
m_VolumeFrameworkUpdateModeOption: 2
|
||||
m_RenderPostProcessing: 0
|
||||
m_Antialiasing: 0
|
||||
m_AntialiasingQuality: 2
|
||||
m_StopNaN: 0
|
||||
m_Dithering: 0
|
||||
m_ClearDepth: 1
|
||||
m_AllowXRRendering: 1
|
||||
m_AllowHDROutput: 1
|
||||
m_UseScreenCoordOverride: 0
|
||||
m_ScreenSizeOverride: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_ScreenCoordScaleBias: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_RequiresDepthTexture: 0
|
||||
m_RequiresColorTexture: 0
|
||||
m_Version: 2
|
||||
m_TaaSettings:
|
||||
m_Quality: 3
|
||||
m_FrameInfluence: 0.1
|
||||
m_JitterScale: 1
|
||||
m_MipBias: 0
|
||||
m_VarianceClampScale: 0.9
|
||||
m_ContrastAdaptiveSharpening: 0
|
||||
--- !u!1 &644319246446733122
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1370,10 +1238,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 7166820878650541780}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 370.01, y: -59.5}
|
||||
m_SizeDelta: {x: 85, y: 85}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4479228720555407959
|
||||
CanvasRenderer:
|
||||
@@ -5061,10 +4929,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 7166820878650541780}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 42.5, y: -59.5}
|
||||
m_SizeDelta: {x: 85, y: 85}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &7052320096474271168
|
||||
CanvasRenderer:
|
||||
@@ -11166,8 +11034,7 @@ RectTransform:
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 5275130098495308601}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 3289674559629147232}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -11231,13 +11098,14 @@ MonoBehaviour:
|
||||
previewLocalPosition: {x: 0, y: 0, z: 100}
|
||||
previewLocalEuler: {x: 0, y: 0, z: 0}
|
||||
previewLocalScale: {x: 1, y: 1, z: 1}
|
||||
inheritPreviewLayer: 1
|
||||
previewCamera: {fileID: 7874153745862569389}
|
||||
previewFrame: {fileID: 6707240765686952970}
|
||||
previewRenderTexture: {fileID: 8400000, guid: 42c3c43cd0c3b704cb6cf0dd1051d9ff, type: 2}
|
||||
autoFocusCamera: 1
|
||||
cameraFocusOffset: {x: 0, y: 0, z: 0}
|
||||
freezeAnimation: 1
|
||||
previewCameraDistance: 3.3
|
||||
previewCameraOffset: {x: 0.06, y: 1.07, z: 0}
|
||||
overrideFieldOfView: 1
|
||||
previewFieldOfView: 44
|
||||
--- !u!1 &5473020210238587200
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -14202,10 +14070,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 7166820878650541780}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 151.67, y: -59.5}
|
||||
m_SizeDelta: {x: 85, y: 85}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &4452551064742165538
|
||||
CanvasRenderer:
|
||||
@@ -19649,10 +19517,10 @@ RectTransform:
|
||||
m_Children: []
|
||||
m_Father: {fileID: 7166820878650541780}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 260.84, y: -59.5}
|
||||
m_SizeDelta: {x: 85, y: 85}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5155025384962724770
|
||||
CanvasRenderer:
|
||||
@@ -20239,7 +20107,7 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7209086543831860202, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -928.02
|
||||
value: -836.15
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8894405194986632892, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchorMax.y
|
||||
@@ -20259,7 +20127,7 @@ PrefabInstance:
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 8894405194986632892, guid: c56ed80641ff74ce49f91401e3eb8367, type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: -464.01
|
||||
value: -418.075
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
|
||||
@@ -32,6 +32,7 @@ RectTransform:
|
||||
- {fileID: 1925327431716214704}
|
||||
- {fileID: 7830969636268911684}
|
||||
- {fileID: 529978810702632783}
|
||||
- {fileID: 1961303628433326950}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -53,6 +54,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
skillNameText: {fileID: 4156282290771635373}
|
||||
imageProgress: {fileID: 7818904766065936941}
|
||||
btnCancel: {fileID: 4979337629572737255}
|
||||
--- !u!1 &1961198748621413970
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -189,6 +191,142 @@ MonoBehaviour:
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &3105178767150005615
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1173275105690546560}
|
||||
- component: {fileID: 2270321894074679265}
|
||||
- component: {fileID: 3782302284108987037}
|
||||
m_Layer: 0
|
||||
m_Name: Text (TMP)
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1173275105690546560
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3105178767150005615}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 1961303628433326950}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2270321894074679265
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3105178767150005615}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &3782302284108987037
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3105178767150005615}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: Cancel
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
|
||||
m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4281479730
|
||||
m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 24
|
||||
m_fontSizeBase: 24
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &4998799320591488598
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -339,3 +477,124 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &8568909860233813620
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1961303628433326950}
|
||||
- component: {fileID: 1490671430424278683}
|
||||
- component: {fileID: 4272345749132423406}
|
||||
- component: {fileID: 4979337629572737255}
|
||||
m_Layer: 0
|
||||
m_Name: BtnCancel
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1961303628433326950
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8568909860233813620}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1173275105690546560}
|
||||
m_Father: {fileID: 3062421795583818898}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -329, y: -243}
|
||||
m_SizeDelta: {x: 160, y: 30}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &1490671430424278683
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8568909860233813620}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &4272345749132423406
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8568909860233813620}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_Type: 1
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &4979337629572737255
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 8568909860233813620}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 4272345749132423406}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
|
||||
@@ -989,8 +989,8 @@ MonoBehaviour:
|
||||
parentItems: {fileID: 2643174602035272289}
|
||||
createCharacterButton: {fileID: 2685968509838782728}
|
||||
_btnEnterGame: {fileID: 5173447691193350084}
|
||||
_btnExit: {fileID: 1166159884785039946}
|
||||
createCharacterScreen: {fileID: 0}
|
||||
playerModelPreview: {fileID: 0}
|
||||
--- !u!1 &7510180475820570348
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"header": 1992,
|
||||
"param": 0,
|
||||
"hasParam": false,
|
||||
"describe": "Buff rage",
|
||||
"lastUsedUtcTicks": 639134653927186702
|
||||
},
|
||||
{
|
||||
"header": 1988,
|
||||
"param": 0,
|
||||
@@ -20,13 +27,6 @@
|
||||
"hasParam": true,
|
||||
"describe": "NoCooldown",
|
||||
"lastUsedUtcTicks": 639123542141980400
|
||||
},
|
||||
{
|
||||
"header": 1992,
|
||||
"param": 0,
|
||||
"hasParam": false,
|
||||
"describe": "Buff rage",
|
||||
"lastUsedUtcTicks": 639119244650372830
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e06e8db90216c9745b7135d4c896cdcf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,344 @@
|
||||
# szActName dump — pre-computed for all skills of this profession
|
||||
# Profession: 0 (PROF_WARRIOR)
|
||||
# Time: 2026-05-04 16:25:37
|
||||
# Total entries: 339
|
||||
|
||||
虎击_吟唱_单手短
|
||||
虎击_施放起_单手短
|
||||
虎击_施放落_单手短
|
||||
虎击_吟唱_双手短
|
||||
虎击_施放起_双手短
|
||||
虎击_施放落_双手短
|
||||
虎击_吟唱_双手长
|
||||
虎击_施放起_双手长
|
||||
虎击_施放落_双手长
|
||||
虎击_吟唱_空拳
|
||||
虎击_施放起_空拳
|
||||
虎击_施放落_空拳
|
||||
寸力_吟唱_单手短
|
||||
寸力_施放起_单手短
|
||||
寸力_施放落_单手短
|
||||
寸力_吟唱_双手短
|
||||
寸力_施放起_双手短
|
||||
寸力_施放落_双手短
|
||||
寸力_吟唱_双手长
|
||||
寸力_施放起_双手长
|
||||
寸力_施放落_双手长
|
||||
寸力_吟唱_空拳
|
||||
寸力_施放起_空拳
|
||||
寸力_施放落_空拳
|
||||
虎跃_吟唱_单手短
|
||||
虎跃_施放起_单手短
|
||||
虎跃_施放落_单手短
|
||||
虎跃_吟唱_双手短
|
||||
虎跃_施放起_双手短
|
||||
虎跃_施放落_双手短
|
||||
虎跃_吟唱_双手长
|
||||
虎跃_施放起_双手长
|
||||
虎跃_施放落_双手长
|
||||
虎跃_吟唱_空拳
|
||||
虎跃_施放起_空拳
|
||||
虎跃_施放落_空拳
|
||||
狮子吼_吟唱_通用
|
||||
狮子吼_施放起_通用
|
||||
狮子吼_施放落_通用
|
||||
狮子吼_吟唱_双手长
|
||||
狮子吼_施放起_双手长
|
||||
狮子吼_施放落_双手长
|
||||
龙现_吟唱_单手短
|
||||
龙现_施放起_单手短
|
||||
龙现_施放落_单手短
|
||||
龙现_吟唱_双手短
|
||||
龙现_施放起_双手短
|
||||
龙现_施放落_双手短
|
||||
龙现_吟唱_双手长
|
||||
龙现_施放起_双手长
|
||||
龙现_施放落_双手长
|
||||
龙现_吟唱_空拳
|
||||
龙现_施放起_空拳
|
||||
龙现_施放落_空拳
|
||||
流水_吟唱_单手短
|
||||
流水_施放起_单手短
|
||||
流水_施放落_单手短
|
||||
流水_吟唱_双手短
|
||||
流水_施放起_双手短
|
||||
流水_施放落_双手短
|
||||
流水_吟唱_双手长
|
||||
流水_施放起_双手长
|
||||
流水_施放落_双手长
|
||||
流水_吟唱_空拳
|
||||
流水_施放起_空拳
|
||||
流水_施放落_空拳
|
||||
狂龙斩_吟唱_单手短
|
||||
狂龙斩_施放起_单手短
|
||||
狂龙斩_施放落_单手短
|
||||
狂龙斩_吟唱_双手短
|
||||
狂龙斩_施放起_双手短
|
||||
狂龙斩_施放落_双手短
|
||||
狂龙斩_吟唱_双手长
|
||||
狂龙斩_施放起_双手长
|
||||
狂龙斩_施放落_双手长
|
||||
狂龙斩_吟唱_空拳
|
||||
狂龙斩_施放起_空拳
|
||||
狂龙斩_施放落_空拳
|
||||
横扫千军_吟唱_单手短
|
||||
横扫千军_施放起_单手短
|
||||
横扫千军_施放落_单手短
|
||||
横扫千军_吟唱_双手短
|
||||
横扫千军_施放起_双手短
|
||||
横扫千军_施放落_双手短
|
||||
横扫千军_吟唱_双手长
|
||||
横扫千军_施放起_双手长
|
||||
横扫千军_施放落_双手长
|
||||
横扫千军_吟唱_空拳
|
||||
横扫千军_施放起_空拳
|
||||
横扫千军_施放落_空拳
|
||||
断岩斩_吟唱_单手短
|
||||
断岩斩_施放起_单手短
|
||||
断岩斩_施放落_单手短
|
||||
断岩斩_吟唱_双手短
|
||||
断岩斩_施放起_双手短
|
||||
断岩斩_施放落_双手短
|
||||
断岩斩_吟唱_双手长
|
||||
断岩斩_施放起_双手长
|
||||
断岩斩_施放落_双手长
|
||||
断岩斩_吟唱_空拳
|
||||
断岩斩_施放起_空拳
|
||||
断岩斩_施放落_空拳
|
||||
劈空掌_吟唱_单手短
|
||||
劈空掌_施放起_单手短
|
||||
劈空掌_施放落_单手短
|
||||
劈空掌_吟唱_双手短
|
||||
劈空掌_施放起_双手短
|
||||
劈空掌_施放落_双手短
|
||||
劈空掌_吟唱_双手长
|
||||
劈空掌_施放起_双手长
|
||||
劈空掌_施放落_双手长
|
||||
劈空掌_吟唱_空拳
|
||||
劈空掌_施放起_空拳
|
||||
劈空掌_施放落_空拳
|
||||
无影脚_吟唱_单手短
|
||||
无影脚_施放起_单手短
|
||||
无影脚_施放落_单手短
|
||||
无影脚_吟唱_双手短
|
||||
无影脚_施放起_双手短
|
||||
无影脚_施放落_双手短
|
||||
无影脚_吟唱_双手长
|
||||
无影脚_施放起_双手长
|
||||
无影脚_施放落_双手长
|
||||
无影脚_吟唱_空拳
|
||||
无影脚_施放起_空拳
|
||||
无影脚_施放落_空拳
|
||||
风卷残云_吟唱_单手短
|
||||
风卷残云_施放起_单手短
|
||||
风卷残云_施放落_单手短
|
||||
风卷残云_吟唱_双手短
|
||||
风卷残云_施放起_双手短
|
||||
风卷残云_施放落_双手短
|
||||
风卷残云_吟唱_双手长
|
||||
风卷残云_施放起_双手长
|
||||
风卷残云_施放落_双手长
|
||||
风卷残云_吟唱_空拳
|
||||
风卷残云_施放起_空拳
|
||||
风卷残云_施放落_空拳
|
||||
云龙九现_吟唱_单手短
|
||||
云龙九现_施放起_单手短
|
||||
云龙九现_施放落_单手短
|
||||
云龙九现_吟唱_双手短
|
||||
云龙九现_施放起_双手短
|
||||
云龙九现_施放落_双手短
|
||||
云龙九现_吟唱_双手长
|
||||
云龙九现_施放起_双手长
|
||||
云龙九现_施放落_双手长
|
||||
云龙九现_吟唱_空拳
|
||||
云龙九现_施放起_空拳
|
||||
云龙九现_施放落_空拳
|
||||
疾风霹雳_吟唱_单手短
|
||||
疾风霹雳_施放起_单手短
|
||||
疾风霹雳_施放落_单手短
|
||||
疾风霹雳_吟唱_双手短
|
||||
疾风霹雳_施放起_双手短
|
||||
疾风霹雳_施放落_双手短
|
||||
疾风霹雳_吟唱_双手长
|
||||
疾风霹雳_施放起_双手长
|
||||
疾风霹雳_施放落_双手长
|
||||
回马枪_吟唱_单手短
|
||||
回马枪_施放起_单手短
|
||||
回马枪_施放落_单手短
|
||||
回马枪_吟唱_双手短
|
||||
回马枪_施放起_双手短
|
||||
回马枪_施放落_双手短
|
||||
回马枪_吟唱_双手长
|
||||
回马枪_施放起_双手长
|
||||
回马枪_施放落_双手长
|
||||
流星赶月_吟唱_单手短
|
||||
流星赶月_施放起_单手短
|
||||
流星赶月_施放落_单手短
|
||||
流星赶月_吟唱_双手短
|
||||
流星赶月_施放起_双手短
|
||||
流星赶月_施放落_双手短
|
||||
流星赶月_吟唱_双手长
|
||||
流星赶月_施放起_双手长
|
||||
流星赶月_施放落_双手长
|
||||
刃域_吟唱_单手短
|
||||
刃域_施放起_单手短
|
||||
刃域_施放落_单手短
|
||||
刃域_吟唱_双手短
|
||||
刃域_施放起_双手短
|
||||
刃域_施放落_双手短
|
||||
刃域_吟唱_双手长
|
||||
刃域_施放起_双手长
|
||||
刃域_施放落_双手长
|
||||
霸王龙飞_吟唱_单手短
|
||||
霸王龙飞_施放起_单手短
|
||||
霸王龙飞_施放落_单手短
|
||||
霸王龙飞_吟唱_双手短
|
||||
霸王龙飞_施放起_双手短
|
||||
霸王龙飞_施放落_双手短
|
||||
霸王龙飞_吟唱_双手长
|
||||
霸王龙飞_施放起_双手长
|
||||
霸王龙飞_施放落_双手长
|
||||
霸王献鼎_吟唱_单手短
|
||||
霸王献鼎_施放起_单手短
|
||||
霸王献鼎_施放落_单手短
|
||||
霸王献鼎_吟唱_双手短
|
||||
霸王献鼎_施放起_双手短
|
||||
霸王献鼎_施放落_双手短
|
||||
霸王献鼎_吟唱_双手长
|
||||
霸王献鼎_施放起_双手长
|
||||
霸王献鼎_施放落_双手长
|
||||
霸王断岳_吟唱_单手短
|
||||
霸王断岳_施放起_单手短
|
||||
霸王断岳_施放落_单手短
|
||||
霸王断岳_吟唱_双手短
|
||||
霸王断岳_施放起_双手短
|
||||
霸王断岳_施放落_双手短
|
||||
霸王断岳_吟唱_双手长
|
||||
霸王断岳_施放起_双手长
|
||||
霸王断岳_施放落_双手长
|
||||
霸王暴怒_吟唱_单手短
|
||||
霸王暴怒_施放起_单手短
|
||||
霸王暴怒_施放落_单手短
|
||||
霸王暴怒_吟唱_双手短
|
||||
霸王暴怒_施放起_双手短
|
||||
霸王暴怒_施放落_双手短
|
||||
霸王暴怒_吟唱_双手长
|
||||
霸王暴怒_施放起_双手长
|
||||
霸王暴怒_施放落_双手长
|
||||
忘情式_吟唱_单手短
|
||||
忘情式_施放起_单手短
|
||||
忘情式_施放落_单手短
|
||||
忘情式_吟唱_双手短
|
||||
忘情式_施放起_双手短
|
||||
忘情式_施放落_双手短
|
||||
忘情式_吟唱_双手长
|
||||
忘情式_施放起_双手长
|
||||
忘情式_施放落_双手长
|
||||
追魂诀_吟唱_单手短
|
||||
追魂诀_施放起_单手短
|
||||
追魂诀_施放落_单手短
|
||||
追魂诀_吟唱_双手短
|
||||
追魂诀_施放起_双手短
|
||||
追魂诀_施放落_双手短
|
||||
追魂诀_吟唱_双手长
|
||||
追魂诀_施放起_双手长
|
||||
追魂诀_施放落_双手长
|
||||
剑气纵横_吟唱_单手短
|
||||
剑气纵横_施放起_单手短
|
||||
剑气纵横_施放落_单手短
|
||||
剑气纵横_吟唱_双手短
|
||||
剑气纵横_施放起_双手短
|
||||
剑气纵横_施放落_双手短
|
||||
剑气纵横_吟唱_双手长
|
||||
剑气纵横_施放起_双手长
|
||||
剑气纵横_施放落_双手长
|
||||
万剑诀_吟唱_单手短
|
||||
万剑诀_施放起_单手短
|
||||
万剑诀_施放落_单手短
|
||||
万剑诀_吟唱_双手短
|
||||
万剑诀_施放起_双手短
|
||||
万剑诀_施放落_双手短
|
||||
万剑诀_吟唱_双手长
|
||||
万剑诀_施放起_双手长
|
||||
万剑诀_施放落_双手长
|
||||
金钟罩_吟唱_通用
|
||||
金钟罩_施放起_通用
|
||||
金钟罩_施放落_通用
|
||||
金钟罩_吟唱_双手长
|
||||
金钟罩_施放起_双手长
|
||||
金钟罩_施放落_双手长
|
||||
回城术_吟唱_通用
|
||||
回城术_施放起_通用
|
||||
回城术_施放落_通用
|
||||
爆气_吟唱_通用
|
||||
爆气_施放起_通用
|
||||
爆气_施放落_通用
|
||||
蓄气_吟唱_通用
|
||||
蓄气_施放起_通用
|
||||
蓄气_施放落_通用
|
||||
挑衅_吟唱_通用
|
||||
挑衅_施放起_通用
|
||||
挑衅_施放落_通用
|
||||
仙元爆发_吟唱_通用
|
||||
仙元爆发_施放起_通用
|
||||
仙元爆发_施放落_通用
|
||||
魔元爆发_吟唱_通用
|
||||
魔元爆发_施放起_通用
|
||||
魔元爆发_施放落_通用
|
||||
雷霆震击_吟唱_通用
|
||||
雷霆震击_施放起_通用
|
||||
雷霆震击_施放落_通用
|
||||
无影_吟唱_单手短
|
||||
无影_施放起_单手短
|
||||
无影_施放落_单手短
|
||||
无影_吟唱_双手短
|
||||
无影_施放起_双手短
|
||||
无影_施放落_双手短
|
||||
一闪_吟唱_单手短
|
||||
一闪_施放起_单手短
|
||||
一闪_施放落_单手短
|
||||
一闪_吟唱_双手短
|
||||
一闪_施放起_双手短
|
||||
一闪_施放落_双手短
|
||||
群体物经_吟唱_通用
|
||||
群体物经_施放起_通用
|
||||
群体物经_施放落_通用
|
||||
狂风_吟唱_双手短
|
||||
狂风_施放起_双手短
|
||||
狂风_施放落_双手短
|
||||
碎颅_吟唱_双手长
|
||||
碎颅_施放起_双手长
|
||||
碎颅_施放落_双手长
|
||||
回旋击_吟唱_双手短
|
||||
回旋击_施放起_双手短
|
||||
回旋击_施放落_双手短
|
||||
龙爪手_施放起_空拳
|
||||
龙爪手_施放落_空拳
|
||||
虎击改_施放起_单手短
|
||||
虎击改_施放落_单手短
|
||||
虎击改_施放起_双手短
|
||||
虎击改_施放落_双手短
|
||||
虎击改_施放起_双手长
|
||||
虎击改_施放落_双手长
|
||||
虎击改_施放起_空拳
|
||||
虎击改_施放落_空拳
|
||||
横扫千军改_施放起_单手短
|
||||
横扫千军改_施放落_单手短
|
||||
横扫千军改_施放起_双手短
|
||||
横扫千军改_施放落_双手短
|
||||
横扫千军改_施放起_双手长
|
||||
横扫千军改_施放落_双手长
|
||||
横扫千军改_施放起_空拳
|
||||
横扫千军改_施放落_空拳
|
||||
凌风改_吟唱_单手短
|
||||
凌风改_施放起_单手短
|
||||
凌风改_施放落_单手短
|
||||
凌风改_吟唱_双手短
|
||||
凌风改_施放起_双手短
|
||||
凌风改_施放落_双手短
|
||||
凌风改_吟唱_双手长
|
||||
凌风改_施放起_双手长
|
||||
凌风改_施放落_双手长
|
||||
凌风改_吟唱_空拳
|
||||
凌风改_施放起_空拳
|
||||
凌风改_施放落_空拳
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2aefef74167a14447b703fe58796fc14
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98a4892172bb4864d8e92a4f17b94d63
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -517,6 +517,7 @@ namespace BrewMonster
|
||||
if (ui != null)
|
||||
{
|
||||
ui.RefreshAll();
|
||||
ui.RefreshCharacterModelPreview();
|
||||
}
|
||||
|
||||
UpdateEquipSkins();
|
||||
|
||||
@@ -578,6 +578,7 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_HST_SETMOVESTAMP: OnMsgHstSetMoveStamp(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_SANCTUARY: OnMsgHstSanctuary(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_RECEIVEEXP: OnMsgHstReceiveExp(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_ROOTNOTIFY: OnMsgHstRootNotify(Msg) ; break;
|
||||
default:
|
||||
// Uncomment to debug unhandled messages
|
||||
// Debug.LogWarning($"[CECHostPlayer] ProcessMessage: Unhandled message {msg}");
|
||||
@@ -604,6 +605,39 @@ namespace BrewMonster
|
||||
}*/
|
||||
}
|
||||
|
||||
private void OnMsgHstRootNotify(in ECMSG Msg)
|
||||
{
|
||||
if ((int)Msg.dwParam2 == CommandID.HOST_NOTIFY_ROOT)
|
||||
{
|
||||
cmd_host_notify_root pCmd = GPDataTypeHelper.FromBytes<cmd_host_notify_root>((byte[])Msg.dwParam1);
|
||||
m_dwLIES |=(uint) (1 << pCmd.type);
|
||||
|
||||
if (pCmd.type != 3)
|
||||
{
|
||||
// Force pull host to specified position
|
||||
SetPos(EC_Utility.ToVector3(pCmd.pos));
|
||||
}
|
||||
|
||||
if (IsRooting())
|
||||
{
|
||||
if (m_pWorkMan.IsFollowing()){
|
||||
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_FOLLOW);
|
||||
}
|
||||
if (m_pWorkMan.IsMovingToPosition()){
|
||||
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_MOVETOPOS);
|
||||
}
|
||||
if (m_pWorkMan.IsTracing()){
|
||||
m_pWorkMan.FinishRunningWork(Host_work_ID.WORK_TRACEOBJECT);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((int)Msg.dwParam2 == CommandID.HOST_DISPEL_ROOT)
|
||||
{
|
||||
cmd_host_dispel_root pCmd = GPDataTypeHelper.FromBytes<cmd_host_dispel_root>((byte[])Msg.dwParam1);
|
||||
m_dwLIES &=(uint) ~(1 << pCmd.type);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnMsgHstPickupMoney(ECMSG msg)
|
||||
{
|
||||
var data = msg.dwParam1 as byte[];
|
||||
|
||||
@@ -18,12 +18,13 @@ namespace BrewMonster.UI
|
||||
[SerializeField] private RectTransform parentItems;
|
||||
[SerializeField] private Button createCharacterButton;
|
||||
[SerializeField] private Button _btnEnterGame;
|
||||
[SerializeField] private Button _btnExit;
|
||||
[SerializeField] private CreateCharacterScreen createCharacterScreen;
|
||||
[SerializeField] private PlayerModelPreview playerModelPreview;
|
||||
|
||||
private CharacterItemUI _selectingCharacterItemUI;
|
||||
private Action<RoleInfo> _onClickItemChar;
|
||||
private Action<RoleInfo> _onCreateCharacterComplete;
|
||||
private Action _onExit;
|
||||
private List<RoleInfo> _roleInfos;
|
||||
|
||||
private Coroutine _showModelReadyCoroutine;
|
||||
@@ -34,13 +35,18 @@ namespace BrewMonster.UI
|
||||
_btnEnterGame.onClick.AddListener(OnClickedEnterGame);
|
||||
_btnEnterGame.gameObject.SetActive(false);
|
||||
|
||||
if(_btnExit != null)
|
||||
{
|
||||
_btnExit.onClick.AddListener(OnClickedExit);
|
||||
}
|
||||
|
||||
if (_roleInfos != null && _roleInfos.Count > 0)
|
||||
{
|
||||
playerModelPreview?.ShowAllPlayerModels(_roleInfos);
|
||||
PlayerModelPreview.Instance?.ShowAllPlayerModels(_roleInfos);
|
||||
}
|
||||
else
|
||||
{
|
||||
playerModelPreview?.ClearModels();
|
||||
PlayerModelPreview.Instance?.ClearModels();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +64,11 @@ namespace BrewMonster.UI
|
||||
}
|
||||
}
|
||||
|
||||
public void InitScreen(List<RoleInfo> roleInfos, Action<RoleInfo> OnClickItemChar, Action<RoleInfo> onCreateCharacterComplete = null)
|
||||
public void InitScreen(List<RoleInfo> roleInfos, Action<RoleInfo> OnClickItemChar, Action<RoleInfo> onCreateCharacterComplete = null, Action onExit = null)
|
||||
{
|
||||
_onClickItemChar = OnClickItemChar;
|
||||
_onCreateCharacterComplete = onCreateCharacterComplete;
|
||||
_onExit = onExit;
|
||||
|
||||
// Clear existing items
|
||||
if (parentItems != null)
|
||||
@@ -111,7 +118,7 @@ namespace BrewMonster.UI
|
||||
addButton.onClick.AddListener(OnCreateCharacterClicked);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -121,14 +128,14 @@ namespace BrewMonster.UI
|
||||
createCharacterButton.gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Load player preview 3D models
|
||||
playerModelPreview?.ShowAllPlayerModels(roleInfos);
|
||||
PlayerModelPreview.Instance?.ShowAllPlayerModels(roleInfos);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (playerModelPreview != null)
|
||||
playerModelPreview.ShowAllPlayerModels(null);
|
||||
if (PlayerModelPreview.Instance != null)
|
||||
PlayerModelPreview.Instance.ShowAllPlayerModels(null);
|
||||
// If roleInfos is null, show createCharacterButton
|
||||
if (createCharacterButton != null)
|
||||
{
|
||||
@@ -144,7 +151,7 @@ namespace BrewMonster.UI
|
||||
return;
|
||||
|
||||
}
|
||||
if(_selectingCharacterItemUI!=null)
|
||||
if (_selectingCharacterItemUI != null)
|
||||
{
|
||||
_selectingCharacterItemUI.SetFocus(false);
|
||||
}
|
||||
@@ -152,9 +159,11 @@ namespace BrewMonster.UI
|
||||
_selectingCharacterItemUI = characterItemUI;
|
||||
_selectingCharacterItemUI.SetFocus(true);
|
||||
_btnEnterGame.gameObject.SetActive(true);
|
||||
_btnEnterGame.interactable = false; // Disable the button until the model is ready
|
||||
|
||||
if (playerModelPreview == null || characterItemUI.RoleInfo == null)
|
||||
if (PlayerModelPreview.Instance == null || characterItemUI.RoleInfo == null)
|
||||
{
|
||||
_btnEnterGame.interactable = true; // If we can't show the model, allow entering the game anyway
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -168,21 +177,23 @@ namespace BrewMonster.UI
|
||||
|
||||
private IEnumerator ShowSelectedModelWhenReady(int roleId)
|
||||
{
|
||||
while (isActiveAndEnabled && playerModelPreview != null)
|
||||
while (isActiveAndEnabled && PlayerModelPreview.Instance != null)
|
||||
{
|
||||
if (_pendingShowModelRoleId != roleId)
|
||||
{
|
||||
yield break; // Role changed, stop this coroutine
|
||||
}
|
||||
|
||||
if (playerModelPreview.playerModelIds != null && playerModelPreview.playerModelIds.Contains(roleId))
|
||||
if (PlayerModelPreview.Instance.playerModelIds != null && PlayerModelPreview.Instance.playerModelIds.Contains(roleId))
|
||||
{
|
||||
playerModelPreview.ShowPlayerModel(roleId);
|
||||
PlayerModelPreview.Instance.ShowPlayerModel(roleId);
|
||||
_btnEnterGame.interactable = true;
|
||||
_showModelReadyCoroutine = null;
|
||||
yield break; // Model is ready, show it and stop this coroutine
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
_btnEnterGame.interactable = true;
|
||||
_showModelReadyCoroutine = null;
|
||||
}
|
||||
|
||||
@@ -227,5 +238,16 @@ namespace BrewMonster.UI
|
||||
BMLogger.LogError("No role selected");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClickedExit()
|
||||
{
|
||||
_onExit?.Invoke();
|
||||
gameObject.SetActive(false);
|
||||
|
||||
if(PlayerModelPreview.Instance != null)
|
||||
{
|
||||
PlayerModelPreview.Instance.HideAllPlayerModels();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
# AddressableManager Public API
|
||||
|
||||
`AddressableManager` is a Unity `MonoSingleton` wrapper around Unity Addressables. It initializes the Addressables system, loads selected asset types, caches loaded handles, and exposes methods for delayed or immediate release.
|
||||
|
||||
This document lists only the public functions from `Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs`.
|
||||
|
||||
## `bool IsInitialized()`
|
||||
|
||||
Returns whether the Addressables initialization callback has completed successfully.
|
||||
|
||||
Use this when another system needs to quickly check if `AddressableManager` is ready before requesting assets. It returns `true` only after `Addressables.InitializeAsync()` finishes with `AsyncOperationStatus.Succeeded`.
|
||||
|
||||
If initialization fails, this method remains `false`.
|
||||
|
||||
## `UniTask WaitUntilInitializedAsync()`
|
||||
|
||||
Waits until `AddressableManager` has finished initializing Unity Addressables.
|
||||
|
||||
If initialization has already completed, this returns `UniTask.CompletedTask` immediately. Otherwise, it waits on the internal initialization completion source that is resolved by the Addressables initialization callback.
|
||||
|
||||
Call this before loading assets from systems that may start before Addressables is ready.
|
||||
|
||||
Example usage:
|
||||
|
||||
```csharp
|
||||
await AddressableManager.Instance.WaitUntilInitializedAsync();
|
||||
```
|
||||
|
||||
## `Task<TextAsset> LoadTextAssetAsync(string assetPath)`
|
||||
|
||||
Loads a `TextAsset` asynchronously through Unity Addressables.
|
||||
|
||||
`assetPath` must match a valid Addressables key, normally the asset address. The method first increases the internal reference count for this path and removes the path from the delayed-release list so the asset will not be released while it is being used again.
|
||||
|
||||
If the text asset was already loaded and the cached handle is still valid, the method returns the cached `TextAsset` immediately. If no valid cached handle exists, it calls:
|
||||
|
||||
```csharp
|
||||
Addressables.LoadAssetAsync<TextAsset>(assetPath)
|
||||
```
|
||||
|
||||
After loading completes, the handle is stored in the text asset cache and the loaded `TextAsset` is returned.
|
||||
|
||||
If loading throws an exception, the method logs an error and returns `null`.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- The loaded asset is cached by `assetPath`.
|
||||
- Repeated calls for the same valid path reuse the cached handle.
|
||||
- The method may return `null` when the asset cannot be loaded.
|
||||
- Release is not automatic after loading. Call a release method when the asset is no longer needed.
|
||||
|
||||
## `Task<GameObject> LoadPrefabAsync(string assetPath)`
|
||||
|
||||
Loads a prefab asynchronously through Unity Addressables and returns it as a `GameObject`.
|
||||
|
||||
`assetPath` must match a valid Addressables key for a `GameObject` prefab. Before loading, the method removes the path from the delayed-release list. It then calls `KeyExists(assetPath, typeof(GameObject))`; if the key is considered missing, it logs a warning and returns `null`.
|
||||
|
||||
If the prefab is already cached and the cached handle is valid, the method returns the cached prefab immediately. Otherwise, it calls:
|
||||
|
||||
```csharp
|
||||
Addressables.LoadAssetAsync<GameObject>(assetPath)
|
||||
```
|
||||
|
||||
After loading completes successfully, the handle is stored in the prefab cache and the prefab `GameObject` is returned.
|
||||
|
||||
If the Addressables operation reports an exception, or if an exception is thrown while loading, the method logs the failure and returns `null`. In the Unity Editor, failed paths are added to an invalid-path cache so later `KeyExists` checks can reject them quickly.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- This loads the prefab asset itself, not an instantiated scene object.
|
||||
- Callers that need an instance should instantiate the returned prefab separately.
|
||||
- The loaded prefab handle is cached by `assetPath`.
|
||||
- The method may return `null` when the key does not exist or loading fails.
|
||||
|
||||
## `Task<AudioClip> LoadAudioClipAsync(string assetPath)`
|
||||
|
||||
Loads an `AudioClip` asynchronously through Unity Addressables.
|
||||
|
||||
`assetPath` must match a valid Addressables key for an audio asset. The method removes the path from the delayed-release list before checking the cache.
|
||||
|
||||
If the audio clip is already cached and the cached handle is valid, the method returns the cached `AudioClip` immediately. Otherwise, it calls:
|
||||
|
||||
```csharp
|
||||
Addressables.LoadAssetAsync<AudioClip>(assetPath.Trim())
|
||||
```
|
||||
|
||||
After loading completes successfully, the handle is stored in the audio cache and the loaded `AudioClip` is returned.
|
||||
|
||||
If the Addressables operation reports an exception, or if an exception is thrown while loading, the method logs the failure and returns `null`.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- The Addressables load uses `assetPath.Trim()`.
|
||||
- The cache key is the original `assetPath` string.
|
||||
- Repeated calls for the same cached path can return immediately.
|
||||
- The method may return `null` when loading fails.
|
||||
|
||||
## `bool TryGetCachedAudioClip(string assetPath, out AudioClip clip)`
|
||||
|
||||
Attempts to retrieve an already loaded `AudioClip` from the internal audio cache without starting a new Addressables load.
|
||||
|
||||
If `assetPath` is null or empty, the method returns `false` and sets `clip` to `null`.
|
||||
|
||||
If the audio cache contains a valid handle for `assetPath` and the handle has a non-null result, the method assigns that cached `AudioClip` to `clip` and returns `true`.
|
||||
|
||||
If no valid cached audio clip exists, the method returns `false` and leaves `clip` as `null`.
|
||||
|
||||
Use this when a caller wants to play audio immediately if it is already loaded, while avoiding an async load path.
|
||||
|
||||
## `void ReleaseAsset(string assetPath)`
|
||||
|
||||
Marks an asset path for delayed release.
|
||||
|
||||
This method does not immediately call `Addressables.Release`. Instead, it records a timestamp in the delayed-release dictionary. During `Update`, once the configured timeout has elapsed, the manager force releases the asset by path.
|
||||
|
||||
If the same path is released multiple times before it is force released, the earliest release timestamp is kept.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- This is a delayed release request.
|
||||
- The asset remains cached until the release timeout expires.
|
||||
- If the asset is loaded again before timeout, load methods remove it from the delayed-release list.
|
||||
- The path must match the same key used to cache the asset.
|
||||
|
||||
## `void ForceReleaseAsset(string assetPath)`
|
||||
|
||||
Immediately releases a cached asset by path.
|
||||
|
||||
The method checks the prefab cache first, then the text asset cache, then the audio cache. If the path exists in one of those caches and the stored handle is valid, it calls:
|
||||
|
||||
```csharp
|
||||
Addressables.Release(handle)
|
||||
```
|
||||
|
||||
After releasing, the method removes the path from the matching cache. For audio assets, it also logs that the audio asset was force released.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- This releases immediately, unlike `ReleaseAsset(string assetPath)`.
|
||||
- Only one matching cache entry is released because the method uses an `if / else if` chain.
|
||||
- If the path is not found in any cache, the method does nothing.
|
||||
|
||||
## `void ReleaseAsset(AsyncOperationHandle<GameObject> handle)`
|
||||
|
||||
Releases a specific `GameObject` Addressables operation handle directly.
|
||||
|
||||
If the provided handle is valid, the method calls:
|
||||
|
||||
```csharp
|
||||
Addressables.Release(handle)
|
||||
```
|
||||
|
||||
This overload does not remove entries from `AddressableManager`'s internal prefab cache because it does not know which `assetPath` the handle belongs to. Prefer releasing by `assetPath` when the asset was loaded through `AddressableManager` and should also be removed from its cache.
|
||||
|
||||
## `void ReleaseAllAssets()`
|
||||
|
||||
Immediately releases all cached prefab and audio assets.
|
||||
|
||||
The method iterates through the prefab cache and releases each valid prefab handle. It then clears the prefab cache. After that, it iterates through the audio cache, releases each valid audio handle, and clears the audio cache.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- This releases prefab and audio caches.
|
||||
- It does not currently release cached text assets from `_loadedTextAssets`.
|
||||
- It logs `"AddressableManager: Released all assets"` after completing.
|
||||
- `OnDestroy` calls this method automatically.
|
||||
|
||||
## `bool IsAssetLoaded(string assetPath)`
|
||||
|
||||
Checks whether a prefab asset path is currently loaded in the prefab cache.
|
||||
|
||||
The method returns `true` only when `_loadedPrefabAssets` contains `assetPath` and the stored handle is valid.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- This checks only loaded prefab assets.
|
||||
- It does not check cached text assets.
|
||||
- It does not check cached audio assets.
|
||||
|
||||
## `static bool KeyExists(object key, System.Type type = null)`
|
||||
|
||||
Checks whether an Addressables key exists.
|
||||
|
||||
In non-editor builds, the method iterates through all loaded Addressables resource locators and calls:
|
||||
|
||||
```csharp
|
||||
locator.Locate(key, type, out var locations)
|
||||
```
|
||||
|
||||
It returns `true` when a locator finds at least one matching resource location. If no locator finds a match, it returns `false`.
|
||||
|
||||
The optional `type` parameter can restrict the lookup to a specific asset type, such as `typeof(GameObject)`.
|
||||
|
||||
In the Unity Editor, this method currently returns `true` unless the key string exists in the manager's `_invalidAssetPaths` set. That means editor behavior is based on paths that previously failed to load, not a full catalog lookup.
|
||||
|
||||
Important behavior:
|
||||
|
||||
- Runtime builds perform a locator-based catalog lookup.
|
||||
- Editor builds use the invalid-path cache.
|
||||
- `LoadPrefabAsync` uses this method before attempting to load a prefab.
|
||||
- Passing a type helps avoid matching an address that exists for a different asset kind.
|
||||
@@ -0,0 +1,74 @@
|
||||
# Pooling Manager Execution Flow
|
||||
|
||||
## Purpose
|
||||
|
||||
The pooling system recycles Addressables-backed `GameObject` instances instead of repeatedly calling `Instantiate` and `Destroy`. Each Addressables key owns one runtime pool that tracks active objects, idle objects, and a memory-release timer.
|
||||
|
||||
`PoolManager` loads prefab assets through `AddressableManager`, so it uses the same Addressables initialization path and loaded-prefab cache as the rest of the project. Runtime instances are ordinary instantiated `GameObject`s owned by the pool.
|
||||
|
||||
## Runtime Files
|
||||
|
||||
- `IPoolable.cs`: prefab-side lifecycle interface.
|
||||
- `ObjectPool.cs`: owns instances and the loaded prefab reference for one Addressables key.
|
||||
- `PoolManager.cs`: singleton service used by gameplay, server packet handlers, UI code, and effects systems.
|
||||
|
||||
## Spawn Flow
|
||||
|
||||
1. Call `PoolManager.Instance.SpawnAsync(...)` or `PoolManager.Instance.Spawn(...)`.
|
||||
2. `PoolManager` finds or creates an `ObjectPool` for the Addressables key.
|
||||
3. The pool updates its `memoryReleaseTTL` from the spawn parameter.
|
||||
4. If a memory release countdown is running, the pool cancels it.
|
||||
5. The pool reuses an idle object when available.
|
||||
6. If no idle object exists, the pool waits for `AddressableManager` initialization, loads the prefab with `AddressableManager.LoadPrefabAsync()`, then instantiates it.
|
||||
7. The instance is parented, positioned, rotated, activated, and all `IPoolable.OnSpawn()` hooks are called.
|
||||
8. If `autoDespawnTime > 0`, `PoolManager` starts a version-checked auto-despawn coroutine.
|
||||
9. The spawned `GameObject` is returned to the caller.
|
||||
|
||||
## Despawn Flow
|
||||
|
||||
1. Call `PoolManager.Instance.Despawn(gameObject)` or `PoolManager.Instance.Despawn(addressableKey, gameObject)`.
|
||||
2. The target pool validates that the object is currently active.
|
||||
3. All `IPoolable.OnDespawn()` hooks are called.
|
||||
4. The object is deactivated, parented under the pool root, and pushed into the idle stack.
|
||||
5. When the active count reaches zero, the pool starts the memory release countdown.
|
||||
|
||||
## Memory Release Flow
|
||||
|
||||
1. The countdown waits for the latest `memoryReleaseTTL` value supplied by spawn calls for that key.
|
||||
2. A new spawn for the same key cancels the countdown and keeps the prefab plus idle instances available.
|
||||
3. If the countdown completes while active count is still zero, the pool:
|
||||
- unregisters itself from `PoolManager`;
|
||||
- destroys all pooled instances;
|
||||
- calls `AddressableManager.ForceReleaseAsset(addressableKey)` to release the cached prefab asset;
|
||||
- destroys the pool root object.
|
||||
|
||||
## Auto Despawn Safety
|
||||
|
||||
Auto despawn stores the instance spawn version when the coroutine starts. If the object is manually despawned and reused before the timer completes, the version changes and the old coroutine will not despawn the new lifecycle.
|
||||
|
||||
## Shutdown Flow
|
||||
|
||||
`PoolManager` subscribes to `AddressableManager.OnDispose`. When the Addressables manager is disposed, all pools release their instances and prefab assets before `AddressableManager.ReleaseAllAssets()` runs. `PoolManager.OnDestroy()` also releases all pools as a fallback.
|
||||
|
||||
## Example
|
||||
|
||||
```csharp
|
||||
GameObject fx = await PoolManager.Instance.SpawnAsync(
|
||||
"effects/fireball.prefab",
|
||||
hitPosition,
|
||||
Quaternion.identity,
|
||||
memoryReleaseTTL: 15f,
|
||||
autoDespawnTime: 2f);
|
||||
```
|
||||
|
||||
For coroutine-based callers:
|
||||
|
||||
```csharp
|
||||
PoolManager.Instance.Spawn(
|
||||
"effects/fireball.prefab",
|
||||
hitPosition,
|
||||
Quaternion.identity,
|
||||
memoryReleaseTTL: 15f,
|
||||
autoDespawnTime: 2f,
|
||||
onComplete: spawned => { /* use spawned */ });
|
||||
```
|
||||
Reference in New Issue
Block a user