Merge branch 'develop' into feature/hp_interact_npc

# Conflicts:
#	Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs
#	Assets/PerfectWorld/Scripts/Move/CECPlayer.cs
#	Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
#	Assets/Scenes/NPCRender.unity
This commit is contained in:
Tungdv
2025-11-17 14:50:24 +07:00
13036 changed files with 747964 additions and 12302 deletions
+1
View File
@@ -114,6 +114,7 @@ public partial class CECGameRun : MonoBehaviour, IMsgHandler
{
Destroy(go,delayTime);
}
public GameObject InitCharacter(info_player_1 info)
{
if (characterPrefab == null)
+161 -38
View File
@@ -104,6 +104,14 @@ public partial class CECHostPlayer : CECPlayer
RaycastHit hit;
private BaseVfxObject m_pSelectedGFX;
private BaseVfxObject m_pHoverGFX;
// Cursor estimation optimization
private Vector2 m_lastMousePosition;
private float m_cursorUpdateTimer;
private const float CURSOR_UPDATE_INTERVAL = 0.05f; // 20 times per second instead of 60+
private UnityEngine.InputSystem.Mouse m_cachedMouse;
private UnityEngine.InputSystem.Keyboard m_cachedKeyboard;
public bool IsChangingFace() { return m_bChangingFace; }
@@ -185,6 +193,10 @@ public partial class CECHostPlayer : CECPlayer
_playerStateMachine.InitState(_idleState);
// btnJump.onClick.AddListener(HandleJump);
// Cache input devices for better performance
m_cachedMouse = UnityEngine.InputSystem.Mouse.current;
m_cachedKeyboard = UnityEngine.InputSystem.Keyboard.current;
}
protected override void Update()
@@ -317,6 +329,9 @@ public partial class CECHostPlayer : CECPlayer
}
m_pWorkMan?.Tick(Time.deltaTime);
// Update cursor based on what's under mouse
EstimateCursor();
// Update GFXs
UpdateGFXs(Time.deltaTime);
}
@@ -559,7 +574,7 @@ public partial class CECHostPlayer : CECPlayer
public bool HostIsReady() { return true /*m_bEnterGame*/; }
private void OnMsgHstDied(in ECMSG msg)
{
EventBus.PublishChannel(GetCharacterID(), new CECPlayer.CleearComActFlagAllRankNodesEvent(true));
EventBus.PublishChannel(GetCharacterID(), new CECPlayer.ClearComActFlagAllRankNodesEvent(true));
PlayAction((int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE);
if (PopupManager.Instance != null)
{
@@ -664,8 +679,6 @@ public partial class CECHostPlayer : CECPlayer
CECNPC pAttacker = EC_ManMessageMono.Instance._CECNPCMan.GetNPC(pCmd.idAttacker);
if (pAttacker)
{
BMLogger.LogError($"HoangDev pAttacker.OnMsgAttackHostResult ");
pAttacker.OnMsgAttackHostResult(GetCharacterID(), pCmd.iDamage, pCmd.attack_flag, pCmd.speed);
}
}
@@ -1118,7 +1131,7 @@ public partial class CECHostPlayer : CECPlayer
isRun = value;
}
public void InitCharacter(cmd_self_info_1 role)
public async void InitCharacter(cmd_self_info_1 role)
{
SetUpPlayer();
controller = GetComponent<CharacterController>();
@@ -1132,7 +1145,7 @@ public partial class CECHostPlayer : CECPlayer
// roleName = Encoding.UTF8.GetString(role.name.ByteArray, 0, role.name.Length);
//}
SetPlayerInfor(new INFO(role.cid, role.crc_e, role.crc_c));
SetModelHostPlayer();
await SetPlayerModel(UnityGameSession.Instance.GetRoleInfo().occupation, UnityGameSession.Instance.GetRoleInfo().gender);
Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z);
string roleName = Encoding.Unicode.GetString(UnityGameSession.Instance.GetRoleInfo().name.ByteArray);
@@ -1174,7 +1187,7 @@ public partial class CECHostPlayer : CECPlayer
var gfxCaster = EC_Game.GetGFXCaster();
// m_pMoveTargetGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_MOVETARGET));
m_pSelectedGFX = await gfxCaster.LoadGFXEx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_SELECTED));
// m_pHoverGFX = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_CURSORHOVER));
m_pHoverGFX = await gfxCaster.LoadGFXEx(EC_Resource.res_GFXFile((int)GfxResourceType.RES_GFX_CURSORHOVER));
// m_pFloatDust = g_pGame->GetGFXCaster()->LoadGFXEx(res_GFXFile(RES_GFX_FLOATING_DUST));
if (true /*CECUIConfig::Instance().GetGameUI().bEnableActionSwitch*/)
@@ -1200,6 +1213,8 @@ public partial class CECHostPlayer : CECPlayer
EventBus.Unsubscribe<JoystickPressEvent>(JoystickStartDrag);
}
//TODO: Remove this function. Since it has been deprecated.
public void InitCharacter(info_player_1 role)
{
string roleName = "(Error decoding name)";
@@ -1210,16 +1225,10 @@ public partial class CECHostPlayer : CECPlayer
Vector3 pos = new Vector3(role.pos.x, role.pos.y, role.pos.z);
if (txtName != null) txtName.text = roleName;
transform.position = pos;
SetModelHostPlayer();
// SetPlayerModel();
//Debug.LogError("Pos Character = " + pos);
}
#region Task
#endregion
private bool NormalAttackObject(int idTarget, bool bForceAttack, bool bMoreClose = false)
{
if (idTarget == 0 || idTarget == m_PlayerInfo.cid)
@@ -2491,44 +2500,46 @@ public partial class CECHostPlayer : CECPlayer
// if (m_pLevelUpGFX)
// m_pLevelUpGFX->SetParentTM(GetAbsoluteTM());
// if (m_pHoverGFX)// && m_idCurHover != m_idSelTarget)
// {
// if (!IsChangingFace() && (ISPLAYERID(m_idCurHover) || ISNPCID(m_idCurHover)))
// {
// CECObject* pObject = pWorld->GetObject(m_idCurHover, 1);
// if (pObject)
// {
// if (m_pHoverGFX->GetState() == ST_STOP)
// m_pHoverGFX->Start();
//
// m_pHoverGFX->SetParentTM(pObject->GetAbsoluteTM());
// }
// else
// m_pHoverGFX->Stop();
// }
// else
// m_pHoverGFX->Stop();
// }
if (m_pHoverGFX)// && m_idCurHover != m_idSelTarget)
{
if (!IsChangingFace() && (GPDataTypeHelper.ISPLAYERID(m_idCurHover) || GPDataTypeHelper.ISNPCID(m_idCurHover)))
{
CECObject pObject = EC_ManMessageMono.Instance?.GetObject(m_idCurHover, 1);
if (pObject)
{
if (m_pHoverGFX.GetState() == GFX_STATE.ST_STOP)
{
m_pHoverGFX.Play();
m_pHoverGFX.transform.parent = pObject.transform;
m_pHoverGFX.transform.localPosition = Vector3.zero;
}
}
else
m_pHoverGFX.Stop(true);
}
else
m_pHoverGFX.Stop(true);
}
if (m_pSelectedGFX)
{
if (!IsChangingFace() && (GPDataTypeHelper.ISPLAYERID(m_idSelTarget) || GPDataTypeHelper.ISNPCID(m_idSelTarget)))
{
var pObject =EC_ManMessageMono.Instance?.GetObject(m_idSelTarget, 1);
var pObject = EC_ManMessageMono.Instance?.GetObject(m_idSelTarget, 1);
if (pObject)
{
if (m_pSelectedGFX.GetState() == GFX_STATE.ST_STOP)
{
m_pSelectedGFX.Play();
// m_pSelectedGFX.SetParentTM(pObject.GetAbsoluteTM());
m_pSelectedGFX.transform.parent = pObject.transform;
m_pSelectedGFX.transform.localPosition = Vector3.zero;
m_pSelectedGFX.transform.parent = pObject.transform;
m_pSelectedGFX.transform.localPosition = Vector3.zero;
}
}
else
m_pSelectedGFX.Stop();
m_pSelectedGFX.Stop(true);
}
else
m_pSelectedGFX.Stop();
m_pSelectedGFX.Stop(true);
}
// if (m_pFloatDust)
@@ -2598,6 +2609,118 @@ public partial class CECHostPlayer : CECPlayer
// ((CDlgOnlineAward*)pGameUI->GetDialog("Win_AddExp2"))->RestartWhenLevelup();
// }
}
// Estimate mouse cursor
private void EstimateCursor()
{
m_cursorUpdateTimer += Time.deltaTime;
if (m_cursorUpdateTimer < CURSOR_UPDATE_INTERVAL)
return;
m_cursorUpdateTimer = 0f;
// Early exit checks
if (IsChangingFace() || mainCam == null || m_cachedMouse == null)
{
m_idCurHover = 0;
return;
}
// Get mouse position using cached device
Vector2 mousePosition = m_cachedMouse.position.ReadValue();
// Early exit if mouse hasn't moved significantly (2 pixel threshold)
if (Vector2.Distance(mousePosition, m_lastMousePosition) < 2f)
return;
m_lastMousePosition = mousePosition;
m_idCurHover = 0;
CursorType cursorType = CursorType.RES_CUR_NORMAL;
// Check modifier keys using cached keyboard
bool isShiftPressed = m_cachedKeyboard != null &&
(m_cachedKeyboard.leftShiftKey.isPressed || m_cachedKeyboard.rightShiftKey.isPressed);
Ray ray = mainCam.ScreenPointToRay(mousePosition);
RaycastHit hit;
// You can add a layer mask here to only raycast against specific layers
// LayerMask interactableMask = LayerMask.GetMask("NPC", "Player", "Item");
// if (Physics.Raycast(ray, out hit, 100f, interactableMask))
if (Physics.Raycast(ray, out hit, 1000f)) // Reduced from 1000f to 100f for better performance
{
// Try to get CECObject component (cached lookup)
CECObject hitObject = hit.collider.GetComponent<CECObject>();
if (hitObject != null)
{
int idHitObject = CECObject.GetObjectID(hitObject);
if (idHitObject != 0)
{
bool bForceAttack = isShiftPressed;
// Check object type and set appropriate cursor
if (GPDataTypeHelper.ISNPCID(idHitObject))
{
// NPC handling
CECNPC pNPC = EC_ManMessageMono.Instance?._CECNPCMan?.GetNPC(idHitObject);
if (pNPC != null && !pNPC.IsDead())
{
m_idCurHover = idHitObject;
if (m_idSelTarget == idHitObject && AttackableJudge(idHitObject, bForceAttack) == 1)
{
cursorType = CursorType.RES_CUR_ATTACK;
}
else if (pNPC.IsServerNPC())
{
if (!IsInBattle() || InSameBattleCamp(pNPC))
{
cursorType = CursorType.RES_CUR_TALK;
}
}
}
}
else if (GPDataTypeHelper.ISPLAYERID(idHitObject))
{
// Player handling
EC_ElsePlayer pPlayer = EC_ManMessageMono.Instance?.GetECManPlayer?.GetPlayer(idHitObject) as EC_ElsePlayer;
if (pPlayer != null)
{
m_idCurHover = idHitObject;
if (m_idSelTarget == idHitObject && AttackableJudge(idHitObject, bForceAttack) == 1)
{
cursorType = CursorType.RES_CUR_ATTACK;
}
}
}
else if (GPDataTypeHelper.ISMATTERID(idHitObject))
{
//todo
// BMLogger.LogError($"[EstimateCursor]- GPDataTypeHelper.ISMATTERID: {idHitObject}");
// Matter/item handling (uncomment when CECMatter is implemented)
// CECMatter pMatter = GetMatterManager()?.GetMatter(idHitObject);
// if (pMatter != null)
// {
// if (!pMatter.IsMine())
// cursorType = CursorType.Pickup;
// else if (CanGatherMatter(pMatter))
// cursorType = pMatter.IsMonsterSpiritMine() ? CursorType.Swallow : CursorType.Dig;
//
// if (cursorType != CursorType.Normal)
// m_idCurHover = idHitObject;
// }
}
}
}
}
// Apply cursor change
EC_Game.ChangeCursor((int)cursorType);
}
}
public enum StateAnim
+6 -3
View File
@@ -40,10 +40,13 @@ public partial class CECHostPlayer
switch (DataType)
{
case DATA_TYPE.DT_WEAPON_ESSENCE:
var equip = (WEAPON_ESSENCE)equipData;
BMLogger.Log($"ShowEquipments():: Weapon Essence: {equip.FileModelRight} -- {equip.FileModelLeft}");
var weaponData = (WEAPON_ESSENCE)equipData;
BMLogger.Log($"ShowEquipments():: Weapon Essence: {weaponData.FileModelRight} -- {weaponData.FileModelLeft}");
break;
case DATA_TYPE.DT_ARMOR_ESSENCE:
var armorData = (ARMOR_ESSENCE)equipData;
BMLogger.Log($"ShowEquipments():: Armor Essence: {armorData.RealName}");
break;
default:
break;
}
+64 -33
View File
@@ -3,6 +3,7 @@ using BrewMonster;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using static CECPlayer;
@@ -14,18 +15,22 @@ public class PlayerVisual : MonoBehaviour
private Dictionary<string, AnimancerState> _activeStates = new();
[SerializeField] private AnimancerState _currentState;
[SerializeField] private Queue<string> _animationQueue = new Queue<string>();
[SerializeField] private List<string> _animationList = new List<string>();
[SerializeField] private bool isHit;
[SerializeField] private int id;
private const float FadeTime = 0.1f;
private const FadeMode FadeMode = Animancer.FadeMode.FixedDuration;
QueueActionEvent queueActionEvent;
private void PlayActionEventHandler(PlayActionEvent @event)
{
_currentState = namedAnimancer.TryPlay(@event.AnimationName);
if (_currentState == null)
{
BMLogger.LogError("HoangDev: PlayActionEventHandler Failed " + @event.AnimationName);
}
// if (_animationQueue.Count > 0)
// {
// _animationQueue.Enqueue(@event.AnimationName);
// return;
// }
InternalPlayAnimation(@event.AnimationName);
}
public void InitPlayerEventDoneHandler()
{
@@ -46,32 +51,33 @@ public class PlayerVisual : MonoBehaviour
id = _playerInfo.cid;
EventBus.SubscribeChannel<PlayActionEvent>(_playerInfo.cid, PlayActionEventHandler);
EventBus.SubscribeChannelClass<QueueActionEvent>(_playerInfo.cid, QueueActionEventHandler);
EventBus.SubscribeChannel<CleearComActFlagAllRankNodesEvent>(_playerInfo.cid, CleearComActFlagAllRankNodesEventHandler);
EventBus.SubscribeChannel<ClearComActFlagAllRankNodesEvent>(_playerInfo.cid, ClearComActFlagAllRankNodesEventHandler);
}
public void InitElsePlayerEventDoneHandler(INFO playerInfo)
{
namedAnimancer = GetComponentInChildren<NamedAnimancerComponent>();
if (namedAnimancer == null)
{
BrewMonster.BMLogger.LogError("animancer == null");
return;
}
//var player = GetComponentInParent<CECPlayer>();
//if (player == null)
//{
// BrewMonster.BMLogger.LogError("player == null");
// return;
//}
_playerInfo = playerInfo;//player.GetPlayInfo();
EventBus.SubscribeChannel<PlayActionEvent>(_playerInfo.cid, PlayActionEventHandler);
EventBus.SubscribeChannelClass<QueueActionEvent>(_playerInfo.cid, QueueActionEventHandler);
EventBus.SubscribeChannel<CleearComActFlagAllRankNodesEvent>(_playerInfo.cid, CleearComActFlagAllRankNodesEventHandler);
}
// public void InitElsePlayerEventDoneHandler(INFO playerInfo)
// {
// namedAnimancer = GetComponentInChildren<NamedAnimancerComponent>();
// if (namedAnimancer == null)
// {
// BrewMonster.BMLogger.LogError("animancer == null");
// return;
// }
// //var player = GetComponentInParent<CECPlayer>();
// //if (player == null)
// //{
// // BrewMonster.BMLogger.LogError("player == null");
// // return;
// //}
// _playerInfo = playerInfo;//player.GetPlayInfo();
// EventBus.SubscribeChannel<PlayActionEvent>(_playerInfo.cid, PlayActionEventHandler);
// EventBus.SubscribeChannelClass<QueueActionEvent>(_playerInfo.cid, QueueActionEventHandler);
// EventBus.SubscribeChannel<CleearComActFlagAllRankNodesEvent>(_playerInfo.cid, CleearComActFlagAllRankNodesEventHandler);
// }
private void CleearComActFlagAllRankNodesEventHandler(CleearComActFlagAllRankNodesEvent @event)
private void ClearComActFlagAllRankNodesEventHandler(ClearComActFlagAllRankNodesEvent @event)
{
_animationQueue.Clear();
_animationList = _animationQueue.ToList();
if (isHit)
{
ApplyDamage();
@@ -93,6 +99,8 @@ public class PlayerVisual : MonoBehaviour
{
if (namedAnimancer == null) return false;
_animationQueue.Enqueue(@event.AnimationName);
_animationList = _animationQueue.ToList();
if (!isHit)
{
queueActionEvent = @event;
@@ -106,15 +114,20 @@ public class PlayerVisual : MonoBehaviour
{
return;
}
if (_currentState == null) return;
if (_currentState.NormalizedTime < 1f) return;
if (isHit)
// if (_currentState == null)
// {
// _animationQueue.Dequeue();
// return;
// }
if (_currentState!=null && _currentState.NormalizedTime < 1f) return;
if (isHit)// have it relative to check _currentState == null?
{
ApplyDamage();
}
string animName = _animationQueue.Dequeue();
_currentState = namedAnimancer.TryPlay(animName);
_animationList = _animationQueue.ToList();
InternalPlayAnimation(animName);
}
void ApplyDamage()
{
@@ -125,10 +138,28 @@ public class PlayerVisual : MonoBehaviour
}
private void OnDestroy()
{
EventBus.UnsubscribeAllInChannel(_playerInfo.cid);
EventBus.UnsubscribeChannel<PlayActionEvent>(_playerInfo.cid, PlayActionEventHandler);
EventBus.UnsubscribeChannelClass<QueueActionEvent>(_playerInfo.cid, QueueActionEventHandler);
EventBus.UnsubscribeChannel<ClearComActFlagAllRankNodesEvent>(_playerInfo.cid, ClearComActFlagAllRankNodesEventHandler);
// EventBus.UnsubscribeAllInChannel(_playerInfo.cid);
}
public bool IsAnimationExist(string animationName)
{
return namedAnimancer.States.TryGet("ActionName", out var existingState) ? true : false;
}
/// <summary>
/// play an animation with name
/// </summary>
/// <param name="animationName"></param>
/// <param name="duration"></param>
/// <param name="fadeMode"></param>
private void InternalPlayAnimation(string animationName, float duration = FadeTime, FadeMode fadeMode = FadeMode)
{
_currentState = namedAnimancer.TryPlay(animationName, duration, fadeMode);
if (_currentState == null)
{
BMLogger.LogError($"Null animation with name: {animationName}");
}
}
}
+14 -13
View File
@@ -2,21 +2,22 @@ using UnityEngine;
namespace BrewMonster
{
// Cursor resource
public enum CursorType
{
RES_CUR_NORMAL = 0,
RES_CUR_ATTACK,
RES_CUR_TALK,
RES_CUR_PICKUP,
RES_CUR_REPAIR,
RES_CUR_HAND,
RES_CUR_FLAG,
RES_CUR_DIG,
RES_CUR_SWALLOW,
NUM_RES_CURSOR,
};
public class EC_Resource
{
// Cursor resource
static readonly string[] l_aCurFiles =
{
"cursors/normal.ani",
"cursors/attack.cur",
"cursors/talk.cur",
"cursors/pick.cur",
"cursors/repair.cur",
"cursors/hand.cur",
"cursors/flag.cur",
"cursors/dig.ani",
"cursors/gourd.cur",
};
// GFX resource
private static readonly string[] l_aGFXFiles = // use where?
{