using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.PerfectWorld.Scripts.Vfx; using BrewMonster.Scripts; using BrewMonster.Scripts.Managers; using BrewMonster.Scripts.Skills; using CSNetwork.GPDataType; using ModelRenderer.Scripts.GameData; using System; using System.Collections; using System.Collections.Generic; using System.Threading.Tasks; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; using System.Runtime.InteropServices; using PerfectWorld.Scripts.Managers.BrewMonster.Managers; using CSNetwork; using ModelRenderer.Scripts.Common; using Unity.VisualScripting; using DG.Tweening.Plugins; using PerfectWorld.Scripts.Managers; using BrewMonster.Scripts.ECModel; namespace BrewMonster { public abstract partial class CECPlayer : CECObject { [SerializeField] protected Transform parentModel; [SerializeField] protected TextMeshProUGUI txtName; [SerializeField] protected Transform pointCam; [ResetStatic] private static PLAYER_ACTION[] _default_actions; [ResetStatic] private static PLAYER_ACTION[] _turning_actions; protected PLAYER_ACTION[] m_PlayerActions; [SerializeField] internal INFO m_PlayerInfo; public CECModel m_pPlayerCECModel; protected GameObject m_pPlayerModel => m_pPlayerCECModel.m_pPlayerModel; public bool IsPlayerModelReady { get; protected set; } protected float rotationSpeed = 5; internal int m_iMoveMode; // Player's move mode [SerializeField] internal int m_idSelTarget; [SerializeField] internal int m_idCurHover; // ID of object under cursor protected int m_iShape; // Ñ¡ÖÐÄ¿±êµÄID protected uint m_dwStates; // Player's basic states protected PVPINFO m_pvp; // pvp information // 当前攻击方式 // Action type for attack animation protected uint m_uAttackType; protected int[] m_aEquips; protected ROLEEXTPROP m_ExtProps; // Extend properties protected int m_iFashionWeaponType; protected float m_fTouchRad = 0.3f; // Touch radius protected bool m_bWeaponAttached; protected bool m_bFight; protected int m_iBattleCamp = Player_camp_in_battle.GP_BATTLE_CAMP_NONE; // Battle this player belongs to byte m_factionPVPMask; // pvp mask protected uint m_dwResFlags; // pvp mask protected ROLEBASICPROP m_BasicProps; public int m_iMoveEnv = Move_environment.MOVEENV_GROUND; // Move environment public bool m_bWalkRun = true; public bool m_bInSanctuary = true; public A3DAABB m_aabbServer = new A3DAABB(); // Óë·þÎñÆ÷±£³ÖÒ»ÖµÄaabb£¬ ²»ÊÜËõ·ÅÓ°Ïì public A3DAABB m_aabb = new A3DAABB(); // Player's aabb£¬ÓÃÓÚÏÔʾµÄaabb£¬ÊÜËõ·ÅÓ°Ïì protected bool m_bCastShadow; // flag indicates whether it will cast shadow public int m_iProfession; // Profession public float m_fScaleBySkill; public int m_iGender; // Gender protected bool m_bFashionMode; public bool m_bShowWeapon; public uint[] m_aExtStates = new uint[OBJECT_EXT_STATE_COUNT]; // Visible extend states from server public uint[] m_aExtStatesShown = new uint[OBJECT_EXT_STATE_COUNT]; // Visible extend states currently shown private QueueActionEvent queueActionEvent; protected static PLAYER_LEVELEXP_CONFIG _player_levelup_exp; protected CECPlayerActionController m_pActionController; protected enumWingType m_wingType = enumWingType.WINGTYPE_FLYSWORD; protected int m_idCurSkillTarget; protected CECSkill m_pCurSkill; protected int m_idFaction; // ID of player's faction protected int m_idForce; // id of the player's force protected BATTLEINFO m_BattleInfo; // Battle information / 战斗信息 protected int NUM_WEAPON_TYPE = 15; public static readonly int[] m_sciStateIDForStateAction = { 117 }; private static Dictionary _default_skill_actions = new Dictionary(); protected int m_iBoothState = 0; // Booth state. 0, none; 1, prepare; 2, open booth; 3, visite other's booth public int m_idFRole = GNETRoles._R_UNMEMBER; // ID of player's faction role protected int m_idCountry = 0; // ¹úÕ½ÕóÓª id public static int MAX_REINCARNATION = 2; protected List m_aCurEffects = new List(); // Current effects protected byte m_ReincarnationCount = 0; protected string m_strName; // Player name // 需要是可能 || Need is possible protected bool m_bHangerOn = false; protected int m_iCurAction; protected bool m_bAboutToDie = false; public bool m_bCandHangerOn = false; public bool m_bPetInSanctuary = false; // true, the pet pet of the player is in sanctuary //The ID of the currently summoned pet protected int m_idCurPet = 0; public List m_aIconStates = new List(); protected byte m_byPariahLvl = 0; // Pariah level public RIDINGPET m_RidingPet; // Riding pet information public GameObject m_pPetModel = null; // Pet model public RIDINGPET m_CandPet;// ID of candidate pet A3DVECTOR3 m_vNamePos; // Æï³Ë×´Ì¬Íæ¼ÒÐÕÃûµÄµ÷Õû // ÒÀ¸½ÀàÐÍ AttachMode m_AttachMode = AttachMode.enumAttachNone; // ÒÀ¸½Õß»ò±»ÒÀ¸½Õßid protected int m_iBuddyId; protected int m_idCandBuddy; // ID of candidate buddy protected EC_ManPlayer m_pPlayerMan => EC_ManMessageMono.Instance?.GetECManPlayer; // Player manager protected Transform playerTransform => _objectTransform ??= transform; protected Transform m_HH_chibang = null; protected Transform m_HH_feijian = null; protected Transform m_CC_chibang = null; protected Transform m_CC_feijian = null; protected Transform m_Wing = null; protected Transform m_Wing2 = null; protected Vector3 m_delta_CC_to_HH = Vector3.zero; public MOVECONST m_MoveConst; // Const used when moving control public Move_Mode m_MoveMode; public MOVECONST[] aMoveConsts = new MOVECONST[(int)PROFESSION.NUM_PROFESSION * GENDER.NUM_GENDER] { // ÎäÏÀ // fStepHei fMinAirHei fMinWaterHei fShoreDepth fWaterSurf new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // ·¨Ê¦ new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // Î×ʦ new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // Ñý¾« new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // ÑýÊÞ new MOVECONST(0.8f, 1.6f, 0.3f, 1.8f, 0.7f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), // ´Ì¿Í new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // Óðâ new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // ÓðÁé new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // ½£Áé new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // ÷ÈÁé new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // Ò¹Ó° new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), // ÔÂÏÉ new MOVECONST(0.8f, 1.6f, 0.3f, 1.6f, 0.6f), new MOVECONST(0.8f, 1.6f, 0.3f, 1.5f, 0.55f), }; public A3DVECTOR3[] aExts = new A3DVECTOR3[(int)PROFESSION.NUM_PROFESSION * GENDER.NUM_GENDER] { new A3DVECTOR3(0.4f, 0.9f, 0.4f), // ÎäÏÀ new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ·¨Ê¦ new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Î×ʦ new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Ñý¾« new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.5f, 1.05f, 0.5f), // ÑýÊÞ new A3DVECTOR3(0.3f, 0.9f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ´Ì¿Í new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Óðâ new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ÓðÁé new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ½£Áé new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ÷ÈÁé new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // Ò¹Ó° new A3DVECTOR3(0.3f, 0.85f, 0.3f), new A3DVECTOR3(0.3f, 0.9f, 0.3f), // ÔÂÏÉ new A3DVECTOR3(0.3f, 0.85f, 0.3f), }; public string[] m_aShapeChineseName = new string[] { //human "武侠男", "武侠女", "法师男", "法师女", // 汐族 巫师 "巫师男", "巫师女", // 妖族 "", "妖精", "妖兽男", "", // 汐族 刺客 "刺客男", "刺客女", // 羽族 "羽芒男", "羽芒女", "羽灵男", "羽灵女", // 灵族 "剑灵男", "剑灵女", "魅灵男", "魅灵女", // 职业变身模型 "白虎", "火狐狸", "影族变身男", "影族变身女", // 技能变身模型(此ID不可变,新模型请往后添加) "金钱蛙", "婚礼童男", "婚礼童女", "园艺区哨兵", "树鸡", "小魔虎", "红色松鼠", "陆化的海龟", "新娘的表哥", "哨兵傀儡", "企鹅帝王", "企鹅皇后", "雪兔", "泰迪熊", "红色松鼠大", "树鸡大", "园艺区哨兵愤怒", "园艺区哨兵沮丧", "园艺区哨兵失落", "雪兔电光", "龙", // 职业变身新模型 "熊猫", "蝶羽狐", // 默认摆摊模型 "男", "女", // 胧族 "夜影男", "夜影女", "月仙男", "月仙女", // 胧族职业变身 "胧族变身夜影男", "胧族变身夜影女", "胧族变身月仙男", "胧族变身月仙女", }; public static class Effect_type { public const int EFF_FACEPILL = 1; } private BaseVfxObject _levelUpVfx; protected GameObject[] m_pModels = new GameObject[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX]; protected int[] m_aShapeID = new int[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX]; protected enum PLAYERMODEL_TYPE { PLAYERMODEL_MAJOR, PLAYERMODEL_PROFESSION, // player profession related PLAYERMODEL_DUMMYTYPE2, // player buff related PLAYERMODEL_DUMMYTYPE3, // not use PLAYERMODEL_MAX, PLAYERMODEL_TYPEALL }; public int PLAYERMODEL_GETTYPE(int iShape) => ((iShape & 0xff) >> 6); public int PLAYERMODEL_GETID(int iShape) => (iShape & 0x3f); protected GameObject GetDummyModel(int i) => (i!=(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR&&i<(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAX) ? m_pModels[i]:null; protected GameObject GetMajorModel() => m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR]; protected GameObject GetPetModel() => m_pPetModel; protected CECModel GetPlayerModel() => m_pPlayerCECModel; protected const int OBJECT_EXT_STATE_COUNT = 6; protected bool IsMajorModel(GameObject pModel) => GetMajorModel() != null && pModel == GetMajorModel(); public enum WeaponHangerPosition { WEAPON_HANGER_HAND, // 左手 WEAPON_HANGER_SHOULDER, // 右手 }; WeaponHangerPosition m_weaponHangerPos = WeaponHangerPosition.WEAPON_HANGER_HAND; protected void Awake() { m_PlayerActions = _default_actions; m_iShape = 0; m_aEquips = new int[(int)IndexOfIteminEquipmentInventory.SIZE_ALL_EQUIPIVTR]; queueActionEvent = new QueueActionEvent("", null, false, null, 200); } /// This function will get the coressponding model player for the player based on the profession and gender public async Task SetPlayerModel(byte profession, byte gender) { // PC prefab used first child as model root; runtime spawns may have no children — avoid GetChild(0) OOB. // PC 预制体用第一个子物体作模型根;运行时生成可能没有子物体 — 避免 GetChild(0) 越界 if (transform.childCount > 0) parentModel = transform.GetChild(0); else parentModel = transform; txtName = GetComponentInChildren(); if (transform.childCount >= 3) { pointCam = transform.GetChild(2); } // Initialize CECModel for hook system // 初始化CECModel以支持挂点系统 await InitializePlayerCECModel(profession,gender); if (m_pPlayerCECModel == null || m_pPlayerModel == null) { throw new InvalidOperationException( $"SetPlayerModel failed to initialize model. profession={profession}, gender={gender}"); } // Cleanup old model if exists // 清理旧模型(如果存在) if (m_pPlayerCECModel != null && m_pPlayerModel != null) { } Debug.Log($"[CECPlayer] SetPlayerModel: profession: {profession}, gender: {gender}"); Debug.Log($"[CECPlayer] SetPlayerModel: m_pPlayerCECModel: {m_pPlayerCECModel}"); Debug.Log($"[CECPlayer] SetPlayerModel: m_pPlayerModel: {m_pPlayerModel}"); Scene scene = SceneManager.GetActiveScene(); SceneManager.MoveGameObjectToScene(m_pPlayerModel, scene); m_pPlayerModel.transform.SetParent(parentModel); m_pPlayerModel.transform.localPosition = Vector3.zero; m_pPlayerModel.SetActive(true); m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR] = m_pPlayerModel; m_iShape = 0; // Set the player model ready flag IsPlayerModelReady = true; // Update visual components after model is set (with delay to ensure NamedAnimancerComponent is available) // 设置模型后更新视觉组件(延迟以确保NamedAnimancerComponent可用) StartCoroutine(UpdateVisualComponentsDelayed()); // Attach weapon after model is set AttachWeapon(); RecreateActionController(); } protected async Task QueueLoadDummyModel(int iShape, bool bAtOnce) { int iShapeType = PLAYERMODEL_GETTYPE(iShape); int iShapeID = PLAYERMODEL_GETID(iShape); // If model already loaded, use it directly. if(m_aShapeID[iShapeType] == iShapeID && m_pModels[iShapeType]) { ApplyShapeModelChange(m_pModels[iShapeType]); return true; } // try to load a new dummy model // if (bAtOnce || !IsLoadThreadReady()) // { // CECModel* pDummyModel = NULL; // if (!LoadDummyModel(iShape, &pDummyModel) || !pDummyModel) // return false; // if (!SetDummyLoadResult(iShape, pDummyModel)) // { // A3DRELEASE(pDummyModel); // return false; // } // } // else // { // int iType = (m_iCID == OCID_HOST_NAVIGATER) ? MTL_ECM_HOST_NAVIGATER_DUMMY:MTL_ECM_PLAYER_DUMMY; // QueueECModelForLoad( // iType, // m_PlayerInfo.cid, // m_dwBornStamp, // GetPos(), // NULL, // iShape); // } //not sure we need the check for IsLoadThreadReady() GameObject pDummyModel = new GameObject("DummyModel"); pDummyModel = await NPCManager.Instance.GetDummyModel(iShapeID); Scene scene = SceneManager.GetActiveScene(); SceneManager.MoveGameObjectToScene(pDummyModel, scene); pDummyModel.transform.SetParent(parentModel); pDummyModel.transform.localPosition = Vector3.zero; pDummyModel.SetActive(true); m_pModels[iShapeType] = pDummyModel; m_aShapeID[iShapeType] = iShapeID; ApplyShapeModelChange(pDummyModel); return true; } protected void ApplyShapeModelChange(GameObject pModel) { // store and reset the attach state int iBuddyId = m_iBuddyId; bool bHangerOn = m_bHangerOn; if (m_AttachMode != AttachMode.enumAttachNone) DetachBuddy(null, false); // logic transform but no model changed if(!pModel) pModel = GetMajorModel(); OnModelChange(pModel); if(pModel && m_pPlayerModel && m_pPlayerModel != pModel) { // sync the position //pModel->SetPos(m_pPlayerModel->GetPos()); // pModel->SetDirAndUp(m_pPlayerModel->GetDir(), m_pPlayerModel->GetUp()); pModel.transform.position = m_pPlayerModel.transform.position; pModel.transform.rotation = m_pPlayerModel.transform.rotation; // if (m_pPlayerModel.transform.forward != Vector3.zero) // { // Quaternion lookRot = Quaternion.LookRotation(m_pPlayerModel.transform.forward, m_pPlayerModel.transform.up); // transform.rotation = lookRot; // } // TODO:sync wing // CECModel* pWing = m_pPlayerModel->GetChildModel(_wing); // m_pPlayerModel->RemoveChildModel(_wing, false); // CECModel* pWing2 = m_pPlayerModel->GetChildModel(_wing2); // m_pPlayerModel->RemoveChildModel(_wing2, false); // if (m_wingType == WINGTYPE_FLYSWORD || m_wingType == WINGTYPE_WING) { // if (pWing) { // pModel->AddChildModel( // _wing, // false, // UsingWing() ? "HH_chibang" : "HH_feijian", // pWing, // UsingWing() ? "CC_chibang" : "CC_feijian"); // } // } else if (m_wingType == WINGTYPE_DOUBLEWHEEL) { // if (pWing) { // pModel->AddChildModel( // _wing, // false, // _hh_left_foot, // pWing, // _cc_fenghuolun); // } // if (pWing2) { // pModel->AddChildModel( // _wing2, // false, // _hh_right_foot, // pWing2, // _cc_fenghuolun); // } // } ShowWing(IsFlying()); // TODO: sync the effect // typedef abase::hash_map::iterator GFXIter; // for(GFXIter i=m_GfxRecords.begin();i!=m_GfxRecords.end();++i) // { // const GFXRECORD& rec = i->second; // m_pPlayerModel->RemoveGfx(rec.strPath, rec.strHook); // if (!pModel->GetGfx(rec.strPath, rec.strHook)){ // pModel->PlayGfx(rec.strPath, rec.strHook, rec.fScale); // } // } } // TODO:change the target if (m_pPlayerModel != pModel){ // ClearShowExtendStates(); // if (IsMajorModel(m_pPlayerModel)){ // RemoveEquipGfx(); // } DetachWeapon(); m_pPlayerModel.SetActive(false); m_pPlayerCECModel.m_pPlayerModel = pModel; pModel.SetActive(true); AttachWeapon(); if (pModel != null){ //ShowExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT); } if (IsMajorModel(m_pPlayerModel)){ //AddEquipGfx(); } RecreateActionController(); // RecreateBodyController(); } // different ground mode SetUseGroundNormal( ShouldUseGroundNormalForCurrentShapeModel() ); PlayAction(GetMoveStandAction(false, IsFighting()), true); // Update NPCVisual's namedAnimancer reference when model changes // 当模型更改时更新NPCVisual的namedAnimancer引用 UpdateVisualComponents(); // Todo: restore the attach state // if (iBuddyId) // { // if( !bHangerOn ) // AttachBuddy(iBuddyId); // else // { // CECPlayer* pBuddy = m_pPlayerMan->GetPlayer(iBuddyId); // if( pBuddy ) pBuddy->AttachBuddy(m_PlayerInfo.cid); // } // } //TODO: ScaleBody //ScaleBody(m_fScaleBySkill); // ս��������Ч����ʱģ���Ѽ��أ�gfx�ɲ��š� // TODO: chariotwar // CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer(); // if (IsHostPlayer() && pHost && pHost->GetBattleInfo().IsChariotWar()) // { // CChariot* pChariot = pHost->GetChariot(); // if (pChariot && pChariot->IsUpdateState()) // { // PlayGfx(res_GFXFile(RES_GFX_LEVELUP), NULL, 4.0, PLAYERMODEL_TYPEALL); // BubbleText(BUBBLE_LEVELUP, 0); // pChariot->UpdateState(0,0);// �ָ�ս��������־ // } // } } bool ShouldUseGroundNormalForCurrentShapeModel() { return IsShapeModelChanged() && !IsTransofrmModelLikeHuman(GetProfession(), GetGender(), GetShapeID()); } static bool IsTransofrmModelLikeHuman(int nChar, int nGender, int nModelID){ bool result = false; int[] likeHumanModelArray = null; int likeHumanModelCount = 0; switch (nChar) { case (int)PROFESSION.PROF_YEYING: if ((int)GENDER.GENDER_MALE == nGender){ const int LIKE_HUMAN_MODEL_COUNT = 1; int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YEYING_RESHAPE_M}; likeHumanModelArray = s_LikeHumanModel; likeHumanModelCount = s_LikeHumanModel.Length; }else{ const int LIKE_HUMAN_MODEL_COUNT = 1; int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YEYING_RESHAPE_F}; likeHumanModelArray = s_LikeHumanModel; likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT; } break; case (int)PROFESSION.PROF_YUEXIAN: if ((int)GENDER.GENDER_MALE == nGender){ const int LIKE_HUMAN_MODEL_COUNT = 1; int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_M}; likeHumanModelArray = s_LikeHumanModel; likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT; }else{ const int LIKE_HUMAN_MODEL_COUNT = 1; int[] s_LikeHumanModel = {(int) ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_F}; likeHumanModelArray = s_LikeHumanModel; likeHumanModelCount = LIKE_HUMAN_MODEL_COUNT; } break; } if (likeHumanModelCount > 0){ // const int *begin = likeHumanModelArray; // const int *end = likeHumanModelArray + likeHumanModelCount; // if (std::find(begin, end, _GetProfessionTransformModelID(nChar, nGender, nModelID)) != end){ // result = true; // } foreach (int model in likeHumanModelArray) { if (model == nModelID) { result = true; break; } } } return result; } protected virtual bool IsShapeModelChanged() { return m_pModels[(int)PLAYERMODEL_TYPE.PLAYERMODEL_MAJOR] != m_pPlayerModel; } /// /// Update visual components (NPCVisual, PlayerVisual) when model changes /// 当模型更改时更新视觉组件(NPCVisual、PlayerVisual) /// private void UpdateVisualComponents() { // Use the current active player model as the search root // 使用当前活动的玩家模型作为搜索根 GameObject modelRoot = m_pPlayerModel; if (modelRoot == null) { BMLogger.LogWarning("CECPlayer: UpdateVisualComponents - _pPlayerModel is null, cannot update visual components"); return; } // Update NPCVisual if it exists // 如果存在NPCVisual则更新它 NPCVisual npcVisual = GetComponent(); if (npcVisual != null) { npcVisual.RefreshNamedAnimancer(modelRoot); } // Update PlayerVisual if it exists // 如果存在PlayerVisual则更新它 PlayerVisual playerVisual = GetComponentInChildren(); if (playerVisual != null) { playerVisual.RefreshNamedAnimancer(modelRoot); } } /// /// Delayed update of visual components to ensure NamedAnimancerComponent is available /// 延迟更新视觉组件以确保NamedAnimancerComponent可用 /// private IEnumerator UpdateVisualComponentsDelayed() { // Wait one frame for NamedAnimancerComponent to be available // 等待一帧以确保NamedAnimancerComponent可用 yield return null; if (m_pPlayerModel == null) yield break; UpdateVisualComponents(); } private async Task InitializePlayerCECModel(byte profession, byte gender) { if(m_pPlayerCECModel!= null && m_pPlayerCECModel.m_pPlayerModel != null) { m_pPlayerCECModel.InvalidateHookCache(); } // Get or create CECModel instance // 获取或创建CECModel实例 if (m_pPlayerCECModel == null) { m_pPlayerCECModel = new CECModel(); } m_pPlayerCECModel.SetId(m_PlayerInfo.cid); if (NPCManager.Instance == null) { BMLogger.LogError("[CECPlayer] NPCManager.Instance is null while loading player model."); return; } m_pPlayerCECModel.m_pPlayerModel = await NPCManager.Instance.GetModelPlayer(profession, gender); if (m_pPlayerCECModel.m_pPlayerModel == null) { BMLogger.LogError($"[CECPlayer] GetModelPlayer returned null. profession={profession}, gender={gender}"); return; } // Find SkeletonBuilder component on model GameObject // 在模型GameObject上查找SkeletonBuilder组件 SkeletonBuilder skeletonBuilder = m_pPlayerModel.GetComponentInChildren(); CombineActHolder combineActHolder = m_pPlayerModel.GetComponentInChildren(); CombinedActionSO combinedAction = null; if (combineActHolder != null) { try { combinedAction = combineActHolder.ActionSO; } catch (Exception ex) { BMLogger.LogWarning($"[CECPlayer] Failed to read CombineActHolder.ActionSO on '{m_pPlayerModel.name}': {ex.Message}"); } } if (skeletonBuilder == null) { // SkeletonBuilder might not be built yet, try to find it after a frame // SkeletonBuilder可能尚未构建,尝试在一帧后查找 StartCoroutine(InitializePlayerCECModelDelayed()); return; } // Set references on CECModel // 在CECModel上设置引用 m_pPlayerCECModel.SetSkeletonBuilder(skeletonBuilder); m_pPlayerCECModel.SetTransform(m_pPlayerModel.transform); if(combinedAction != null) { m_pPlayerCECModel.SetCombinedAction(combinedAction); } // Initialize skeleton builder (ensures hooks are available) // 初始化骨架构建器(确保挂点可用) m_pPlayerCECModel.InitializeSkeletonBuilder(); } public void OnModelChange(GameObject changeModel) { RefreshCECModel(changeModel); } public void RefreshCECModel(GameObject changeModel) { if (changeModel == null) { return; } m_pPlayerCECModel.SetSkeletonBuilder(changeModel.GetComponentInChildren()); m_pPlayerCECModel.SetTransform(changeModel.transform); // Keep action map in sync with the currently active model (major/dummy). // 让动作映射与当前激活模型(主模型/变身模型)保持一致。 CombineActHolder combineActHolder = changeModel.GetComponentInChildren(); if (combineActHolder != null) { try { if (combineActHolder.ActionSO != null) { m_pPlayerCECModel.SetCombinedAction(combineActHolder.ActionSO); } else { BMLogger.LogWarning($"[CECPlayer] RefreshCECModel: CombineActHolder.ActionSO is null on '{changeModel.name}'."); } } catch (Exception ex) { BMLogger.LogWarning($"[CECPlayer] RefreshCECModel: Failed to read CombineActHolder.ActionSO on '{changeModel.name}': {ex.Message}"); } } else { BMLogger.LogWarning($"[CECPlayer] RefreshCECModel: CombineActHolder not found on '{changeModel.name}'."); } m_pPlayerCECModel.InitializeSkeletonBuilder(); } /// /// Delayed initialization coroutine for cases where SkeletonBuilder builds after model load /// 延迟初始化协程,用于SkeletonBuilder在模型加载后构建的情况 /// private IEnumerator InitializePlayerCECModelDelayed() { // Wait one frame for SkeletonBuilder to be built // 等待一帧以便SkeletonBuilder被构建 yield return null; if (m_pPlayerModel == null) yield break; SkeletonBuilder skeletonBuilder = m_pPlayerModel.GetComponentInChildren(); if (skeletonBuilder != null) { if (m_pPlayerCECModel == null) { m_pPlayerCECModel = new CECModel(); } m_pPlayerCECModel.SetSkeletonBuilder(skeletonBuilder); m_pPlayerCECModel.SetTransform(m_pPlayerModel.transform); // Initialize skeleton builder (ensures hooks are available) // 初始化骨架构建器(确保挂点可用) m_pPlayerCECModel.InitializeSkeletonBuilder(); } else { BMLogger.LogWarning($"[CECPlayer] SkeletonBuilder not found on player model after delay. Hook system may not work."); } } public virtual void OnMsgPlayerExtState(ECMSG Msg) { if (Convert.ToInt32(Msg.dwParam2) == CommandID.UPDATE_EXT_STATE) { cmd_update_ext_state pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); if (pCmd.id == m_PlayerInfo.cid) { SetNewExtendStates(0, pCmd.states, (int)OBJECT_EXT_STATE.OBJECT_EXT_STATE_COUNT); } } else if (Convert.ToInt32(Msg.dwParam2) == CommandID.ICON_STATE_NOTIFY) { cmd_icon_state_notify cmd = new cmd_icon_state_notify(); if (!cmd.Initialize((byte[])Msg.dwParam1)) { return; } if (cmd.id == m_PlayerInfo.cid) { m_aIconStates = cmd.states; if (m_aIconStates.Count > 1) { m_aIconStates.Sort((a, b) => { if (a.id < b.id) return -1; if (a.id > b.id) return 1; return 0; }); } } } } public virtual void SetNewExtendStates(int start, uint[] pData, int count) { if(pData == null || start + count > OBJECT_EXT_STATE_COUNT) { return; } ShowExtendStates(start, pData, count); Array.Copy(pData, start, m_aExtStates, start, count); if(GetExtState(111)) { // ������ת���� ̫�顤����� m_PlayerActions = _turning_actions; } else { m_PlayerActions = _default_actions; } } void ShowExtendStates(int start, uint[] pData, int count, bool bIgnoreOptimize=false ) { if(pData == null || start + count > OBJECT_EXT_STATE_COUNT) { return; } if (!IsAllResReady() || !GetMajorModel()) return; //TODO: Implement optimization // if (!bIgnoreOptimize && // !CECOptimize::Instance().GetGFX().CanShowState(GetCharacterID(), GetClassID())) // return; //static const char* szBasePath = "�߻�����\\״̬Ч��\\"; const int bitSize = sizeof(uint) * 8; BMLogger.LogError($"[CECPlayer] ShowExtendStates: start: {start}, count: {count}, bitSize: {bitSize}"); for (int index = 0; indexGetEffect(); // if (!strGFXFile.GetLength()) // continue; // strGFXFile = szBasePath + strGFXFile; // if (TestProcessPetCureGFX(strGFXFile, dwFlag2 != 0, i + idState*bitSize)) // continue; if (dwFlag1 != 0) { 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 { // ģ������Ч // RemoveGfx(strGFXFile, pvs->GetHH(), PLAYERMODEL_TYPEALL); } } // 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); // } // } } } Array.Copy(pData, start, m_aExtStatesShown, start, count); } bool GetExtState(int n) { const int bitSize = sizeof(uint) * 8; const int totalBitSize = bitSize * OBJECT_EXT_STATE_COUNT; if(n < 0 || n >= totalBitSize) return false; int index = n / bitSize; int bitOffset = n % bitSize; return (m_aExtStates[index] & (1 << bitOffset)) != 0; } public virtual void SetUpPlayer() { m_dwResFlags = 0; m_iFashionWeaponType = -1; m_uAttackType = DEFAULT_ACTION_TYPE; } public void SetPlayerInfor(INFO playinfo) { m_PlayerInfo = playinfo; if (m_pPlayerCECModel != null) { m_pPlayerCECModel.SetId(m_PlayerInfo.cid); } } public INFO GetPlayInfo() { return m_PlayerInfo; } public void CalcPlayerAABB() { int iIndex = m_iProfession * GENDER.NUM_GENDER + m_iGender; m_aabb.Extents = aExts[iIndex] * m_fScaleBySkill; m_aabbServer.Extents = aExts[iIndex]; m_MoveConst = aMoveConsts[iIndex]; } public static async Task LoadPlayerSkin(GameObject aSkins, int index, string szFile) { // these are LOD suffix string[] suffix1 = { "一�?", "二级", "三级" }; string[] suffix2 = { "", "二级", "三级" }; string szSkinFile = ""; if (index == EC_Player_Skin_Const.SKIN_BODY_INDEX || index == EC_Player_Skin_Const.SKIN_HEAD_INDEX) szSkinFile = $"{szFile}{suffix2[0]}"; else szSkinFile = $"{szFile}{suffix1[0]}"; aSkins = await AddressableManager.Instance.LoadPrefabAsync(szSkinFile); if (aSkins == null) return false; return true; } public static void InitStaticRes() { BuildActionList(); DATA_TYPE dt = default; _player_levelup_exp = (PLAYER_LEVELEXP_CONFIG)ElementDataManProvider.GetElementDataMan() .get_data_ptr(202, ID_SPACE.ID_SPACE_CONFIG, ref dt); } public bool IsDead() { return (m_dwStates & PlayerNPCState.GP_STATE_CORPSE) != 0; } public bool IsInvisible() { return (m_dwStates & PlayerNPCState.GP_STATE_INVISIBLE) != 0; } public bool IsInSanctuary() { return m_bInSanctuary; } public bool IsValidAction(int iIndex) { return (iIndex >= 0 && iIndex < (int)PLAYER_ACTION_TYPE.ACT_MAX) ? true : false; } public int GetCharacterID() { return m_PlayerInfo.cid; } /// /// Get player's CECModel instance /// 获取玩家的CECModel实例 /// /// CECModel instance or null / CECModel实例,未找到返回null public CECModel GetPlayerCECModel() { return m_pPlayerCECModel; } /// /// Get hook Transform by name (convenience method) /// 根据名称获取挂点变换(便捷方法) /// /// Hook name / 挂点名称 /// Search recursively / 递归搜索 /// Hook Transform or null / 挂点变换,未找到返回null public Transform GetHook(string hookName, bool recursive = true) { CECModel model = GetPlayerCECModel(); return model?.GetHook(hookName, recursive); } private static void BuildActionList() { if (_default_actions == null) { Dictionary actionMap = new Dictionary(100); Dictionary skillActionMap = new Dictionary(100); elementdataman dataman = ElementDataManProvider.GetElementDataMan(); PLAYER_ACTION_INFO_CONFIG data; int count = dataman.get_data_num(ID_SPACE.ID_SPACE_CONFIG); DATA_TYPE dt = default; uint id = 0; for (int i = 0; i < count; ++i) { id = dataman.get_data_id(ID_SPACE.ID_SPACE_CONFIG, i, ref dt); if (dt != DATA_TYPE.DT_PLAYER_ACTION_INFO_CONFIG) continue; data = (PLAYER_ACTION_INFO_CONFIG)dataman.get_data_ptr(id, ID_SPACE.ID_SPACE_CONFIG, ref dt); if (!string.IsNullOrEmpty(data.ActionName)) { if (!actionMap.TryAdd(data.ActionName, data)) { } } if (!string.IsNullOrEmpty(data.ActionName)) { if (!skillActionMap.TryAdd(data.Name, data)) { } } } /// CECStringTab actionNames = new CECStringTab(); actionNames.Init("actions_player", false); _default_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX]; for (int i = 0; i < _default_actions.Length; i++) { _default_actions[i].type = (PLAYER_ACTION_TYPE)i; string szName = actionNames.GetANSIString(i); if (!string.IsNullOrEmpty(szName)) { if (actionMap.TryGetValue(szName, out var it)) { _default_actions[i].data = it; } } } if (_turning_actions != null) _turning_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX]; _turning_actions = new PLAYER_ACTION[(int)PLAYER_ACTION_TYPE.ACT_MAX]; if (actionMap.TryGetValue("自身旋转", out PLAYER_ACTION_INFO_CONFIG turningData)) { for (int i = 0; i < (int)PLAYER_ACTION_TYPE.ACT_MAX; i++) { if (i < (int)PLAYER_ACTION_TYPE.ACT_GROUNDDIE || i > (int)PLAYER_ACTION_TYPE.ACT_REVIVE) { // Dùng hành động xoay thay thế hành động thường _turning_actions[i].type = (PLAYER_ACTION_TYPE)i; _turning_actions[i].data = turningData; } else { // Dùng hành động mặc định _turning_actions[i] = _default_actions[i]; } } } uint idSkill = 0; while (true) { idSkill = ElementSkill.NextSkill(idSkill); if (idSkill == 0) break; string skillName = ElementSkill.GetName(idSkill); if (!string.IsNullOrEmpty(skillName)) { var checkExist = skillActionMap.TryGetValue(skillName, out PLAYER_ACTION_INFO_CONFIG data1); if (checkExist) { if(!_default_skill_actions.ContainsKey(idSkill)) { _default_skill_actions.Add(idSkill, data1); } #if DEBUG_OUTPUT_ACTIONS for (int n = 0; n < PlayerSkillAction.NUM_WEAPON_TYPE; n++) { var suffix = data.action_weapon_suffix[n].suffix; if (!string.IsNullOrEmpty(suffix)) { Debug.Log($"{data.action_prefix}_Ò÷³ª_{suffix}"); Debug.Log($"{data.action_prefix}_Ê©·ÅÆð_{suffix}"); Debug.Log($"{data.action_prefix}_Ê©·ÅÂä_{suffix}"); } } #endif continue; } } // ❌ not found // Debug.LogWarning($"CECPlayer::BuildActionList() Failed to find skill action {idSkill}!"); } } } public bool PlayAction(int iAction, bool bRestart = true, int iTransTime = 200, bool bQueue = false) { return PlayActionWithConfig(iAction, 0, bRestart, iTransTime, bQueue); } public bool PlayAction(int iAction, int actionConfigID, bool bRestart = true, int iTransTime = 200, bool bQueue = false) { return PlayActionWithConfig(iAction, actionConfigID, bRestart, iTransTime, bQueue); } private bool PlayActionWithConfig(int iAction, int actionConfigID, bool bRestart = true, int iTransTime = 200, bool bQueue = false) { if (iAction < 0 || iAction >= (int)PLAYER_ACTION_TYPE.ACT_MAX) { return false; } if (actionConfigID > 0) { DATA_TYPE dt = DATA_TYPE.DT_INVALID; var p = ElementDataManProvider.GetElementDataMan() .get_data_ptr((uint)actionConfigID, ID_SPACE.ID_SPACE_CONFIG, ref dt); if (dt == DATA_TYPE.DT_PLAYER_ACTION_INFO_CONFIG) { PLAYER_ACTION actionConfig; actionConfig.type = (PLAYER_ACTION_TYPE)iAction; actionConfig.data = (PLAYER_ACTION_INFO_CONFIG)p; return PlayActionWithConfig(iAction, actionConfig, bRestart, iTransTime, bQueue); } else { } } return PlayActionWithConfig(iAction, m_PlayerActions[iAction], bRestart, iTransTime, bQueue); } const int COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX = 3; private bool PlayActionWithConfig(int iAction, in PLAYER_ACTION actionConfig, bool bRestart = true, int iTransTime = 200, bool bQueue = false) { m_iCurAction = iAction; PLAYER_ACTION action = actionConfig; int weapon_type = GetShowingWeaponType(); string szAct = ""; if(m_pActionController != null) { if (iAction != (int)PLAYER_ACTION_TYPE.ACT_WOUNDED) { if (iAction == (int)PLAYER_ACTION_TYPE.ACT_TAKEOFF){ ShowWing(true); }else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_LANDON){ ShowWing(false); } if( action.data.id == 0 ) return false; if( !bQueue ) { // update show weapon states. m_bShowWeapon = action.data.hide_weapon != 0 ? false : true; } if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 && iAction <= (int)PLAYER_ACTION_TYPE.ACT_ATTACK_4 ) { // attack action should not be played by this function return false; } else if( iAction == (int)PLAYER_ACTION_TYPE.ACT_ATTACK_TOSS ) { // we use toss second part action as a common action // sprintf(szAct, "%s_%s��", action.data->action_prefix, action.data->action_weapon_suffix[weapon_type].suffix); szAct = $"{action.data.ActionPrefix}_{action.data.action_weapon_suffix[weapon_type].Suffix}"; if( !bQueue ){ m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime); }else{ m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTransTime, bRestart, false, false, true, null, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX); } return true; } else if( ( iAction >= (int)PLAYER_ACTION_TYPE.ACT_EXP_WAVE && iAction <= (int)PLAYER_ACTION_TYPE.ACT_EXP_KISS_END) || (iAction >= (int)PLAYER_ACTION_TYPE.ACT_EXP_FIGHT && iAction <= (int)PLAYER_ACTION_TYPE.ACT_EXP_DANCE) ) { // ���鶯�� string strFashionAction=""; if (iAction == (int)PLAYER_ACTION_TYPE.ACT_EXP_DANCE && InFashionMode()) strFashionAction = GetFashionActionName(); szAct = $"{(string.IsNullOrEmpty(strFashionAction) ? action.data.ActionPrefix : strFashionAction)}_{action.data.action_weapon_suffix[weapon_type].Suffix}"; if( !bQueue ){ m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime); }else{ m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTransTime, false, false, false, true, null, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX); } return true; } else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_EXP_FASHIONWEAPON) { if (CanShowFashionWeapon((int)m_uAttackType, m_iFashionWeaponType)) { string strAction = ""; int idEquipment = m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WEAPON] & 0x0000ffff; GetFashionActionNameByID(idEquipment, ref strAction); if (!string.IsNullOrEmpty(strAction)) { //by2024 sprintf_s //sprintf(szAct, "%s_%s", strAction, action.data->action_weapon_suffix[weapon_type].suffix); szAct = $"{strAction}_{action.data.action_weapon_suffix[weapon_type].Suffix}"; if( !bQueue ){ m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime); }else{ m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTransTime, false, false, false, true, null, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX); } } } return true; } else { // ͨ�ö��� if (m_pPetModel) { if( iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND ) action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND]; else if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_PICKUP && iAction <= (int)PLAYER_ACTION_TYPE.ACT_PICKUP_MATTER ) action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND]; // if( iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS ) // sprintf(szAct, "վ��_����_˫��_ͨ��"); // else // sprintf(szAct, "%s_%s", action.data->action_prefix, "���_ͨ��"); string szPetAct = ""; if (iAction == (int)PLAYER_ACTION_TYPE.ACT_STAND || iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND) szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_STAND); else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_RUN) szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_RUN); else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK) szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_WALK); else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_START) szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_JUMP_START); else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LAND) szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_JUMP_LAND); else if (iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP) szPetAct = CECPet.GetBaseActionName((int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP); if( !bQueue ) { //Play pet action here // m_pPetModel->PlayActionByName(szPetAct, 1.0f, bRestart, iTransTime, true); } else { //Play pet action here // m_pPetModel->QueueAction(szPetAct, iTransTime); } // now weapon wanted. m_bShowWeapon = false; } else if (m_bHangerOn) { if( iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND ) action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND]; else if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_PICKUP && iAction <= (int)PLAYER_ACTION_TYPE.ACT_PICKUP_MATTER ) action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND]; if( iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS ) { if (m_AttachMode == AttachMode.enumAttachRideOnPlayer) szAct = "亲吻_双人_通用"; // Kiss_TwoPerson_Common else if (m_AttachMode == AttachMode.enumAttachHugPlayer) szAct = "亲吻_抱_通用"; // Kiss_Hug_Common else if (m_AttachMode == AttachMode.enumAttachRideOnPet) szAct = "亲吻_双人_通用"; // Kiss_TwoPerson_Common } else { // if (m_AttachMode == enumAttachRideOnPlayer) // sprintf(szAct, "%s_%s", action.data->action_prefix, "˫��_ͨ��"); // else if (m_AttachMode == enumAttachHugPlayer) // { // if( iAction != ACT_RUN ) // sprintf(szAct, "%s", "վ��_��_ͨ��"); // else // sprintf(szAct, "%s", "����_��_ͨ��"); // } // else if (m_AttachMode == enumAttachRideOnPet) // sprintf(szAct, "%s_%s", action.data->action_prefix, "˫��_ͨ��"); } // now weapon wanted. m_bShowWeapon = false; } else if (m_AttachMode == AttachMode.enumAttachHugPlayer || m_AttachMode == AttachMode.enumAttachRideOnPlayer) { if( iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND ) action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND]; else if( iAction >= (int)PLAYER_ACTION_TYPE.ACT_PICKUP && iAction <= (int)PLAYER_ACTION_TYPE.ACT_PICKUP_MATTER ) action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_STAND]; if( iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS ) { action = m_PlayerActions[GetMoveStandAction(false, false)]; // if (m_AttachMode == enumAttachHugPlayer) // sprintf(szAct, "%s_%s", action.data->action_prefix, "����_��_ͨ��"); // else // sprintf(szAct, "%s_%s", action.data->action_prefix, "����_��_ͨ��"); } else szAct= $"{action.data.ActionPrefix}_抱_通用"; // Hug_Common // now weapon wanted. m_bShowWeapon = false; } // else szAct= $"{action.data.ActionPrefix}_{action.data.action_weapon_suffix[weapon_type].Suffix}"; // CECModel pRightHandWeapon = GetRightHandWeapon(); // if( !bQueue ) // { // PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime); // if(pRightHandWeapon && IsUsingMagicWeapon()) // pRightHandWeapon->PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, bRestart, iTransTime, true, iAction); // } // else // { // QueueNonSkillActionWithName(iAction, szAct, iTransTime, bRestart, false, false, true, NULL, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX); // if(pRightHandWeapon && IsUsingMagicWeapon()) // pRightHandWeapon->QueueAction(_GenWeaponActionName(szAct, m_iGender), iTransTime, iAction, bRestart ? true : false); // } if (m_iBuddyId != 0) { if( !m_bHangerOn ) { CECPlayer pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId); if (pBuddy) { if( iAction == (int)PLAYER_ACTION_TYPE.ACT_STAND || iAction == (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND || iAction == (int)PLAYER_ACTION_TYPE.ACT_RUN || iAction == (int)PLAYER_ACTION_TYPE.ACT_WALK || iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_START || iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LOOP || iAction == (int)PLAYER_ACTION_TYPE.ACT_JUMP_LAND || iAction == (int)PLAYER_ACTION_TYPE.ACT_WOUNDED || iAction == (int)PLAYER_ACTION_TYPE.ACT_TWO_KISS ) { pBuddy.PlayAction(iAction, bRestart, iTransTime, bQueue); } else pBuddy.PlayAction((int)PLAYER_ACTION_TYPE.ACT_STAND, bRestart, iTransTime, bQueue); } } } } } else // iAction == ACT_WOUNDED { PLAYER_ACTION elseAction = m_PlayerActions[iAction]; m_pActionController.PlayWoundActionWithName(ByteToStringUtils.ByteArrayToUTF8String(action.data.action_name)); return true; // if (m_pPetModel != null) // { // A3DSkinModel pSkinModel = m_pPetModel.GetA3DSkinModel(); // const char* szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_WOUNDED); // if (!pSkinModel->GetAction(szPetAct)) // { // szPetAct = CECNPC::GetBaseActionName(CECNPC::ACT_WOUNDED2); // if (!pSkinModel->GetAction(szPetAct)) // szPetAct = NULL; // if (szPetAct) // pSkinModel->PlayActionByName(szPetAct, CECModel::ACTCHA_WOUND, 1, 0, false); // } // } } // if( !bQueue ) // { // if( !m_bShowWeapon ) // ShowWeapon(false); // else // { // // ��ʦ��Ծʱ��Ҫ���ط��� // if(IsUsingMagicWeapon() && (iAction == ACT_JUMP_START || iAction == ACT_JUMP_LAND || iAction == ACT_JUMP_LOOP)) // ShowWeapon(false); // else // ShowWeapon(true); // } // // ���ݲ��Ŷ�����������������λ�� // UpdateWeaponHangerPosByAction(iAction); // } // EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szShapeName, szAct, iTransTime)); m_pActionController.PlayNonSkillActionWithName(iAction, szAct, bRestart, iTransTime); return true; } else { return false; } //var szAct = EC_Utility.BuildActionName(action, weapon_type); return true; } public static void Dispose() { _default_actions = null; _turning_actions = null; } public INFO GetPlayerInfo() { return m_PlayerInfo; } // Get basic properties public ROLEBASICPROP GetBasicProps() { return m_BasicProps; } // Get extend properties public ROLEEXTPROP GetExtendProps() { return m_ExtProps; } protected override void Update() { base.Update(); if (m_CandPet.id != 0 /*&& GetMajorModel()*/) { string szPetPath = GetRidingPetFileName(m_CandPet.id); QueueLoadPetModel(szPetPath, false); m_CandPet.Reset(); } } public void PlayAttackEffect(int idTarget, int idSkill, int skillLevel, int nDamage, uint dwModifier, int nAttackSpeed, ref int piAttackTime, int nSection = 0) { if (!IsAllResReady()) return; if (idSkill == 0) { int idWeapon = IsShapeChanged() ? 0 : GetWeaponID(); int nTimeFly = 10; if (idWeapon != 0) { // ¿´¿´ÊDz»ÊÇÔ¶³ÌÎäÆ÷ DATA_TYPE dt = default; WEAPON_ESSENCE? pWeapon = (WEAPON_ESSENCE)ElementDataManProvider.GetElementDataMan() .get_data_ptr((uint)idWeapon, ID_SPACE.ID_SPACE_ESSENCE, ref dt); if (dt == DATA_TYPE.DT_WEAPON_ESSENCE && pWeapon != null && pWeapon.Value.require_projectile != 0) { nTimeFly = 700; if (m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE] != 0) idWeapon = m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_PROJECTILE]; } } if (CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid)) { ClearComActFlagAllRankNodes(true); } // melee attack CECAttackEvent pAttack1 = CECAttacksMan.Instance.AddMeleeAttack( GetPlayerInfo().cid, idTarget, idWeapon, dwModifier, nDamage, nTimeFly); if (pAttack1 != null) { if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0 && (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0 && PlayAttackAction(nAttackSpeed, ref piAttackTime, pAttack1) && (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0) { } else { pAttack1.m_bSignaled = true; } } } else { if (skillLevel == 0) { if (m_pCurSkill != null) skillLevel = m_pCurSkill.GetSkillLevel(); else skillLevel = 1; } CECAttackEvent pAttack = null; // first try to find if there is already a skill attack event in attackman CECAttackerEvents attackerEvents = CECAttacksMan.Instance.FindAttackByAttacker(GetPlayerInfo().cid); if (attackerEvents) { CECAttackEvent pAttack1 = attackerEvents.Find(idSkill, nSection); if (pAttack1 != null) { // Ãæ¹¥»÷µÄ·ÇµÚÒ»´ÎÉ˺¦ÏûÏ¢ pAttack1.AddTarget(idTarget, dwModifier, nDamage); goto EXIT; } else { attackerEvents.Signal(); } } if (ElementSkill.IsGoblinSkill((uint)idSkill) && ElementSkill.GetType((uint)idSkill) == 2) { pAttack = CECAttacksMan.Instance.AddSkillAttack( GetPlayerInfo().cid, GetPlayerInfo().cid, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage); } else { // begin a skill attack pAttack = CECAttacksMan.Instance.AddSkillAttack( GetPlayerInfo().cid, m_idCurSkillTarget, idTarget, GetWeaponID(), idSkill, skillLevel, dwModifier, nDamage); } if (pAttack != null) { int unusedInt = 0; pAttack.SetSkillSection(nSection); if (!IsDead() && (dwModifier & (uint)MOD.MOD_RETORT) == 0 && (dwModifier & (uint)MOD.MOD_ATTACK_AURA) == 0 && PlaySkillAttackAction(idSkill, nAttackSpeed, ref unusedInt, nSection, pAttack) && (dwModifier & (uint)MOD.MOD_BEAT_BACK) == 0) { pAttack.m_bSignaled = true; } else { pAttack.m_bSignaled = true; } } EXIT: // // For skill attacking, time is always set to 0 if (piAttackTime != 0) piAttackTime = 0; } } protected void ClearComActFlagAllRankNodes(bool v) { //EventBus.PublishChannel(m_PlayerInfo.cid, new ClearComActFlagAllRankNodesEvent(v)); m_pActionController.ClearComActFlagAllRankNodes(v); } public bool PlayAttackAction(int nAttackSpeed, ref int attackTime, CECAttackEvent attackEvent) { //attackTime = 0; //if (_pPlayerModel == null) // return false; int nRand = UnityEngine.Random.Range(0, 4); string szAct = string.Empty; string szShapeName = string.Empty; GetShapeName(ref szShapeName); int weapon_type = GetShowingWeaponType(); Debug.Log($"[THN]: PlayAttackAction weapon_type: {weapon_type}"); int nTime1 = 0, nTime2 = 0; int iAction = (int)PLAYER_ACTION_TYPE.ACT_ATTACK_1 + nRand; bool bHideFX = false;//!CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID()); PLAYER_ACTION action = m_PlayerActions[iAction]; if (string.IsNullOrEmpty(action.data.ActionPrefix)) return false; ShowWeaponByConfig(action.data); /* var pRightHandWeapon = GetRightHandWeapon(); bool bHideFX = !CECOptimize.Instance.GFX.CanShowAttack(GetCharacterID(), GetClassID());*/ // ============================== // Ground Attack // ============================== if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND) { // “起�? 动作(挥起) Debug.Log($"[THN]: PlayAttackAction action with weapon type: {weapon_type} and weapon attached: {m_bWeaponAttached}"); szAct = EC_Utility.BuildActionName(action, weapon_type, "起"); int iTransTime = 200; //EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szShapeName, szAct, iTransTime, true)); m_pActionController.PlayNonSkillActionWithName(iAction, szAct, true, iTransTime, bHideFX, attackEvent,COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX); szAct = EC_Utility.BuildActionName(action, weapon_type, "落"); queueActionEvent.SetData(szShapeName, szAct, SetApplyDamage, true, attackEvent, iTransTime,false); //EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent); m_pActionController.QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX); //PlayNonSkillActionWithName(iAction, szAct, true, 200, true, ref pActFlag, COMACT_FLAG_MODE_ONCE_MULTIIGNOREGFX);gagága /* if (pRightHandWeapon != null && IsUsingMagicWeapon()) pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX); nTime1 = _pPlayerModel.GetComActTimeSpanByName(szAct); // “收” 动作(挥下) szAct = $"{action.data.action_prefix}_{action.data.action_weapon_suffix[weapon_type].suffix}Âä"; QueueNonSkillActionWithName(iAction, szAct, 0, false, bHideFX); if (pRightHandWeapon != null && IsUsingMagicWeapon()) pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX); nTime2 = _pPlayerModel.GetComActTimeSpanByName(szAct);*/ } // ============================== // Air Attack // ============================== else { string szActionMiddleName; if ((m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) || GetProfession() == (int)PROFESSION.PROF_ANGEL || GetProfession() == (int)PROFESSION.PROF_ARCHOR || GetProfession() == (int)PROFESSION.PROF_MONK || GetProfession() == (int)PROFESSION.PROF_GHOST) { szActionMiddleName = "空中翅膀"; // tấn công trên không } else { szActionMiddleName = "空中飞剑"; // rơi xuống hoặc bay } szAct = EC_Utility.BuildActionName(action, weapon_type, "起", szActionMiddleName); //EventBus.PublishChannel(m_PlayerInfo.cid, new PlayActionEvent(szShapeName, szAct, 200, true)); m_pActionController.PlayNonSkillActionWithName(iAction, szAct, true, 200); // if (pRightHandWeapon != null && IsUsingMagicWeapon()) // pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, iAction, bHideFX); // nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct); szAct = EC_Utility.BuildActionName(action, weapon_type, "落", szActionMiddleName); queueActionEvent.SetData(szShapeName, szAct, SetApplyDamage, false, attackEvent, 0, false); //EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent); m_pActionController.QueueNonSkillActionWithName(iAction, szAct, 0, false, false, true, false); // if (pRightHandWeapon != null && IsUsingMagicWeapon()) // pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, iAction, false, false, bHideFX); // nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct); } // ============================== // Kết thúc bằng FightStand // ============================== PLAYER_ACTION stand_action = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND]; szAct = EC_Utility.BuildActionName(stand_action, 0); int iTranstime = 300; queueActionEvent.SetData(szShapeName, szAct, SetApplyDamage, false, attackEvent, iTranstime, false); //EventBus.PublishChannelClass(m_PlayerInfo.cid, queueActionEvent); m_pActionController.QueueNonSkillActionWithName(iAction, szAct, iTranstime, false, false, true, false); /* QueueNonSkillActionWithName(ACT_FIGHTSTAND, szAct, 300, false, bHideFX, true); if (pRightHandWeapon != null && IsUsingMagicWeapon()) pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 300, iAction, false, false, bHideFX, true);*/ // ============================== // Điều chỉnh tốc độ phát animation theo tốc độ tấn công // ============================== /* if (nAttackSpeed > 0) { float vScale = (nTime1 + nTime2) / (float)nAttackSpeed; if (vScale > 0f) { m_pPlayerModel.SetPlaySpeed(vScale); if (pRightHandWeapon != null && IsUsingMagicWeapon()) pRightHandWeapon.SetPlaySpeed(vScale); } } attackTime = nTime1 + nTime2;*/ // ============================== // Cập nhật vị trí weapon hanger (vũ khí) // ============================== //UpdateWeaponHangerPosByAction(iAction); return true; } void GetShapeName(ref string szShapeName) { if(IsShapeChanged()) { //the index and the shape name is different by 2 szShapeName =m_aShapeChineseName[GetShapeID()-2]+"_"; } else { szShapeName = m_aShapeChineseName[m_iProfession*GENDER.NUM_GENDER+m_iGender] +"_"; } } public void SetApplyDamage(bool isApplyDamage, CECAttackEvent cECAttackEvent) { cECAttackEvent.m_bSignaled = isApplyDamage; } public void ShowWeaponByConfig(PLAYER_ACTION_INFO_CONFIG p) { m_bShowWeapon = p.hide_weapon != 0 ? false : true; //ShowWeapon(m_bShowWeapon); } public int GetShowingWeaponType() { int weapon_type = 0; if (CanShowFashionWeapon((int)m_uAttackType, m_iFashionWeaponType) && m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WEAPON] != 0) { weapon_type = (EC_Utility.BinaryEquals(m_iFashionWeaponType, DEFAULT_ACTION_TYPE) || !IsWeaponAttached()) ? 10 : m_iFashionWeaponType; } else { weapon_type = (EC_Utility.BinaryEquals(m_uAttackType, DEFAULT_ACTION_TYPE) || !IsWeaponAttached()) ? 10 : (int)m_uAttackType; } return weapon_type; } public bool IsWeaponAttached() { return m_bWeaponAttached; } bool AttachWeapon() { bool result = (false); while (GetMajorModel()){ if (!m_pPlayerCECModel.GetHook(GetLeftWeaponHookPos(m_weaponHangerPos),true) || !m_pPlayerCECModel.GetHook(GetRightWeaponHookPos(m_weaponHangerPos),true)){ break; } m_bWeaponAttached = true; break; } /*while (GetPlayerModel() && (GetLeftHandWeapon() || GetRightHandWeapon())){ A3DSkinModel *pSkinModel = GetPlayerModel().GetA3DSkinModel(); if (!pSkinModel || !pSkinModel.GetSkeleton()){ break; } if (!pSkinModel.GetSkeletonHook(GetLeftWeaponHookPos(m_weaponHangerPos),true) || !pSkinModel.GetSkeletonHook(GetRightWeaponHookPos(m_weaponHangerPos),true)){ break; } if (GetLeftHandWeapon()){ GetPlayerModel().AddChildModel( _left_hand_weapon, false, GetLeftWeaponHookPos(m_weaponHangerPos), GetLeftHandWeapon(), GetLeftWeaponOwnHookPos(GetLeftHandWeapon())); } if (GetRightHandWeapon()){ GetPlayerModel().AddChildModel( _right_hand_weapon, false, GetRightWeaponHookPos(m_weaponHangerPos), GetRightHandWeapon(), GetRightWeaponOwnHookPos(GetRightHandWeapon())); } ALog log; log.Init("EC.log", "My Application Log"); // Anywhere in your code where you want to see the call flow: log.Log("[HoangDev]Checking execution flow at this point:"); log.LogStackTrace(); log.Release(); m_bWeaponAttached = true; result = true; break; }*/ result = true; return result; } public string GetLeftWeaponHookPos(WeaponHangerPosition p) { switch(p) { case WeaponHangerPosition.WEAPON_HANGER_HAND: return _hh_left_hand_weapon; case WeaponHangerPosition.WEAPON_HANGER_SHOULDER: return _hh_left_shoulder_weapon; } return null; } public string GetRightWeaponHookPos(WeaponHangerPosition p) { switch(p) { case WeaponHangerPosition.WEAPON_HANGER_HAND: return _hh_right_hand_weapon; case WeaponHangerPosition.WEAPON_HANGER_SHOULDER: return _hh_right_shoulder_weapon; } return null; } public void DetachWeapon() { if (IsWeaponAttached()){ // if (GetLeftHandWeapon()){ // GetMajorModel()->RemoveChildModel(_left_hand_weapon, false); // } // if (GetRightHandWeapon()){ // GetPlayerModel()->RemoveChildModel(_right_hand_weapon, false); // } m_bWeaponAttached = false; } } public bool InFashionMode() { return m_bFashionMode; } public bool CanShowFashionWeapon(int weapon_type, int fashion_weapon_type) { return IsFashionWeaponTypeFit(weapon_type, fashion_weapon_type) && InFashionMode(); } public bool IsFashionWeaponTypeFit(int weapon_type, int fashion_weapon_type) { if (fashion_weapon_type < 0 || fashion_weapon_type >= NUM_WEAPON_TYPE) return false; FASHION_WEAPON_CONFIG? pConfig = GetFashionConfig(); if (null == pConfig) { BMLogger.LogError("CECPlayer::GetFashionConfig, Failed to load fashion weapon config"); return false; } int fashion_weapon_mask = (int)pConfig.Value.action_mask[fashion_weapon_type]; return (fashion_weapon_mask & (1 << GetWeaponType(weapon_type))) != 0; } public FASHION_WEAPON_CONFIG GetFashionConfig() { FASHION_WEAPON_CONFIG? pFashionConfig = null; if (null == pFashionConfig) { elementdataman pDataMan = ElementDataManProvider.GetElementDataMan(); DATA_TYPE DataType = DATA_TYPE.DT_FASHION_WEAPON_CONFIG; uint tid = pDataMan.get_id_with_data_type(ID_SPACE.ID_SPACE_CONFIG, DataType); if (tid != 0) { pFashionConfig = (FASHION_WEAPON_CONFIG)pDataMan.get_data_ptr(tid, ID_SPACE.ID_SPACE_CONFIG, ref DataType); BMLogger.LogError($"HoangDev : get_data_ptr {pFashionConfig.GetType()}"); } } return pFashionConfig == null ? default : pFashionConfig.Value; } public int GetSelectedTarget() { return m_idSelTarget; } public float GetTouchRadius() { return m_fTouchRad; } // Is player in battle public bool IsInBattle() { return m_iBattleCamp != Player_camp_in_battle.GP_BATTLE_CAMP_NONE; } // Check whether specified npc in a same battle camp public bool InSameBattleCamp(CECNPC pNPC) { if (!pNPC || m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_NONE || (m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_INVADER && !pNPC.IsInBattleInvaderCamp()) || (m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_DEFENDER && !pNPC.IsInBattleDefenderCamp())) return false; return true; } public int GetBattleCamp() { return m_iBattleCamp; } public bool InSameBattleCamp(CECPlayer pPlayer) { if (!pPlayer || m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_NONE || m_iBattleCamp != pPlayer.GetBattleCamp()) return false; return true; } public const uint DEFAULT_ACTION_TYPE = 0xFFFFFFFF; public static int GetWeaponType(int iWeaponType) { return iWeaponType == DEFAULT_ACTION_TYPE ? 10 : iWeaponType; } public bool IsInFactionPVP() => (m_factionPVPMask & 0x01) != 0; public bool CanAttackFactionPVPMineCar() => (m_factionPVPMask & 0x02) != 0; public bool CanAttackFactionPVPMineBase() => (m_factionPVPMask & 0x04) != 0; public int GetLevelUpExp(int iLevel) { return _player_levelup_exp.exp[iLevel - 1]; //return iLevel * iLevel * 500; } public override void TurnFaceTo(int idTarget, float dwTime = 200) { if (idTarget != 0) { if (idTarget == GetCharacterID()) { return; } if (IsWorkMoveRunning() /*&& !IsPlayingCastingSkillAndMoveActions()*/) { // ÒÆ¶¯Ê±Ò»°ãÓ¦ÃæÏòÒÆ¶¯·½Ïò¡¢Ö»ÔÚÒÆ¶¯Ê©·¨ÖвÅתÏò return; } } var target = EC_ManMessageMono.Instance?.GetObject(idTarget, 0)?.gameObject.transform; if (target == null) { //BMLogger.LogError("HoangDev: ko có transform "); return; } Vector3 direction = (target.position - transform.position).normalized; direction.y = 0f; int turnSpeed = 5; if (direction.sqrMagnitude > 0.001f) { // T�?o rotation mới hướng tới target Quaternion targetRotation = Quaternion.LookRotation(direction, Vector3.up); // Xoay mư�?t t�? rotation hiện t�?i sang rotation m�?c tiêu //transform.rotation = Quaternion.Slerp( // transform.rotation, // targetRotation, // Time.deltaTime * turnSpeed //); transform.rotation = targetRotation; } } public virtual bool IsWorkMoveRunning() { return false; } /* public bool IsPlayingCastingSkillAndMoveActions() { return IsPlayingCastingSkillAction() && IsPlayingMoveAction(); } public bool IsPlayingCastingSkillAction() { return m_pActionController ? m_pActionController.IsPlayingCastingSkillAction() : false; } bool IsPlayingMoveAction() { return m_pActionController ? m_pActionController.IsPlayingMoveAction() : false; }*/ public int GetMoveStandAction(bool bMove, bool bFight = false) { int iMoveEnv = m_iMoveEnv; //if (m_AttachMode != enumAttachNone) //{ // bFight = false; // if (m_bHangerOn) // iMoveEnv = MOVEENV_GROUND; //} int iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; if (bMove) { // Play appropriate actions if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND) { if (m_bWalkRun) iAction = (int)PLAYER_ACTION_TYPE.ACT_RUN; else iAction = (int)PLAYER_ACTION_TYPE.ACT_WALK; } else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR) { if (/*UsingWing()*/ m_wingType == enumWingType.WINGTYPE_WING) iAction = (int)PLAYER_ACTION_TYPE.ACT_FLY; else iAction = (int)PLAYER_ACTION_TYPE.ACT_FLY_SWORD; } else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_WATER) { //if (CanCombineWithMoveForSkill()) //{ // iAction = (int)PLAYER_ACTION_TYPE.ACT_SWIM_FOR_MOVESKILL; //} //else { iAction = (int)PLAYER_ACTION_TYPE.ACT_SWIM; } } } else { // Play appropriate actions if (iMoveEnv == (int)MoveEnvironment.MOVEENV_GROUND) { if (bFight) iAction = (int)PLAYER_ACTION_TYPE.ACT_FIGHTSTAND; else iAction = (int)PLAYER_ACTION_TYPE.ACT_STAND; } else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_AIR) { if (/*UsingWing()*/ m_wingType == enumWingType.WINGTYPE_WING) iAction = (int)PLAYER_ACTION_TYPE.ACT_HANGINAIR; else iAction = (int)PLAYER_ACTION_TYPE.ACT_HANGINAIR_SWORD; } else if (iMoveEnv == (int)MoveEnvironment.MOVEENV_WATER) iAction = (int)PLAYER_ACTION_TYPE.ACT_HANGINWATER; } return iAction; } public A3DVECTOR3 GetModelMoveDir() { // ÒÆ¶¯Ê±¡¢·µ»ØÒƶ¯³¯Ïò£¬¾²Ö¹Ê±¡¢·µ»ØÄ£Ðͳ¯Ïò return EC_Utility.ToA3DVECTOR3(transform.forward); } public void Damaged(int nDamage, uint dwModifier = 0, int skill = 0) { if (nDamage == -2) { if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0) BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0); else if ((dwModifier & (uint)MOD.MOD_NULLITY) != 0) BubbleText((int)BubbleTextType.BUBBLE_INVALIDHIT, 0); else if ((dwModifier & (uint)MOD.MOD_DODGE_DEBUFF) != 0) BubbleText((int)BubbleTextType.BUBBLE_DODGE_DEBUFF, 0); } else if (nDamage == -1) { // when else player hit this player iDamage is -1, // Just play a wounded action if (!OnDamaged(skill)) { PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED); } if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0) BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0); else if ((dwModifier & (uint)MOD.MOD_NULLITY) != 0) BubbleText((int)BubbleTextType.BUBBLE_INVALIDHIT, 0); else if ((dwModifier & (uint)MOD.MOD_DODGE_DEBUFF) != 0) BubbleText((int)BubbleTextType.BUBBLE_DODGE_DEBUFF, 0); } else { // Popup a damage decal if (nDamage > 0) { int p1 = 0; if ((dwModifier & (int)MOD.MOD_CRITICAL_STRIKE) != 0) p1 |= 0x0001; if ((dwModifier & (uint)MOD.MOD_RETORT) != 0) p1 |= 0x0002; if (!OnDamaged(skill)) PlayAction((int)PLAYER_ACTION_TYPE.ACT_WOUNDED); if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0) BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0); else if ((dwModifier & (uint)MOD.MOD_REBOUND) != 0) BubbleText((int)BubbleTextType.BUBBLE_REBOUND, (uint)nDamage); else if ((dwModifier & (uint)MOD.MOD_BEAT_BACK) != 0) BubbleText((int)BubbleTextType.BUBBLE_BEAT_BACK, (uint)nDamage); else BubbleText((int)BubbleTextType.BUBBLE_DAMAGE, (uint)nDamage, p1); } else if ((dwModifier & (uint)MOD.MOD_IMMUNE) != 0) BubbleText((int)BubbleTextType.BUBBLE_IMMUNE, 0); else if ((dwModifier & (uint)MOD.MOD_NULLITY) != 0) BubbleText((int)BubbleTextType.BUBBLE_INVALIDHIT, 0); else BubbleText((int)BubbleTextType.BUBBLE_HITMISSED, 0); } } public void BubbleText(int iIndex, uint dwNum, int p1 = 0) { bool bHost = IsHostPlayer(); // if (iIndex == BUBBLE_EXP || iIndex == BUBBLE_SP) // bHost = false; Color dwCol = new Color(255, 205, 75); if (bHost) { var pGameRun = EC_Game.GetGameRun(); CECHostPlayer pHost = pGameRun?.GetHostPlayer(); if (iIndex == (int)BubbleTextType.BUBBLE_EXP) { bool hasBookExp = pHost != null && pHost.IsReincarnationTomeActive; int msgId = (int)dwNum > 0 ? (hasBookExp ? (int)FixedMsg.FIXMSG_GOT_BOOKEXP : (int)FixedMsg.FIXMSG_GOTEXP) : (int)FixedMsg.FIXMSG_LOSTEXP; pGameRun?.AddFixedChannelMsg(msgId, (int)ChatChannel.GP_CHAT_FIGHT, (int)dwNum); } if (iIndex == (int)BubbleTextType.BUBBLE_SP) pGameRun?.AddFixedChannelMsg((int)FixedMsg.FIXMSG_GOTSP, (int)ChatChannel.GP_CHAT_FIGHT, (int)dwNum); if (iIndex == (int)BubbleTextType.BUBBLE_REALMEXP) pGameRun?.AddFixedChannelMsg((int)FixedMsg.FIXMSG_GOT_REALMEXP, (int)ChatChannel.GP_CHAT_FIGHT, (int)dwNum); } // Chariot / mount (C++): raise bubble by mount dummy AABB * 2.3f. IsInChariot() lives on CECHostPlayer; wire via override or protected hook when ready. // if (IsInChariot()) // { // var dummy = GetDummyModel((int)PLAYERMODEL_TYPE.PLAYERMODEL_DUMMYTYPE2); // if (dummy != null) // vPos = GetPosVector3() + g_vAxisY * (dummy.GetModelAABB().Extents.y * 2.3f); // else // vPos = GetPosVector3() + g_vAxisY * (m_aabb.Extents.y * 2.5f); // } // else // vPos = GetPosVector3() + g_vAxisY * (m_aabb.Extents.y * 2.5f); Vector3 vPos = GetPosVector3() + g_vAxisY * (m_aabb.Extents.y * 2.5f); ImageResType bubbleTextType = ImageResType.NUM_IMAGE; switch (iIndex) { case (int)BubbleTextType.BUBBLE_DAMAGE: if (!bHost) dwCol = new Color(237, 56, 0); if ((p1 & 0x0001) != 0) bubbleTextType = ImageResType.IMG_DEADLYSTRIKE; else if ((p1 & 0x0002) != 0) bubbleTextType = ImageResType.IMG_RETORT; break; case (int)BubbleTextType.BUBBLE_EXP: bubbleTextType = ImageResType.IMG_GOTEXP; // pDecal->SetScreenPos(80, 70); // pDecal->EnableScreenPos(true); break; case (int)BubbleTextType.BUBBLE_SP: bubbleTextType = ImageResType.IMG_GOTSP; // pDecal->SetScreenPos(80, 90); // pDecal->EnableScreenPos(true); break; case (int)BubbleTextType.BUBBLE_MONEY: bubbleTextType = ImageResType.IMG_GOTMONEY; break; case (int)BubbleTextType.BUBBLE_LEVELUP: bubbleTextType = ImageResType.IMG_LEVELUP; break; case (int)BubbleTextType.BUBBLE_HITMISSED: if (!bHost) dwCol = new Color(237, 56, 0); bubbleTextType = ImageResType.IMG_HITMISSED; break; case (int)BubbleTextType.BUBBLE_INVALIDHIT: if (!bHost) dwCol = new Color(237, 56, 0); bubbleTextType = ImageResType.IMG_INVALIDHIT; break; case (int)BubbleTextType.BUBBLE_IMMUNE: if (!bHost) dwCol = new Color(237, 56, 0); bubbleTextType = ImageResType.IMG_IMMUNE; break; case (int)BubbleTextType.BUBBLE_HPWARN: dwCol = new Color(255, 255, 255); bubbleTextType = ImageResType.IMG_HPWARN; break; case (int)BubbleTextType.BUBBLE_MPWARN: dwCol = new Color(255, 255, 255); bubbleTextType = ImageResType.IMG_MPWARN; break; case (int)BubbleTextType.BUBBLE_REBOUND: bubbleTextType = ImageResType.IMG_REBOUND; break; case (int)BubbleTextType.BUBBLE_BEAT_BACK: bubbleTextType = ImageResType.IMG_BEAT_BACK; break; case (int)BubbleTextType.BUBBLE_ADD: dwCol = new Color(126, 206, 244); bubbleTextType = ImageResType.IMG_ADD; break; case (int)BubbleTextType.BUBBLE_DODGE_DEBUFF: if (!bHost) dwCol = new Color(237, 56, 0); bubbleTextType = ImageResType.IMG_DODGE_DEBUFF; break; default: bubbleTextType = ImageResType.NUM_IMAGE; break; } FLoatingTextManager.Instance.ShowText(vPos, (int)dwNum, dwCol, 1f, bubbleTextType, this); } public void StopSkillAttackAction() { if (m_pActionController != null) { m_pActionController.StopSkillAttackAction(); } } public void StopSkillCastAction() { if (m_pActionController != null) { m_pActionController.StopSkillCastAction(); } } public bool PlaySkillCastAction(int idSkill, CECAttackEvent attackEvent = null) { string szAct = ""; int weapon_type = GetShowingWeaponType(); int moveEnv = GetMoveEnv(); if (!_default_skill_actions.TryGetValue((uint)idSkill, out PLAYER_ACTION_INFO_CONFIG data) || data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0) { if (ElementSkill.GetCommonCoolDown((uint)idSkill) > 1 << 4) { data = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_USING_TARGET_ITEM].data; if (data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0) { return false; } } else { return false; } } if (moveEnv == (int)MoveEnvironment.MOVEENV_GROUND) { szAct = EC_Utility.BuildActionName(data, weapon_type, "_吟唱_"); } else { /* if ((*//*UsingWing()*//*m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) || (GetProfession() == PROF_ANGEL) || (GetProfession() == PROF_ARCHOR) || (GetProfession() == PROF_MONK) || (GetProfession() == PROF_GHOST)) sprintf(szAct, "%s_¿ÕÖгá°ò_Ò÷³ª_%s", data.action_prefix, data.action_weapon_suffix[weapon_type].suffix); else sprintf(szAct, "%s_¿ÕÖзɽ£_Ò÷³ª_%s", data.action_prefix, data.action_weapon_suffix[weapon_type].suffix);*/ } bool bHideFX = false; /*!CECOptimize::Instance().GetGFX().CanShowCast(GetCharacterID(), GetClassID());*/ if (!PlaySkillCastActionWithName(idSkill, szAct, bHideFX)) { return false; } ShowWeaponByConfig(data); //UpdateWeaponHangerPosBySkillAction(idSkill);// ¸ù¾Ý¼¼Äܲ¥·ÅµÄ¶¯×÷£¬¸ü¸ÄÎäÆ÷Ðü¹ÒλÖã¨Ö»Äܼì²é²»ÅŶӶ¯×÷£© return true; } public bool OnDamaged(int skill) { var atkMan = CECAttacksMan.Instance; if (atkMan == null) return false; string name1, name2; for (int i = 0; i < m_sciStateIDForStateAction.Length; i++) { /* if (atkMan.GetSkillStateActionName(skill, m_sciStateIDForStateAction[i], out name1, out name2)) { m_SkillIDForStateAction = skill; return true; }*/ } return false; } public CECSkill GetCurSkill() { return m_pCurSkill; } public bool IsHangerOn() { return m_bHangerOn; } public bool IsPlayingAction() { return true /*GetLowerBodyAction() != -1*/ ; } public bool PlaySkillCastActionWithName(int idSkill, string szActName, bool bNoFX/* =false */) { return m_pActionController != null && m_pActionController.PlaySkillCastActionWithName(idSkill, szActName, bNoFX); } public bool PlaySkillAttackAction(int idSkill, int nAttackSpeed, ref int piAttackTime, int nSection = 0, CECAttackEvent attackEvent = null) { if (m_pPlayerModel == null) return false; string szAct = ""; int weapon_type = GetShowingWeaponType(); if (!_default_skill_actions.TryGetValue((uint)idSkill, out PLAYER_ACTION_INFO_CONFIG data) || data.action_prefix == null || data.action_prefix.Length == 0 || data.action_prefix[0] == 0) { // Check if it's a target item skill / 检查是否为目标道具技能 if (ElementSkill.GetCommonCoolDown((uint)idSkill) > 1 << 4) { PLAYER_ACTION_INFO_CONFIG? data2 = m_PlayerActions[(int)PLAYER_ACTION_TYPE.ACT_USING_TARGET_ITEM].data; if (data2 == null || data2.Value.action_prefix == null || data2.Value.action_prefix.Length == 0 || data2.Value.action_prefix[0] == 0) return false; } else return false; } int nTime1, nTime2; bool bInfinite = false; // CECModel pRightHandWeapon = GetRightHandWeapon(); // 获取右手武器 / Get right hand weapon bool bHideFX = false; // !CECOptimize::Instance().GetGFX().CanShowAttack(GetCharacterID(), GetClassID()); var atkMan = CECAttacksMan.Instance; if (GetMoveEnv() == (int)MoveEnvironment.MOVEENV_GROUND) { szAct = EC_Utility.BuildActionName(data, weapon_type, "_施放起_"); GetSkillSectionActionName(ref szAct, idSkill, nSection); if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent)) { return false; } // nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct); // 获取动作时长 / Get action time span // pAct = m_pPlayerModel.GetComActByName(szAct); // if (pAct) bInfinite |= pAct.IsInfinite(); nTime1 = 1000; // 临时值 / Temporary value szAct = EC_Utility.BuildActionName(data, weapon_type, "_施放落_"); GetSkillSectionActionName(ref szAct, idSkill, nSection); QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX); // nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct); // pAct = m_pPlayerModel.GetComActByName(szAct); // if (pAct) bInfinite |= pAct.IsInfinite(); nTime2 = 1000; // 临时值 / Temporary value } else { // 空中动作 / Air action string szActionMiddleName = null; if ((m_wingType == enumWingType.WINGTYPE_WING && IsFlying()) || (m_iProfession == (int)PROFESSION.PROF_ANGEL) || (m_iProfession == (int)PROFESSION.PROF_ARCHOR) || (m_iProfession == (int)PROFESSION.PROF_MONK) || (m_iProfession == (int)PROFESSION.PROF_GHOST)) { szActionMiddleName = "_空中翅膀"; // Air with wings / 空中翅膀 } else { szActionMiddleName = "_空中飞剑"; // Air with sword / 空中飞剑 } szActionMiddleName += "_施放起_"; szAct = EC_Utility.BuildActionName(data, weapon_type, szActionMiddleName); GetSkillSectionActionName(ref szAct, idSkill, nSection); if (!PlaySkillAttackActionWithName(idSkill, szAct, bHideFX, attackEvent)) { return false; } // if (pRightHandWeapon && IsUsingMagicWeapon()) // pRightHandWeapon.PlayActionByName(_GenWeaponActionName(szAct, m_iGender), 1.0f, true, 200, true, ACT_CASTSKILL, bHideFX); // nTime1 = m_pPlayerModel.GetComActTimeSpanByName(szAct); // pAct = m_pPlayerModel.GetComActByName(szAct); // if (pAct) bInfinite |= pAct.IsInfinite(); nTime1 = 1000; // 临时值 / Temporary value szAct = $"{data.ActionPrefix}_{szActionMiddleName}_施法行_{data.action_weapon_suffix[weapon_type].Suffix}"; GetSkillSectionActionName(ref szAct, idSkill, nSection); QueueSkillAttackActionWithName(idSkill, szAct, 0, bHideFX); // if (pRightHandWeapon && IsUsingMagicWeapon()) // pRightHandWeapon.QueueAction(_GenWeaponActionName(szAct, m_iGender), 0, ACT_CASTSKILL, false, false, bHideFX); // nTime2 = m_pPlayerModel.GetComActTimeSpanByName(szAct); // pAct = m_pPlayerModel.GetComActByName(szAct); // if (pAct) bInfinite |= pAct.IsInfinite(); nTime2 = 1000; // 临时值 / Temporary value } // int nExecuteTime = GNET::ElementSkill::GetExecuteTime(idSkill, 0); // 获取技能执行时间 / Get skill execute time int nExecuteTime = 2000; // 临时值 / Temporary value // 调整动画速度以匹配攻击速度 / Adjust animation speed to match attack speed if (!bInfinite) { if (nExecuteTime > 0) { float vScale = (nTime1 + nTime2) / (float)nExecuteTime; // m_pPlayerModel.SetPlaySpeed(vScale * 1.2f); // if (pRightHandWeapon && IsUsingMagicWeapon()) // pRightHandWeapon.SetPlaySpeed(vScale * 1.2f); } piAttackTime = nTime1 + nTime2; } else { // 动作循环,返回技能决定的执行时间 / Action loops, return skill-determined execute time piAttackTime = nExecuteTime; } ShowWeaponByConfig(data); // UpdateWeaponHangerPosBySkillAction(idSkill); // 根据技能播放的动作,更改武器悬挂位置 / Update weapon hanger position based on skill action return true; } /// Override in CECHostPlayer to return current team; base returns null. public virtual CECTeam GetTeam() { return null; } public bool IsTeamMember(int idPlayer) { var pTeam = GetTeam(); if (pTeam == null) return false; return pTeam.GetMemberByID(idPlayer) != null; } public bool PlaySkillAttackActionWithName(int idSkill, string szActName, bool bNoFX = false, CECAttackEvent attackEvent = null) { return m_pActionController != null && m_pActionController.PlaySkillAttackActionWithName(idSkill, szActName, bNoFX, attackEvent, 0); } public bool QueueSkillAttackActionWithName(int idSkill, string szActName, int nTransTime = 200, bool bNoFX = false, bool bResetSpeed = false, bool bResetActFlag = false, CECAttackEvent attackEvent = null, uint dwNewFlagMode = 0) { return m_pActionController != null && m_pActionController.QueueSkillAttackActionWithName(idSkill, szActName, nTransTime, bNoFX, bResetSpeed, bResetActFlag, attackEvent, dwNewFlagMode); } private void GetSkillSectionActionName(ref string szAct, int idSkill, int nSection) { if (nSection != 0) { var pAtkMan = CECAttacksMan.Instance; if (pAtkMan != null && pAtkMan.GetSkillSectionActionSuffix(idSkill, nSection, out string suffix)) { szAct += "_" + suffix; } } } protected void OnMsgEnchantResult(ECMSG msg) { // 从消息中获取cmd_enchant_result结构 // Get cmd_enchant_result structure from message cmd_enchant_result pCmd = GPDataTypeHelper.FromBytes((byte[])msg.dwParam1); // 初始化掩码为全1 // Initialize mask to all 1s uint mask = 0xFFFFFFFF; // 如果目标不是主机玩家且当前不是主机玩家,则过滤会引起气泡文本的修饰符 // We should filter out these things that will cause bubble texts CECHostPlayer pHost = EC_ManMessageMono.Instance.GetECManPlayer.GetHostPlayer(); if (pCmd.target != pHost.GetCharacterID() && !IsHostPlayer()) { mask &= (uint)(MOD.MOD_PHYSIC_ATTACK_RUNE | MOD.MOD_MAGIC_ATTACK_RUNE | MOD.MOD_CRITICAL_STRIKE | MOD.MOD_ENCHANT_FAILED); } // 获取修饰符 // Get modifier uint dwModifier = (uint)pCmd.attack_flag; // 获取技能类型 // Get skill type int nDamage = -2; // 默认为-2,不会引起受伤动作 // Default to -2, will not cause wounded action if (ElementSkill.GetType((uint)pCmd.skill) == (byte)skill_type.TYPE_ATTACK) { // 只有攻击技能会引起受伤动作,伤害值为-1 // Only attack skill will cause wounded action, when damage is -1 nDamage = -1; } else { // 其他技能不会引起受伤动作,伤害值设为-2 // Other skills will not cause wounded action, so we set damage to -2 nDamage = -2; } // 播放攻击效果 // Play attack effect int attackTime = 0; PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage, dwModifier & mask, 0, ref attackTime, pCmd.section); } // 判断是否在飞行 / Check if flying public bool IsFlying() { // 临时实现 / Temporary implementation return (m_dwStates & PlayerNPCState.GP_STATE_FLY) != 0 ? true : false; } public bool IsInvader() { return (m_dwStates & PlayerNPCState.GP_STATE_INVADER) != 0; } public int GetFactionID() { return m_idFaction; } public int GetForce() { return m_idForce; } public bool IsInDuel() { return m_pvp.iDuelState == (int)DuelState.DUEL_ST_INDUEL; } // Duel state public enum DuelState { DUEL_ST_NONE = 0, DUEL_ST_PREPARE, DUEL_ST_INDUEL, DUEL_ST_STOPPING, }; public bool IsPariah() { return (m_dwStates & PlayerNPCState.GP_STATE_PARIAH) != 0; } bool GetSkillStateActionName(int skill, int state, string name1, string name2) { /* for (int i = 0; i < (int)m_SkillStateActionVec.size(); i++) { if (m_SkillStateActionVec[i].skill == skill && m_SkillStateActionVec[i].state == state) { name1 = m_SkillStateActionVec[i].beHitAction; name2 = m_SkillStateActionVec[i].stayDownAction; return true; } }*/ return false; } public virtual bool IsFighting() { return m_bFight; } public float GetGroundSpeed() { // return m_bWalkRun ? g_pGame.GetConfigs().GetHostRunSpeed() : m_ExtProps.mv.walk_speed; // return 5f; return m_bWalkRun ? m_ExtProps.mv.run_speed : m_ExtProps.mv.walk_speed; } // Get move environment public int GetMoveEnv() { return m_iMoveEnv; } public bool IsShapeChanged() { return m_iShape != 0; } // 获取职业 // Get profession public int GetProfession() { return m_iProfession; } public int GetLevel() { return GetBasicProps().iLevel; } // 获取性别 // Get gender public int GetGender() { return m_iGender; } // 获取变身类型 // Get shape type // PLAYERMODEL_GETTYPE(iShape) = (iShape & 0xff) >> 6 public int GetShapeType() { return (m_iShape & 0xff) >> 6; } // 获取变身ID // Get shape ID // PLAYERMODEL_GETID(iShape) = iShape & 0x3f public int GetShapeID() { return m_iShape & 0x3f; } public int GetWeaponID() { return m_aEquips[(int)IndexOfIteminEquipmentInventory.EQUIPIVTR_WEAPON] & 0xffff; } public bool IsAllResReady() { return (m_dwResFlags & (uint)PlayerResourcesReadyFlag.RESFG_ALL) == (uint)PlayerResourcesReadyFlag.RESFG_ALL; } // Get character ID public static int GetRealmLayer(int realmLevel) { return realmLevel != 0 ? (realmLevel + 9) / 10 : 0; } public static int GetRealmSubLevel(int realmLevel) { return realmLevel != 0 ? (realmLevel % 10 != 0 ? realmLevel % 10 : 10) : 0; } string GetFashionActionName() { // ����ʱװװ����Я���Ķ������� // string strAction = ""; int[] local_check_order = { (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_HEAD, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_BODY, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_WRIST, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_LEG, (int)IndexOfIteminEquipmentInventory.EQUIPIVTR_FASHION_FOOT }; int idEquipment = 0; for (int i = 0; i < local_check_order.Length; ++ i) { // ��˳�����ָ����װ idEquipment = m_aEquips[local_check_order[i]] & 0x0000ffff; GetFashionActionNameByID(idEquipment, ref strAction); if (!string.IsNullOrEmpty(strAction)) { // ���ַǿ�ʱװ������������ break; } } return strAction; } void GetFashionActionNameByID(int idEquipment, ref string strAction) { if (idEquipment != 0) { DATA_TYPE dt = DATA_TYPE.DT_INVALID; object pEquip = EC_Game.GetElementDataMan().get_data_ptr( (uint)idEquipment, ID_SPACE.ID_SPACE_ESSENCE, ref dt); if (pEquip != null && dt == DATA_TYPE.DT_FASHION_ESSENCE) { FASHION_ESSENCE pEssence = (FASHION_ESSENCE)pEquip; strAction = ByteToStringUtils.ByteArrayToCP936String(pEssence.wear_action); } } } protected bool PlayGfx(string szPath, string szHook, float fScale /*1.0f*/, uint iShapeTypeMask /*(1<(); _levelUpVfx.Play(); // vfx.transform.SetParent(transform); transform.position, prefab.transform.rotation _levelUpVfx.transform.localPosition = Vector3.zero; } else { BMLogger.LogError($"Failed to load level up effect prefab at: {path}"); } } // Get booth state public int GetBoothState() { return m_iBoothState; } // Check whether player has effect of specified type public bool HasEffectType(int iEffType) { int i; switch (iEffType) { case Effect_type.EFF_FACEPILL: { elementdataman pDataMan = EC_Game.GetElementDataMan(); // Get item data type for (i = 0; i < m_aCurEffects.Count; i++) { DATA_TYPE DataType = pDataMan.get_data_type((uint)m_aCurEffects[i], ID_SPACE.ID_SPACE_ESSENCE); if (DataType == DATA_TYPE.DT_FACEPILL_ESSENCE) return true; } break; } } return false; } public byte GetReincarnationCount() { return m_ReincarnationCount; } public string GetName() { return m_strName; } /// Set player display name (used when base info is received, e.g. else player). protected void SetPlayerName(string name) { m_strName = name ?? ""; if (gameObject != null) gameObject.name = m_strName; } public enumWingType GetWingType() { return m_wingType; } // Set part extend properties public void SetPartExtendProps(int iPropIdx, object pData) { // BMLogger.LogError($"HoangDev: SetPartExtendProps iPropIdx={iPropIdx} pData={pData} "); switch (iPropIdx) { case (int)ExtendPropertyClass.EXTPROPIDX_BASE: m_ExtProps.bs = (ROLEEXTPROP_BASE)pData; break; case (int)ExtendPropertyClass.EXTPROPIDX_MOVE: m_ExtProps.mv = (ROLEEXTPROP_MOVE)pData; break; case (int)ExtendPropertyClass.EXTPROPIDX_ATTACK: m_ExtProps.ak = (ROLEEXTPROP_ATK)pData; break; case (int)ExtendPropertyClass.EXTPROPIDX_DEF: m_ExtProps.df = (ROLEEXTPROP_DEF)pData; break; default: //ASSERT(0); return; } } #region Team // Get team to which this player belongs to // public CECTeam GetTeam() { return m_pTeam; } #endregion public static bool IsMoveStandAction(int action) { // tương đương: const static int s_MoveStandAction[] PLAYER_ACTION_TYPE[] s_MoveStandAction = { PLAYER_ACTION_TYPE.ACT_RUN, PLAYER_ACTION_TYPE.ACT_WALK, PLAYER_ACTION_TYPE.ACT_FLY, PLAYER_ACTION_TYPE.ACT_FLY_SWORD, PLAYER_ACTION_TYPE.ACT_SWIM, PLAYER_ACTION_TYPE.ACT_SWIM_FOR_MOVESKILL, PLAYER_ACTION_TYPE.ACT_STAND, PLAYER_ACTION_TYPE.ACT_FIGHTSTAND, PLAYER_ACTION_TYPE.ACT_HANGINAIR, PLAYER_ACTION_TYPE.ACT_HANGINAIR_SWORD, PLAYER_ACTION_TYPE.ACT_HANGINWATER, }; int begin = 0; int end = s_MoveStandAction.Length - 1; for (int i = begin; i < end; i++) { if ((int)s_MoveStandAction[i] == action) return true; } return false; } public int GetLowerBodyAction() { return m_pActionController?.GetLowerBodyAction() ?? -1; } // Check water moving environment public bool CheckWaterMoveEnv(A3DVECTOR3 vPos, float fWaterHei, float fGndHei) { bool bRet = false; /* if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth) bRet = true; else if (vPos.y < fWaterHei && fWaterHei - fGndHei > m_MoveConst.fShoreDepth) bRet = true; */ // if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf - m_aabb.Extents.y) // if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f) /* if (vPos.y < fWaterHei - m_MoveConst.fShoreDepth) bRet = true; else if (vPos.y < fWaterHei - m_MoveConst.fWaterSurf + 0.01f && fWaterHei - fGndHei > m_MoveConst.fShoreDepth) bRet = true; */ //@note : modify the water test. By Kuiwu[12/10/2005] if (vPos.y + m_aabbServer.Extents.y < fWaterHei - m_MoveConst.fWaterSurf - 0.001f) { bRet = true; } //else if (vPos.y + m_aabb.Extents.y < fWaterHei- m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.2f ) else if (vPos.y + m_aabbServer.Extents.y < fWaterHei - m_MoveConst.fWaterSurf + 1E-4f && vPos.y - fGndHei >= 0.01f) { bRet = true; } return bRet; } public bool IsAboutToDie() { return m_bAboutToDie; } public void SetAboutToDie(bool bFlag) { m_bAboutToDie = bFlag; } // Show / hide wing public void ShowWing(bool bShow) { if (m_pPlayerModel) { // var pWing = FindChildRecursive(m_pPlayerModel.transform, _wing); if (m_Wing != null) { m_Wing.gameObject.SetActive(bShow); } // var pWing2 = FindChildRecursive(m_pPlayerModel.transform, _wing2); // m_Wing2.gameObject.SetActive(bShow); } } // Get current pet id public int GetCurPetID() { return m_idCurPet; } // Set current pet id public void SetCurPetID(int id) { m_idCurPet = id; } // Get player name color public uint GetNameColor() { uint dwNameCol = NameColor.NAMECOL_MAUVE; if (IsInBattle()) // Player is in battle { if (m_iBattleCamp == Player_camp_in_battle.GP_BATTLE_CAMP_INVADER) dwNameCol = NameColor.NAMECOL_BC_RED; else // (m_iBattleCamp == GP_BATTLE_CAMP_DEFENDER) dwNameCol = NameColor.NAMECOL_BC_BLUE; } else if (IsPariah()) { switch (m_byPariahLvl) { case 0: dwNameCol = NameColor.NAMECOL_RED0; break; case 1: dwNameCol = NameColor.NAMECOL_RED1; break; default: dwNameCol = NameColor.NAMECOL_RED2; break; } } else if (IsInvader()) dwNameCol = NameColor.NAMECOL_PINK; else if (m_pvp.bEnable) dwNameCol = NameColor.NAMECOL_WHITE; return dwNameCol; } // Riding pet info. public struct RIDINGPET { public int id; public ushort color; public void Reset() { id = 0; color = 0; } public bool GetColor(ref Color clr) { // Get the current pet’s dye/color return id > 0 && GetColor(color, ref clr); } public static bool GetColor(ushort c, ref Color clr) { // Check whether the current pet has been dyed; if so, return the dyed color. bool bRet = false; if ((c & (1 << (Marshal.SizeOf(c) * 8 - 1))) != 0) { // unsigned short: if the highest bit is 1, it means the pet has been dyed; // in this case, the dyed color can be retrieved. clr = new Color(((c) & (0x1f << 10)) >> 7, ((c) & (0x1f << 5)) >> 2, ((c) & 0x1f) << 3); bRet = true; } return bRet; } public static Color GetDefaultColor() { return new Color(255f / 255f, 255f / 255f, 255f / 255f); } }; public bool IsRidingOnPet() { return m_RidingPet.id != 0; } // Get riding pet info. public RIDINGPET GetRidingPetInfo() { return m_RidingPet; } public void RideOnPet(int id, ushort color) { m_CandPet.id = id; m_CandPet.color = color; m_RidingPet.id = id; m_RidingPet.color = color; } public void GetOffPet(bool bResetData) { int iBuddyId = 0; m_CandPet.Reset(); SetNamePos(new A3DVECTOR3(0.0f)); if (m_AttachMode != AttachMode.enumAttachNone) { iBuddyId = m_iBuddyId; DetachBuddy(null, bResetData); } if (m_pPetModel) { GameObject.Destroy(m_pPetModel); m_pPetModel = null; } if (bResetData) m_RidingPet.Reset(); // Re-calculate player's AABB CalcPlayerAABB(); //SetUseGroundNormal(ShouldUseGroundNormalForCurrentShapeModel()); SetPos(GetPosVector3()); //if (iBuddyId != 0) // AttachBuddy(iBuddyId); //else PlayAction(GetMoveStandAction(false, IsFighting()), true); } void SetNamePos(A3DVECTOR3 vPos) { m_vNamePos = vPos; } // Player Attach mode public enum AttachMode { enumAttachNone, enumAttachRideOnPet, enumAttachRideOnPlayer, enumAttachHugPlayer, }; void DetachBuddy(CECPlayer pBuddy, bool bResetData) { if (m_AttachMode == AttachMode.enumAttachNone) return; if (m_bHangerOn) { if (!pBuddy) pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId); if (pBuddy) pBuddy.DetachBuddy(this, bResetData); else { if (bResetData) { m_AttachMode = AttachMode.enumAttachNone; m_bHangerOn = false; m_iBuddyId = 0; } } } else { if (!pBuddy) pBuddy = m_pPlayerMan.GetPlayer(m_iBuddyId); if (m_AttachMode == AttachMode.enumAttachRideOnPlayer) { //if (m_pPlayerModel) m_pPlayerModel.RemoveChildModel(_hanger_ride, false); } else if (m_AttachMode == AttachMode.enumAttachHugPlayer) { //if (m_pPlayerModel) m_pPlayerModel.RemoveChildModel(_hanger_hug, false); } else if (m_AttachMode == AttachMode.enumAttachRideOnPet) { if (m_pPetModel) { //A3DSkinModelHanger* pHanger = m_pPetModel.GetA3DSkinModel().GetSkinModelHanger(_hanger_ride); //if (pHanger) pHanger.SetOffsetMat(a3d_IdentityMatrix()); //m_pPetModel.RemoveChildModel(_hanger_ride2, false); } } if (bResetData) { m_AttachMode = AttachMode.enumAttachNone; m_bHangerOn = false; m_iBuddyId = 0; } if (pBuddy) { if (bResetData) { pBuddy.m_AttachMode = AttachMode.enumAttachNone; pBuddy.m_bHangerOn = false; pBuddy.m_iBuddyId = 0; } pBuddy.SetPos(pBuddy.GetPosVector3()); pBuddy.SetDirAndUp(pBuddy.transform.forward, pBuddy.transform.up); pBuddy.PlayAction(GetMoveStandAction(false, IsFighting()), true); } PlayAction(GetMoveStandAction(IsPlayingMoveAction(), IsFighting()), true); } } public virtual void SetPos(Vector3 pos) { playerTransform.position = pos; m_aabb.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabb.Extents.y, 0.0f); m_aabb.CompleteMinsMaxs(); m_aabbServer.Center = EC_Utility.ToA3DVECTOR3(pos) + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); m_aabbServer.CompleteMinsMaxs(); } public bool IsPlayingMoveAction() { return m_iCurAction == (int)PLAYER_ACTION_TYPE.ACT_STAND; } public void OnMsgPlayerMount(ECMSG Msg) { cmd_player_mounting pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); if (pCmd.mount_id != 0) RideOnPet(pCmd.mount_id, pCmd.mount_color); else GetOffPet(true); } // Build riding pet file name string GetRidingPetFileName(int idPet) { string szDef = "Models/NPCs/宠物/骑宠/骑宠马/骑宠马白.ecm"; DATA_TYPE DataType = new DATA_TYPE(); var pDataPtr = ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)idPet, ID_SPACE.ID_SPACE_ESSENCE, ref DataType); if (DataType != DATA_TYPE.DT_PET_ESSENCE) return szDef; PET_ESSENCE pData = (PET_ESSENCE)pDataPtr; if (pData.file_model[0] == 0) return szDef; return ByteToStringUtils.ByteArrayToUTF8String(pData.file_model); } public async void QueueLoadPetModel(string szPetPath, bool bAtOnce) { var modelPet = await LoadPetModel(szPetPath); if (modelPet == null) { return; } SetPetLoadResult(modelPet); } public async Task LoadPetModel(string szPetPath) { var pPetModel = CECGameRun.Instance.GetPetMount(); if(pPetModel == null) { return null; } try { var model = await AddressableManager.Instance.LoadPrefabAsync(AFile.NormalizePath(szPetPath.ToLower(), true)); if(model == null) { model = GameObject.CreatePrimitive(PrimitiveType.Capsule); } var obModel = GameObject.Instantiate(model); obModel.transform.SetParent(pPetModel.transform); AddressableManager.Instance.ReleaseAsset(szPetPath); } catch { var model = GameObject.CreatePrimitive(PrimitiveType.Capsule); var obModel = GameObject.Instantiate(model); obModel.transform.SetParent(pPetModel.transform); AddressableManager.Instance.ReleaseAsset(szPetPath); //return null; } return pPetModel; } bool SetPetLoadResult(GameObject pPetModel) { if (m_RidingPet.id == 0 /*|| !GetMajorModel() || m_CandPet.id != 0*/ || !pPetModel) return false; if (m_pPetModel) { RIDINGPET pet = m_RidingPet; GetOffPet(true); m_RidingPet = pet; } A3DVECTOR3 vCurPos = GetPos(); m_aabbServer.Center = vCurPos + new A3DVECTOR3(0.0f, m_aabbServer.Extents.y, 0.0f); m_aabbServer.CompleteMinsMaxs(); m_pPetModel = pPetModel; // ½«³èÎïÑÕÉ«ÉèÖõ½Ä£ÐÍÉÏ //SetRidingPetColor(m_RidingPet.color); SetUseGroundNormal(true); //m_pPetModel.SetAffectedByParent(false); m_pPetModel.transform.position = EC_Utility.ToVector3(vCurPos); //m_pPetModel.SetDirAndUp(GetDir(), GetUp()); //int iIndex; //A3DSkeletonHook* pHook = GetMajorModel().GetA3DSkinModel().GetSkeleton().GetHook(_cc_ride, &iIndex); //if (pHook) pHook.SetFixDirFlag(true); int iBuddyId = m_iBuddyId; if (m_AttachMode != AttachMode.enumAttachNone) DetachBuddy(null, true); m_pPetModel.transform.SetParent(transform); //m_pPetModel.AddChildModel(_hanger_ride, false, _hh_ride, GetMajorModel(), _cc_ride); //m_pPetModel.GetA3DSkinModel().Update(0); //if (iBuddyId != 0) // AttachBuddy(iBuddyId); //else PlayAction(GetMoveStandAction(false, IsFighting()), true); return true; } protected void RecreateActionController() { if (m_pPlayerModel == null){ m_pActionController = null; return; } if (m_pActionController == null){ m_pActionController = new CECPlayerActionController(); } m_pActionController.Bind(this, m_pPlayerCECModel); } protected bool ShouldUseModel() { if (!IsElsePlayer()){ return true; } bool result = (true); //switch (m_iMemUsage){ //case CECMemSimplify::MEMUSAGE_NOMODEL: // result = g_pGame->GetGameRun()->GetMemSimplify()->IsMostImportant(this); // break; //case CECMemSimplify::MEMUSAGE_NOMODEL_UNIMPORTANT: // result = g_pGame->GetGameRun()->GetMemSimplify()->IsImportant(this); // break; //} return result; } protected async Task LoadPlayerSkeleton(bool bAtOnce) { int[] aEnabledEquips = new int[InventoryConst.SIZE_ALL_EQUIPIVTR]; for (int i = 0; i < InventoryConst.SIZE_ALL_EQUIPIVTR; i++) { // TODO: m_i64EquipDisabled — zero slot when disabled: ((1L << i) & m_i64EquipDisabled) != 0 ? 0 : m_aEquips[i] aEnabledEquips[i] = m_aEquips[i]; } string szPetPath = null; if (m_RidingPet.id != 0) szPetPath = GetRidingPetFileName(m_RidingPet.id); int[] aEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK]; uint EquipMask = 0; if (aEnabledEquips[InventoryConst.EQUIPIVTR_WEAPON] > 0) EquipMask |= 1 << InventoryConst.EQUIPIVTR_WEAPON; if (aEnabledEquips[InventoryConst.EQUIPIVTR_FASHION_WEAPON] > 0) EquipMask |= 1 << InventoryConst.EQUIPIVTR_FASHION_WEAPON; Array.Copy(aEnabledEquips, aEquips, InventoryConst.IVTRSIZE_EQUIPPACK); DecideWeaponLoad(aEquips, EquipMask); // Same pipeline as SetPlayerModel / TransformShape: NPCManager model load + optional pet + dummy shape. int shapeSnapshot = m_iShape; try { await SetPlayerModel((byte)m_iProfession, (byte)m_iGender); // load all equipments } catch (Exception ex) { BMLogger.LogError($"CECPlayer::LoadPlayerSkeleton, SetPlayerModel failed: {ex}"); return false; } SetPlayerLoadedResult(default(EC_PLAYERLOADRESULT)); if (!string.IsNullOrEmpty(szPetPath)) { GameObject petGo = await LoadPetModel(szPetPath); SetPetLoadResult(petGo); } if (shapeSnapshot != 0 && !await QueueLoadDummyModel(shapeSnapshot, bAtOnce)) { BMLogger.LogError("CECPlayer::LoadPlayerSkeleton, failed to call QueueLoadDummyModel() !"); return false; } BMLogger.Log($"CECPlayer::LoadPlayerSkeleton completed, shapeSnapshot: {shapeSnapshot}"); return true; } void DecideWeaponLoad(int[] pEquipmentID, uint Mask) { bool bNormalWeaponChanged = ((1 << InventoryConst.EQUIPIVTR_WEAPON) & Mask) != 0; bool bFashionWeaponChanged = ((1 << InventoryConst.EQUIPIVTR_FASHION_WEAPON) & Mask) != 0; WEAPON_ESSENCE pWeapon = new WEAPON_ESSENCE(); FASHION_ESSENCE pFashion = new FASHION_ESSENCE(); WEAPON_SUB_TYPE pSubType = new WEAPON_SUB_TYPE(); int[] Index = {InventoryConst.EQUIPIVTR_WEAPON, InventoryConst.EQUIPIVTR_FASHION_WEAPON}; for (int i = 0; i < 2; ++i) { int idEquipment = pEquipmentID[Index[i]]; idEquipment &= 0x0000ffff; DATA_TYPE dt = DATA_TYPE.DT_INVALID; if (idEquipment != 0) { var pEquip =ElementDataManProvider.GetElementDataMan().get_data_ptr( // TODO: Implement this (uint)idEquipment, ID_SPACE.ID_SPACE_ESSENCE, ref dt); if (dt == DATA_TYPE.DT_WEAPON_ESSENCE) { pWeapon = (WEAPON_ESSENCE)pEquip; pSubType =(WEAPON_SUB_TYPE)ElementDataManProvider.GetElementDataMan().get_data_ptr( pWeapon.id_sub_type, ID_SPACE.ID_SPACE_ESSENCE, ref dt); if (dt != DATA_TYPE.DT_WEAPON_SUB_TYPE) pSubType = new WEAPON_SUB_TYPE(); } else if (dt == DATA_TYPE.DT_FASHION_ESSENCE) pFashion = (FASHION_ESSENCE)pEquip; } } // bool bCanShowFashionWeaponBefore = CanShowFashionWeapon((int)m_uAttackType, m_iFashionWeaponType); // bool bCanShowFashionWeapon = false; //var pGameUI = GameUIManagerProvider.GetGameUIManager().GetInGameUIMan(); // ��ͨ�����ı� // if (bNormalWeaponChanged) // { // // ʱװ�����ı� // if (bFashionWeaponChanged) // { // // װ��ʱװ��������ͨ���� // if (pSubType != null && pFashion != null) // { // if (CanShowFashionWeapon((int)pSubType.action_type, (int)pFashion.action_type)) // { // CLEAR_WEAPON(InventoryConst.EQUIPIVTR_WEAPON); // } // else // { // CLEAR_WEAPON(InventoryConst.EQUIPIVTR_FASHION_WEAPON); // } // } // // װ����ͨ���� // else if(pSubType && !pFashion) // { // } // // װ��ʱװ���� // else if (!pSubType && pFashion) // { // if (CanShowFashionWeapon(m_uAttackType, pFashion->action_type)) // { // CLEAR_WEAPON(EQUIPIVTR_WEAPON); // } // else // { // CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON); // } // } // // û��װ���������� // else // { // } // if (pSubType) RECORD_NORMAL_WEAPON( // pWeapon->file_model_left, pWeapon->file_model_right, pSubType->action_type); // if (pFashion) RECORD_FASHION_WEAPON( // pFashion->file_model_left, pFashion->file_model_right, pFashion->action_type); // } // else // { // // װ����ͨ���� // if (pSubType) // { // bCanShowFashionWeapon = CanShowFashionWeapon(pSubType->action_type, m_iFashionWeaponType); // if (bCanShowFashionWeapon) // { // CLEAR_WEAPON(EQUIPIVTR_WEAPON); // if (!bCanShowFashionWeaponBefore) // SET_WEAPON(EQUIPIVTR_FASHION_WEAPON, m_aEquips[EQUIPIVTR_FASHION_WEAPON]); // } // RECORD_NORMAL_WEAPON( // pWeapon->file_model_left, pWeapon->file_model_right, pSubType->action_type); // } // // ������ͨ���� // else // { // bCanShowFashionWeapon = CanShowFashionWeapon(DEFAULT_ACTION_TYPE, m_iFashionWeaponType); // if (bCanShowFashionWeapon) // { // CLEAR_WEAPON(EQUIPIVTR_WEAPON); // if (!bCanShowFashionWeaponBefore) // SET_WEAPON(EQUIPIVTR_FASHION_WEAPON, m_aEquips[EQUIPIVTR_FASHION_WEAPON]); // } // RECORD_NORMAL_WEAPON((char*)NULL, (char*)NULL, DEFAULT_ACTION_TYPE); // } // } // } // else if (bFashionWeaponChanged) // { // // װ��ʱװ���� // if (pFashion) // { // bCanShowFashionWeapon = CanShowFashionWeapon(m_uAttackType, pFashion->action_type); // if (!bCanShowFashionWeapon) // { // if (pGameUI && this == g_pGame->GetGameRun()->GetHostPlayer() && InFashionMode()) // pGameUI->AddChatMessage(pGameUI->GetStringFromTable(906), GP_CHAT_SYSTEM); // CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON); // if (bCanShowFashionWeaponBefore) // SET_WEAPON(EQUIPIVTR_WEAPON, m_aEquips[EQUIPIVTR_WEAPON]); // } // // ����ʾʱװ�������˴�Ҫ��m_stoneWeapon���� // else CLEAR_WEAPON(EQUIPIVTR_WEAPON); // RECORD_FASHION_WEAPON( // pFashion->file_model_left, pFashion->file_model_right, pFashion->action_type); // } // // ����ʱװ���� // else // { // if (0 != m_aEquips[EQUIPIVTR_WEAPON]) // { // CLEAR_WEAPON(EQUIPIVTR_FASHION_WEAPON); // if (bCanShowFashionWeaponBefore) // SET_WEAPON(EQUIPIVTR_WEAPON, m_aEquips[EQUIPIVTR_WEAPON]); // } // RECORD_FASHION_WEAPON((char*)NULL, (char*)NULL, DEFAULT_ACTION_TYPE); // } // } // if (bCanShowFashionWeaponBefore && !bCanShowFashionWeapon // && pGameUI && !bFashionWeaponChanged && bNormalWeaponChanged && this == g_pGame->GetGameRun()->GetHostPlayer()) // pGameUI->AddChatMessage(pGameUI->GetStringFromTable(906), GP_CHAT_SYSTEM); } protected bool SetPlayerLoadedResult(EC_PLAYERLOADRESULT ret) { OnAllResourceReady(); return true; } protected void OnAllResourceReady() { CECHostSkillModel.Instance.Initialize(); } // Is resources ready ? protected bool IsSkeletonReady() { return (m_dwResFlags & (uint)PlayerResourcesReadyFlag.RESFG_SKELETON) != 0 ? true : false; } // Set resources ready flag protected void SetResReadyFlag(uint dwFlag, bool bSet) { if (bSet) { m_dwResFlags |= dwFlag; } else m_dwResFlags &= ~dwFlag; } public virtual void Release() { //TODO: Implement this latter // DetachBuddy(); // // Clear extend states before model is released // ClearShowExtendStates(); // ::memset(m_aExtStates, 0, sizeof(m_aExtStates)); // m_aIconStates.clear(); // if (m_pPateName) // { // delete m_pPateName; // m_pPateName = NULL; // } // if (m_pPateMarry) // { // delete m_pPateMarry; // m_pPateMarry = NULL; // } // if (m_pPateForce) // { // delete m_pPateForce; // m_pPateForce = NULL; // } // if (m_pPateTitle) // { // delete m_pPateTitle; // m_pPateTitle = NULL; // } // if (m_pPateLastWords1) // { // delete m_pPateLastWords1; // m_pPateLastWords1 = NULL; // } // if (m_pPateLastWords2) // { // delete m_pPateLastWords2; // m_pPateLastWords2 = NULL; // } // if (m_pPateTeamReq) // { // delete m_pPateTeamReq; // m_pPateTeamReq = NULL; // } // if (m_pPateBooth) // { // delete m_pPateBooth; // m_pPateBooth = NULL; // } // if (m_pPateFaction) // { // delete m_pPateFaction; // m_pPateFaction = NULL; // } // if (m_pFactionDecal) // { // delete m_pFactionDecal; // m_pFactionDecal = NULL; // } // if (m_pPateCountry) // { // delete m_pPateCountry; // m_pPateCountry = NULL; // } // if (m_pCountryDecal) // { // delete m_pCountryDecal; // m_pCountryDecal = NULL; // } // if (m_pBubbleTexts) // { // delete m_pBubbleTexts; // m_pBubbleTexts = NULL; // } // if (m_pLevelUpGFX) // { // g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pLevelUpGFX); // m_pLevelUpGFX = NULL; // } // if (m_pPetCureGFX) // { // A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan(); // if (pGFXExMan) // pGFXExMan->CacheReleasedGfx(m_pPetCureGFX); // m_pPetCureGFX = NULL; // m_pPetCureGFXtate = -1; // } // for (int i = 0; i < sizeof(m_pMonsterSpiritGFX) / sizeof(m_pMonsterSpiritGFX[0]); ++i) { // A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan(); // if (pGFXExMan) // pGFXExMan->CacheReleasedGfx(m_pMonsterSpiritGFX[i]); // m_pMonsterSpiritGFX[i] = NULL; // } // if (m_pWaterWaveStill) // { // g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pWaterWaveStill); // m_pWaterWaveStill = NULL; // } // if (m_pWaterWaveMove) // { // g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pWaterWaveMove); // m_pWaterWaveMove = NULL; // } // if (m_pAirBubble) // { // g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pAirBubble); // m_pAirBubble = NULL; // } // if (m_pSwimBubble) // { // g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pSwimBubble); // m_pSwimBubble = NULL; // } // if (m_pTransformGfx) // { // g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pTransformGfx); // m_pTransformGfx = NULL; // } // if (m_pDuelStateGFX) // { // g_pGame->GetGFXCaster()->ReleaseGFXEx(m_pDuelStateGFX); // m_pDuelStateGFX = NULL; // } // if (m_pPetModel) // { // m_pPetModel->RemoveChildModel(_hanger_ride, false); // A3DRELEASE(m_pPetModel); // } // ClearBoothModel(); // for (MOEffectMAP::iterator it = m_mapMOEffect.begin();it != m_mapMOEffect.end();++it) // { // A3DGFXExMan *pGFXExMan = g_pGame->GetA3DGFXExMan(); // pGFXExMan->CacheReleasedGfx(it->second); // } // m_mapMOEffect.clear(); // // Release face model // ReleaseFaceModel(); // // Release player model // ReleasePlayerModel(); // // Clear resource ready flags // SetResReadyFlag(RESFG_ALL, false); // m_bAboutToDie = false; } public void CloneSimplePropertyTo(CECPlayer player) { //TOdo: Complete this function(remove all commented code) player.transform.position = m_pPlayerModel.transform.position; player.transform.rotation = m_pPlayerModel.transform.rotation; player.SetGroundNormal(GetGroundNormal()); player.SetUseGroundNormal(GetUseGroundNormal()); // CECPlayer player.m_PlayerInfo = GetPlayerInfo(); player.SetBornStamp(GetBornStamp()); player.name = GetName(); //player.SetProps(&GetBasicProps(), &GetExtendProps()); player.m_iGender = GetGender(); player.m_iProfession = GetProfession(); //player.m_pvp = GetPVPInfo(); //player.m_aIconStates = GetIconStates(); player.SetMoneyAmount(GetMoneyAmount()); player.m_iMaxMoney = GetMaxMoneyAmount(); //player.m_i64EquipDisabled = m_i64EquipDisabled; //player.SetBoothState(GetBoothState()); //player.m_factionPVPMask= m_factionPVPMask; //player.m_RidingPet = GetRidingPetInfo(); //player.m_iBattleCamp = GetBattleCamp(); //player.m_dwGMFlags = m_dwGMFlags; //player.SetSpouse(GetSpouse()); player.m_idForce = GetForce(); //player.SetCountry(GetCountry()); //player.SetMoveMode(GetMoveMode()); //player.SetMoveEnv(GetMoveEnv()); //player.SetWalkRunFlag(GetWalkRunFlag()); player.m_MoveConst = m_MoveConst; player.m_aabbServer = m_aabbServer; player.m_aabb = m_aabb; player.m_dwStates = m_dwStates; //player.m_dwStates2 = m_dwStates2; player.m_fTouchRad = GetTouchRadius(); //player.m_byPariahLvl = GetPariahLevel(); //player.SetBoothName(GetBoothName()); // player.m_CustomizeFactor = m_CustomizeFactor; // player.ChangeCustomizeData(m_CustomizeData); // for (int i=0; i < GetEffectCount(); i++) // player.ApplyEffect(GetEffect(i), true); // player.SetFactionID(GetFactionID()); player.SetCurPetID(GetCurPetID()); // player.SetCurrentTitle(GetCurrentTitle()); // player.SetReputation(GetReputation()); // player.SetFashionMode(InFashionMode()); // player.SetFRoleID(GetFRoleID()); // player.SetMeridiansProp(GetMeridiansProp()); // player->SetReincarnationCount(GetReincarnationCount()); // player.SetRealmLevel(GetRealmLevel()); // player.ScaleBody(GetScaleBySkill()); // player.SetTeamRequire(GetTeamRequire(), false); player.SetNewExtendStates(0, m_aExtStates, OBJECT_EXT_STATE_COUNT); // player.m_GoblinRenderCnt = m_GoblinRenderCnt; // player.m_bRenderGoblin = m_bRenderGoblin; } public int GetOriginalShapeID() { return m_iShape; } public async Task TransformShape(byte iShape, bool bLoadAtOnce = false/* =false */) { SetShape(iShape); //a_LogOutput(1, "CECPlayer::TransformShape(iShape=%d)(iShapeType=%d,iShapeID=%d)", iShape, PLAYERMODEL_GETTYPE(iShape), PLAYERMODEL_GETID(iShape)); if (!GetMajorModel()) return; if (IsShapeChanged()) { m_bWeaponAttached = false; // change to a dummy model, may cause an asynchronous loading await QueueLoadDummyModel(m_iShape, bLoadAtOnce); } else { m_bWeaponAttached = true; // back to major model is a synchronous operation ApplyShapeModelChange(GetMajorModel()); } } void SetShape(byte iShape) { // The shape id from the server is a 8-bit number // The meaning of each bit: // | 7 6 | 5 4 3 2 1 0 | // |-TYPE-|-----Model ID-----| int iNewShape = (iShape & 0xff); // only accept 8bit // �Ծɵ�Shape�������ݽ������� FixOldShapeInfo(ref iNewShape); // ְҵ������Model IDҪ��ת�� if( PLAYERMODEL_GETTYPE(iNewShape) == (int)PLAYERMODEL_TYPE.PLAYERMODEL_PROFESSION ) { int iRealID = _GetProfessionTransformModelID( m_iProfession, m_iGender, PLAYERMODEL_GETID(iNewShape)); iNewShape = 0x40 | iRealID; } // ��ְҵ������Model IDΪEC_Resource.h���ֵ���ʲ������� else { } // store the original data into 8~15 bit m_iShape = iNewShape | ((iShape & 0xff) << 8); } void FixOldShapeInfo(ref int iShape) { // �Ǹ�ʱ��shapeΪ0����û�б�������0����ְҵ���� if(iShape != 0 && PLAYERMODEL_GETTYPE(iShape) == 0) iShape |= 0x40; } public int _GetProfessionTransformModelID(int nChar, int nGender, int nModelID) { int result = 0; switch (nChar){ case (int)PROFESSION.PROF_HAG: // ���� result = (2 == nModelID) ? (int)ModelResourceType.RES_MOD_ORC_FOX2 : (int)ModelResourceType.RES_MOD_ORC_FOX; break; case (int)PROFESSION.PROF_ORC: // ���� result = (2 == nModelID) ? (int)ModelResourceType.RES_MOD_ORC_PANDER : (int)ModelResourceType.RES_MOD_ORC_TIGER; break; case (int)PROFESSION.PROF_MONK: // ��ʦ case (int)PROFESSION.PROF_GHOST: // �̿� result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_SHADOW_FISH_M : (int)ModelResourceType.RES_MOD_SHADOW_FISH_F; break; case (int)PROFESSION.PROF_YEYING: // ҹӰ result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_YEYING_RESHAPE_M : (int)ModelResourceType.RES_MOD_YEYING_RESHAPE_F; break; case (int)PROFESSION.PROF_YUEXIAN: // ���� result = ((int)Gender.GENDER_MALE == nGender) ? (int)ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_M : (int)ModelResourceType.RES_MOD_YUEXIAN_RESHAPE_F; break; } return result; } } public struct PlayActionEvent { public string AnimationName; public int ITransTime; public bool IsForceStopPrevious; public CECAttackEvent AttackEvent; public PlayActionEvent(string shapeName, string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null) { this.AnimationName = shapeName + animationName; ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; AttackEvent = attackEvent; } public PlayActionEvent(string animationName, int iTransTime, bool isForceStopPrevious = false, CECAttackEvent attackEvent = null) { this.AnimationName = animationName; ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; AttackEvent = attackEvent; } } public struct PLAYER_ACTION { public PLAYER_ACTION_TYPE type; public PLAYER_ACTION_INFO_CONFIG data; }; public class QueueActionEvent { public string AnimationName; public int ITransTime; public Action SetFlag; public CECAttackEvent AttackEvent; public bool IsHitAnim; public bool IsForceStopPrevious; public QueueActionEvent(string animationName, Action setFlag, bool isHitAnim, CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false) { this.AnimationName = animationName; SetFlag = setFlag; IsHitAnim = isHitAnim; AttackEvent = attackEvent; ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; } public void SetData(string shapeName, string animationName, Action setFlag, bool isHitAnim, CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false) { this.AnimationName = shapeName + animationName; SetFlag = setFlag; IsHitAnim = isHitAnim; AttackEvent = attackEvent; ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; } public void SetData(string animationName, Action setFlag, bool isHitAnim, CECAttackEvent attackEvent, int iTransTime, bool isForceStopPrevious = false) { this.AnimationName = animationName; SetFlag = setFlag; IsHitAnim = isHitAnim; AttackEvent = attackEvent; ITransTime = iTransTime; IsForceStopPrevious = isForceStopPrevious; } } public enum PLAYER_ACTION_TYPE { // 0 ACT_STAND = 0, // Đứng ACT_FIGHTSTAND, // Đứng chiến đ�?u ACT_WALK, // Đi b�? ACT_RUN, // Ch�?y ACT_JUMP_START, // Bắt đ�?u nh�?y // 5 ACT_JUMP_LOOP, // Nh�?y trên không lặp l�?i ACT_JUMP_LAND, // Nh�?y tiếp đ�?t ACT_SWIM, // Bơi ACT_HANGINWATER, // Lơ lửng trong nước ACT_TAKEOFF, // C�?t cánh (should be ACT_TAKEOFF_WING) // 10 ACT_HANGINAIR, // Treo trên không (should be ACT_HANGINAIR_WING) ACT_FLY, // Bay (should be ACT_FLY_WING) ACT_FLYDOWN, // Bay xuống cao (should be ACT_FLYDOWN_WING_HIGH) ACT_FLYDOWN_WING_LOW, // Bay xuống th�?p (should be ACT_FLYDOWN_WING_LOW) ACT_LANDON, // H�? cánh (should be ACT_LAND_WING) // 15 ACT_TAKEOFF_SWORD, // Kiếm bay - c�?t cánh ACT_HANGINAIR_SWORD, // Kiếm bay - treo không trung ACT_FLY_SWORD, // Kiếm bay - tiến tới ACT_FLYDOWN_SWORD_HIGH, // Kiếm bay - rơi cao ACT_FLYDOWN_SWORD_LOW, // Kiếm bay - rơi th�?p // 20 ACT_LANDON_SWORD, // Kiếm bay - h�? cánh ACT_SITDOWN, // Ngồi ACT_SITDOWN_LOOP, // Ngồi lặp l�?i ACT_STANDUP, // Đứng dậy ACT_WOUNDED, // B�? thương // 25 ACT_GROUNDDIE, // Chết trên mặt đ�?t ACT_GROUNDDIE_LOOP, // Chết trên đ�?t (loop) ACT_WATERDIE, // Chết trong nước ACT_WATERDIE_LOOP, // Chết trong nước (loop) ACT_AIRDIE_ST, // Chết trên không (bắt đ�?u) // 30 ACT_AIRDIE, // Chết trên không (loop rơi) ACT_AIRDIE_ED, // Chết trên không (ch�?m đ�?t) ACT_AIRDIE_LAND_LOOP, // Chết rơi đ�?t (loop) ACT_REVIVE, // Hồi sinh ACT_CUSTOMIZE, // Động tác tùy chỉnh // 35 ACT_STRIKEBACK, // B�? đánh lùi ACT_STRIKEDOWN, // B�? đánh ngã ACT_STRIKEDOWN_LOOP, // B�? đánh ngã (loop) ACT_STRIKEDOWN_STANDUP, // B�? đánh ngã rồi đứng dậy ACT_PICKUP, // Nhặt đ�? // 40 ACT_PICKUP_LOOP, // Nhặt đ�? (loop) ACT_PICKUP_STANDUP, // Nhặt đ�? đứng dậy ACT_PICKUP_MATTER, // Nhặt vật th�? ACT_GAPE, // Há miệng ACT_LOOKAROUND, // Nhìn quanh // 45 ACT_PLAYWEAPON, // Vung vũ khí ACT_EXP_WAVE, // Vẫy tay ACT_EXP_NOD, // Gật đ�?u ACT_EXP_SHAKEHEAD, // Lắc đ�?u ACT_EXP_SHRUG, // Nhún vai // 50 ACT_EXP_LAUGH, // Cười lớn ACT_EXP_ANGRY, // Tức giận ACT_EXP_STUN, // Choáng ACT_EXP_DEPRESSED, // Buồn bã ACT_EXP_KISSHAND, // Hôn tay // 55 ACT_EXP_SHY, // Ng�?i ngùng ACT_EXP_SALUTE, // Chào ACT_EXP_SITDOWN, // Ngồi xuống ACT_EXP_SITDOWN_LOOP, // Ngồi xuống (loop) ACT_EXP_SITDOWN_STANDUP, // Ngồi xuống rồi đứng dậy // 60 ACT_EXP_ASSAULT, // T�?n công ACT_EXP_THINK, // Suy nghĩ ACT_EXP_DEFIANCE, // Thách thức ACT_EXP_VICTORY, // Chiến thắng ACT_EXP_KISS, // Hôn // 65 ACT_EXP_KISS_LOOP, // Hôn (loop) ACT_EXP_KISS_END, // Kết thúc hôn ACT_ATTACK_1, // T�?n công 1 ACT_ATTACK_2, // T�?n công 2 ACT_ATTACK_3, // T�?n công 3 // 70 ACT_ATTACK_4, // T�?n công 4 ACT_ATTACK_TOSS, // Ném vũ khí ACT_TRICK_RUN, // Chiêu khi ch�?y ACT_TRICK_JUMP, // Chiêu khi nh�?y ACT_FLY_GLIDE, // Lư�?n // 75 ACT_FLY_GLIDE_SWORD, // Kiếm bay - lư�?n ACT_EXP_FIGHT, // Tư th�? chiến đ�?u ACT_EXP_ATTACK1, // T�?n công diễn xu�?t 1 ACT_EXP_ATTACK2, // T�?n công diễn xu�?t 2 ACT_EXP_ATTACK3, // T�?n công diễn xu�?t 3 // 80 ACT_EXP_ATTACK4, // T�?n công diễn xu�?t 4 ACT_EXP_DEFENCE, // Phòng th�? ACT_EXP_FALL, // Té ngã ACT_EXP_FALLONGROUND, // Ngã xuống đ�?t ACT_EXP_LOOKAROUND, // Nhìn quanh // 85 ACT_EXP_DANCE, // Nh�?y múa ACT_EXP_FASHIONWEAPON, // Động tác vũ khí thời trang ACT_USEITEM, // Dùng item ACT_USEITMELOOP, // Dùng item (loop) ACT_TWO_KISS, // Hôn đôi // 90 ACT_USING_TARGET_ITEM, // Dùng đ�?o c�? ACT_SWIM_FOR_MOVESKILL, // Bơi trong lúc dùng skill di chuyển ACT_MAX, ACT_CASTSKILL // Ch�? là placeholder cho skill actions } public struct ClearComActFlagAllRankNodesEvent { public bool v; public ClearComActFlagAllRankNodesEvent(bool value) { v = value; } } [Serializable] public struct INFO { public int cid; // Character ID public int crc_c; // customized data crc public int crc_e; // Equipment data crc public INFO(int cid, int crc_c, int crc_) { this.cid = cid; this.crc_c = crc_c; this.crc_e = crc_; } } public enum enumWingType { WINGTYPE_WING, // 飞行器类型:翅膀 WINGTYPE_FLYSWORD, // 飞行器类型:飞剑 WINGTYPE_DOUBLEWHEEL, // 飞行器类型:双脚飞行器 }; // Bubble text public enum BubbleTextType { BUBBLE_DAMAGE = 0, BUBBLE_EXP, BUBBLE_SP, BUBBLE_MONEY, BUBBLE_LEVELUP, BUBBLE_HITMISSED, BUBBLE_INVALIDHIT, BUBBLE_IMMUNE, BUBBLE_HPWARN, BUBBLE_MPWARN, BUBBLE_REBOUND, // ���� BUBBLE_BEAT_BACK, // ���� BUBBLE_ADD, // ��Ѫ�ļӺ� BUBBLE_DODGE_DEBUFF, BUBBLE_REALMEXP, BUBBLE_NUM, }; public struct PVPINFO { public bool bEnable; // PVP switch public uint dwCoolTime; public uint dwMaxCoolTime; public bool bFreePVP; // Free PVP flag, ignore bEnable flag public bool bInPVPCombat; // true, in PVP combat public int iDuelState; // Duel state public int idDuelOpp; // Duel opponent public int iDuelTimeCnt; // Duel time counter public int iDuelRlt; // Duel result. 0, no defined; 1-win; 2-lose; 3-draw }; // Battle type / 战斗类型 public enum BattleType { BT_NONE = 0, // No battle / 无战斗 BT_GUILD = 1, // Guild war / 帮派战 BT_COUNTRY = 2, // Country war / 国战 BT_CHARIOT = 3, // Chariot war / 战车战 }; // Score rank entry for country battle live show / 国战直播显示分数排行条目 [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ScoreRankEntry { public int idPlayer; // Player ID / 玩家ID public int iScore; // Score / 分数 public int iKillCount; // Kill count / 击杀数 public int iDeathCount; // Death count / 死亡数 }; // Death entry for country battle live show / 国战直播显示死亡条目 [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct DeathEntry { public int idKiller; // Killer ID / 击杀者ID public int idVictim; // Victim ID / 受害者ID public int iTime; // Death time / 死亡时间 }; // Battle information / 战斗信息 [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BATTLEINFO { public int nType; // Battle type / 战斗类型 (BattleType) public int idBattle; // Battle id / 战斗ID public int iResult; // Battle result / 战斗结果 (0 = no result, 1 = win, 2 = lose, 3 = draw) public int iResultCnt; // Result time counter / 结果时间计数器 public int iMaxScore_I; // Maximum score of invader / 攻击方最大分数 public int iMaxScore_D; // Maximum score of defender / 防守方最大分数 public int iScore_I; // Score of invader / 攻击方分数 public int iScore_D; // Score of defender / 防守方分数 public int iEndTime; // Battle end time / 战斗结束时间 // 国战专用数据 / Country war specific data public int iOffenseCountry; // Offense country / 攻击方国家 public int iDefenceCountry; // Defence country / 防守方国家 public int iReviveTimes; // 剩余复活次数 / Remaining revive times [MarshalAs(UnmanagedType.U1)] public bool bFlagCarrier; // 是否是旗手 / Is flag carrier public int iCarrierID; // 扛旗者ID(bFlagCarrier为false时有效)/ Carrier ID (valid when bFlagCarrier is false) public A3DVECTOR3 posCarrier; // 扛旗者位置(bFlagCarrier为false时有效)/ Carrier position (valid when bFlagCarrier is false) [MarshalAs(UnmanagedType.U1)] public bool bCarrierInvader; // 扛旗者是攻击方(bFlagCarrier为false时有效)/ Carrier is invader (valid when bFlagCarrier is false) public int iCombatTime; // 战斗时间(秒)/ Combat time (seconds) public int iAttendTime; // 参加战场时间(秒)/ Attend time (seconds) public int iKillCount; // 击杀次数 / Kill count public int iDeathCount; // 死亡次数 / Death count public int iCountryKillCount; // 同国家击杀次数 / Same country kill count public int iCountryDeathCount;// 同国家死亡次数 / Same country death count public int iAttackerCount; // 攻击方人数 / Attacker count public int iDefenderCount; // 防守方人数 / Defender count public int iStrongHoldCount; // 据点个数 / Stronghold count [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public int[] iStrongHoldState; // 据点占领状态 8 == ARRAY_SIZE(COUNTRY_CONFIG::stronghold) / Stronghold occupation state // Score rank containers (using List instead of std::vector) / 分数排行容器(使用List代替std::vector) public List OffenseRanks; // Offense ranks / 攻击方排行 public List DefenceRanks; // Defence ranks / 防守方排行 // Death containers (using List instead of std::vector) / 死亡容器(使用List代替std::vector) public List OffenseDeaths; // Offense deaths / 攻击方死亡 public List DefenceDeaths; // Defence deaths / 防守方死亡 // 战车 / Chariot public int iChariot; // 战车id / Chariot id public int iEnergy; // 能量 / Energy public int iScoreSelf; // 自己成绩 / Self score public int iMultiKill; // 连杀 / Multi kill // Initialize arrays and lists / 初始化数组和列表 public void Initialize() { if (iStrongHoldState == null) iStrongHoldState = new int[8]; if (OffenseRanks == null) OffenseRanks = new List(); if (DefenceRanks == null) DefenceRanks = new List(); if (OffenseDeaths == null) OffenseDeaths = new List(); if (DefenceDeaths == null) DefenceDeaths = new List(); } // Set country battle live show info / 设置国战直播显示信息 // TODO: Implement when cmd_countrybattle_live_show_result is available // 当cmd_countrybattle_live_show_result可用时实现 public void SetCountryBattleLiveShowInfo(/*const S2C::cmd_countrybattle_live_show_result& cmd*/) { // TODO: Implement SetCountryBattleLiveShowInfo // 实现SetCountryBattleLiveShowInfo } // Check if in guild war / 检查是否在帮派战中 public bool IsGuildWar() { return nType == (int)BattleType.BT_GUILD; } // Check if in country war / 检查是否在国战中 public bool IsCountryWar() { return nType == (int)BattleType.BT_COUNTRY; } // Check if is flag carrier / 检查是否是旗手 public bool IsFlagCarrier() { return IsCountryWar() && bFlagCarrier; } // Check if in chariot war / 检查是否在战车战中 public bool IsChariotWar() { return nType == (int)BattleType.BT_CHARIOT; } // Reset battle info / 重置战斗信息 public void Reset() { nType = (int)BattleType.BT_NONE; idBattle = 0; iResult = 0; iResultCnt = 0; iMaxScore_I = 0; iMaxScore_D = 0; iScore_I = 0; iScore_D = 0; iEndTime = 0; iOffenseCountry = 0; iDefenceCountry = 0; iReviveTimes = 0; bFlagCarrier = false; iCarrierID = 0; posCarrier = new A3DVECTOR3(0, 0, 0); bCarrierInvader = false; iCombatTime = 0; iAttendTime = 0; iKillCount = 0; iDeathCount = 0; iCountryKillCount = 0; iCountryDeathCount = 0; iAttackerCount = 0; iDefenderCount = 0; iStrongHoldCount = 0; if (iStrongHoldState != null) { for (int i = 0; i < iStrongHoldState.Length; i++) iStrongHoldState[i] = 0; } OffenseRanks?.Clear(); DefenceRanks?.Clear(); OffenseDeaths?.Clear(); DefenceDeaths?.Clear(); iChariot = 0; iEnergy = 0; iScoreSelf = 0; iMultiKill = 0; } }; public enum PlayerResourcesReadyFlag { RESFG_SKELETON = 0x01, RESFG_SKIN = 0x02, RESFG_CUSTOM = 0x04, RESFG_ASSEMBLED = 0x08, RESFG_ALL = 0x0f, }; public static class Duel_state // Duel state { public const int DUEL_ST_NONE = 0, DUEL_ST_PREPARE = 1, DUEL_ST_INDUEL = 2, DUEL_ST_STOPPING = 3; } //// Move mode public class Move_Mode { public const int MOVE_STAND = 0, MOVE_MOVE = 1, // Normal move, walk, run, swim or fly MOVE_JUMP = 2, MOVE_FREEFALL = 3, MOVE_SLIDE = 4; } public class EC_Player_Skin_Const { // Skin index public static byte SKIN_BODY_INDEX = 0; public static byte SKIN_UPPER_BODY_INDEX = 1; public static byte SKIN_WRIST_INDEX = 2; public static byte SKIN_LOWER_INDEX = 3; public static byte SKIN_FOOT_INDEX = 4; public static byte SKIN_HEAD_INDEX = 5; public static byte SKIN_FASHION_UPPER_BODY_INDEX = 6; public static byte SKIN_FASHION_WRIST_INDEX = 7; public static byte SKIN_FASHION_LOWER_INDEX = 8; public static byte SKIN_FASHION_FOOT_INDEX = 9; public static byte NUM_SKIN_INDEX = 10; } public enum enumSkinShow { enumSkinShowNone = 0, enumSkinShowUpperBody, enumSkinShowWrist, enumSkinShowLowerBody, enumSkinShowFoot, enumSkinShowUpperAndLower, enumSkinShowUpperAndWrist, enumSkinShowLowerAndFoot, enumSkinShowUpperLowerAndWrist, enumSkinShowArmet, enumSkinShowHand, }; /// /// Place holder for riding pet. Not test logic yet. /// public struct RIDINGPET { public int id; public ushort color; public RIDINGPET(bool isReset = true) { id = 0; color = 0; } public bool GetColor(Color clr) { // ��ȡ��ǰ����Ⱦɫ��ɫ return id > 0 && GetColor(color, clr); } public static bool GetColor(ushort c, Color clr) { // ��ѯ��ǰ����Ƿ�Ⱦ��ɫ�����Ⱦ��ɫ�����ر�Ⱦ֮�����ɫ bool bRet = false; if ((c & (1 << (8 - 1))) != 0) { // unsigned short ��λΪ1ʱ����ʾȾ��ɫ����ʱ�ɻ�ȡ��ɫ clr = new Color(((c) & (0x1f << 10)) >> 7, ((c) & (0x1f << 5)) >> 2, ((c) & 0x1f) << 3); bRet = true; } return bRet; } public static Color GetDefaultColor() { return new Color(255, 255, 255); } }; }