using System.IO; using BrewMonster; using BrewMonster.Network; using BrewMonster.Scripts; using BrewMonster.Scripts.Managers; using ModelRenderer.Scripts.GameData; using UnityEngine; namespace BrewMonster { public partial class CECPlayer { public const int NUM_PROFESSION = (int)Profession.NUM_PROFESSION; public const int NUM_GENDER = (int)Gender.NUM_GENDER; public static readonly string _left_hand_weapon = "LeftHand"; public static readonly string _right_hand_weapon = "RightHand"; public static readonly string _wing = "Wing"; public static readonly string _wing2 = "Wing2"; public const string _cc_ride = "CC_ride"; public static readonly string _cc_ride2 = "CC_Ride2"; public const string _hh_ride = "HH_Ride"; public const string _hanger_ride = "Rider"; public static readonly string _hanger_ride2 = "Rider2"; public static readonly string _hanger_hug = "Hug"; public static readonly string _hh_bind = "HH_Bind"; public static readonly string _cc_bind = "CC_Bind"; public const string _cc_fenghuolun = "CC_feijian"; public const string _hh_left_foot = "HH_左脚"; public const string _hh_right_foot = "HH_右脚"; public static readonly string _hh_left_shoulder_weapon = "HH_leftsword"; public static readonly string _hh_right_shoulder_weapon = "HH_rightsword"; public static readonly string _hh_left_hand_weapon = "HH_lefthandweapon"; public static readonly string _hh_right_hand_weapon = "HH_righthandweapon"; public static readonly string _hh_qiu = "HH_qiu"; public static readonly string _hh_right_hand_nickle_weapon = "HH_weapon"; public static readonly string _cc_weapon = "CC_weapon"; public static readonly string _cc_qiu = "CC_qiu"; public static readonly string _hh_qiu_base = "HH_base"; public static readonly string[] _multiobject_effect = { "绿色连线.gfx", "红色连线.gfx", "黑色连线.gfx" }; public static readonly string[] _equipment_skin = { "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "", "models/players/装备/女/{0}/妖精{1}", "models/players/装备/男/{0}/妖兽{1}", "", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", "models/players/装备/男/{0}/男通用{1}", "models/players/装备/女/{0}/女通用{1}", }; // Skin index public enum SkinIndex { SKIN_BODY_INDEX = 0, SKIN_UPPER_BODY_INDEX, SKIN_WRIST_INDEX, SKIN_LOWER_INDEX, SKIN_FOOT_INDEX, SKIN_HEAD_INDEX, SKIN_FASHION_UPPER_BODY_INDEX, SKIN_FASHION_WRIST_INDEX, SKIN_FASHION_LOWER_INDEX, SKIN_FASHION_FOOT_INDEX, NUM_SKIN_INDEX, } // Wing types public enum WingType { WINGTYPE_WING, // 锟斤拷锟斤拷锟斤拷锟斤拷锟酵o拷锟斤拷锟?????? WINGTYPE_FLYSWORD, // 锟斤拷锟斤拷锟斤拷锟斤拷锟酵o拷锟缴斤拷 WINGTYPE_DOUBLEWHEEL, // 锟斤拷锟斤拷锟斤拷锟斤拷锟酵o拷双锟脚凤拷锟斤拷锟斤�? } private static readonly SkinIndex[] _location_skin_map = { SkinIndex.SKIN_BODY_INDEX, SkinIndex.SKIN_UPPER_BODY_INDEX, SkinIndex.SKIN_WRIST_INDEX, SkinIndex.SKIN_LOWER_INDEX, SkinIndex.SKIN_FOOT_INDEX, SkinIndex.SKIN_UPPER_BODY_INDEX, SkinIndex.SKIN_UPPER_BODY_INDEX, SkinIndex.SKIN_LOWER_INDEX, SkinIndex.SKIN_UPPER_BODY_INDEX }; // The skeleton builder holds the reference to the player's bones // We use this to setup the bones for the equipment skinned mesh renderers private SkeletonBuilder _skeletonBuilder; private PlayerDefaultEquipments _playerDefaultEquipments; // Track instantiated armor objects for each slot private GameObject _currentUpperArmor; private GameObject _currentLowerArmor; private GameObject _currentWristArmor; private GameObject _currentFootArmor; // Track instantiated weapon objects private GameObject _currentRightHandWeapon; private GameObject _currentLeftHandWeapon; protected PlayerDefaultEquipments PlayerDefaultEquipments { get { if (_playerDefaultEquipments == null) { _playerDefaultEquipments = GetComponentInChildren(); } return _playerDefaultEquipments; } } public bool UpdateEquipSkins() { int[] aNewEquips = new int[InventoryConst.IVTRSIZE_EQUIPPACK]; EC_IvtrItem pItem = null; for (int i = 0; i < InventoryConst.IVTRSIZE_EQUIPPACK; i++) { // Use host player's equipment inventory (per-instance CECInventory) var host = CECGameRun.Instance?.GetHostPlayer(); var equipInv = host?.IvtrEquipPack; pItem = equipInv?.GetItem(i, false); if (pItem != null) aNewEquips[i] = pItem.m_tid; } ShowEquipments(aNewEquips, true, true); return true; } public async void ShowEquipments(int[] pEquipmentID, bool bLoadAtOnce, bool bForceLoad) { var elemendataman = BrewMonster.ElementDataManProvider.GetElementDataMan(); DATA_TYPE DataType = default; bool useDefaultUpper = false; bool useDefaultLower = false; bool useDefaultWrist = false; bool useDefaultFoot = false; for (int i = 0; i < InventoryConst.IVTRSIZE_EQUIPPACK; i++) { //TODO: The equipment ids store the stone information, we need to extract the stone information from the equipment id. /* int idEquipment = pEquipmentID[i]; if((i >= EQUIPIVTR_FASHION_BODY && i <= EQUIPIVTR_FASHION_WRIST ) || i == EQUIPIVTR_FASHION_HEAD || i == EQUIPIVTR_FASHION_WEAPON) { WORD wColor = (idEquipment & 0xffff0000) >> 16; idEquipment &= 0x0000ffff; color = FASHION_WORDCOLOR_TO_A3DCOLOR(wColor); } else { if( i == EQUIPIVTR_WEAPON ) { pResult->stoneWeapon = (idEquipment & 0xffff0000) >> 16; } if( i == EQUIPIVTR_BODY ) { pResult->stoneUpperBody = (idEquipment & 0xffff0000) >> 16; } if( i == EQUIPIVTR_WRIST ) { pResult->stoneWrist = (idEquipment & 0xffff0000) >> 16; } if( i == EQUIPIVTR_LEG ) { pResult->stoneLowerBody = (idEquipment & 0xffff0000) >> 16; } if( i == EQUIPIVTR_FOOT ) { pResult->stoneFoot = (idEquipment & 0xffff0000) >> 16; } idEquipment &= 0x0000ffff; } */ if (pEquipmentID[i] != m_aEquips[i]) { m_aEquips[i] = pEquipmentID[i]; // store the current equipment id // new equipment. Need to load and equip to host player var equipData = elemendataman.get_data_ptr((uint)pEquipmentID[i], ID_SPACE.ID_SPACE_ESSENCE, ref DataType); object subTypeData = null; switch (DataType) { case DATA_TYPE.DT_WEAPON_ESSENCE: var weaponData = (WEAPON_ESSENCE)equipData; subTypeData = elemendataman.get_data_ptr((uint)weaponData.id_sub_type, ID_SPACE.ID_SPACE_ESSENCE, ref DataType); if (subTypeData != null && DataType == DATA_TYPE.DT_WEAPON_SUB_TYPE) { var subTypeDataWeapon = (WEAPON_SUB_TYPE)subTypeData; m_uAttackType = subTypeDataWeapon.action_type; m_ExtProps.ak.AttackRange = weaponData.attack_range; } string fileModelRight = AFile.NormalizePath(weaponData.FileModelRight, true).ToLower(); string fileModelLeft = AFile.NormalizePath(weaponData.FileModelLeft, true).ToLower(); // BMLogger.Log($"ShowEquipments():: Weapon Essence: {fileModelRight} -- {fileModelLeft}"); // Destroy existing right hand weapon before creating new one if (_currentRightHandWeapon != null) { Destroy(_currentRightHandWeapon); _currentRightHandWeapon = null; } // Destroy existing left hand weapon before creating new one if (_currentLeftHandWeapon != null) { Destroy(_currentLeftHandWeapon); _currentLeftHandWeapon = null; } GameObject weaponPrefab = null; if (!string.IsNullOrEmpty(fileModelRight)) { weaponPrefab = await AddressableManager.Instance.LoadPrefabAsync(fileModelRight); var weaponObject = Instantiate(weaponPrefab); if (weaponObject != null) { weaponObject.transform.SetParent(FindChildObjectRecursive(transform, _hh_right_hand_weapon).transform); weaponObject.transform.localPosition = weaponPrefab.transform.localPosition; weaponObject.transform.localRotation = weaponPrefab.transform.localRotation; weaponObject.transform.localScale = Vector3.one; weaponObject.SetActive(true); _currentRightHandWeapon = weaponObject; } } if (!string.IsNullOrEmpty(fileModelLeft)) { weaponPrefab = await AddressableManager.Instance.LoadPrefabAsync(fileModelLeft); var weaponObject = Instantiate(weaponPrefab); if (weaponObject != null) { weaponObject.transform.SetParent(FindChildObjectRecursive(transform, _hh_left_hand_weapon).transform); weaponObject.transform.localPosition = weaponPrefab.transform.localPosition; weaponObject.transform.localRotation = weaponPrefab.transform.localRotation; weaponObject.transform.localScale = Vector3.one; weaponObject.SetActive(true); _currentLeftHandWeapon = weaponObject; } } break; case DATA_TYPE.DT_ARMOR_ESSENCE: var pArmor = (ARMOR_ESSENCE)equipData; var nLocation = pArmor.equip_location; // BMLogger.Log($"ShowEquipments():: Armor Essence: {pArmor.RealName}"); var armorSkinPath = _GenEquipmentSkinPath(m_iProfession, m_iGender, pArmor.RealName); if (!armorSkinPath.EndsWith(".ecm")) { armorSkinPath += ".ecm"; } var armorPrefab = await AddressableManager.Instance.LoadPrefabAsync(armorSkinPath); if (armorPrefab != null) { // Destroy existing armor for this slot before creating new one switch (nLocation) { case (uint)SkinIndex.SKIN_UPPER_BODY_INDEX: if (_currentUpperArmor != null) { Destroy(_currentUpperArmor); _currentUpperArmor = null; } break; case (uint)SkinIndex.SKIN_LOWER_INDEX: if (_currentLowerArmor != null) { Destroy(_currentLowerArmor); _currentLowerArmor = null; } break; case (uint)SkinIndex.SKIN_WRIST_INDEX: if (_currentWristArmor != null) { Destroy(_currentWristArmor); _currentWristArmor = null; } break; case (uint)SkinIndex.SKIN_FOOT_INDEX: if (_currentFootArmor != null) { Destroy(_currentFootArmor); _currentFootArmor = null; } break; } var armorObject = Instantiate(armorPrefab); armorObject.transform.SetParent(GetSkeletonBuilder()?.transform); armorObject.transform.localPosition = Vector3.zero; armorObject.transform.localRotation = Quaternion.identity; armorObject.transform.localScale = Vector3.one; var skinnedMeshRenderer = armorObject.GetComponent(); var skinnedMeshRenderereFromDataList = armorObject.GetComponentsInChildren(); foreach (var skinnedMeshRenderereFromData in skinnedMeshRenderereFromDataList) { if (skinnedMeshRenderereFromData != null) { skinnedMeshRenderereFromData._skinnedMeshRenderer.bones = GetSkeletonBuilder().GetBones(skinnedMeshRenderereFromData.BoneNames); skinnedMeshRenderereFromData._skinnedMeshRenderer.rootBone = skinnedMeshRenderereFromData._skinnedMeshRenderer.bones[^1]; } } // Store the armor object for this slot switch (nLocation) { case (uint)SkinIndex.SKIN_UPPER_BODY_INDEX: _currentUpperArmor = armorObject; useDefaultUpper = false; break; case (uint)SkinIndex.SKIN_LOWER_INDEX: _currentLowerArmor = armorObject; useDefaultLower = false; break; case (uint)SkinIndex.SKIN_WRIST_INDEX: _currentWristArmor = armorObject; useDefaultWrist = false; break; case (uint)SkinIndex.SKIN_FOOT_INDEX: _currentFootArmor = armorObject; useDefaultFoot = false; break; } } else { // disable/enable the default equipment switch (nLocation) { case (uint)SkinIndex.SKIN_UPPER_BODY_INDEX: useDefaultUpper = true; break; case (uint)SkinIndex.SKIN_LOWER_INDEX: useDefaultLower = true; break; case (uint)SkinIndex.SKIN_WRIST_INDEX: useDefaultWrist = true; break; case (uint)SkinIndex.SKIN_FOOT_INDEX: useDefaultFoot = true; break; } } break; case DATA_TYPE.DT_WINGMANWING_ESSENCE: m_wingType = enumWingType.WINGTYPE_WING; //ChangeWing(pResult, static_cast(pEquip)->file_model); var pWingData = (WINGMANWING_ESSENCE)equipData; //string path1 = "models/players/通用装备/翅膀/天鹅之翼/天鹅之翼_Test.ecm"; //var pWingPrefab = await AddressableManager.Instance.LoadPrefabAsync(path1); var pWingPrefab = await AddressableManager.Instance.LoadPrefabAsync(pWingData.FileModel.ToLower().Replace('\\', '/')); //Transform parentWing = FindChildRecursive(_pPlayerModel.transform, "HH_chibang"); if(pWingPrefab != null) { var pflySwordObject = Instantiate(pWingPrefab).transform; pflySwordObject.parent = m_pPlayerCECModel.m_skeletonBuilder.GetHook("HH_chibang").transform; pflySwordObject.localPosition = Vector3.zero; pflySwordObject.localRotation = Quaternion.identity; pflySwordObject.localScale = Vector3.one; m_Wing = pflySwordObject.transform; m_Wing.gameObject.SetActive(false); } BMLogger.Log($"ShowEquipments():: Wingman Wing Essence: {pWingData.id} {pWingData.Name} -- {pWingData.FileModel}"); break; case DATA_TYPE.DT_FLYSWORD_ESSENCE: if (m_Wing != null) { Destroy(m_Wing.gameObject); m_Wing = null; } if (equipData == null) { BMLogger.LogError($"ShowEquipments():: Flysword Essence is null: id: {pEquipmentID[i]}"); break; } var pFlySword = (FLYSWORD_ESSENCE)equipData; m_wingType = FlyMode2WingType(pFlySword.fly_mode); BMLogger.Log($"ShowEquipments():: Flysword Essence: {pFlySword.id} {pFlySword.Name} -- {pFlySword.FileModel}"); string path = AFile.NormalizePath(pFlySword.FileModel, true).ToLower(); //var pflySwordPrefab = await AddressableManager.Instance.LoadPrefabAsync(pFlySword.FileModel.ToLower().Replace('\\', '/')); var pflySwordPrefab = await AddressableManager.Instance.LoadPrefabAsync(path); //var parentSword = FindChildRecursive(_pPlayerModel.transform, "HH_feijian"); if(pflySwordPrefab != null) { var pflySwordObject = Instantiate(pflySwordPrefab).transform; pflySwordObject.parent = m_pPlayerCECModel.m_skeletonBuilder.GetHook("HH_feijian").transform; pflySwordObject.localPosition = Vector3.zero; pflySwordObject.localRotation = Quaternion.identity; pflySwordObject.localScale = Vector3.one; m_Wing = pflySwordObject.transform; m_Wing.gameObject.SetActive(false); } break; default: break; } } if (m_aEquips[i] == 0) { switch (i) { case InventoryConst.EQUIPIVTR_WEAPON: // Destroy weapons when weapon slot is empty m_uAttackType = 10; if (_currentRightHandWeapon != null) { Destroy(_currentRightHandWeapon); _currentRightHandWeapon = null; } if (_currentLeftHandWeapon != null) { Destroy(_currentLeftHandWeapon); _currentLeftHandWeapon = null; } break; case InventoryConst.EQUIPIVTR_BODY: useDefaultUpper = true; break; case InventoryConst.EQUIPIVTR_LEG: useDefaultLower = true; break; case InventoryConst.EQUIPIVTR_WRIST: useDefaultWrist = true; break; case InventoryConst.EQUIPIVTR_FOOT: useDefaultFoot = true; break; } } } // enable/disable the default equipment // If using default, destroy non-default equipment if it exists if (useDefaultUpper) { if (_currentUpperArmor != null) { Destroy(_currentUpperArmor); _currentUpperArmor = null; } } PlayerDefaultEquipments.DefaultUpper.SetActive(useDefaultUpper); if (useDefaultLower) { if (_currentLowerArmor != null) { Destroy(_currentLowerArmor); _currentLowerArmor = null; } } PlayerDefaultEquipments.DefaultLower.SetActive(useDefaultLower); if (useDefaultWrist) { if (_currentWristArmor != null) { Destroy(_currentWristArmor); _currentWristArmor = null; } } PlayerDefaultEquipments.DefaultWirst.SetActive(useDefaultWrist); if (useDefaultFoot) { if (_currentFootArmor != null) { Destroy(_currentFootArmor); _currentFootArmor = null; } } PlayerDefaultEquipments.DefaultFoot.SetActive(useDefaultFoot); } public enumWingType FlyMode2WingType(uint flymode) { switch (flymode){ case 0: return enumWingType.WINGTYPE_FLYSWORD; case 1: return enumWingType.WINGTYPE_WING; case 2: return enumWingType.WINGTYPE_DOUBLEWHEEL; default: BMLogger.LogError($"unknow fly mode: {flymode}"); return enumWingType.WINGTYPE_FLYSWORD; } } protected Transform FindChildRecursive(Transform parent, string name) { foreach (Transform child in parent) { if (child.name == name) return child; Transform found = FindChildRecursive(child, name); if (found != null) return found; } return null; } #region Helper Methods protected GameObject FindChildObjectRecursive(Transform parent, string name) { foreach (Transform child in parent) { if (child.name == name) { return child.gameObject; } var childObject = FindChildObjectRecursive(child, name); if (childObject != null) { return childObject; } } return null; } protected SkeletonBuilder GetSkeletonBuilder() { if (_skeletonBuilder == null) { _skeletonBuilder = GetComponentInChildren(); } return _skeletonBuilder; } #endregion public static string _GenEquipmentSkinPath(int nProfession, int nGender, string szSkinName) { return string.Format(_equipment_skin[nProfession * NUM_GENDER + nGender], szSkinName, szSkinName); } } }