diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..d6869adadc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# EditorConfig for Unity Project +root = true + +[*] +charset = utf-8 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.cs] +indent_style = space +indent_size = 4 +end_of_line = crlf + +# Unity Editor Only Usage Analyzer +# ERROR (màu đỏ) khi sử dụng code trong #if UNITY_EDITOR từ code không có directive +dotnet_diagnostic.UNITY_EDITOR_ONLY_USAGE.severity = error + +# Các rule khác cho Unity +dotnet_analyzer_diagnostic.category-Unity.severity = warning + +[*.{asmdef,asmref}] +indent_size = 2 + +[*.{json,md}] +indent_size = 2 diff --git a/.gitignore b/.gitignore index e947009f12..d6c6bb7a8c 100644 --- a/.gitignore +++ b/.gitignore @@ -102,4 +102,4 @@ InitTestScene*.unity* .idea # AI Context -claude.md + diff --git a/Assets/Analyzers.meta b/Assets/Analyzers.meta new file mode 100644 index 0000000000..bc69ce053c --- /dev/null +++ b/Assets/Analyzers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d6389bfe41ba69e42991434d87c1319f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Editor/AddAnalyzerPostprocessor.cs b/Assets/Editor/AddAnalyzerPostprocessor.cs new file mode 100644 index 0000000000..1ff01a4e44 --- /dev/null +++ b/Assets/Editor/AddAnalyzerPostprocessor.cs @@ -0,0 +1,157 @@ +#if UNITY_EDITOR +using System.IO; +using UnityEditor; +using UnityEngine; + +/// +/// Tự động thêm UnityEditorOnlyAnalyzer vào các .csproj files khi Unity generate chúng +/// Analyzer phải ở project root, KHÔNG trong Assets/ để tránh Unity load như runtime assembly +/// +public class AddAnalyzerPostprocessor : AssetPostprocessor +{ + private static string GetAnalyzerPath() + { + string projectRoot = Path.GetDirectoryName(Application.dataPath); + string analyzerPath = Path.Combine(projectRoot, "UnityEditorOnlyAnalyzer/bin/Release/netstandard2.0/UnityEditorOnlyAnalyzer.dll"); + return Path.GetFullPath(analyzerPath); + } + + /// + /// Unity gọi method này cho từng .csproj file được generate + /// Return content đã được modify - Unity sẽ ghi content này vào file + /// + public static string OnGeneratedCSProject(string path, string content) + { + string fileName = Path.GetFileName(path); + + // Chỉ thêm vào các runtime assemblies, không thêm vào Editor assemblies + if (fileName != "Assembly-CSharp.csproj" && fileName != "Assembly-CSharp-firstpass.csproj") + { + return content; + } + + // Kiểm tra xem đã có analyzer chưa + if (content.Contains("UnityEditorOnlyAnalyzer.dll")) + { + return content; + } + + string analyzerPath = GetAnalyzerPath(); + + // Kiểm tra analyzer có tồn tại không + if (!File.Exists(analyzerPath)) + { + Debug.LogWarning($"[UnityEditorOnlyAnalyzer] Analyzer not found at {analyzerPath}. " + + "Please build the analyzer first: cd UnityEditorOnlyAnalyzer && dotnet build -c Release"); + return content; + } + + // Bug fix 1: Tìm "" không có dấu cách ở đầu + int lastProjectTag = content.LastIndexOf(""); + if (lastProjectTag < 0) + { + Debug.LogWarning($"[UnityEditorOnlyAnalyzer] Could not find tag in {fileName}"); + return content; + } + + // Bug fix 2: Không double-escape backslash trong XML - XML tự động escape + // Chỉ cần đảm bảo path có backslash đúng format Windows + string analyzerInclude = $@" + + +"; + + string modifiedContent = content.Substring(0, lastProjectTag) + analyzerInclude; + Debug.Log($"[UnityEditorOnlyAnalyzer] ✅ Added analyzer to {fileName}"); + + return modifiedContent; + } + + /// + /// Public method để menu item có thể gọi thủ công + /// + public static void AddAnalyzerToProjects() + { + // Trigger Unity regenerate .csproj files để OnGeneratedCSProject được gọi + UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal("", 0); + AssetDatabase.Refresh(); + + // Cũng gọi fallback method để đảm bảo + OnGeneratedCSProjectFiles(); + } + + /// + /// Backup method: Unity gọi method này sau khi generate tất cả .csproj files + /// Chỉ dùng nếu OnGeneratedCSProject không hoạt động + /// + private static void OnGeneratedCSProjectFiles() + { + // Fallback: patch files sau khi đã được generate + string projectRoot = Path.GetDirectoryName(Application.dataPath); + string analyzerPath = GetAnalyzerPath(); + + if (!File.Exists(analyzerPath)) + { + Debug.LogWarning($"[UnityEditorOnlyAnalyzer] Analyzer not found at {analyzerPath}. " + + "Please build the analyzer first: cd UnityEditorOnlyAnalyzer && dotnet build -c Release"); + return; + } + + string[] csprojFiles = Directory.GetFiles(projectRoot, "*.csproj", SearchOption.TopDirectoryOnly); + bool anyModified = false; + + foreach (string csprojFile in csprojFiles) + { + string fileName = Path.GetFileName(csprojFile); + if (fileName == "Assembly-CSharp.csproj" || fileName == "Assembly-CSharp-firstpass.csproj") + { + string content = File.ReadAllText(csprojFile); + + if (!content.Contains("UnityEditorOnlyAnalyzer.dll")) + { + // Bug fix: Tìm "" không có dấu cách + int lastProjectTag = content.LastIndexOf(""); + if (lastProjectTag >= 0) + { + string analyzerInclude = $@" + + +"; + + content = content.Substring(0, lastProjectTag) + analyzerInclude; + File.WriteAllText(csprojFile, content); + anyModified = true; + Debug.Log($"[UnityEditorOnlyAnalyzer] ✅ Added analyzer to {fileName} (fallback method)"); + } + } + } + } + + if (anyModified) + { + Debug.Log("[UnityEditorOnlyAnalyzer] ✅ Analyzer added to .csproj files! Please reload your IDE."); + } + } +} + +/// +/// Menu item để trigger thủ công việc thêm analyzer +/// +public class UnityEditorOnlyAnalyzerMenu +{ + [MenuItem("Tools/Unity Editor Only Analyzer/Add Analyzer to Projects")] + public static void AddAnalyzerManually() + { + AddAnalyzerPostprocessor.AddAnalyzerToProjects(); + } + + [MenuItem("Tools/Unity Editor Only Analyzer/Regenerate Project Files")] + public static void RegenerateProjectFiles() + { + // Trigger Unity regenerate .csproj files + UnityEditorInternal.InternalEditorUtility.OpenFileAtLineExternal("", 0); + AssetDatabase.Refresh(); + Debug.Log("[UnityEditorOnlyAnalyzer] Project files regeneration triggered. Check Console for analyzer messages."); + } +} +#endif diff --git a/Assets/Editor/AddAnalyzerPostprocessor.cs.meta b/Assets/Editor/AddAnalyzerPostprocessor.cs.meta new file mode 100644 index 0000000000..bb0cd62190 --- /dev/null +++ b/Assets/Editor/AddAnalyzerPostprocessor.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f4597c784f3bab545bcae652cd8541d9 \ No newline at end of file diff --git a/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/金钟罩击中.prefab b/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/金钟罩击中.prefab index 0b37cc7274..dcea6356d1 100644 --- a/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/金钟罩击中.prefab +++ b/Assets/ModelRenderer/Art/Gfx/gfx/策划联入/人物技能/击中/金钟罩击中.prefab @@ -50,7 +50,7 @@ ParticleSystem: ringBufferMode: 0 ringBufferLoopRange: {x: 0, y: 1} emitterVelocityMode: 1 - looping: 1 + looping: 0 prewarm: 0 playOnAwake: 1 useUnscaledTime: 0 @@ -4883,7 +4883,7 @@ ParticleSystem: ringBufferMode: 0 ringBufferLoopRange: {x: 0, y: 1} emitterVelocityMode: 1 - looping: 1 + looping: 0 prewarm: 0 playOnAwake: 1 useUnscaledTime: 0 @@ -9774,7 +9774,7 @@ ParticleSystem: ringBufferMode: 0 ringBufferLoopRange: {x: 0, y: 1} emitterVelocityMode: 1 - looping: 1 + looping: 0 prewarm: 0 playOnAwake: 1 useUnscaledTime: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_右.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_右.prefab index a714c71c4e..66da39859d 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_右.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_右.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 7683706845393114874} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.365, y: -0.002, z: -0.002} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} --- !u!33 &2133889840078759797 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_左.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_左.prefab index 6a2822b6ee..6954966b5d 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_左.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/刀剑/双手双剑/子母剑/子母剑_左.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 1062321236472470772} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.365, y: -0.002, z: -0.002} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} --- !u!33 &3655013707296471465 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/闪华斧/闪华斧.prefab b/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/闪华斧/闪华斧.prefab index 29ca14ed5c..adb24198a2 100644 --- a/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/闪华斧/闪华斧.prefab +++ b/Assets/ModelRenderer/Art/Models/models/weapons/人物/斧锤/双手双斧/闪华斧/闪华斧.prefab @@ -26,13 +26,13 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 3330708356810309571} serializedVersion: 2 - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalRotation: {x: 0, y: 0.7071068, z: 0, w: 0.7071068} + m_LocalPosition: {x: 0.388, y: -0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 m_Children: [] m_Father: {fileID: 0} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0} --- !u!33 &666975227472843166 MeshFilter: m_ObjectHideFlags: 0 diff --git a/Assets/PerfectWorld/Prefab/UI/MessageBox.prefab b/Assets/PerfectWorld/Prefab/UI/MessageBox.prefab index ac34a8df7b..824b9eab6e 100644 --- a/Assets/PerfectWorld/Prefab/UI/MessageBox.prefab +++ b/Assets/PerfectWorld/Prefab/UI/MessageBox.prefab @@ -620,7 +620,7 @@ GameObject: - component: {fileID: 8250962023850685786} - component: {fileID: 7766051278568089760} m_Layer: 5 - m_Name: ButtonOk + m_Name: ButtonYes m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -927,7 +927,7 @@ MonoBehaviour: imageProgress: {fileID: 0} titleText: {fileID: 5031655611580643013} messageText: {fileID: 7448521238108099750} - okButton: {fileID: 7766051278568089760} + _yesButton: {fileID: 7766051278568089760} _noButton: {fileID: 7010901635634620631} _closeButton: {fileID: 482550456836939169} --- !u!1 &5664175764923475105 diff --git a/Assets/PerfectWorld/Prefab/UI/PlayerOptionPopup.prefab b/Assets/PerfectWorld/Prefab/UI/PlayerOptionPopup.prefab index d432d82ba0..c71763bd99 100644 --- a/Assets/PerfectWorld/Prefab/UI/PlayerOptionPopup.prefab +++ b/Assets/PerfectWorld/Prefab/UI/PlayerOptionPopup.prefab @@ -509,7 +509,7 @@ MonoBehaviour: m_PressedTrigger: Pressed m_SelectedTrigger: Selected m_DisabledTrigger: Disabled - m_Interactable: 0 + m_Interactable: 1 m_TargetGraphic: {fileID: 3492245093881047436} m_OnClick: m_PersistentCalls: diff --git a/Assets/PerfectWorld/Prefab/UIManager.prefab b/Assets/PerfectWorld/Prefab/UIManager.prefab index b445272f96..7dead6e323 100644 --- a/Assets/PerfectWorld/Prefab/UIManager.prefab +++ b/Assets/PerfectWorld/Prefab/UIManager.prefab @@ -774,6 +774,96 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &613919380239545636 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7289690895179691343} + - component: {fileID: 690144092504553638} + - component: {fileID: 8175991538683025488} + - component: {fileID: 7195446286131223763} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7289690895179691343 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 613919380239545636} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5747822187000379196} + m_Father: {fileID: 5798497331256291745} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 10, y: -10} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &690144092504553638 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 613919380239545636} + m_CullTransparentMesh: 1 +--- !u!114 &8175991538683025488 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 613919380239545636} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &7195446286131223763 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 613919380239545636} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 1 --- !u!1 &649076494997171084 GameObject: m_ObjectHideFlags: 0 @@ -910,6 +1000,168 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &659277667126742134 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1505082503590519222} + - component: {fileID: 2952576131963749004} + - component: {fileID: 3464748071021900582} + - component: {fileID: 2027788820829355354} + m_Layer: 5 + m_Name: Panel (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1505082503590519222 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 659277667126742134} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 5798497331256291745} + m_Father: {fileID: 2907261990866691440} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 133.1923, y: -138.03845} + m_SizeDelta: {x: 0, y: 11} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &2952576131963749004 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 659277667126742134} + m_CullTransparentMesh: 1 +--- !u!114 &3464748071021900582 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 659277667126742134} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 0 + m_Spacing: 25 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 0 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 + m_ReverseArrangement: 0 +--- !u!114 &2027788820829355354 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 659277667126742134} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 2 + m_VerticalFit: 0 +--- !u!1 &706528413708330951 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5196010413898095880} + - component: {fileID: 6965363531247653623} + - component: {fileID: 6091427522402735754} + m_Layer: 0 + m_Name: WarningIcon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5196010413898095880 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 706528413708330951} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 3233441867675090637} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 95.5, y: -30} + m_SizeDelta: {x: 191, y: 60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6965363531247653623 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 706528413708330951} + m_CullTransparentMesh: 1 +--- !u!114 &6091427522402735754 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 706528413708330951} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: b2f1cd3ee517556479672deef3004b2d, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!1 &806379414455135824 GameObject: m_ObjectHideFlags: 0 @@ -2292,14 +2544,13 @@ RectTransform: - {fileID: 9056141770234008732} - {fileID: 6541409353547558602} - {fileID: 2907261990866691440} + - {fileID: 5196010413898095880} - {fileID: 3483809415181351540} - {fileID: 7451658084820611230} - {fileID: 7749074831901819156} - {fileID: 5949267495910746152} - - {fileID: 4633732041680916750} - - {fileID: 3045057319077202999} - - {fileID: 1801315025016986229} - - {fileID: 6551985120193569788} + - {fileID: 9121369084142034904} + - {fileID: 1416757586547742942} m_Father: {fileID: 2780428059708698453} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} m_AnchorMin: {x: 0, y: 0} @@ -2683,144 +2934,6 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!1 &2697130145581150145 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 4003332200156938686} - - component: {fileID: 4074076591324235108} - - component: {fileID: 5717971096408508686} - m_Layer: 0 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &4003332200156938686 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2697130145581150145} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 3045057319077202999} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &4074076591324235108 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2697130145581150145} - m_CullTransparentMesh: 1 ---- !u!114 &5717971096408508686 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2697130145581150145} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: 'TeamList - -' - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 21.28 - m_fontSizeBase: 21.28 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 1 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 0 - m_ActiveFontFeatures: 6e72656b - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_EmojiFallbackSupport: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &2776183232214485049 GameObject: m_ObjectHideFlags: 0 @@ -3759,7 +3872,81 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: inputField: {fileID: 9217902013627304316} - sendButton: {fileID: 0} +--- !u!1 &3409671269413610538 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1850256271896360758} + - component: {fileID: 1625775608542215426} + - component: {fileID: 3281637513634336494} + m_Layer: 5 + m_Name: Checkmark + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1850256271896360758 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3409671269413610538} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8192498249288210842} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1625775608542215426 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3409671269413610538} + m_CullTransparentMesh: 1 +--- !u!114 &3281637513634336494 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3409671269413610538} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -2152444580018807177, guid: 7c25a5fa6c0f21a4293b99a5a43b5441, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!1 &3640198580623993119 GameObject: m_ObjectHideFlags: 0 @@ -4476,6 +4663,96 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] m_IsOn: 1 +--- !u!1 &4566977944242119824 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8192498249288210842} + - component: {fileID: 3842594147762699738} + - component: {fileID: 4927233417060385840} + - component: {fileID: 5022165723285944668} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8192498249288210842 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4566977944242119824} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1850256271896360758} + m_Father: {fileID: 3773110008012193810} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 10, y: -10} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3842594147762699738 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4566977944242119824} + m_CullTransparentMesh: 1 +--- !u!114 &4927233417060385840 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4566977944242119824} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10913, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &5022165723285944668 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4566977944242119824} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 1 --- !u!1 &4656111575523843201 GameObject: m_ObjectHideFlags: 0 @@ -4612,6 +4889,91 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &4870054906152145333 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5798497331256291745} + - component: {fileID: 3469126208788821280} + m_Layer: 5 + m_Name: BuffIconTemplate + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5798497331256291745 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4870054906152145333} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7289690895179691343} + m_Father: {fileID: 1505082503590519222} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &3469126208788821280 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4870054906152145333} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 0 + m_TargetGraphic: {fileID: 8175991538683025488} + toggleTransition: 1 + graphic: {fileID: 886384831200045356} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 1 --- !u!1 &5137013593162142802 GameObject: m_ObjectHideFlags: 0 @@ -4939,6 +5301,91 @@ MonoBehaviour: m_OnClick: m_PersistentCalls: m_Calls: [] +--- !u!1 &5417864904386168706 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3773110008012193810} + - component: {fileID: 8469410254513498276} + m_Layer: 5 + m_Name: BuffIconTemplate + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3773110008012193810 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5417864904386168706} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8192498249288210842} + m_Father: {fileID: 5191021986578083479} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &8469410254513498276 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5417864904386168706} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 9085046f02f69544eb97fd06b6048fe2, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 0 + m_TargetGraphic: {fileID: 4927233417060385840} + toggleTransition: 1 + graphic: {fileID: 3281637513634336494} + m_Group: {fileID: 0} + onValueChanged: + m_PersistentCalls: + m_Calls: [] + m_IsOn: 1 --- !u!1 &5490291313877083687 GameObject: m_ObjectHideFlags: 0 @@ -5686,144 +6133,6 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!1 &5804481939490819770 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 3896779004240998762} - - component: {fileID: 432590474551140442} - - component: {fileID: 3984354575793935746} - m_Layer: 0 - m_Name: Text (TMP) - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &3896779004240998762 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5804481939490819770} - m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: [] - m_Father: {fileID: 4633732041680916750} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0} - m_AnchorMax: {x: 1, y: 1} - m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &432590474551140442 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5804481939490819770} - m_CullTransparentMesh: 1 ---- !u!114 &3984354575793935746 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 5804481939490819770} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_text: 'TeamList - -' - m_isRightToLeft: 0 - m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} - m_fontSharedMaterials: [] - m_fontMaterial: {fileID: 0} - m_fontMaterials: [] - m_fontColor32: - serializedVersion: 2 - rgba: 4281479730 - m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} - m_enableVertexGradient: 0 - m_colorMode: 3 - m_fontColorGradient: - topLeft: {r: 1, g: 1, b: 1, a: 1} - topRight: {r: 1, g: 1, b: 1, a: 1} - bottomLeft: {r: 1, g: 1, b: 1, a: 1} - bottomRight: {r: 1, g: 1, b: 1, a: 1} - m_fontColorGradientPreset: {fileID: 0} - m_spriteAsset: {fileID: 0} - m_tintAllSprites: 0 - m_StyleSheet: {fileID: 0} - m_TextStyleHashCode: -1183493901 - m_overrideHtmlColors: 0 - m_faceColor: - serializedVersion: 2 - rgba: 4294967295 - m_fontSize: 21.28 - m_fontSizeBase: 21.28 - m_fontWeight: 400 - m_enableAutoSizing: 0 - m_fontSizeMin: 18 - m_fontSizeMax: 72 - m_fontStyle: 1 - m_HorizontalAlignment: 2 - m_VerticalAlignment: 512 - m_textAlignment: 65535 - m_characterSpacing: 0 - m_wordSpacing: 0 - m_lineSpacing: 0 - m_lineSpacingMax: 0 - m_paragraphSpacing: 0 - m_charWidthMaxAdj: 0 - m_TextWrappingMode: 1 - m_wordWrappingRatios: 0.4 - m_overflowMode: 0 - m_linkedTextComponent: {fileID: 0} - parentLinkedComponent: {fileID: 0} - m_enableKerning: 0 - m_ActiveFontFeatures: 6e72656b - m_enableExtraPadding: 0 - checkPaddingRequired: 0 - m_isRichText: 1 - m_EmojiFallbackSupport: 1 - m_parseCtrlCharacters: 1 - m_isOrthographic: 1 - m_isCullingEnabled: 0 - m_horizontalMapping: 0 - m_verticalMapping: 0 - m_uvLineOffset: 0 - m_geometrySortingOrder: 0 - m_IsTextObjectScaleStatic: 0 - m_VertexBufferAutoSizeReduction: 0 - m_useMaxVisibleDescender: 1 - m_pageToDisplay: 1 - m_margin: {x: 0, y: 0, z: 0, w: 0} - m_isUsingLegacyAnimationComponent: 0 - m_isVolumetricText: 0 - m_hasFontAssetChanged: 0 - m_baseMaterial: {fileID: 0} - m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &5885931642767984348 GameObject: m_ObjectHideFlags: 0 @@ -6333,139 +6642,6 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: m_ShowMaskGraphic: 1 ---- !u!1 &6325511248940727398 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 3045057319077202999} - - component: {fileID: 162626341667579305} - - component: {fileID: 8499852562167418146} - - component: {fileID: 1152087078303231916} - m_Layer: 0 - m_Name: team_list_btn - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!224 &3045057319077202999 -RectTransform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6325511248940727398} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} - m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 4003332200156938686} - m_Father: {fileID: 3233441867675090637} - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.5} - m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 63.289795, y: 128.1304} - m_SizeDelta: {x: 101.855, y: 57.3622} - m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &162626341667579305 -CanvasRenderer: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6325511248940727398} - m_CullTransparentMesh: 1 ---- !u!114 &8499852562167418146 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6325511248940727398} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Material: {fileID: 0} - m_Color: {r: 1, g: 1, b: 1, a: 1} - m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} - m_Maskable: 1 - m_OnCullStateChanged: - m_PersistentCalls: - m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!114 &1152087078303231916 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6325511248940727398} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 8499852562167418146} - m_OnClick: - m_PersistentCalls: - m_Calls: - - m_Target: {fileID: 1890210201668811196} - m_TargetAssemblyTypeName: CECUIManager, Assembly-CSharp - m_MethodName: ShowUI - m_Mode: 5 - m_Arguments: - m_ObjectArgument: {fileID: 0} - m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine - m_IntArgument: 0 - m_FloatArgument: 0 - m_StringArgument: Win_TeamMain - m_BoolArgument: 0 - m_CallState: 2 --- !u!1 &6470418459643444397 GameObject: m_ObjectHideFlags: 0 @@ -6722,7 +6898,7 @@ MonoBehaviour: m_hasFontAssetChanged: 0 m_baseMaterial: {fileID: 0} m_maskOffset: {x: 0, y: 0, z: 0, w: 0} ---- !u!1 &6647846787028180792 +--- !u!1 &6631939314334477079 GameObject: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} @@ -6730,55 +6906,53 @@ GameObject: m_PrefabAsset: {fileID: 0} serializedVersion: 6 m_Component: - - component: {fileID: 4633732041680916750} - - component: {fileID: 1947094226586639141} - - component: {fileID: 3855216381802363264} - - component: {fileID: 2959558982813704450} + - component: {fileID: 4956381234499428555} + - component: {fileID: 1356460769230622399} + - component: {fileID: 9053880274918013220} m_Layer: 0 - m_Name: team_list_btn + m_Name: Text (TMP) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 m_IsActive: 1 ---- !u!224 &4633732041680916750 +--- !u!224 &4956381234499428555 RectTransform: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6647846787028180792} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_GameObject: {fileID: 6631939314334477079} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} m_LocalScale: {x: 1, y: 1, z: 1} m_ConstrainProportionsScale: 0 - m_Children: - - {fileID: 3896779004240998762} - m_Father: {fileID: 3233441867675090637} + m_Children: [] + m_Father: {fileID: 9121369084142034904} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} - m_AnchorMin: {x: 0, y: 0.5} - m_AnchorMax: {x: 0, y: 0.5} - m_AnchoredPosition: {x: 63.289795, y: 128.1304} - m_SizeDelta: {x: 101.855, y: 57.3622} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} m_Pivot: {x: 0.5, y: 0.5} ---- !u!222 &1947094226586639141 +--- !u!222 &1356460769230622399 CanvasRenderer: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6647846787028180792} + m_GameObject: {fileID: 6631939314334477079} m_CullTransparentMesh: 1 ---- !u!114 &3855216381802363264 +--- !u!114 &9053880274918013220 MonoBehaviour: m_ObjectHideFlags: 0 m_CorrespondingSourceObject: {fileID: 0} m_PrefabInstance: {fileID: 0} m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6647846787028180792} + m_GameObject: {fileID: 6631939314334477079} m_Enabled: 1 m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} m_Name: m_EditorClassIdentifier: m_Material: {fileID: 0} @@ -6789,60 +6963,79 @@ MonoBehaviour: m_OnCullStateChanged: m_PersistentCalls: m_Calls: [] - m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} - m_Type: 1 - m_PreserveAspect: 0 - m_FillCenter: 1 - m_FillMethod: 4 - m_FillAmount: 1 - m_FillClockwise: 1 - m_FillOrigin: 0 - m_UseSpriteMesh: 0 - m_PixelsPerUnitMultiplier: 1 ---- !u!114 &2959558982813704450 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 6647846787028180792} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} - m_Name: - m_EditorClassIdentifier: - m_Navigation: - m_Mode: 3 - m_WrapAround: 0 - m_SelectOnUp: {fileID: 0} - m_SelectOnDown: {fileID: 0} - m_SelectOnLeft: {fileID: 0} - m_SelectOnRight: {fileID: 0} - m_Transition: 1 - m_Colors: - m_NormalColor: {r: 1, g: 1, b: 1, a: 1} - m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} - m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} - m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} - m_ColorMultiplier: 1 - m_FadeDuration: 0.1 - m_SpriteState: - m_HighlightedSprite: {fileID: 0} - m_PressedSprite: {fileID: 0} - m_SelectedSprite: {fileID: 0} - m_DisabledSprite: {fileID: 0} - m_AnimationTriggers: - m_NormalTrigger: Normal - m_HighlightedTrigger: Highlighted - m_PressedTrigger: Pressed - m_SelectedTrigger: Selected - m_DisabledTrigger: Disabled - m_Interactable: 1 - m_TargetGraphic: {fileID: 3855216381802363264} - m_OnClick: - m_PersistentCalls: - m_Calls: [] + m_text: 'TeamList + +' + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4281479730 + m_fontColor: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 21.28 + m_fontSizeBase: 21.28 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 1 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_TextWrappingMode: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 0 + m_ActiveFontFeatures: 6e72656b + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_EmojiFallbackSupport: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} --- !u!1 &6749548056585646144 GameObject: m_ObjectHideFlags: 0 @@ -6918,6 +7111,127 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 +--- !u!1 &6949335809637514808 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9121369084142034904} + - component: {fileID: 3863452661654338700} + - component: {fileID: 2508677705417309257} + - component: {fileID: 540188344648694736} + m_Layer: 0 + m_Name: team_list_btn + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9121369084142034904 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6949335809637514808} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4956381234499428555} + m_Father: {fileID: 3233441867675090637} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 63.289795, y: 128.1304} + m_SizeDelta: {x: 101.855, y: 57.3622} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3863452661654338700 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6949335809637514808} + m_CullTransparentMesh: 1 +--- !u!114 &2508677705417309257 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6949335809637514808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 10905, guid: 0000000000000000f000000000000000, type: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &540188344648694736 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6949335809637514808} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 2508677705417309257} + m_OnClick: + m_PersistentCalls: + m_Calls: [] --- !u!1 &6950113420985123515 GameObject: m_ObjectHideFlags: 0 @@ -7271,7 +7585,7 @@ MonoBehaviour: _btnTask: {fileID: 8640845703001841192} _btnInvntory: {fileID: 7124460838393469068} _btnTeam: {fileID: 6273023266110177064} - _btnTeamList: {fileID: 2959558982813704450} + _btnTeamList: {fileID: 540188344648694736} --- !u!1 &7329846701007506760 GameObject: m_ObjectHideFlags: 0 @@ -7701,6 +8015,81 @@ MonoBehaviour: serializedVersion: 2 m_Bits: 64 _target: {x: 0, y: 0, z: 0} +--- !u!1 &7770570364241053217 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5747822187000379196} + - component: {fileID: 4010750841144926585} + - component: {fileID: 886384831200045356} + m_Layer: 5 + m_Name: Checkmark + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5747822187000379196 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7770570364241053217} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7289690895179691343} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0.5, y: 0.5} + m_AnchorMax: {x: 0.5, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4010750841144926585 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7770570364241053217} + m_CullTransparentMesh: 1 +--- !u!114 &886384831200045356 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7770570364241053217} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: -2152444580018807177, guid: 7c25a5fa6c0f21a4293b99a5a43b5441, type: 3} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 --- !u!1 &7786113674810984593 GameObject: m_ObjectHideFlags: 0 @@ -8236,6 +8625,93 @@ MonoBehaviour: m_bShowAll2: 0 m_nDisplayPanels1: 0 m_nDisplayPanels2: 0 +--- !u!1 &8599704669003951618 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5191021986578083479} + - component: {fileID: 7969492018491211435} + - component: {fileID: 6619954850633260582} + - component: {fileID: 8157700299204431448} + m_Layer: 5 + m_Name: Panel (1) + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5191021986578083479 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8599704669003951618} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3773110008012193810} + m_Father: {fileID: 2907261990866691440} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 0, y: 1} + m_AnchoredPosition: {x: 133.1923, y: -138.03845} + m_SizeDelta: {x: 0, y: 11} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &7969492018491211435 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8599704669003951618} + m_CullTransparentMesh: 1 +--- !u!114 &6619954850633260582 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8599704669003951618} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 0 + m_Right: 0 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 0 + m_Spacing: 25 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 0 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 + m_ReverseArrangement: 0 +--- !u!114 &8157700299204431448 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8599704669003951618} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 2 + m_VerticalFit: 0 --- !u!1 &8644839137304674498 GameObject: m_ObjectHideFlags: 0 @@ -14037,236 +14513,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: a9e669c5ab4137449aacd686ed4d5d9f, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!1001 &7164061422049248145 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 3233441867675090637} - m_Modifications: - - target: {fileID: 1177418169026887077, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 1177418169026887077, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 1177418169026887077, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 536.6 - objectReference: {fileID: 0} - - target: {fileID: 1177418169026887077, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: -40 - objectReference: {fileID: 0} - - target: {fileID: 2114068002568865089, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_SizeDelta.x - value: 636.60004 - objectReference: {fileID: 0} - - target: {fileID: 2193345427363373405, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2193345427363373405, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2193345427363373405, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 327.54254 - objectReference: {fileID: 0} - - target: {fileID: 2193345427363373405, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: -40.55655 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_Pivot.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_Pivot.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.x - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_SizeDelta.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_SizeDelta.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 5391320483290769481, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 5391320483290769481, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 5391320483290769481, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 318.3 - objectReference: {fileID: 0} - - target: {fileID: 5391320483290769481, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: -40 - objectReference: {fileID: 0} - - target: {fileID: 6089726915740343573, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_SizeDelta.y - value: 117 - objectReference: {fileID: 0} - - target: {fileID: 6417814924206042159, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 6417814924206042159, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 6417814924206042159, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 6417814924206042159, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 6739367966453075612, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 6739367966453075612, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 6739367966453075612, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 100 - objectReference: {fileID: 0} - - target: {fileID: 6739367966453075612, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: -40 - objectReference: {fileID: 0} - - target: {fileID: 6826604567124609485, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_SizeDelta.x - value: 655.0851 - objectReference: {fileID: 0} - - target: {fileID: 7412700196827410432, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7412700196827410432, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7412700196827410432, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 112.28085 - objectReference: {fileID: 0} - - target: {fileID: 7412700196827410432, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: -40.55655 - objectReference: {fileID: 0} - - target: {fileID: 7959803810568030828, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_Name - value: DlgFriendList - objectReference: {fileID: 0} - - target: {fileID: 7959803810568030828, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_IsActive - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 8453814530783954666, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8453814530783954666, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchorMin.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8453814530783954666, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.x - value: 542.80426 - objectReference: {fileID: 0} - - target: {fileID: 8453814530783954666, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - propertyPath: m_AnchoredPosition.y - value: -40.55655 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} ---- !u!224 &6551985120193569788 stripped -RectTransform: - m_CorrespondingSourceObject: {fileID: 4145150215317037165, guid: c3fe60ca49d530e4a9d03e185154c4f5, type: 3} - m_PrefabInstance: {fileID: 7164061422049248145} - m_PrefabAsset: {fileID: 0} --- !u!1001 &7509275976277896982 PrefabInstance: m_ObjectHideFlags: 0 @@ -14482,6 +14728,116 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 67fd391520cbfd44f84a1c6bb57673c0, type: 3} m_Name: m_EditorClassIdentifier: +--- !u!1001 &8152930184191170387 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 3233441867675090637} + m_Modifications: + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_Pivot.x + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_Pivot.y + value: 0.5 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_AnchorMax.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_AnchorMax.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_AnchorMin.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_AnchorMin.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_SizeDelta.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_SizeDelta.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalRotation.w + value: 1 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalRotation.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalRotation.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_AnchoredPosition.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_AnchoredPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 7292124547459743165, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_SizeDelta.x + value: 6.26355 + objectReference: {fileID: 0} + - target: {fileID: 9152579472324007262, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_Name + value: Win_TeamMain + objectReference: {fileID: 0} + - target: {fileID: 9152579472324007262, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} +--- !u!224 &1416757586547742942 stripped +RectTransform: + m_CorrespondingSourceObject: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} + m_PrefabInstance: {fileID: 8152930184191170387} + m_PrefabAsset: {fileID: 0} --- !u!1001 &8244659259478137406 PrefabInstance: m_ObjectHideFlags: 0 @@ -15144,6 +15500,10 @@ PrefabInstance: propertyPath: m_Name value: HUDPlayer objectReference: {fileID: 0} + - target: {fileID: 4823752405346273106, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} + propertyPath: m_IsActive + value: 1 + objectReference: {fileID: 0} - target: {fileID: 5335503683694560306, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} propertyPath: m_Type value: 3 @@ -15281,15 +15641,21 @@ PrefabInstance: m_AddedGameObjects: - targetCorrespondingSourceObject: {fileID: 6806681442789174374, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} insertIndex: 7 - addedObject: {fileID: 494610354563246192} + addedObject: {fileID: 1505082503590519222} - targetCorrespondingSourceObject: {fileID: 6806681442789174374, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} insertIndex: 8 - addedObject: {fileID: 2090006027067688671} + addedObject: {fileID: 5191021986578083479} - targetCorrespondingSourceObject: {fileID: 6806681442789174374, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} insertIndex: 9 - addedObject: {fileID: 5264098290850076161} + addedObject: {fileID: 494610354563246192} - targetCorrespondingSourceObject: {fileID: 6806681442789174374, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} insertIndex: 10 + addedObject: {fileID: 2090006027067688671} + - targetCorrespondingSourceObject: {fileID: 6806681442789174374, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} + insertIndex: 11 + addedObject: {fileID: 5264098290850076161} + - targetCorrespondingSourceObject: {fileID: 6806681442789174374, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} + insertIndex: 12 addedObject: {fileID: 6421830357984996457} m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 76408ccdbeb4c654291462fcff24a8c5, type: 3} @@ -15309,116 +15675,6 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} m_Name: m_EditorClassIdentifier: ---- !u!1001 &8823639301883745784 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - serializedVersion: 3 - m_TransformParent: {fileID: 3233441867675090637} - m_Modifications: - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_Pivot.x - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_Pivot.y - value: 0.5 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_AnchorMax.x - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_AnchorMin.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_AnchorMin.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_SizeDelta.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_SizeDelta.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalPosition.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_AnchoredPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_AnchoredPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 7292124547459743165, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_SizeDelta.x - value: 6.26355 - objectReference: {fileID: 0} - - target: {fileID: 9152579472324007262, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_Name - value: Win_TeamMain - objectReference: {fileID: 0} - - target: {fileID: 9152579472324007262, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - propertyPath: m_IsActive - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_RemovedGameObjects: [] - m_AddedGameObjects: [] - m_AddedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} ---- !u!224 &1801315025016986229 stripped -RectTransform: - m_CorrespondingSourceObject: {fileID: 7101142292773392269, guid: 2060bbc2e61f6db4590ab041243b6294, type: 3} - m_PrefabInstance: {fileID: 8823639301883745784} - m_PrefabAsset: {fileID: 0} --- !u!1001 &8966214373927126746 PrefabInstance: m_ObjectHideFlags: 0 diff --git a/Assets/PerfectWorld/Scene/Bootstrap.unity b/Assets/PerfectWorld/Scene/Bootstrap.unity index 4dd1dfe017..db4113e554 100644 --- a/Assets/PerfectWorld/Scene/Bootstrap.unity +++ b/Assets/PerfectWorld/Scene/Bootstrap.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0dd087950038db412bdd07208e3e3dc407a2da4ebecc8fbd49ad2246197aecdb -size 314447 +oid sha256:47ff1377fe87865c1bdada70b8f6fee638a20879f70b84b40d62fb978aee203e +size 325051 diff --git a/Assets/PerfectWorld/Scene/LoginScene.unity b/Assets/PerfectWorld/Scene/LoginScene.unity index 639ee865aa..41fd65b332 100644 --- a/Assets/PerfectWorld/Scene/LoginScene.unity +++ b/Assets/PerfectWorld/Scene/LoginScene.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c97935b0995b6688065daf1645d0f26e8b964dd5bf92b6cd66c37c5f97b5586 -size 104077 +oid sha256:4b854fd255462f21d3b44d27526138345930a673f5c74cd2c1ca261ebd834048 +size 106212 diff --git a/Assets/PerfectWorld/Scripts/Chat.meta b/Assets/PerfectWorld/Scripts/Chat.meta new file mode 100644 index 0000000000..f50f9c0813 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2f24d310ca7b52342ab8380890ad8c0b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/PerfectWorld/Scripts/Chat/CECPateText.cs b/Assets/PerfectWorld/Scripts/Chat/CECPateText.cs new file mode 100644 index 0000000000..d7a5c6fbd5 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/CECPateText.cs @@ -0,0 +1,239 @@ +using System.Collections.Generic; +using BrewMonster.Network; +using BrewMonster.Scripts.Managers; +using BrewMonster.UI; +using UnityEngine; + +namespace BrewMonster.Scripts.Chat +{ + public class CECPateText + { + protected List m_aTextStrs; + //protected List<> m_aEmotions; + //protected List m_aItems; + //protected EditBoxItemSet m_ItemSet; + + // Text item type + public enum ETextType + { + TYPE_TEXT = 0, + TYPE_EMOTION, + TYPE_BOOTHNAME, + } + + // Text item + public struct ITEM + { + public int iType; // Text type + public int iIndex; // Index of item + public int iExtX; // Extent + public int iExtY; + + public int iLine; + + //A3DCOLOR clItem; + public Color clItem; + }; + + public int SetText(string szText, + bool bIncEmotion, + out string pstrTextConverted, + bool bEllipsis = true, + EC_IvtrItem pIvtrItem = null) + { + // Clear old content + Clear(); + + pstrTextConverted = null; + + if (string.IsNullOrEmpty(szText)) + return 0; + + CECGameUIMan pGameUI = + EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + + /*string str = pGameUI.AUI_FilterEditboxItem( + szText, + CECGameUIMan.AUI_EditboxItemMaskFilter(1 << (int)enumEICoord) + ); + + string strName; + A3DCOLOR clrName; + + pGameUI.TransformNameColor(pIvtrItem, out strName, out clrName); + + str = UnmarshalEditBoxText(str, m_ItemsSet, 0, strName, clrName); + + szText = str; + pstrTextConverted = str; + + int iAddedChar = 0; + + if (!bIncEmotion) + { + int iLen = szText.Length; + + if (iLen > m_iMaxLineLen) + { + string sub = szText.Substring(0, m_iMaxLineLen); + + if (bEllipsis) + sub += "..."; + + CreateTextItem(sub, -1, 0); + + iAddedChar = m_iMaxLineLen; + } + else + { + CreateTextItem(szText, -1, 0); + iAddedChar = iLen; + } + } + else + { + int i = 0; + int iStart = 0; + int iEnd = 0; + int iLenCnt = 0; + + bool bTooLong = false; + int iLine = 0; + + while (i < szText.Length) + { + char ch = szText[i]; + + if (IsEditboxItemCode(ch)) + { + if (iEnd > iStart) + CreateTextItem(szText.Substring(iStart, iEnd - iStart), -1, iLine); + + EditBoxItemBase pItem = m_ItemsSet.GetItemByChar(ch); + + if (pItem != null) + { + if (pItem.GetType() == enumEIEmotion) + { + int nSet = 0; + int nIndex = 0; + + UnmarshalEmotionInfo(pItem.GetInfo(), out nSet, out nIndex); + + CreateEmotionItem(nSet, nIndex, iLine); + + iLenCnt += 2; + } + else + { + string szName = pItem.GetName(); + + CreateTextItem(szName, -1, iLine, pItem.GetColor()); + + iLenCnt += szName.Length; + } + } + + i++; + iStart = i; + iEnd = i; + + goto CheckLength; + } + + iEnd++; + i++; + iLenCnt++; + + CheckLength: + + if (iLenCnt > m_iMaxLineLen) + { + if (iLine + 1 >= m_iMaxLines) + { + bTooLong = true; + break; + } + + if (iEnd > iStart) + CreateTextItem(szText.Substring(iStart, iEnd - iStart), -1, iLine); + + iStart = i; + iLine++; + iLenCnt = 0; + } + } + + iAddedChar = i; + + if (iEnd > iStart) + { + if (bTooLong) + { + string strEnd = szText.Substring(iStart, iEnd - iStart); + + if (bEllipsis) + strEnd += "..."; + + CreateTextItem(strEnd, -1, iLine); + } + else + { + CreateTextItem(szText.Substring(iStart, iEnd - iStart), -1, iLine); + } + } + else if (bTooLong) + { + if (bEllipsis) + CreateTextItem("...", -1, iLine); + } + } + + // Calculate extent + + m_iExtX = 0; + m_iExtY = 0; + + int iLineExtX = 0; + int iLastLine = 0; + + for (int i = 0; i < m_aItems.GetSize(); i++) + { + ITEM item = m_aItems[i]; + + if (item.iLine != iLastLine) + { + iLastLine = item.iLine; + + if (m_iExtX < iLineExtX) + m_iExtX = iLineExtX; + + iLineExtX = item.iExtX; + } + else + { + iLineExtX += item.iExtX; + } + + if (m_iExtY < item.iExtY) + m_iExtY = item.iExtY; + } + + m_iLines = iLastLine + 1; + + if (m_iExtX < iLineExtX) + m_iExtX = iLineExtX;*/ + //return iAddedChar; + + return 0; + } + + public void Clear() + { + m_aTextStrs.Clear(); + /*m_aEmotions.Clear(); + m_aItems.Clear(); + m_ItemsSet.Clear();*/ + } + } +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/CECPateText.cs.meta b/Assets/PerfectWorld/Scripts/Chat/CECPateText.cs.meta new file mode 100644 index 0000000000..b9484999d0 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/CECPateText.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f6eb4b59e25704044a88b0055abb0e99 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/CECPlayer.cs b/Assets/PerfectWorld/Scripts/Chat/CECPlayer.cs new file mode 100644 index 0000000000..83780b3d6c --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/CECPlayer.cs @@ -0,0 +1,26 @@ +using BrewMonster.Scripts.Managers; +using CSNetwork; + +namespace BrewMonster.Scripts.Chat +{ + public abstract partial class CECPlayer : CECObject + { + private CECPateText m_pPateLastWords1; + private CECPateText m_pPateLastWords2; + private CECCounter m_strLastSayCnt; + + // Set last said words + public void SetLastSaidWords(string szWords, int nEmotionSet, EC_IvtrItem pItem) + { + if (m_pPateLastWords1 == null || m_pPateLastWords2 == null) + return; + + string str = AUICommon.FilterEmotionSet(szWords, nEmotionSet); + szWords = str; + + m_pPateLastWords1.SetText(szWords, true , out var newStr,true, pItem); + m_pPateLastWords2.Clear(); + m_strLastSayCnt.Reset(); + } + } +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/CECPlayer.cs.meta b/Assets/PerfectWorld/Scripts/Chat/CECPlayer.cs.meta new file mode 100644 index 0000000000..26eed1206d --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/CECPlayer.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2c109cbbaf8d4ce19a93990a5f5883f6 +timeCreated: 1772699598 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/CHAT_S2C.cs b/Assets/PerfectWorld/Scripts/Chat/CHAT_S2C.cs new file mode 100644 index 0000000000..07dbde0aed --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/CHAT_S2C.cs @@ -0,0 +1,254 @@ +using System; +using System.Buffers.Binary; +using System.Runtime.InteropServices; +using BrewMonster.Network; +using BrewMonster.Scripts.Managers; +using CSNetwork; +using CSNetwork.GPDataType; + +namespace BrewMonster.Scripts.Chat +{ + struct chat_policy_parameter + { + short cmd_id; + + int parameter_mask; + //if(parameter_mask & CHAT_PARAMETER_ROLEID) 1 int insert here + //if(parameter_mask & CHAT_PARAMETER_LOCALVAL0) 1 int insert here + //if(parameter_m ask & CHAT_PARAMETER_LOCALVAL1) 1 int insert here + //if(parameter_mask & CHAT_PARAMETER_LOCALVAL2) 1 int insert here + }; + + public struct chat_item_base + { + public short cmd_id; + } + + public struct chat_equip_item + { + public short cmd_id; + public char where; + public short index; + } + + struct chat_generalcard_collection + { + public short cmd_id; + public int card_id; + }; + + public static class CHAT_S2C + { + public struct chat_equip_item + { + public short cmd_id; + public int type; + public int expire_date; + public int proc_type; + public ushort content_length; + public byte[] content; + + public int LenghtHeader() + { + return Marshal.SizeOf() + (Marshal.SizeOf() * 3) + Marshal.SizeOf(); + } + } + + public enum EChatS2CCommand : short + { + CHAT_EQUIP_ITEM, + CHAT_GENERALCARD_COLLECTION, + CHAT_POLICYCHAT_PARAMETER, + } + + public static EC_IvtrItem CreateChatItem(Octets data) + { + EC_IvtrItem pIvtrItem = null; + if (data.Size > 0) + { + chat_item_base pInfo = GPDataTypeHelper.FromBytes(data.ByteArray); + if (pInfo.cmd_id == (short)EChatS2CCommand.CHAT_EQUIP_ITEM) + { + chat_equip_item pItemInfo = default; + var sz = pItemInfo.LenghtHeader(); + + if (data.Size >= sz && sz + pItemInfo.content_length == data.Size) + { + if (pItemInfo.cmd_id == (short)EChatS2CCommand.CHAT_EQUIP_ITEM) + { + pIvtrItem = EC_IvtrItem.CreateItem(pItemInfo.type, pItemInfo.expire_date, 1); + if (pIvtrItem != null) + { + pIvtrItem.SetProcType(pItemInfo.proc_type); + pIvtrItem.SetItemInfo(pItemInfo.content, pItemInfo.content_length); + } + } + } + } + else if (pInfo.cmd_id == (short)EChatS2CCommand.CHAT_GENERALCARD_COLLECTION) + { + chat_generalcard_collection pItemInfo = + GPDataTypeHelper.FromBytes(data.ByteArray); + if (data.Size > Marshal.SizeOf()) + { + if (pItemInfo.cmd_id == (short)EChatS2CCommand.CHAT_GENERALCARD_COLLECTION) + { + pIvtrItem = EC_IvtrItem.CreateItem(pItemInfo.card_id, 0, 1); + if (pIvtrItem != null) + { + pIvtrItem.GetDetailDataFromLocal(); + } + } + } + } + } + + return pIvtrItem; + } + + [System.Flags] + public enum ChatParameterMask + { + CHAT_PARAMETER_ROLEID = 0x00000001, + CHAT_PARAMETER_LOCALVAL0 = 0x00000002, + CHAT_PARAMETER_LOCALVAL1 = 0x00000004, + CHAT_PARAMETER_LOCALVAL2 = 0x00000008 + } + + public class PolicyChatParameter + { + public int role_id = -1; + public string name = string.Empty; + public ChatParameterMask parameter_mask = 0; + + private int localval_0 = -1; + private int localval_1 = -1; + private int localval_2 = -1; + + EC_Game g_pGame; + + public bool HasRoleID() + { + return (parameter_mask & ChatParameterMask.CHAT_PARAMETER_ROLEID) != 0; + } + + public bool HasLocalValue(int valueNum) + { + switch (valueNum) + { + case 0: + return (parameter_mask & ChatParameterMask.CHAT_PARAMETER_LOCALVAL0) != 0; + case 1: + return (parameter_mask & ChatParameterMask.CHAT_PARAMETER_LOCALVAL1) != 0; + case 2: + return (parameter_mask & ChatParameterMask.CHAT_PARAMETER_LOCALVAL2) != 0; + default: + return false; + } + } + + public void GetNameFromServer() + { + if (role_id != -1 && HasRoleID()) + { + int[] arr = new int[1] { role_id }; + UnityGameSession.Instance.GameSession.CmdCache.SendGetPlayerBriefInfo(1, arr, 1); + } + } + + public void SetLocalValue(int localValue, int id) + { + switch (id) + { + case 0: + localval_0 = localValue; + parameter_mask |= ChatParameterMask.CHAT_PARAMETER_LOCALVAL0; + break; + case 1: + localval_1 = localValue; + parameter_mask |= ChatParameterMask.CHAT_PARAMETER_LOCALVAL1; + break; + case 2: + localval_2 = localValue; + parameter_mask |= ChatParameterMask.CHAT_PARAMETER_LOCALVAL2; + break; + } + } + + public bool TryGetLocalValue(int localVariableID, out int localVariable) + { + localVariable = -1; + + if (!HasLocalValue(localVariableID)) + return false; + + switch (localVariableID) + { + case 0: localVariable = localval_0; break; + case 1: localVariable = localval_1; break; + case 2: localVariable = localval_2; break; + } + + return true; + } + + public bool IsNameReady() + { + return HasRoleID() ? !string.IsNullOrEmpty(name) : true; + } + } + + public static PolicyChatParameter CreatPolicyChatParameter(Octets data) + { + PolicyChatParameter result = null; + if (data.Size >= Marshal.SizeOf(typeof(chat_item_base))) + { + chat_item_base pInfo = GPDataTypeHelper.FromBytes(data.ByteArray); + if (pInfo.cmd_id == (short)EChatS2CCommand.CHAT_POLICYCHAT_PARAMETER) + { + if (data.Size >= Marshal.SizeOf(typeof(chat_policy_parameter))) + { + Byte pData = GPDataTypeHelper.FromBytes(data.ByteArray, + Marshal.SizeOf(typeof(chat_policy_parameter))); + result = new PolicyChatParameter(); + // Todo: Check logic + result.parameter_mask = + GPDataTypeHelper.FromBytes(data.ByteArray, sizeof(short)); + /*int paraMask = result.parameter_mask; + if (paraMask & ChatParameterMask.CHAT_PARAMETER_ROLEID){ + if (pData + sizeof(int) > data.end()){ + return null; + } + result->SetRoleId(*(int*)pData); + pData += sizeof(int); + } + if (paraMask & ChatParameterMask.CHAT_PARAMETER_LOCALVAL0){ + if (pData + sizeof(int) > data.end()){ + return null; + } + result->SetLocaValue(*(int*)pData, 0); + pData += sizeof(int); + } + if (paraMask & ChatParameterMask.CHAT_PARAMETER_LOCALVAL1){ + if (pData + sizeof(int) > data.end()){ + return null; + } + result.SetLocaValue((int)pData, 1); + pData += sizeof(int); + } + if (paraMask & ChatParameterMask.CHAT_PARAMETER_LOCALVAL2){ + if (pData + sizeof(int) > data.end()){ + return null; + } + // Check logic + result.SetLocalValue((int)pData, 2); + pData += sizeof(int); + }*/ + } + } + } + + return result; + } + } +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/CHAT_S2C.cs.meta b/Assets/PerfectWorld/Scripts/Chat/CHAT_S2C.cs.meta new file mode 100644 index 0000000000..48a8790ff9 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/CHAT_S2C.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: f7564fa8d29f58c40a1aa0425fc0c046 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs b/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs new file mode 100644 index 0000000000..84fce2a20f --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs @@ -0,0 +1,243 @@ +using System; +using System.Collections.Generic; +using BrewMonster.Network; +using BrewMonster.Scripts.UI; +using CSNetwork.GPDataType; +using CSNetwork.Protocols; + +namespace BrewMonster.Scripts.Chat +{ + public static class Chat_GameSession + { + private static List m_aPendingProtocols = new(); + private static List m_aPendingPlayers = new(); + + public static void AddElemForPendingProtocols(Protocol p) + { + m_aPendingProtocols.Add(p); + } + + // Add one player's id to a buffer in order to get his name later + public static void AddChatPlayerID(int id) + { + if (EC_Game.GetGameRun().GetPlayerName(id, false) != null) + { + m_aPendingPlayers.Add(id); + } + } + + public static bool ShouldBlockByLevel(chatmessage p) + { + int levelBlock = EC_Game.GetConfigs().GetBlackListSettings().levelBlock; + if (p.Srclevel > 0 && p.Srclevel < levelBlock) + { + if ((ChatChannel)p.Channel is ChatChannel.GP_CHAT_LOCAL + or ChatChannel.GP_CHAT_WHISPER + or ChatChannel.GP_CHAT_TRADE) + { + if (!EC_Game.GetGameRun().GetHostPlayer().IsOmitBlocking(p.Srcroleid)) + { + // should be filted by level + return true; + } + } + } + + return false; + } + + public static bool PolicyResolver(Protocol pProtocol, chatmessage p, ref string strTemp) + { + if (IsPolicyChat(p)) + { + // Todo: check logic + CHAT_S2C.PolicyChatParameter pPolicyChatPara = CHAT_S2C.CreatPolicyChatParameter(p.Data); + if (pPolicyChatPara != null && p.Data.Size > 0) + { + strTemp = ("???"); + } + else + { + if (pPolicyChatPara != null && !pPolicyChatPara.IsNameReady()) + { + pPolicyChatPara.GetNameFromServer(); + m_aPendingProtocols.Add(pProtocol); + return false; + } + + strTemp = CECUIHelper.PolicySpecialCharReplace(strTemp, pPolicyChatPara); + if (CanFormatCoordText(p)) + { + //strTemp = CECUIHelper.FormatCoordText(strTemp); + } + } + //int strLen = strTemp.GetLength(); + //wcsncpy(szMsg, strTemp, strLen); + //szMsg[strLen] = 0; + } + else + { + //AUI_ConvertChatString(strTemp, szMsg, false); + } + + return true; + } + + /*private void AUI_ConvertChatString(string pszChat, string pszConv, bool bName) + { + int i, nLen = 0; + if (pszChat != null || pszConv != null) + return; + + pszConv[0] = 0; + for( i = 0; i < (int)a_strlen(pszChat); i++ ) + { + if( pszChat[i] == '^' ) + { + pszConv[nLen] = '^'; + pszConv[nLen + 1] = '^'; + nLen += 2; + } + else if( pszChat[i] == '&' ) + { + pszConv[nLen] = '^'; + pszConv[nLen + 1] = '&'; + nLen += 2; + } + else + { + pszConv[nLen] = pszChat[i]; + nLen++; + } + } + pszConv[nLen] = 0; + }*/ + + private static bool IsPolicyChat(chatmessage p) + { + bool bOK = false; + switch (p.Channel) + { + case (byte)ChatChannel.GP_CHAT_LOCAL: // ÃæÏò¸Ã NPC ¿É¼ûÓòÖÐËùÓÐÍæ¼Ò + if (p.Srcroleid == 0 || // £¨²ßÂÔº°»°Öбê¼Ç $A £© + ISNPCID(p.Srcroleid)) + { + // £¨²ßÂÔº°»°ÖÐÎÞ±ê¼Ç £© + bOK = true; + } + + break; + case (byte)ChatChannel.GP_CHAT_BATTLE: // ÃæÏò³ÇÕ½¸±±¾Ö¸¶¨ÕóÓª»òÈ«²¿Íæ¼Òº°»°£¨²ßÂÔº°»°Öбê¼Ç $F¡¢$T £© + if (p.Srcroleid == 0) + { + // Ϊ·ÀÒÔºóÓб仯£¬Ôö¼Ó´ËÅÐ¶Ï + bOK = true; + } + + break; + case (byte)ChatChannel.GP_CHAT_BROADCAST: // ÃæÏòÈ«ÌåÔÚÏßÍæ¼Ò£¨²ßÂÔº°»°Öбê¼Ç $S £© + if (p.Srcroleid == 0) + { + bOK = true; + } + + break; + case (byte)ChatChannel.GP_CHAT_INSTANCE + : // ÃæÏò¸±±¾ÖÐÍæ¼Ò£¨²ßÂÔº°»°Öбê¼Ç $I £©£¨ $X ±ê¼Çʱ p->srcroleid == 1£¬´Ëʱֻ³öÏÖÔÚÆÁÄ»ÖÐÑ룩 + if (p.Srcroleid == 0 || p.Srcroleid == 1) + { + bOK = true; + } + + break; + } + + return bOK; + } + + static bool ISNPCID(int id) + { + uint uid = (uint)id; + return (uid & 0x80000000) != 0 && + (uid & 0x40000000) == 0; + } + + static bool CanFormatCoordText(chatmessage p) + { + bool bOK = false; + switch (p.Channel) + { + case (byte)ChatChannel.GP_CHAT_LOCAL: // ÃæÏò¸Ã NPC ¿É¼ûÓòÖÐËùÓÐÍæ¼Ò + if (p.Srcroleid == 0 || // £¨²ßÂÔº°»°Öбê¼Ç $A £© + ISNPCID(p.Srcroleid)) + { + // £¨²ßÂÔº°»°ÖÐÎÞ±ê¼Ç £© + bOK = true; + } + + break; + case (byte)ChatChannel.GP_CHAT_BATTLE: // ÃæÏò³ÇÕ½¸±±¾Ö¸¶¨ÕóÓª»òÈ«²¿Íæ¼Òº°»°£¨²ßÂÔº°»°Öбê¼Ç $F¡¢$T £© + if (p.Srcroleid == 0) + { + // Ϊ·ÀÒÔºóÓб仯£¬Ôö¼Ó´ËÅÐ¶Ï + bOK = true; + } + + break; + case (byte)ChatChannel.GP_CHAT_BROADCAST: // ÃæÏòÈ«ÌåÔÚÏßÍæ¼Ò£¨²ßÂÔº°»°Öбê¼Ç $S £© + if (p.Srcroleid == 0) + { + bOK = true; + } + + break; + case (byte)ChatChannel.GP_CHAT_INSTANCE: //p->srcroleid == 1 ʱ²»½øÐÐ×ø±êµÄÌæ»» + if (p.Srcroleid == 0) + { + bOK = true; + } + + break; + } + + return bOK; + } + + public class AUICTranslate + { + protected string m_AString = string.Empty; + protected string m_AWString = string.Empty; + + public AUICTranslate() + { + } + + public string Translate(string str) + { + // In original C++ this likely performs UI charset translation. + // Here we simply return the same string or store it. + m_AString = str; + return m_AString; + } + + public string Translate(ReadOnlySpan str) + { + m_AWString = new string(str); + return m_AWString; + } + + public string ReverseTranslate(string str) + { + // Reverse translation placeholder + m_AString = str; + return m_AString; + } + + public string ReverseTranslate(ReadOnlySpan str) + { + m_AWString = new string(str); + return m_AWString; + } + } + } +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs.meta b/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs.meta new file mode 100644 index 0000000000..e9f0f60376 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/Chat_GameSession.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 7c774ca3c7d345e4ea0fbb7397bf1d88 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/Chat_Helper.cs b/Assets/PerfectWorld/Scripts/Chat/Chat_Helper.cs new file mode 100644 index 0000000000..678b0d3f6b --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/Chat_Helper.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +namespace BrewMonster.Scripts.Chat +{ + public static class Chat_Helper + { + public static Color32 ToColor32(uint c) + { + byte a = (byte)((c >> 24) & 0xFF); + byte r = (byte)((c >> 16) & 0xFF); + byte g = (byte)((c >> 8) & 0xFF); + byte b = (byte)(c & 0xFF); + + return new Color32(r, g, b, a); + } + } +} diff --git a/Assets/PerfectWorld/Scripts/Chat/Chat_Helper.cs.meta b/Assets/PerfectWorld/Scripts/Chat/Chat_Helper.cs.meta new file mode 100644 index 0000000000..5cea223658 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/Chat_Helper.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5ef4426a7625eb74aa802808e2223421 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/UI.meta b/Assets/PerfectWorld/Scripts/Chat/UI.meta new file mode 100644 index 0000000000..5b95658c75 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3d2c00e6fd97fce4c8061a0c54327a5f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/ChatMessageView.cs b/Assets/PerfectWorld/Scripts/Chat/UI/ChatMessageView.cs new file mode 100644 index 0000000000..6397bb2b6d --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/UI/ChatMessageView.cs @@ -0,0 +1,15 @@ +using TMPro; +using UnityEngine; + +namespace BrewMonster.Scripts.ChatUI +{ + public class ChatMessageView : MonoBehaviour + { + public TextMeshProUGUI messageText; + + public void Bind(string message) + { + messageText.text = message; + } + } +} diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/ChatMessageView.cs.meta b/Assets/PerfectWorld/Scripts/Chat/UI/ChatMessageView.cs.meta new file mode 100644 index 0000000000..96290dd492 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/UI/ChatMessageView.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 179d32c667fc2f641bdcb7afb18046b9 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs b/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs new file mode 100644 index 0000000000..b40a8bf148 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs @@ -0,0 +1,177 @@ +using System; +using System.Collections.Generic; +using CSNetwork; +using UnityEngine; +using UnityEngine.Pool; +using UnityEngine.UI; + +namespace BrewMonster.Scripts.ChatUI +{ + public class ChatPanelUI : MonoBehaviour + { + [Header("UI")] public ScrollRect scrollRect; + public GameObject chatPanelUIGO; + public RectTransform content; + public ChatMessageView messagePrefab; + //public GameObject newMessageIndicator; + + [Header("Config")] public int maxVisibleMessages = 30; + public int maxStoredMessages = 2000; + + private List _messages = new(); + private List _visibleViews = new(); + + private ObjectPool _pool; + + private bool _userAtBottom = true; + + void Awake() + { + EventBus.Subscribe(OnChatMessageReceived); + _pool = new ObjectPool( + CreateItem, + OnGetItem, + OnReleaseItem, + OnDestroyItem, + false, + 10, + 100 + ); + + scrollRect.onValueChanged.AddListener(OnScrollChanged); + } + + private void OnDestroy() + { + EventBus.Unsubscribe(OnChatMessageReceived); + } + + private void OnChatMessageReceived(GameSession.ChatMessageEvent x) + { + ChatThreadDispatcher.Instance.Post(() => + { + AddMessage(x.context); + }); + } + + ChatMessageView CreateItem() + { + var item = Instantiate(messagePrefab); + item.transform.SetParent(content, false); + return item; + } + + void OnGetItem(ChatMessageView item) + { + item.gameObject.SetActive(true); + } + + void OnReleaseItem(ChatMessageView item) + { + item.gameObject.SetActive(false); + } + + void OnDestroyItem(ChatMessageView item) + { + Destroy(item.gameObject); + } + + void OnScrollChanged(Vector2 pos) + { + _userAtBottom = scrollRect.verticalNormalizedPosition <= 0.001f; + + if (_userAtBottom) + { + //newMessageIndicator.SetActive(false); + } + } + + bool IsAtBottom() + { + return scrollRect.verticalNormalizedPosition <= 0.001f; + } + + public void AddMessage(string msg) + { + _messages.Add(msg); + + if (_messages.Count > maxStoredMessages) + _messages.RemoveAt(0); + + if (!chatPanelUIGO.activeSelf) + return; + + AddMessageView(msg); + + if (_userAtBottom) + ScrollToBottom(); + } + + void AddMessageView(string msg) + { + var view = _pool.Get(); + view.transform.SetParent(content, false); + view.transform.SetAsLastSibling(); + view.Bind(msg); + + _visibleViews.Add(view); + + if (_visibleViews.Count > maxVisibleMessages) + { + var old = _visibleViews[0]; + _visibleViews.RemoveAt(0); + _pool.Release(old); + } + + Canvas.ForceUpdateCanvases(); + } + + void RefreshVisible() + { + foreach (var view in _visibleViews) + _pool.Release(view); + + _visibleViews.Clear(); + + int start = Mathf.Max(0, _messages.Count - maxVisibleMessages); + + for (int i = start; i < _messages.Count; i++) + { + var view = _pool.Get(); + view.transform.SetParent(content, false); + view.transform.SetAsLastSibling(); + view.Bind(_messages[i]); + + _visibleViews.Add(view); + } + + Canvas.ForceUpdateCanvases(); + ScrollToBottom(); + } + + public void ScrollToBottom() + { + Canvas.ForceUpdateCanvases(); + scrollRect.verticalNormalizedPosition = 0f; + //newMessageIndicator.SetActive(false); + } + + public void ClearChat() + { + foreach (var view in _visibleViews) + _pool.Release(view); + + _visibleViews.Clear(); + _messages.Clear(); + } + + public void OnHandlerChatButton() + { + bool open = !chatPanelUIGO.activeSelf; + chatPanelUIGO.SetActive(open); + + if (open) + RefreshVisible(); + } + } +} diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs.meta b/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs.meta new file mode 100644 index 0000000000..8c8314a16a --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/UI/ChatPanelUI.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 5790dcd71bafcec4697f10b5366bec2c \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/ChatThreadDispatcher.cs b/Assets/PerfectWorld/Scripts/Chat/UI/ChatThreadDispatcher.cs new file mode 100644 index 0000000000..4714f62af9 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/UI/ChatThreadDispatcher.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Concurrent; +using UnityEngine; + +namespace BrewMonster.Scripts.ChatUI +{ + /// + /// Responsible for switching chat messages from background threads to Unity main thread. + /// Only handles chat related actions. + /// + public class ChatThreadDispatcher : MonoSingleton + { + private static readonly ConcurrentQueue _queue = new ConcurrentQueue(); + + protected override void Awake() + { + base.Awake(); + DontDestroyOnLoad(gameObject); + } + + /// + /// Called from ANY thread (network thread safe) + /// + public void Post(Action action) + { + if (action == null) + return; + + _queue.Enqueue(action); + } + + private void Update() + { + while (_queue.TryDequeue(out var action)) + { + try + { + action?.Invoke(); + } + catch (Exception e) + { + Debug.LogError($"ChatThreadDispatcher error: {e}"); + } + } + } + } +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Chat/UI/ChatThreadDispatcher.cs.meta b/Assets/PerfectWorld/Scripts/Chat/UI/ChatThreadDispatcher.cs.meta new file mode 100644 index 0000000000..1c00a8022a --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Chat/UI/ChatThreadDispatcher.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 00392315a7ee47e7a9527eda504fb312 +timeCreated: 1773310087 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Common/EC_C2SCmdCache.cs b/Assets/PerfectWorld/Scripts/Common/EC_C2SCmdCache.cs index dc659560ff..1a0901486b 100644 --- a/Assets/PerfectWorld/Scripts/Common/EC_C2SCmdCache.cs +++ b/Assets/PerfectWorld/Scripts/Common/EC_C2SCmdCache.cs @@ -270,7 +270,7 @@ namespace BrewMonster.Common { m_UseItemCmdList.Clear(); - // C2S ʱ + // ���� C2S �����ʱ�� m_CounterMap[(int)CommandID.USE_ITEM].Reset(true); m_EnterSanctuaryList.Clear(); @@ -280,7 +280,7 @@ namespace BrewMonster.Common m_PresentInfoList.Clear(); m_CounterMap[(int)CommandID.PLAYER_GIVE_PRESENT].Reset(true); - // Эʱ + // ����Э���ʱ�� m_GetPlayerBriefInfoList.Clear(); m_CounterMap2[(int)ProtocolType.PROTOCOL_GETPLAYERBRIEFINFO].Reset(true); @@ -377,13 +377,13 @@ namespace BrewMonster.Common getplayerbriefinfo p = m_GetPlayerBriefInfoList[0]; if (p.Playerlist.Count != 0) { - // ȡһidЭ + // ��ȡ��һ�����id�������������Э�� getplayerbriefinfo temp = p; temp.Playerlist.Clear(); temp.Playerlist.Add(p.Playerlist[0]); UnityGameSession.Instance.GameSession.SendProtocol(temp); - // б + // ���б������ p.Playerlist.Remove(p.Playerlist[0]); } @@ -670,12 +670,12 @@ namespace BrewMonster.Common } // Send protocols ... - void SendGetPlayerBriefInfo(int iNumPlayer, int[] aIDs, int iReason) + public void SendGetPlayerBriefInfo(int iNumPlayer, int[] aIDs, int iReason) { if (iNumPlayer == 0 || aIDs == null || aIDs.Length == 0) return; - // 1.ϲӵб + // 1.�ϲ���ӵ��б� getplayerbriefinfo p = new getplayerbriefinfo(); p.Roleid = EC_Game.GetGameRun().GetHostPlayer().GetCharacterID(); p.Reason = (byte)iReason; @@ -687,7 +687,7 @@ namespace BrewMonster.Common if (p.Playerlist.Count > 0) m_GetPlayerBriefInfoList.Add(p); - // 2.鲢 + // 2.��鲢���� SendCachedGetPlayerBriefInfo(); } diff --git a/Assets/PerfectWorld/Scripts/DebugCommandMenu/DlgConsole.cs b/Assets/PerfectWorld/Scripts/DebugCommandMenu/DlgConsole.cs index d2db270052..e7768b4ab5 100644 --- a/Assets/PerfectWorld/Scripts/DebugCommandMenu/DlgConsole.cs +++ b/Assets/PerfectWorld/Scripts/DebugCommandMenu/DlgConsole.cs @@ -124,3 +124,5 @@ namespace BrewMonster.Scripts } } } +/// d 2000 la kn +/// d 1988 + so tien diff --git a/Assets/PerfectWorld/Scripts/GameData/EC_RoleType.cs b/Assets/PerfectWorld/Scripts/GameData/EC_RoleType.cs index 665c65cbe3..8aa9ea705f 100644 --- a/Assets/PerfectWorld/Scripts/GameData/EC_RoleType.cs +++ b/Assets/PerfectWorld/Scripts/GameData/EC_RoleType.cs @@ -4,6 +4,11 @@ using UnityEngine; public static class GameConstants { public static int NUM_MAGICCLASS = 5; + public static int ARMOR_RUIN_SPEED = -25; + public static int WEAPON_RUIN_SPEED = -2; + public static float PLAYER_PRICE_SCALE = 1.0f; + public static int ENDURANCE_SCALE = 100; + } public struct ROLEBASICPROP diff --git a/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs b/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs index 2f7240ff90..5e4f43354d 100644 --- a/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs +++ b/Assets/PerfectWorld/Scripts/Inventory/EC_IvtrType.cs @@ -2,10 +2,6 @@ namespace BrewMonster.Scripts { public class InventoryConst { - // Equipment endurance scale - public const int ENDURANCE_SCALE = 100; - // NUM_MAGICCLASS - public const int NUM_MAGICCLASS = 5; // Index of item in equipment inventory public const int EQUIPIVTR_WEAPON = 0; public const int EQUIPIVTR_HEAD = 1; diff --git a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs index 7bd5336355..d9ea7b5505 100644 --- a/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs +++ b/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs @@ -316,8 +316,8 @@ namespace BrewMonster.Network } public static void update_require_data(ref prerequisition require) { - require.durability *= BrewMonster.Scripts.InventoryConst.ENDURANCE_SCALE; - require.max_durability *= BrewMonster.Scripts.InventoryConst.ENDURANCE_SCALE; + require.durability *= GameConstants.ENDURANCE_SCALE; + require.max_durability *= GameConstants.ENDURANCE_SCALE; } public static void set_to_classid(DATA_TYPE type, byte[] data, int major_type) { diff --git a/Assets/PerfectWorld/Scripts/Managers/A3DSkillGfxMan.cs b/Assets/PerfectWorld/Scripts/Managers/A3DSkillGfxMan.cs index 93f8d6a1ac..d19c956ff4 100644 --- a/Assets/PerfectWorld/Scripts/Managers/A3DSkillGfxMan.cs +++ b/Assets/PerfectWorld/Scripts/Managers/A3DSkillGfxMan.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -146,6 +146,7 @@ namespace BrewMonster pEvent.SetDelay(dwDelayTime); pEvent.SetReverse(bReverse); pEvent.SetParam(param); + BMLogger.LogError("[HoangDev] bTraceTarget=" + bTraceTarget); pEvent.SetTraceTarget(bTraceTarget); pEvent.SetModifier(dwModifier); pEvent.SetIsCluster(bCluster); @@ -503,4 +504,4 @@ namespace BrewMonster public bool bGfxDisableCamShake; public bool bHostECMCreatedByGfx; }; -} \ No newline at end of file +} diff --git a/Assets/PerfectWorld/Scripts/Managers/CECSkillGfxMan.cs b/Assets/PerfectWorld/Scripts/Managers/CECSkillGfxMan.cs index 9a94bab79b..ae0675bbb2 100644 --- a/Assets/PerfectWorld/Scripts/Managers/CECSkillGfxMan.cs +++ b/Assets/PerfectWorld/Scripts/Managers/CECSkillGfxMan.cs @@ -271,7 +271,6 @@ namespace BrewMonster if (m_enumState == GfxSkillEventState.enumHit && m_bTraceTarget) { UpdateHitGfxTransform(); - // Check if hit GFX has been destroyed (3 second lifetime) or target is destroyed // 检查命中特效是否已被销毁(3秒生命周期)或目标是否已销毁 if (m_hitGfxInstance == null || (!m_bTargetExist && m_nTargetID != 0)) @@ -296,7 +295,26 @@ namespace BrewMonster protected override void HitTarget(Vector3 vTarget) { base.HitTarget(vTarget); - DestroyFlyGfx(); + + // Only destroy fly GFX if NOT tracing target + // If tracing target, fly GFX will be cleaned up when buff expires + // 只有在不跟踪目标时才销毁飞行特效 + // 如果跟踪目标,飞行特效将在buff过期时清理 + if (!m_bTraceTarget) + { + DestroyFlyGfx(); + } + else + { + // If fly GFX exists and m_bTraceTarget is true, add to tracking list + // 如果飞行特效存在且m_bTraceTarget为true,添加到跟踪列表 + if (m_flyGfxInstance != null) + { + SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_flyGfxInstance, 0); // Skill ID not available, use 0 + BMLogger.Log($"[TRACE_TARGET_GFX] HitTarget: Added fly GFX to trace target list (m_bTraceTarget=true)"); + } + } + SpawnHitGfx(vTarget); // TODO Phase 2: Special hit effects (rune, critical, nullity) @@ -333,6 +351,13 @@ namespace BrewMonster m_flyGfxInstance = GameObject.Instantiate(prefab, pos, prefab.transform.rotation); + // If m_bTraceTarget is true, add to tracking list when spawned + // 如果m_bTraceTarget为true,在生成时添加到跟踪列表 + if (m_bTraceTarget) + { + SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_flyGfxInstance, 0); // Skill ID not available, use 0 + BMLogger.Log($"[TRACE_TARGET_GFX] SpawnFlyGfx: Added fly GFX to trace target list (m_bTraceTarget=true)"); + } } /// @@ -401,7 +426,8 @@ namespace BrewMonster // 这与C++逻辑匹配:当投射物击中地面(无目标)时使用m_szHitGrndGfx bool bTargetExists = m_bTargetExist && m_nTargetID != 0; GameObject prefab = bTargetExists ? m_pComposer.GetHitGFX() : m_pComposer.GetHitGrdGFX(); - BMLogger.LogError("HitGfx : " + m_pComposer.hitGfxName); + //BMLogger.LogError("bTargetExists : " + bTargetExists); + //BMLogger.LogError("HitGfx : " + m_pComposer.hitGfxName); if (prefab == null) { @@ -429,9 +455,21 @@ namespace BrewMonster m_hitGfxInstance = GameObject.Instantiate(prefab, vTarget, prefab.transform.rotation); - // Destroy hit GFX after 3 seconds (unless m_bTraceTarget is true, then it follows target until destroyed) - // 3秒后销毁命中特效(除非m_bTraceTarget为true,否则它会跟随目标直到被销毁) - //GameObject.Destroy(m_hitGfxInstance, 3.0f); + // If m_bTraceTarget is true, add to tracking list (don't auto-destroy) + // 如果m_bTraceTarget为true,添加到跟踪列表(不自动销毁) + if (m_bTraceTarget) + { + SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_hitGfxInstance, 0); // Skill ID not available, use 0 + //BMLogger.Log($"[TRACE_TARGET_GFX] SpawnHitGfx: Added hit GFX to trace target list (m_bTraceTarget=true)"); + } + else + { + // Destroy hit GFX after 5 seconds (unless m_bTraceTarget is true, then it follows target until destroyed) + // 5秒后销毁命中特效(除非m_bTraceTarget为true,否则它会跟随目标直到被销毁) + //HIT_GFX_MAX_TIMESPAN 5000 + //BMLogger.Log($"[TRACE_TARGET_GFX] SpawnHitGfx: GameObject.Destroy(m_hitGfxInstance, 5.0f);"); + GameObject.Destroy(m_hitGfxInstance, 5.0f); + } } /// @@ -440,10 +478,28 @@ namespace BrewMonster /// public new void Resume() { - DestroyFlyGfx(); - // Hit GFX is auto-destroyed by Unity's Destroy timer, don't null it here - // 命中特效由Unity的Destroy计时器自动销毁,不在此处置null - m_hitGfxInstance = null; + // Don't destroy GFX if it's in trace target list + // It will be cleaned up when buff expires + // 如果GFX在跟踪目标列表中,不要销毁它 + // 它将在buff过期时清理 + if (m_flyGfxInstance != null) + { + if (SkillGfxMan.InstanceSub != null && !SkillGfxMan.InstanceSub.IsTraceTargetGfx(m_flyGfxInstance)) + { + DestroyFlyGfx(); + } + } + + if (m_hitGfxInstance != null) + { + if (SkillGfxMan.InstanceSub != null && !SkillGfxMan.InstanceSub.IsTraceTargetGfx(m_hitGfxInstance)) + { + // Hit GFX is auto-destroyed by Unity's Destroy timer, don't null it here + // 命中特效由Unity的Destroy计时器自动销毁,不在此处置null + m_hitGfxInstance = null; + } + } + base.Resume(); } @@ -878,6 +934,13 @@ namespace BrewMonster protected EC_ManPlayer m_pPlayerMan; protected CECNPCMan m_pNPCMan; + // Track GFX instances that have m_bTraceTarget = true + // These are typically buff-related trail effects that persist until buff expires + // 跟踪具有m_bTraceTarget = true的GFX实例 + // 这些通常是持续到buff结束的buff相关轨迹效果 + private List m_TraceTargetGfxList = new List(); + private Dictionary m_TraceTargetGfxSkillMap = new Dictionary(); + public SkillGfxMan(CECGameRun pGameRun) { m_EventLst = new LinkedList(); @@ -971,6 +1034,110 @@ namespace BrewMonster { m_FreeLst[i].Clear(); } + + // Clean up trace target GFX + // 清理跟踪目标GFX + RemoveAllTraceTargetGfx(); + } + + /// + /// Add a GFX instance to trace target tracking list + /// 将GFX实例添加到跟踪目标跟踪列表 + /// + public void AddTraceTargetGfx(GameObject gfxInstance, int skillId) + { + if (gfxInstance == null) return; + + if (!m_TraceTargetGfxList.Contains(gfxInstance)) + { + m_TraceTargetGfxList.Add(gfxInstance); + m_TraceTargetGfxSkillMap[gfxInstance] = skillId; + + BMLogger.Log($"[TRACE_TARGET_GFX] Added GFX for skill {skillId}, total tracked: {m_TraceTargetGfxList.Count}"); + } + } + + /// + /// Remove all trace target GFX (called when buff states update) + /// 移除所有跟踪目标GFX(在buff状态更新时调用) + /// + public void RemoveAllTraceTargetGfx() + { + BMLogger.Log($"[TRACE_TARGET_GFX] Removing {m_TraceTargetGfxList.Count} trace target GFX"); + + foreach (GameObject gfx in m_TraceTargetGfxList) + { + if (gfx != null) + { + GameObject.Destroy(gfx); + } + } + + m_TraceTargetGfxList.Clear(); + m_TraceTargetGfxSkillMap.Clear(); + } + + /// + /// Remove trace target GFX for specific skill + /// 移除特定技能的跟踪目标GFX + /// + public void RemoveTraceTargetGfxForSkill(int skillId) + { + List toRemove = new List(); + + foreach (var kvp in m_TraceTargetGfxSkillMap) + { + if (kvp.Value == skillId) + { + toRemove.Add(kvp.Key); + } + } + + foreach (GameObject gfx in toRemove) + { + if (gfx != null) + { + GameObject.Destroy(gfx); + } + m_TraceTargetGfxList.Remove(gfx); + m_TraceTargetGfxSkillMap.Remove(gfx); + } + + if (toRemove.Count > 0) + { + BMLogger.Log($"[TRACE_TARGET_GFX] Removed {toRemove.Count} GFX for skill {skillId}"); + } + } + + /// + /// Check if a GFX instance is tracked as trace target GFX + /// 检查GFX实例是否被跟踪为跟踪目标GFX + /// + public bool IsTraceTargetGfx(GameObject gfx) + { + return m_TraceTargetGfxList.Contains(gfx); + } + + /// + /// Clean up null references (GFX destroyed elsewhere) + /// 清理空引用(在其他地方销毁的GFX) + /// + public void CleanupTraceTargetGfx() + { + m_TraceTargetGfxList.RemoveAll(gfx => gfx == null); + + List nullKeys = new List(); + foreach (var kvp in m_TraceTargetGfxSkillMap) + { + if (kvp.Key == null) + { + nullKeys.Add(kvp.Key); + } + } + foreach (var key in nullKeys) + { + m_TraceTargetGfxSkillMap.Remove(key); + } } /// diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Faction.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Faction.cs index 54a576234a..01bff104af 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_Faction.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Faction.cs @@ -12,13 +12,17 @@ namespace BrewMonster public int m_nLev; public int m_nMemNum; - public int GetLevel() { return m_nLev; } + public int GetLevel() + { + return m_nLev; + } } public class CECFactionMan { Dictionary m_FactionMap; public List m_alliance = new List(); + public Faction_Info GetFaction(uint uId, bool bRequestFromServer) { if (!m_FactionMap.TryGetValue(uId, out var it)) @@ -30,6 +34,7 @@ namespace BrewMonster return it; } + public bool IsFactionAlliance(int fid) { if (fid == 0) @@ -43,5 +48,35 @@ namespace BrewMonster return false; } + + private Dictionary m_MemMap; + + public Faction_Mem_Info GetMember(int roleId) + { + if (m_MemMap.TryGetValue(roleId, out var member)) + return member; + + return null; + } + } + + public class Faction_Mem_Info + { + public int RoleId { get; set; } + public int FRoleId { get; set; } + public int Level { get; set; } + public int Profession { get; set; } + public byte OnlineStatus { get; set; } + public byte Gender { get; set; } + public int LoginTime { get; set; } + public string Name { get; set; } = string.Empty; + public string NickName { get; set; } = string.Empty; + public int Contrib { get; set; } + public bool DelayExpel { get; set; } + public uint ExpelEndTime { get; set; } + public int Reputation { get; set; } + public int ReincarnationTimes { get; set; } + + public bool IsOnline => OnlineStatus != 0; } } diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Friend.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Friend.cs new file mode 100644 index 0000000000..f48abf62e3 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Friend.cs @@ -0,0 +1,251 @@ +using System.Collections.Generic; +using BrewMonster.Network; + +namespace BrewMonster +{ + public class CECFriendMan + { + // ========================= + // Nested Types + // ========================= + + public struct Friend + { + public int Id; + public int Profession; + public int GroupId; + public byte Status; + public int Level; + public int AreaId; + public string Name; + + public bool IsGameOnline() => IsGameOnline(Status); + public bool IsGTOnline() => IsGTOnline(Status); + + public static bool IsGameOnline(byte s) + { + // TODO: implement đúng theo logic C++ + return (s & 0x01) != 0; + } + + public static bool IsGTOnline(byte s) + { + // TODO: implement đúng theo logic C++ + return (s & 0x02) != 0; + } + } + + public class FRIEND_EX + { + public bool NewFriendPlaceHolder; + public int Uid; + public int Rid; + public int Level; + public long LastLoginTime; + public long UpdateTime; + public int ReincarnationCount; + public string Remarks = string.Empty; + } + + public class SEND_INFO + { + public int Rid; + public long SendMailTime; + } + + public class GROUP + { + public string Name = string.Empty; + public int GroupId; + public uint Color; // nếu dùng Unity thì có thể đổi sang Color + + public List Friends = new(); + } + + public class MESSAGE + { + public string SenderName = string.Empty; + public int SenderId; + public string MessageText = string.Empty; + public byte Flag; + } + + // ========================= + // Fields + // ========================= + + private List m_Groups = new(); + private Dictionary m_FriendTable = new(); + private List m_OfflineMsgs = new(); + private List m_FriendEx = new(); + private List m_SendInfo = new(); + + // ========================= + // Operations + // ========================= + + public bool CheckInit() => m_Groups.Count > 0; + + public Friend AddFriend(int id, int profession, int groupId, byte status, string name) + { + var friend = new Friend + { + Id = id, + Profession = profession, + GroupId = groupId, + Status = status, + Name = name + }; + + m_FriendTable[id] = friend; + + var group = GetGroupByID(groupId); + group?.Friends.Add(friend); + if (friend.IsGameOnline()) + { + // Todo: Check again + EC_Game.GetGameRun().AddPlayerName(id, name); + } + + return friend; + } + + public void RemoveFriend(int idFriend) + { + if (!m_FriendTable.TryGetValue(idFriend, out var friend)) + return; + + m_FriendTable.Remove(idFriend); + + var group = GetGroupByID(friend.GroupId); + group?.Friends.Remove(friend); + } + + public void RemoveAllFriends() + { + m_FriendTable.Clear(); + foreach (var group in m_Groups) + group.Friends.Clear(); + } + + public void ChangeFriendStatus(int idFriend, byte status) + { + if (m_FriendTable.TryGetValue(idFriend, out var friend)) + friend.Status = status; + } + + public void ChangeFriendGroup(int idFriend, int newGroupId) + { + if (!m_FriendTable.TryGetValue(idFriend, out var friend)) + return; + + var oldGroup = GetGroupByID(friend.GroupId); + oldGroup?.Friends.Remove(friend); + + friend.GroupId = newGroupId; + + var newGroup = GetGroupByID(newGroupId); + newGroup?.Friends.Add(friend); + } + + public Friend? GetFriendByID(int idFriend) + { + m_FriendTable.TryGetValue(idFriend, out var friend); + return friend; + } + + public Friend? GetFriendByName(string name) + { + foreach (var friend in m_FriendTable.Values) + { + if (friend.Name == name) + return friend; + } + + return null; + } + + public void SetFriendLevel(int idFriend, int level) + { + if (m_FriendTable.TryGetValue(idFriend, out var friend)) + friend.Level = level; + } + + public void SetFriendArea(int idFriend, int areaId) + { + if (m_FriendTable.TryGetValue(idFriend, out var friend)) + friend.AreaId = areaId; + } + + // ========================= + // Group Operations + // ========================= + + public bool AddGroup(int idGroup, string name) + { + if (GetGroupByID(idGroup) != null) + return false; + + m_Groups.Add(new GROUP + { + GroupId = idGroup, + Name = name + }); + + return true; + } + + public void RemoveGroup(int idGroup) + { + m_Groups.RemoveAll(g => g.GroupId == idGroup); + } + + public void ChangeGroupName(int idGroup, string name) + { + var group = GetGroupByID(idGroup); + if (group != null) + group.Name = name; + } + + public void SetGroupColor(int idGroup, uint color) + { + var group = GetGroupByID(idGroup); + if (group != null) + group.Color = color; + } + + public int GetGroupNum() => m_Groups.Count; + + public GROUP? GetGroupByIndex(int index) + { + if (index < 0 || index >= m_Groups.Count) + return null; + + return m_Groups[index]; + } + + public GROUP? GetGroupByID(int id) + { + return m_Groups.Find(g => g.GroupId == id); + } + + // ========================= + // Offline Messages + // ========================= + + public int GetOfflineMsgNum() => m_OfflineMsgs.Count; + + public MESSAGE? GetOfflineMsg(int index) + { + if (index < 0 || index >= m_OfflineMsgs.Count) + return null; + + return m_OfflineMsgs[index]; + } + + public void RemoveAllOfflineMsgs() + { + m_OfflineMsgs.Clear(); + } + } +} \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Friend.cs.meta b/Assets/PerfectWorld/Scripts/Managers/EC_Friend.cs.meta new file mode 100644 index 0000000000..45f5f08f51 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Friend.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b5aa739db9534099a9eead426912429c +timeCreated: 1772089238 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMove.cs b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMove.cs index ad6a54d52b..1603aad83f 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMove.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_HPWorkMove.cs @@ -1349,11 +1349,12 @@ namespace BrewMonster.Scripts string message = $"Cannot find path to target position.\nPlease move manually to target location.\n\nMap Coordinates: ({mapX}, {mapZ}, ↑{mapY})"; string messageCN = $"无法找到到目标位置的路径。\n请手动移动到目标位置。\n\n地图坐标: ({mapX}, {mapZ}, ↑{mapY})"; - CECUIManager.Instance.ShowMessageBox( - "Path Not Found", // 路径未找到 - message, // English message with map coordinates - BrewMonster.MessageBoxType.YesButton - ); + // CECUIManager.Instance.ShowMessageBox( + // "Path Not Found", // 路径未找到 + // message, // English message with map coordinates + // BrewMonster.MessageBoxType.YesButton + // ); + CECUIManager.Instance.ShowMessageBoxYes("Path Not Found", message, null, null); } else { diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs index 5e020ab927..7d113a8309 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs @@ -11,7 +11,8 @@ namespace BrewMonster.Scripts.Managers public class EC_Inventory { // ===== Instance-based inventory (per-pack) ===== - + public static int IVTRTYPE_CLIENT_GENERALCARD_PACK = 1024; // �ͻ��˱��ذ����� ���ڿ���ͼ��Ҫ����ѻ�ÿ���ͨ�����췢�͡�Ϊ��ͳһ�������촰�ڵ���Ʒ�����ӱ��ذ����� + // Item array: index is slot, null means empty. private EC_IvtrItem[] m_aItems = Array.Empty(); @@ -27,12 +28,6 @@ namespace BrewMonster.Scripts.Managers IVTRTYPE_GENERALCARD_BOX = 7; // ���ư��� }; - // ע�� IVTRTYPE_CLIENT_GENERALCARD_PACK ö��ֵ���ܺ������ Inventory type ֵ�ظ����� - public static class IVTRTYPE_PACK_CLIENT_GENERALCAR - { - public const int IVTRTYPE_CLIENT_GENERALCARD_PACK = 1024; // �ͻ��˱��ذ����� ���ڿ���ͼ��Ҫ����ѻ�ÿ���ͨ�����췢�͡�Ϊ��ͳһ�������촰�ڵ���Ʒ�����ӱ��ذ����� - }; - public EC_Inventory() { } diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/CECIvtrWeapon.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/CECIvtrWeapon.cs index 6c4ef2cabd..f2f1f55b28 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/CECIvtrWeapon.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/CECIvtrWeapon.cs @@ -201,8 +201,8 @@ namespace PerfectWorld.Scripts.Managers StrengthReq = m_pDBEssence.require_strength; AgilityReq = m_pDBEssence.require_agility; ReputationReq = m_pDBEssence.require_reputation; - CurEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE; - MaxEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE; + CurEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE; + MaxEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE; } // Get item icon file name public override string GetIconFile() diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrArmor.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrArmor.cs index db680f2a08..4938df1c5c 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrArmor.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrArmor.cs @@ -207,8 +207,8 @@ namespace PerfectWorld.Scripts.Managers StrengthReq = m_pDBEssence.require_strength; AgilityReq = m_pDBEssence.require_agility; ReputationReq = m_pDBEssence.require_reputation; - CurEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE; - MaxEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE; + CurEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE; + MaxEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE; } // Get item icon file name public override string GetIconFile() diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrDecoration.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrDecoration.cs index ad175bdd60..b805e5b45d 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrDecoration.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrDecoration.cs @@ -174,8 +174,8 @@ namespace PerfectWorld.Scripts.Managers StrengthReq = 0; AgilityReq = 0; ReputationReq = m_pDBEssence.require_reputation; - CurEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE; - MaxEndurance = m_pDBEssence.durability_min * ENDURANCE_SCALE; + CurEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE; + MaxEndurance = m_pDBEssence.durability_min * GameConstants.ENDURANCE_SCALE; } public override string GetIconFile() { diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrEquip.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrEquip.cs index 1ee7462d39..c3df0b8b5d 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrEquip.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrEquip.cs @@ -14,7 +14,6 @@ using System.Text.RegularExpressions; using System.Reflection; using BrewMonster.Scripts.Managers; using BrewMonster.Scripts; - namespace PerfectWorld.Scripts.Managers { /// @@ -161,9 +160,6 @@ namespace PerfectWorld.Scripts.Managers // Scale Types public const int SCALE_SELL = 1; - // Endurance Scale - public const int ENDURANCE_SCALE = 100; - #endregion #region Public Fields @@ -925,7 +921,7 @@ namespace PerfectWorld.Scripts.Managers /// public static int VisualizeEndurance(int v) { - return (v + ENDURANCE_SCALE - 1) / ENDURANCE_SCALE; + return (v + GameConstants.ENDURANCE_SCALE - 1) / GameConstants.ENDURANCE_SCALE; } /// diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrType.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrType.cs index 663d1d1ff5..306ebb5dd3 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrType.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrType.cs @@ -115,8 +115,8 @@ namespace BrewMonster.Scripts.Managers magic_damage = dr.ReadInt(); defense = dr.ReadInt(); armor = dr.ReadInt(); - resistance = new int[InventoryConst.NUM_MAGICCLASS]; - for (int i = 0; i < InventoryConst.NUM_MAGICCLASS; i++) + resistance = new int[GameConstants.NUM_MAGICCLASS]; + for (int i = 0; i < GameConstants.NUM_MAGICCLASS; i++) { resistance[i] = dr.ReadInt(); } @@ -132,13 +132,13 @@ namespace BrewMonster.Scripts.Managers public int[] resistance; public IVTR_ESSENCE_ARMOR(byte[] data) { - resistance = new int[InventoryConst.NUM_MAGICCLASS]; + resistance = new int[GameConstants.NUM_MAGICCLASS]; CECDataReader dr = new(data, data.Length); defense = dr.ReadInt(); armor = dr.ReadInt(); mp_enhance = dr.ReadInt(); hp_enhance = dr.ReadInt(); - for (int i = 0; i < InventoryConst.NUM_MAGICCLASS; i++) + for (int i = 0; i < GameConstants.NUM_MAGICCLASS; i++) { resistance[i] = dr.ReadInt(); } diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs index 370dc5ff35..940057abac 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs @@ -69,6 +69,7 @@ namespace PerfectWorld.Scripts.Managers case EC_MsgDef.MSG_PM_PLAYERFLY: case EC_MsgDef.MSG_PM_PLAYERMOUNT: case EC_MsgDef.MSG_PM_PLAYERCHGSHAPE: + case EC_MsgDef.MSG_PM_PLAYERSKILLRESULT: TransmitMessage(Msg); break; case EC_MsgDef.MSG_PM_PLAYERDIED: @@ -141,14 +142,22 @@ namespace PerfectWorld.Scripts.Managers if (host != null && cid == host.GetCharacterID()) { - host.ProcessMessage(Msg); + // Call OnMsgPlayerExtState directly instead of ProcessMessage + // ProcessMessage doesn't handle MSG_PM_PLAYEREXTSTATE + // 直接调用OnMsgPlayerExtState而不是ProcessMessage + // ProcessMessage不处理MSG_PM_PLAYEREXTSTATE + host.OnMsgPlayerExtState(Msg); } else { EC_ElsePlayer elsePlayer = SeekOutElsePlayer(cid); if (elsePlayer != null) { - elsePlayer.ProcessMessage(Msg); + // Call OnMsgPlayerExtState directly instead of ProcessMessage + // ProcessMessage doesn't handle MSG_PM_PLAYEREXTSTATE + // 直接调用OnMsgPlayerExtState而不是ProcessMessage + // ProcessMessage不处理MSG_PM_PLAYEREXTSTATE + elsePlayer.OnMsgPlayerExtState(Msg); } if (Convert.ToInt32(Msg.dwParam2) == CommandID.ICON_STATE_NOTIFY && host != null && host.GetTeam() != null) @@ -735,6 +744,9 @@ namespace PerfectWorld.Scripts.Managers case EC_MsgDef.MSG_PM_PLAYERCHGSHAPE: cid = (GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1)).idPlayer; break; + case EC_MsgDef.MSG_PM_PLAYERSKILLRESULT: + cid = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1).attacker_id; + break; default: System.Diagnostics.Debug.Assert(false, "Unknown message"); return false; @@ -917,4 +929,4 @@ namespace PerfectWorld.Scripts.Managers public CECModel pFlyNviagteModel; //CECPlayer::EquipsLoadResult EquipResult; }; -} \ No newline at end of file +} diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs index e622efd239..95f9c347d2 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_Object.cs @@ -13,9 +13,8 @@ using UnityEngine; // /////////////////////////////////////////////////////////////////////////// -public class CECObject : MonoBehaviour +public partial class CECObject : MonoBehaviour { - protected static int ALPHA_HASH = Shader.PropertyToID("_Alpha"); protected Quaternion targetRotation; protected Quaternion startRotation; // Store starting rotation for Slerp diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_RoleTypes.cs b/Assets/PerfectWorld/Scripts/Managers/EC_RoleTypes.cs index 94779620d3..88288c73b2 100644 --- a/Assets/PerfectWorld/Scripts/Managers/EC_RoleTypes.cs +++ b/Assets/PerfectWorld/Scripts/Managers/EC_RoleTypes.cs @@ -231,8 +231,7 @@ namespace BrewMonster.Scripts { // Constants public const int EC_MAXNOPKLEVEL = 0; // The maximum no PK level - public const float EC_TABSEL_DIST = 60.0f; // Distance of TAB selection - public const int NUM_MAGICCLASS = 5; + public const float EC_TABSEL_DIST = 60.0f; public const int NUM_ESBYTE = (int)(ExtendState.NUM_EXTSTATE + 31) >> 5; // Helper methods for bit manipulation (equivalent to the C++ inline functions) diff --git a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs index 2f50b604d3..70942446f6 100644 --- a/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs +++ b/Assets/PerfectWorld/Scripts/Move/CECPlayer.cs @@ -36,6 +36,11 @@ namespace BrewMonster [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; @@ -331,6 +336,9 @@ namespace BrewMonster 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()); @@ -741,6 +749,15 @@ namespace BrewMonster public virtual void SetNewExtendStates(int unknown, uint[] states, int count) { // TODO: Implement appearance or physics change + + // Remove all trace target GFX when buff states change + // This ensures buff-related trail effects are cleaned up when buffs expire + // 当buff状态改变时移除所有跟踪目标GFX + // 这确保buff相关的轨迹效果在buff过期时被清理 + if (SkillGfxMan.InstanceSub != null) + { + SkillGfxMan.InstanceSub.RemoveAllTraceTargetGfx(); + } } public virtual void SetUpPlayer() @@ -2202,7 +2219,45 @@ namespace BrewMonster } } } + 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() { diff --git a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs index eecf3cb4d8..13bc6471e2 100644 --- a/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs +++ b/Assets/PerfectWorld/Scripts/NPC/CECNPC.cs @@ -6,6 +6,7 @@ using CSNetwork.GPDataType; using ModelRenderer.Scripts.Common; using System; using System.Threading.Tasks; +using BrewMonster.Scripts.Chat; using UnityEngine; public class CECNPC : CECObject @@ -469,7 +470,7 @@ public class CECNPC : CECObject { return m_pNPCModelPolicy.PlayAttackAction(nAttackSpeed, attackevent); } - void NPCTurnFaceTo(int idTarget, float dwTime = 0.3f) + public void NPCTurnFaceTo(int idTarget, float dwTime = 0.3f) { if (IsDirFixed()) { @@ -1602,6 +1603,34 @@ public class CECNPC : CECObject // Get NPC name color public virtual uint GetNameColor() { return 0xffffff00; } + + CECPateText m_pPateLastWords1; + CECPateText m_pPateLastWords2; + public void SetLastSaidWords(string words, int timeShow = -1) + { + if (m_pPateLastWords1 == null) + { + m_pPateLastWords1 = new CECPateText(); + } + + if (m_pPateLastWords2 == null) + { + m_pPateLastWords2 = new CECPateText(); + } + + if (words == null) + return; + + int len1 = m_pPateLastWords1.SetText(words, true, out string strWords, false, null); + + /* + if (len1 < strWords.Length) + m_pPateLastWords2.SetText(strWords.Substring(len1), true, true); + else + m_pPateLastWords2.Clear(); + + m_iLastSayCnt = timeShow > 0 ? timeShow : 20000;*/ + } /// /// Get NPC's CECModel instance diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs index 9bb345d99f..cb9e652961 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/AUICommon.cs @@ -1,12 +1,34 @@ -using System; +using System; using System.Collections.Generic; +using System.Linq; using System.Text; +using CSNetwork; namespace CSNetwork { public static class AUICommon { - public static void AUI_ConvertChatString(string pszChat, char[] pszConv, bool bName) + public const char AUICOMMON_ITEM_CODE_START = (char)0xE000; + public const char AUICOMMON_ITEM_CODE_END = (char)0xE3FF; + public const int AUIMANAGER_MAX_EMOTIONGROUPS = 32; + + public const int MAX_EDITBOX_ITEM_NUM = + AUICOMMON_ITEM_CODE_END - AUICOMMON_ITEM_CODE_START + 1; + + public const int MAXNUM_CUSTOM_ITEM = 255; + + public enum EditboxItemType + { + enumEIEmotion = 0, + enumEIIvtrlItem, + enumEICoord, + enumEIImage, + enumEIScriptItem, + enumEICustom, + enumEINum = enumEICustom + MAXNUM_CUSTOM_ITEM + } + + public static void AUI_ConvertChatString(ref string pszChat, ref char[] pszConv, bool bName) { if (string.IsNullOrEmpty(pszChat) || pszConv == null) return; @@ -49,5 +71,782 @@ namespace CSNetwork pszConv[nLen] = '\0'; } + public static string FilterEmotionSet(string szText, int nEmotionSet) + { + EditBoxItemsSet itemsSet = new EditBoxItemsSet(); + + string strOrgText = UnmarshalEditBoxText(szText, itemsSet); + + int nCount = itemsSet.GetItemCount(); + + if (nCount == 0) + return szText; + + var it = itemsSet.GetItemIterator(); + + for (int i = 0; i < nCount; i++) + { + EditBoxItemBase pItem = it.Current.Value; + + if (pItem.GetType() == EditboxItemType.enumEIEmotion) + { + int nSet = 0; + int nIndex = 0; + + UnmarshalEmotionInfo(pItem.GetInfo(), ref nSet, ref nIndex); + + pItem.SetInfo(MarshalEmotionInfo(nEmotionSet, nIndex)); + } + + it.MoveNext(); + } + + return MarshalEditBoxText(strOrgText, itemsSet); + } + + public static string MarshalEmotionInfo(int nEmotionSet, int nIndex) + { + return nEmotionSet.ToString() + ":" + nIndex.ToString(); + } + + public static void UnmarshalEmotionInfo(string szText, ref int nEmotionSet, ref int nIndex) + { + if (string.IsNullOrEmpty(szText)) + return; + + var parts = szText.Split(':'); + + if (parts.Length >= 2) + { + int.TryParse(parts[0], out nEmotionSet); + int.TryParse(parts[1], out nIndex); + } + + // a_ClampFloor(nEmotionSet, 0); + if (nEmotionSet < 0) + nEmotionSet = 0; + + // a_ClampFloor(nIndex, 0); + if (nIndex < 0) + nIndex = 0; + + if (nEmotionSet >= AUIMANAGER_MAX_EMOTIONGROUPS) + nEmotionSet = 0; + } + + public static string MarshalEditBoxText(string text, EditBoxItemsSet itemsSet) + { + var sb = new StringBuilder(text.Length * 2); + + int start = 0; + + for (int i = 0; i < text.Length; i++) + { + char ch = text[i]; + + if (IsEditboxItemCode(ch)) + { + sb.Append(text, start, i - start + 1); + + var item = itemsSet.GetItemByChar(ch); + if (item != null) + sb.Append(item.Serialize()); + + start = i + 1; + } + } + + if (start < text.Length) + sb.Append(text, start, text.Length - start); + + return sb.ToString(); + } + + public static bool IsEditboxItemCode(char ch) + { + return ch >= AUICOMMON_ITEM_CODE_START && ch <= AUICOMMON_ITEM_CODE_END; + } + + public static string UnmarshalEditBoxText(string szText, EditBoxItemsSet itemsSet) + { + return UnmarshalEditBoxText( + szText, + itemsSet, + 0, + null, + 0, + 0, + null, + 0, + false, + false, + 0 + ); + } + + public static string UnmarshalEditBoxText( + string? sztext, + EditBoxItemsSet itemsSet, + int msgIndex, + string ivtrItem, + uint clIvtrItem, + int itemMask, + EditboxScriptItem[]? scriptItems, + int scriptItemCount, + bool underLine, + bool sameColor, + uint clUnderLine) + { + if (sztext == null) + return ""; + + var scriptInfo = new AUI_UNMARSH_SCRIPTITEM_INFO + { + ScriptItems = scriptItems, + ScriptItemCount = scriptItemCount + }; + + var underlineInfo = new AUI_UNMARSH_UNDERLINE_INFO + { + UnderLine = underLine, + SameColor = sameColor, + UnderLineColor = clUnderLine + }; + + return UnmarshalEditBoxTextEx( + sztext, + itemsSet, + msgIndex, + ivtrItem, + clIvtrItem, + itemMask, + scriptInfo, + underlineInfo + ); + } + + public static string UnmarshalEditBoxTextEx( + string text, + EditBoxItemsSet itemsSet, + int msgIndex, + string ivtrItem, + uint clIvtrItem, + int itemMask, + AUI_UNMARSH_SCRIPTITEM_INFO? scriptInfo, + AUI_UNMARSH_UNDERLINE_INFO? underlineInfo) + { + if (text == null) + return ""; + + int start = 0; + int i = 0; + int curScriptIndex = 0; + + var sb = new StringBuilder(); + + while (i < text.Length) + { + char ch = text[i]; + + if (IsEditboxItemCode(ch)) + { + if (i > start) + sb.Append(text, start, i - start); + + i++; + + EditBoxItemBase? item = EditBoxItemBase.Unserialize(text, ref i); + start = i; + + if (item != null) + { + if ((itemMask & (1 << (int)item.GetType())) != 0) + { + char newChar = itemsSet.AppendItem(item); + + if (newChar != '\0') + { + sb.Append(newChar); + + item.SetMsgIndex(msgIndex); + + if (underlineInfo != null) + { + item.SetUnderLine( + underlineInfo.UnderLine, + underlineInfo.SameColor, + underlineInfo.UnderLineColor); + } + + switch (item.GetType()) + { + case EditboxItemType.enumEIIvtrlItem: + + item.SetName(ivtrItem); + item.SetColor(clIvtrItem); + break; + + case EditboxItemType.enumEIScriptItem: + + if (scriptInfo != null && + curScriptIndex < scriptInfo.ScriptItemCount) + { + var sItem = scriptInfo.ScriptItems![curScriptIndex]; + + item.SetName(sItem.Name); + item.SetColor(sItem.Color); + + var data = sItem.Name; + if (data != null) + item.SetExtraData(sItem.Data, sItem.GetDataSize()); + + curScriptIndex++; + } + + break; + } + } + } + } + } + else + { + i++; + } + } + + if (i > start) + sb.Append(text, start, i - start); + + return sb.ToString(); + } + + /// + /// Chuyển đổi định dạng printf (C-style: %s, %d) sang string.Format (C#-style: {0}, {1}) + /// + public static string ConvertPrintfToCSharpFormat(string format) + { + if (string.IsNullOrEmpty(format)) return ""; + + StringBuilder sb = new StringBuilder(); + int argIndex = 0; + for (int i = 0; i < format.Length; i++) + { + if (format[i] == '%' && i + 1 < format.Length) + { + char next = format[i + 1]; + if (next == '%') // Trường hợp %% -> % + { + sb.Append('%'); + i++; + } + else + { + sb.Append('{').Append(argIndex++).Append('}'); + + i++; + // Nhảy qua các ký tự định dạng (ví dụ: %02d, %ls, %f) + while (i < format.Length && (char.IsDigit(format[i]) || format[i] == '.' || format[i] == 'l' || format[i] == 'u' || format[i] == 'd' || format[i] == 's' || format[i] == 'f' || format[i] == 'x')) + { + // Nếu gặp ký tự kết thúc định dạng (s, d, f, ...) thì dừng lại sau ký tự đó + char c = format[i]; + if (c == 's' || c == 'd' || c == 'f' || c == 'u' || c == 'x' || c == 'g') + { + // i++; // Đã ở đúng vị trí để vòng lặp cha thực hiện i++ tiếp theo + break; + } + i++; + } + } + } + else + { + sb.Append(format[i]); + } + } + return sb.ToString(); + } } -} \ No newline at end of file +} + +public class AUI_UNMARSH_SCRIPTITEM_INFO +{ + public EditboxScriptItem[]? ScriptItems; + public int ScriptItemCount; +} + +public class AUI_UNMARSH_UNDERLINE_INFO +{ + public bool UnderLine; + public bool SameColor; + public uint UnderLineColor; +} + +public class EditBoxItemsSet +{ + const char AUICOMMON_ITEM_CODE_START = '\u0001'; + const char AUICOMMON_ITEM_CODE_END = '\u0010'; + protected Dictionary m_Items = new(); + protected int[] m_ItemsCount = new int[(int)AUICommon.EditboxItemType.enumEINum]; + protected char m_cNextItemChar; + + public EditBoxItemsSet() + { + Array.Clear(m_ItemsCount, 0, m_ItemsCount.Length); + m_cNextItemChar = AUICommon.AUICOMMON_ITEM_CODE_START; + } + + public EditBoxItemsSet(EditBoxItemsSet itemsset) + { + this.Assign(itemsset); + } + + public void Assign(EditBoxItemsSet src) + { + m_Items.Clear(); + + foreach (var kv in src.m_Items) + { + m_Items[kv.Key] = new EditBoxItemBase(kv.Value); + } + + Array.Copy(src.m_ItemsCount, m_ItemsCount, m_ItemsCount.Length); + m_cNextItemChar = src.m_cNextItemChar; + } + + public void Release() + { + m_Items.Clear(); + + Array.Clear(m_ItemsCount, 0, m_ItemsCount.Length); + + m_cNextItemChar = AUICommon.AUICOMMON_ITEM_CODE_START; + } + + public int GetItemCount() + { + return m_Items.Count; + } + + public Dictionary.Enumerator GetItemIterator() + { + return m_Items.GetEnumerator(); + } + + public EditBoxItemBase? GetItemByChar(char ch) + { + if (!IsEditboxItemCode(ch)) + throw new Exception("Invalid editbox item char"); + + if (m_Items.TryGetValue(ch, out var item)) + return item; + + return null; + } + + public bool IsEditboxItemCode(char ch) + { + return ch >= AUICOMMON_ITEM_CODE_START && ch <= AUICOMMON_ITEM_CODE_END; + } + + public int GetItemCountByType(AUICommon.EditboxItemType type) + { + return m_ItemsCount[(int)type]; + } + + public void DelItemByChar(char ch) + { + if (m_Items.TryGetValue(ch, out var item)) + { + m_ItemsCount[(int)item.GetType()]--; + m_Items.Remove(ch); + } + } + + public char AppendItem(EditBoxItemBase pItem) + { + if (m_Items.Count >= AUICommon.MAX_EDITBOX_ITEM_NUM) + return '\0'; + + char cur = m_cNextItemChar; + + do + { + if (m_Items.ContainsKey(m_cNextItemChar)) + { + m_cNextItemChar = EditboxGetNextChar(m_cNextItemChar); + } + else + { + m_Items[m_cNextItemChar] = pItem; + m_ItemsCount[(int)pItem.GetType()]++; + + char ret = m_cNextItemChar; + m_cNextItemChar = EditboxGetNextChar(m_cNextItemChar); + + return ret; + } + } while (m_cNextItemChar != cur); + + return '\0'; + } + + public char EditboxGetNextChar(char cur) + { + if (cur >= AUICOMMON_ITEM_CODE_END) + return AUICOMMON_ITEM_CODE_START; + else + return (char)(cur + 1); + } + + public char AppendItem(AUICommon.EditboxItemType type, uint cl, string szName, string szInfo) + { + // Implement theo logic C++ gốc + throw new NotImplementedException(); + } + + public int GetTotalExtraDataSize() + { + int sz = 0; + + foreach (var item in m_Items.Values) + { + sz += item.GetExtraDataSize(); + } + + return sz; + } +} + +public class EditBoxItemBase +{ + protected AUICommon.EditboxItemType m_type; + protected uint m_dwColor; + protected string m_strName = ""; + protected string m_strInfo = ""; + + protected int m_nMsgIndex; + protected int m_nImageIndex; + protected int m_nImageFrame; + protected float m_fImageScale; + + protected byte[]? m_pExtraData; + protected int m_uExtraDataSize; + + protected bool m_bUnderLine; + protected bool m_bSameColor; + protected uint m_dwUnderLineColor; + + protected static EditBoxItemBase?[] m_mapCustomType = new EditBoxItemBase[AUICommon.MAXNUM_CUSTOM_ITEM]; + + public EditBoxItemBase(AUICommon.EditboxItemType type) + { + m_type = type; + m_dwColor = 0xffffffff; + + m_nMsgIndex = 0; + m_nImageIndex = 0; + m_nImageFrame = 0; + m_fImageScale = 1.0f; + + m_bUnderLine = false; + m_bSameColor = true; + m_dwUnderLineColor = 0; + + RegisterCustomType(type); + } + + public EditBoxItemBase(EditBoxItemBase src) + { + Assign(src); + } + + public bool UnserializeContent(string text, ref int index) + { + int szNext; + int szEnd = text.IndexOf("<", index); + + if (szEnd == -1) + return false; + + if (m_type == AUICommon.EditboxItemType.enumEICoord) + { + szNext = szEnd + 1; + + if (!TryParseInt(text, szNext, out int color)) + return false; + + SetColor((uint)color); + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + szNext = szEnd + 2; + + if (!TryParseInt(text, szNext, out int underline)) + return false; + + m_bUnderLine = underline != 0; + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + szNext = szEnd + 2; + + if (!TryParseInt(text, szNext, out int underlineColor)) + return false; + + m_dwUnderLineColor = (uint)underlineColor; + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + m_bSameColor = (m_dwUnderLineColor == m_dwColor); + + szNext = szEnd + 2; + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + SetName(text.Substring(szNext, szEnd - szNext)); + + szEnd += 1; + } + else if (m_type == AUICommon.EditboxItemType.enumEIImage) + { + szNext = szEnd + 1; + + if (!TryParseUInt(text, szNext, out uint color)) + return false; + + SetColor(color); + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + szNext = szEnd + 2; + + if (!TryParseInt(text, szNext, out int imageIndex)) + return false; + + SetImageIndex(imageIndex); + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + szNext = szEnd + 2; + + if (!TryParseInt(text, szNext, out int frame)) + return false; + + SetImageFrame(frame); + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + szNext = szEnd + 2; + + if (!float.TryParse(text.Substring(szNext), out float f)) + return false; + + SetImageScale(f); + + szEnd = text.IndexOf("><", szNext); + if (szEnd == -1) return false; + + szEnd += 1; + } + else if (m_type == AUICommon.EditboxItemType.enumEIEmotion) + { + SetName("W"); + } + + szNext = szEnd + 1; + + szEnd = text.IndexOf('>', szNext); + + if (szEnd == -1) + return false; + + SetInfo(text.Substring(szNext, szEnd - szNext)); + + index = szEnd + 1; + + return true; + } + + private bool TryParseInt(string text, int start, out int value) + { + int end = start; + + while (end < text.Length && char.IsDigit(text[end])) + end++; + + return int.TryParse(text.Substring(start, end - start), out value); + } + + private bool TryParseUInt(string text, int start, out uint value) + { + int end = start; + + while (end < text.Length && char.IsDigit(text[end])) + end++; + + return uint.TryParse(text.Substring(start, end - start), out value); + } + + protected void RegisterCustomType(AUICommon.EditboxItemType type) + { + if (type >= AUICommon.EditboxItemType.enumEICustom && + type < AUICommon.EditboxItemType.enumEINum) + { + int index = (int)type - (int)AUICommon.EditboxItemType.enumEICustom; + + if (m_mapCustomType[index] == null) + m_mapCustomType[index] = this; + } + } + + protected virtual EditBoxItemBase Create() + { + return new EditBoxItemBase(m_type); + } + + protected static EditBoxItemBase? GetCustomItemFromType(AUICommon.EditboxItemType type) + { + if (type >= AUICommon.EditboxItemType.enumEICustom && + type < AUICommon.EditboxItemType.enumEINum) + { + return m_mapCustomType[(int)type - (int)AUICommon.EditboxItemType.enumEICustom]; + } + + return null; + } + + public uint GetColor() => m_dwColor; + public AUICommon.EditboxItemType GetType() => m_type; + public string GetName() => m_strName; + public string GetInfo() => m_strInfo; + public int GetMsgIndex() => m_nMsgIndex; + public int GetImageIndex() => m_nImageIndex; + public int GetImageFrame() => m_nImageFrame; + public float GetImageScale() => m_fImageScale; + public bool GetUnderLine() => m_bUnderLine; + public bool GetSameColor() => m_bSameColor; + public uint GetUnderLineColor() => m_dwUnderLineColor; + + public void SetColor(uint cl) => m_dwColor = cl; + public void SetName(string name) => m_strName = name; + public void SetInfo(string info) => m_strInfo = info; + public void SetMsgIndex(int n) => m_nMsgIndex = n; + public void SetImageIndex(int n) => m_nImageIndex = n; + public void SetImageFrame(int n) => m_nImageFrame = n; + public void SetImageScale(float f) => m_fImageScale = f; + + public byte[]? GetExtraData() => m_pExtraData; + public int GetExtraDataSize() => m_uExtraDataSize; + + public void SetUnderLine(bool underline, bool sameColor = true, uint underlineColor = 0) + { + m_bUnderLine = underline; + m_bSameColor = sameColor; + m_dwUnderLineColor = underlineColor; + } + + public void SetExtraData(byte[] data, int size) + { + m_pExtraData = new byte[size]; + Array.Copy(data, 0, m_pExtraData, 0, size); + m_uExtraDataSize = size; + } + + public virtual string Serialize() + { + return ""; + } + + public static EditBoxItemBase Unserialize(string text, ref int index) + { + int start = text.IndexOf('<', index); + if (start == -1) + return null; + + start++; + + int endType = text.IndexOf('>', start); + if (endType == -1) + return null; + + string typeStr = text.Substring(start, endType - start); + + if (!int.TryParse(typeStr, out int type)) + return null; + + if (type < 0 || type >= (int)AUICommon.EditboxItemType.enumEINum) + return null; + + index = endType + 1; + + EditBoxItemBase pItem = EditBoxItemBase.GetCustomItemFromType((AUICommon.EditboxItemType)type); + + EditBoxItemBase pItemNew; + + if (pItem == null) + { + pItemNew = new EditBoxItemBase((AUICommon.EditboxItemType)type); + } + else + { + pItemNew = pItem.Create(); + } + + if (!pItemNew.UnserializeContent(text, ref index)) + { + return null; + } + + return pItemNew; + } + + public void Assign(EditBoxItemBase src) + { + m_type = src.m_type; + m_dwColor = src.m_dwColor; + m_strName = src.m_strName; + m_strInfo = src.m_strInfo; + + m_nMsgIndex = src.m_nMsgIndex; + m_nImageIndex = src.m_nImageIndex; + m_nImageFrame = src.m_nImageFrame; + m_fImageScale = src.m_fImageScale; + + if (src.m_pExtraData != null) + { + SetExtraData(src.m_pExtraData, src.m_uExtraDataSize); + } + else + { + m_pExtraData = null; + m_uExtraDataSize = 0; + } + + RegisterCustomType(m_type); + } +} + +public class EditboxScriptItem +{ + public string Name { get; set; } = ""; + public uint Color { get; set; } + public byte[]? Data { get; private set; } + + public void SetData(byte[] data) + { + Data = data.ToArray(); // deep copy + } + + public int GetDataSize() + { + return Data?.Length ?? 0; + } +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs index 6f544b78f2..aaa747621a 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs @@ -381,7 +381,7 @@ namespace CSNetwork.C2SCommand public static Octets CreateGetOtherEquipCmd(int iNumID, int[] aIDs) { var cmd = new CMD_GetOtherEquip { size = (ushort)iNumID, idList = aIDs }; - return SerializeCommand(CommandID.GET_OTHER_EQUIP, cmd); + return SerializeCommand(CommandID.GET_OTHER_EQUIP, cmd, false); } /// Create C2S GET_OTHER_EQUIP_DETAIL command (view other player profile/equip). Sends cmd + roleId only (4-byte body). diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs index e70d330201..2092498f76 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs @@ -1539,6 +1539,18 @@ namespace CSNetwork.GPDataType public byte section; }; [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct cmd_host_skill_attacked + { + public int idAttacker; + public int idSkill; + public int iDamage; + public byte cEquipment; // The equipment which is mangled, ��λ������ι����Dz���Ӧ�ñ��ɫ + + public int attack_flag; //��Ǹù����Ƿ��й����Ż����ͷ����Ż������ػ����� + public byte speed; //�����ٶ� speed * 50 ms + public byte section; // skill section + }; + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct cmd_matter_info_list { public ushort count; @@ -1800,6 +1812,46 @@ namespace CSNetwork.GPDataType Marshal.FreeHGlobal(ptr); } } + + /// + /// Convert data become byte array (Demo) + /// + /// Marshal.SizeOf() + /// Max size data + /// Removes the number of leading bytes + /// Remove the last byte count + /// + public static byte[] ContentBytes(int dataTypeLenght, int totalSize, int lenghtHeaderIgnore, int lenghtLastIgnore = 0) + { + int dataLength = totalSize - (lenghtHeaderIgnore + lenghtLastIgnore); + if(dataLength <= 0) throw new ArgumentException("Buffer không đủ dữ liệu"); + byte[] dataContent = new byte[dataLength]; + int offset = dataTypeLenght; + + for (int i = 0; i < dataLength; i++) + { + dataContent[i] = FromBytes(dataContent, offset); + offset += dataTypeLenght; + } + return dataContent; + } + + public static byte[] ContentBytes(int totalSize, int lenghtHeaderIgnore, int lenghtLastIgnore = 0) + { + int dataLength = totalSize - (lenghtHeaderIgnore + lenghtLastIgnore); + if(dataLength <= 0) throw new ArgumentException("Buffer không đủ dữ liệu"); + byte[] dataContent = new byte[dataLength]; + int dataTypeSize = Marshal.SizeOf(); + int offset = dataTypeSize; + + for (int i = 0; i < dataLength; i++) + { + dataContent[i] = FromBytes(dataContent, offset); + offset += dataTypeSize; + } + return dataContent; + } + /// Parse variable-length cmd_team_member_data from buffer. Returns (header, data[]) and bytes consumed. public static (cmd_team_member_data_header header, cmd_team_member_data_MEMBER[] data) ParseTeamMemberData(byte[] data, int startIndex = 0) { diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs index dba6c7c1c8..327035dcbd 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs @@ -14,9 +14,15 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using BrewMonster.PerfectWorld.Scripts.UI; +using BrewMonster.Scripts; +using BrewMonster.Scripts.Chat; +using BrewMonster.Scripts.Managers; +using BrewMonster.Scripts.UI; using BrewMonster.Scripts; using BrewMonster.Scripts.Managers; using UnityEngine; +using CECPlayer = BrewMonster.CECPlayer; using CommandID = CSNetwork.GPDataType.CommandID; namespace CSNetwork @@ -51,6 +57,15 @@ namespace CSNetwork /// Raised when server sends PROTOCOL_PLAYERLOGOUT(69). public event Action PlayerLogoutReceived; + /// + /// Raised when server sends RPC_ADDFRIENDRQST(204) — another player wants to add you as friend. + /// Args: xid (RPC transaction id), srcroleid, askerName. + /// + public event Action FriendRequestReceived; + + /// Raised when server sends PROTOCOL_ADDFRIEND_RE(203). Args: retcode (0=success), message. + public event Action AddFriendResultReceived; + /// Raised when the underlying network disconnects. public event Action Disconnected; @@ -253,7 +268,7 @@ namespace CSNetwork Debug.Log($"[GameSession] Creating role - UserID: {_currentUserId}, Localsid: {_localsid}, Profession: {roleInfo.occupation}, Gender: {roleInfo.gender}"); Debug.Log($"[GameSession] RoleInfo details - Name size: {roleInfo.name?.Size ?? 0}, Equipment count: {roleInfo.equipment?.Count ?? 0}, Custom data size: {roleInfo.custom_data?.Size ?? 0}, Race: {roleInfo.race}"); - + // Log first few bytes of custom_data for debugging if (roleInfo.custom_data != null && roleInfo.custom_data.Size > 0) { @@ -262,7 +277,7 @@ namespace CSNetwork string hexPreview = BitConverter.ToString(customDataPreview).Replace("-", " "); Debug.Log($"[GameSession] Custom_data preview (first 16 bytes): {hexPreview}"); } - + Debug.Log($"[GameSession] Sending createrole protocol (Type: {createRoleProtocol.Type})"); SendProtocol(createRoleProtocol); } @@ -325,7 +340,7 @@ namespace CSNetwork // Initialize custom data exactly as C++ does: memset to 0, then set specific values // This matches C++ LoadDefaultCustomizeData behavior roleInfo.custom_data = CreateDefaultCustomizeData(profession, gender); - + // Initialize other empty custom data fields roleInfo.custom_status = new Octets(); roleInfo.charactermode = new Octets(); @@ -364,31 +379,31 @@ namespace CSNetwork const int CUSTOMIZE_DATA_SIZE = 176; // Match server expectation (176 bytes from response) const uint CUSTOMIZE_DATA_VERSION = 0x10007001; // CUSTOMIZE_DATA_VERSION from C++ byte[] customDataBytes = new byte[CUSTOMIZE_DATA_SIZE]; - + // Step 1: memset to 0 (already done by new byte[]) - + // Step 2: Set dwVersion at offset 0-3 (little-endian) byte[] versionBytes = BitConverter.GetBytes(CUSTOMIZE_DATA_VERSION); Array.Copy(versionBytes, 0, customDataBytes, 0, 4); - + // Step 3: FACE_CUSTOMIZEDATA at offset 4-87 is already zero (84 bytes) // (In C++ this would be loaded from INI, but for now we use zeros) - + // Step 4: bodyID at offset 88-89 is already zero (2 bytes) // Note: There might be 2 bytes padding here if struct is 4-byte aligned - - // Step 5: Set colorBody to 0xffffffff + + // Step 5: Set colorBody to 0xffffffff // Try offset 90 first (no padding), if that doesn't work try 92 (with padding) byte[] colorBodyBytes = BitConverter.GetBytes(0xffffffffu); Array.Copy(colorBodyBytes, 0, customDataBytes, 90, 4); // Try 90 first - + // Step 6: Set all 6 scale fields to 128 // Try offset 94 first (no padding), if that doesn't work try 96 (with padding) for (int i = 94; i < 100; i++) { customDataBytes[i] = 128; } - + return new Octets(customDataBytes); } @@ -531,7 +546,6 @@ namespace CSNetwork private void OnProtocolReceived(Protocol protocol) { _logger.Log(LogType.Debug, $"Received protocol: {protocol.GetType().Name} (Type: {protocol.Type})"); - BMLogger.Log($"Received protocol: {protocol.GetType().Name} (Type: {protocol.Type})"); if (protocol is null) return; @@ -569,6 +583,9 @@ namespace CSNetwork case ProtocolType.PROTOCOL_CHATMESSAGE: OnPrtcChatMessage(protocol, false); break; + case ProtocolType.PROTOCOL_WORLDCHAT: + OnPrtcWorldChat(protocol, false); + break; case ProtocolType.PROTOCOL_PLAYERBASEINFO_RE: OnPrtcPlayerBaseInfoRe(protocol); break; @@ -587,6 +604,14 @@ namespace CSNetwork } break; + case ProtocolType.RPC_ADDFRIENDRQST: + OnAddFriendRqst((addfriendrqst)protocol); + break; + + case ProtocolType.PROTOCOL_ADDFRIEND_RE: + OnAddFriendRe((addfriend_re)protocol); + break; + default: _logger.Log(LogType.Warning, $"Received unhandled protocol type: {protocol.GetPType()}"); break; @@ -601,6 +626,49 @@ namespace CSNetwork // PostToUnityContext(() => PlayerLogoutReceived?.Invoke(protocol)); } + private void OnAddFriendRqst(addfriendrqst p) + { + string askerName = ""; + if (p.Srcname != null && p.Srcname.Size > 0) + askerName = System.Text.Encoding.Unicode.GetString(p.Srcname.ToArray(), 0, p.Srcname.Size); + // Forward xid + srcroleid + name to Unity layer so it can answer via Friend_AddResponse(xid, agree) + PostToUnityContext(() => FriendRequestReceived?.Invoke(p.Xid, p.Srcroleid, askerName)); + } + + private void OnAddFriendRe(addfriend_re p) + { + string friendName = ""; + if (p.info?.name != null && p.info.name.Size > 0) + friendName = System.Text.Encoding.Unicode.GetString(p.info.name.ToArray(), 0, p.info.name.Size); + string msg = p.retcode == 0 + ? $"Add friend success: {friendName}" + : $"Add friend failed: {GetAddFriendRetcodeMessage(p.retcode)}"; + if (p.retcode == 0) + { + Friend_GetList(); + } + + PostToUnityContext(() => AddFriendResultReceived?.Invoke(p.retcode, msg)); + } + + /// FS_ERR server retcodes for addfriend_re. + private static string GetAddFriendRetcodeMessage(byte retcode) + { + switch (retcode) + { + case 0: return "Success"; + case 1: return "Player is offline"; + case 2: return "Request was refused"; + case 3: return "Timeout"; + case 4: return "No remaining space"; + case 5: return "Not found"; + case 6: return "Invalid parameter"; + case 7: return "Duplicate entry"; + case 8: return "Friend list has not been retrieved yet"; + default: return $"retcode={retcode}"; + } + } + // void CECGameSession::OnPrtcPlayerLogout(GNET::Protocol* pProtocol) // { // using namespace GNET; @@ -989,7 +1057,7 @@ namespace CSNetwork } else if (pCmd.iMessage == 133 || pCmd.iMessage == 134) { - // deal failed + // deal failed //pGameRun.PostMessage(MSG_HST_BUY_SELL_FAIL, MAN_PLAYER, 0, (DWORD)pDataBuf, pCmdHeader.cmd); } else if (pCmd.iMessage == 158) @@ -1115,6 +1183,9 @@ namespace CSNetwork case CommandID.HOST_SKILL_ATTACK_RESULT: EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_SKILLRESULT, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; + case CommandID.HOST_SKILL_ATTACKED: + EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_SKILLATTACKED, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); + break; case CommandID.CHANGE_FACE_START: case CommandID.CHANGE_FACE_END: EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CHANGEFACE, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader, dwDataSize); @@ -1300,6 +1371,16 @@ namespace CSNetwork case CommandID.LEAVE_SANCTUARY: EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_SANCTUARY, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader); break; + case CommandID.OBJECT_SKILL_ATTACK_RESULT: + { + cmd_object_skill_attack_result pCmd = GPDataTypeHelper.FromBytes ((byte[])pDataBuf); + if (ISPLAYERID(pCmd.attacker_id)) + EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_PLAYERSKILLRESULT, MANAGER_INDEX.MAN_PLAYER, -1,pDataBuf, pCmdHeader); + else if (ISNPCID(pCmd.attacker_id)) + EC_ManMessage.PostMessage(EC_MsgDef.MSG_NM_NPCSKILLRESULT, MANAGER_INDEX.MAN_NPC, 0, pDataBuf, pCmdHeader); + + break; + } default: #if UNITY_EDITOR if (isDebug) @@ -1326,7 +1407,7 @@ namespace CSNetwork private void HandleCreateRoleResponse(createrole_re protocol) { Debug.Log($"[GameSession] HandleCreateRoleResponse - result: {protocol.result}, roleid: {protocol.roleid}"); - + if (protocol.result != (int)ErrCode.ERR_SUCCESS) { string errorMsg = $"Create role failed with result code: {protocol.result} (ERR_SUCCESS = {(int)ErrCode.ERR_SUCCESS})"; @@ -1347,7 +1428,7 @@ namespace CSNetwork private void HandleErrorInfo(errorinfo protocol) { Debug.LogError($"[GameSession] Server error - Errcode: {protocol.Errcode}"); - + // If we're waiting for create role response and get an error, fail the callback if (_createRoleCallback != null) { @@ -1639,8 +1720,8 @@ namespace CSNetwork g.Data = C2SCommandFactory.CreatePlayerLogoutCmd(outType); SendProtocol(g, complete); } - - + + public void c2s_SendCmdStopMove(in Vector3 vDest, float fSpeed, int iMoveMode, byte byDir, ushort wStamp, int iTime) { @@ -1657,17 +1738,94 @@ namespace CSNetwork gamedatasend.Data = C2SCommandFactory.CreateNakeCmd(C2SCommand.CommandID.ENTER_PK_PROTECTED); SendProtocol(gamedatasend); } + + public const int SUPER_FAR_CRY_EMOTION_SET = 6; + /// + /// Convert string become byte (Encoding.Unicode trong .NET = UTF-16 LE) + /// + /// Data type: enum, Chanel chat + /// Text send to server + /// + /// public void SendChatData(byte cChannel, in string szMsg, int iPack, int iSlot) { - publicchat publicChat = new publicchat(); - publicChat.Channel = cChannel; - publicChat.Roleid = m_iCharID; + if (string.IsNullOrEmpty(szMsg)) + return; + + publicchat p = new publicchat(); + p.Channel = cChannel; + p.Roleid = m_iCharID; + if (iPack == EC_Inventory.IVTRTYPE_CLIENT_GENERALCARD_PACK) + { + CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer(); + EC_Inventory clientPack = + pHost != null ? pHost.GetPack(EC_Inventory.IVTRTYPE_CLIENT_GENERALCARD_PACK) : null; + + if (pHost != null && clientPack != null) + { + EC_IvtrItem pCard = clientPack.GetItem(iSlot); + + if (pCard != null) + { + short cmd = (short)CHAT_S2C.EChatS2CCommand.CHAT_GENERALCARD_COLLECTION; + int cardId = pCard.GetTemplateID(); + + byte[] bytes = new byte[6]; + + BitConverter.GetBytes(cmd).CopyTo(bytes, 0); + BitConverter.GetBytes(cardId).CopyTo(bytes, 2); + p.Data.Replace(bytes); + } + } + } + else if (iPack >= 0 && iSlot >= 0) + { + byte[] bytes = new byte[5]; + + short cmd = (short)CHAT_S2C.EChatS2CCommand.CHAT_EQUIP_ITEM; + short index = (short)iSlot; + byte where = (byte)iPack; + + BitConverter.GetBytes(cmd).CopyTo(bytes, 0); + bytes[2] = where; + BitConverter.GetBytes(index).CopyTo(bytes, 3); + p.Data.Replace(bytes); + } byte[] unicodeBytes = Encoding.Unicode.GetBytes(szMsg); - publicChat.Msg.Replace(unicodeBytes); - _logger.Log(LogType.Warning, $"HoangDev : publicChat {publicChat}"); - SendProtocol(publicChat); + p.Msg.Replace(unicodeBytes); + SendProtocol(p); + + if (cChannel is (byte)ChatChannel.GP_CHAT_LOCAL + or (byte)ChatChannel.GP_CHAT_FARCRY + or (byte)ChatChannel.GP_CHAT_SUPERFARCRY + or (byte)ChatChannel.GP_CHAT_BATTLE + or (byte)ChatChannel.GP_CHAT_COUNTRY) { + CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer(); + //int nEmotionSet = pHost.GetCurEmotionSet(); + int nEmotionSet = 0; + string strMsg = szMsg; + if (cChannel == (byte)ChatChannel.GP_CHAT_SUPERFARCRY) + { + if (strMsg.Length > 8) + { + strMsg = strMsg.Substring(0, strMsg.Length - 8); + } + nEmotionSet = SUPER_FAR_CRY_EMOTION_SET; + } + + EC_IvtrItem pItem = null; + if (iPack >= 0 && iSlot >= 0) { + EC_Inventory pPack = pHost.GetPack(iPack); + if (pPack != null) { + pItem = pPack.GetItem(iSlot); + } + } + EventBus.PublishChannel(pHost.GetCharacterID(), new EventChatMessageOnTopPlayer(pHost.GetCharacterID(), szMsg)); + EventBus.Publish(new ChatMessageEvent(szMsg, p.Channel)); + } } + public void LoadConfigData() { getuiconfig p = new getuiconfig(); @@ -1682,7 +1840,7 @@ namespace CSNetwork public void SaveConfigData(byte[] pBuf, int len) { BMLogger.Log($"[MH] Session.SaveConfigData | len={len}"); - + if (pBuf == null || len <= 0) return; var p = new setuiconfig(); p.Roleid = m_iCharID; @@ -1690,7 +1848,7 @@ namespace CSNetwork byte[] slice = new byte[len]; Buffer.BlockCopy(pBuf, 0, slice, 0, len); p.Ui_config = new Octets(slice); - + // return; SendProtocol(p); } @@ -1700,23 +1858,226 @@ namespace CSNetwork m_iCharID = iCharID; } - private void OnPrtcChatMessage(Protocol pProtocol, bool bCalledagain) + private bool OnPrtcWorldChat(Protocol pProtocol, bool bCalledagain) { + worldchat p = (worldchat)pProtocol; + /*if (p.Channel == (byte)ChatChannel.GP_CHAT_FARCRY && p.Roleid == 24) + { + OnTaskChatMessage(p.Msg.RawBuffer, p.Msg.Size); + return true; + }*/ + + // TODO: Porting logic OnPrtcWorldChat hoàn chỉnh từ C++ if needed + Debug.Log("[Cuong] OnPrtcWorldChat"); + return true; + } + + /*private void OnTaskChatMessage(byte[] pBuf, int sz) + { + ... logic ẩn ... + }*/ + + private bool OnBattleChatMessage(chatmessage p, List pPendingFactions) + { + // Tương đương OnBattleChatMessage trong C++ + // Hiện tại đơn giản hóa việc hiển thị, thực tế cần parse nội dung Battle cụ thể + Debug.Log($"[Battle Chat] RoleID: {p.Srcroleid}"); + return true; + } + + private bool OnFortressChatMessage(chatmessage p, List pPendingFactions) + { + // Tương đương OnFortressChatMessage trong C++ + Debug.Log($"[Fortress Chat] RoleID: {p.Srcroleid}"); + return true; + } + + private bool OnKingChatMessage(chatmessage p, bool bGetPlayerName = true) + { + // Tương đương OnKingChatMessage trong C++ + Debug.Log($"[King Chat] RoleID: {p.Srcroleid}"); + return true; + } + + private void OnFactionPVPChatMessage(chatmessage p) + { + // Tương đương OnFactionPVPChatMessage trong C++ + Debug.Log($"[FactionPVP Chat] RoleID: {p.Srcroleid}"); + } + + private bool OnPrtcChatMessage(Protocol pProtocol, bool bCalledagain) + { + CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan(); + chatmessage p = (chatmessage)pProtocol; + //var channel = (ChatChannel)p.Channel; + Debug.Log("[Cuong] reciver chat channel: " + p.Channel); - string strTemp = System.Text.Encoding.Unicode.GetString(p.Msg.ToArray(), 0, p.Msg.Length); + if (Chat_GameSession.ShouldBlockByLevel(p)) + { + Debug.Log("[Cuong] 1"); + return true; + } - _logger.Log(LogType.Warning, $"HoangDev : OnPrtcChatMessage :{strTemp}"); - EventBus.Publish(new ChatMessageEvent(strTemp)); + EC_IvtrItem pItem = CHAT_S2C.CreateChatItem(p.Data); + + string szMsg = null; + string strTemp = Encoding.Unicode.GetString(p.Msg.ToArray(), 0, p.Msg.Length); + string strMsgOrigion = strTemp; + // Todo: Show Text on Ui Game + //strTemp = pGameUI.FilterInvalidTags(strTemp, pItem==NULL); + /*if (!Chat_GameSession.PolicyResolver(pProtocol, p, ref strTemp)) + { + Debug.Log("[Cuong] 2"); + return false; + } + + if (Chat_GameSession.HanldeGPChatSystem(p, bCalledagain)) + { + Debug.Log("[Cuong] 3"); + }*/ + + if (p.Channel is (byte)ChatChannel.GP_CHAT_BROADCAST + or (byte)ChatChannel.GP_CHAT_SYSTEM || p.Srcroleid == 0) + { + if (p.Channel == (byte)ChatChannel.GP_CHAT_SYSTEM && p.Srcroleid > 0) + { + switch (p.Srcroleid) + { + case 1: case 2: case 3: case 4: case 6: case 7: // Battle Message + if (!bCalledagain) + { + List pending = new List(); + if (!OnBattleChatMessage(p, pending)) + { + // Handle pending faction info + return false; + } + } + break; + case 18: case 19: case 20: case 21: case 22: // Auction Message + // pGameUI.AddSysAuctionMessage(...) + Debug.Log("[Auction] " + strTemp); + EventBus.Publish(new ChatMessageEvent(strTemp, p.Channel)); + break; + case 24: // Task Message + // OnTaskChatMessage(p.Data.RawBuffer, p.Data.Size); + break; + case 29: case 30: case 31: case 32: case 33: case 34: + case 35: case 36: case 37: case 38: case 39: case 40: + case 41: case 42: case 43: case 45: // Fortress Message + OnFortressChatMessage(p, null); + break; + case 46: case 47: case 48: case 49: // Country Battle + // OnCountryChatMessage(p); + break; + case 50: case 51: case 52: case 53: case 54: + case 55: case 56: case 57: case 58: case 59: // King Chat + OnKingChatMessage(p); + break; + case 60: case 61: case 62: case 63: case 64: // Faction PVP + OnFactionPVPChatMessage(p); + break; + } + } + else + { + Debug.Log("[Cuong] 5"); + EventBus.Publish(new ChatMessageEvent(strTemp, p.Channel)); + } + }else if (p.Channel == (byte)ChatChannel.GP_CHAT_INSTANCE && p.Srcroleid == 1) + { + Debug.Log("[Cuong] 6"); + // Chat_GameSession.AUICTranslate trans; + // EC_Game.GetGameRun().GetUIManager().GetInGameUIMan().AddHeartBeatHint(trans.Translate(szMsg )); + } + else + { + Debug.Log("[Cuong] Other"); + CECStringTab pStrTab = EC_Game.GetFixedMsgs(); + + if (ISPLAYERID(p.Srcroleid)) + { + string szName = EC_Game.GetGameRun().GetPlayerName(p.Srcroleid, false); + if (string.IsNullOrEmpty(strTemp)) + { + Debug.Log("[Cuong] Other 0"); + if (!bCalledagain) + { + Chat_GameSession.AddElemForPendingProtocols(pProtocol); + Chat_GameSession.AddChatPlayerID(p.Srcroleid); + } + return false; + } + else + { + Debug.Log("[Cuong] Other 1"); + char[] szText = new char[80]; + AUICommon.AUI_ConvertChatString(ref szName,ref szText, false); + + string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT)); + string str = string.Format( + fmt, + szName, + strTemp + ); + // Convert to EventBus + /*EC_Game.GetGameRun().AddChatMessage(strTemp, p.Channel, p.Srcroleid, + null, 0, p.Emotion, null, strMsgOrigion);*/ + EventBus.Publish(new ChatMessageEvent(str, p.Channel)); + // Set player's last said words + CECPlayer pPlayer = EC_Game.GetGameRun().GetWorld().GetPlayerMan().GetPlayer(p.Srcroleid); + if (pPlayer != null) + { + EventBus.PublishChannel(p.Srcroleid, new EventChatMessageOnTopPlayer(p.Srcroleid, strTemp)); + //pPlayer.SetLastSaidWords(strTemp, p.Emotion); + } + } + } + else if(ISNPCID(p.Srcroleid)) + { + Debug.Log("[Cuong] ISNPCID " + strTemp); + CECNPC pNPC = EC_Game.GetGameRun().GetWorld().GetNPCMan().GetNPC(p.Srcroleid); + + if (pNPC != null) + { + string str; + string template = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT2)); + + string message = string.Format( + template, + pNPC.GetName(), + strTemp + ); + + EC_Game.GetGameRun().AddChatMessage( + message, + p.Channel, + p.Srcroleid, + null, + 0, + p.Emotion + ); + EventBus.Publish(new ChatMessageEvent(message)); + + CECUIHelper.RemoveNameFlagFromNPCChat(strTemp, out szMsg); + + pNPC.SetLastSaidWords(szMsg); + } + } + } + return true; } public struct ChatMessageEvent { public string context; + public byte channel; - public ChatMessageEvent(string context) + public ChatMessageEvent(string context, byte channel = 0) { this.context = context; + this.channel = channel; } } public void OnPrtcGetConfigRe(Protocol pProtocol) @@ -1733,7 +2094,7 @@ namespace CSNetwork EC_Game.GetConfigs().ApplyUserSetting(); } - // Now, Get config data request is sent after all host initial data ready. + // Now, Get config data request is sent after all host initial data ready. // so when we receive this reply, we can do some last work before game // really starts. Maybe it's not the best place to do these work, but // now we do it here. @@ -1744,7 +2105,7 @@ namespace CSNetwork pGameUI.EnableUI(true); // Get referral name for adding friend or other display - //TODO: a Hung lam phan select role info di + //TODO: a Hung lam phan select role info di /* RoleInfo info = EC_Game.GetGameRun().GetSelectedRoleInfo(); if (info.referrer_role > 0) GetPlayerBriefInfo(1, info.referrer_role, 2);*/ @@ -1765,7 +2126,7 @@ namespace CSNetwork CECMCDownload::GetInstance().SendGetDownloadOK();*/ } } - + private void OnPrtcSetConfigRe(Protocol pProtocol) { SetUIConfig_Re p = (SetUIConfig_Re)pProtocol; @@ -1775,12 +2136,12 @@ namespace CSNetwork if (CECGameRun.Instance != null) { TestLogoutLogic.Instance.WasClientSendLogoutMessage = true; - + CECGameRun.Instance.GetPendingLogOut().TriggerAll(); CECGameRun.Instance.GetPendingLogOut().Clear(); } } - + private void OnPrtcPlayerBaseInfoRe(Protocol pProtocol) { playerbaseinfo_re p = (playerbaseinfo_re)pProtocol; @@ -1898,7 +2259,7 @@ namespace CSNetwork BYTE* pBuf = (BYTE*)a_malloctemp(iSize); if (!pBuf) return; - + ((cmd_header*)pBuf)->cmd = C2S::GET_OTHER_EQUIP; cmd_get_other_equip* pCmd = (cmd_get_other_equip*)(pBuf + sizeof (cmd_header)); @@ -1915,7 +2276,7 @@ namespace CSNetwork var idlist = new int[iNumSend]; for (int i=0; i < iNumSend; i++) idlist[i] = aIDs[iCount+i]; - + gamedatasend gamedatasend = new gamedatasend(); gamedatasend.Data = C2SCommandFactory.CreateGetOtherEquipCmd(iNumID, idlist); SendProtocol(gamedatasend); @@ -2031,7 +2392,7 @@ namespace CSNetwork gamedatasend.Data = C2SCommandFactory.CreateNakeCmd(C2SCommand.CommandID.STAND_UP); SendProtocol(gamedatasend); } - + public void c2s_SendCmdAutoTeamSetGoal(int type, int goal_id, int op) { gamedatasend gamedatasend = new gamedatasend(); @@ -2074,6 +2435,43 @@ namespace CSNetwork SendProtocol(g); } + /// Send PROTOCOL_ADDFRIEND(202). Port of CECGameSession::friend_Add(idPlayer, szName). + public void Friend_Add(int idPlayer, string name) + { + var p = new addfriend(); + p.Srcroleid = m_iCharID; + p.Dstroleid = idPlayer; + if (!string.IsNullOrEmpty(name)) + p.Dstname = new Octets(System.Text.Encoding.Unicode.GetBytes(name)); + else + p.Dstname = new Octets(); + p.Srclsid = (int)_localsid; + SendProtocol(p); + } + + /// + /// Send RPC_ADDFRIENDRQST(204) response. Port of CECGameSession::friend_AddResponse(dwHandle, bAgree). + /// Answer to received friend request: xid from request, agree = true (0) or false (69). + /// Matches GNET Rpc XID: low bit = is_request; response must clear that bit. + /// + public void Friend_AddResponse(uint xid, bool agree) + { + const byte ERR_TRADE_AGREE = 0; + const byte ERR_TRADE_REFUSE = 69; + uint responseXid = xid & 0x7FFFFFFFu; // clear request bit, keep count + var p = new addfriendrqstres(responseXid, agree ? ERR_TRADE_AGREE : ERR_TRADE_REFUSE); + SendProtocol(p); + } + + /// Send PROTOCOL_GETFRIENDS(206). Port of CECGameSession::friend_GetList(). + public void Friend_GetList() + { + var p = new getfriends(); + p.Roleid = m_iCharID; + p.Localsid = (int)_localsid; + SendProtocol(p); + } + public void c2s_SendCmdTeamKickMember(int idMember) { var g = new gamedatasend(); @@ -2082,7 +2480,7 @@ namespace CSNetwork } public void c2s_SendCmdTeamLeaveParty() - { + { var g = new gamedatasend(); g.Data = C2SCommandFactory.CreateTeamLeavePartyCommand(); SendProtocol(g); @@ -2119,9 +2517,9 @@ namespace CSNetwork public void c2s_CmdGoto(float x, float y, float z) { - c2s_SendCmdGoto(x, y, z); + c2s_SendCmdGoto(x, y, z); } - + // Send C2S::GOTO command data void c2s_SendCmdGoto(float x, float y, float z) { @@ -2248,7 +2646,7 @@ namespace CSNetwork gamedatasend.Data = C2SCommandFactory.CreateNPCSevRestorePetCmd(iPetIdx); SendProtocol(gamedatasend); } - + // Cross-server get in (C++: c2s_CmdNPCSevCrossServerGetIn) — TODO: implement C2S packet when needed public void c2s_CmdNPCSevCrossServerGetIn() { @@ -2260,6 +2658,6 @@ namespace CSNetwork { // TODO: C2SCommandFactory.CreateNPCSevCrossServerGetOutCmd() and SendProtocol } - + } -} \ No newline at end of file +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/OctetsStream.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/OctetsStream.cs index 5e9d7affe4..24402c1b0b 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/OctetsStream.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/OctetsStream.cs @@ -109,6 +109,23 @@ namespace CSNetwork _position += 4; } + /// Write int32 in little-endian (for GNET protocol compatibility with C++ client/server). + public void WriteInt32LE(int value) + { + var bytes = BitConverter.GetBytes(value); + _octets.Insert(_position, bytes); + _position += 4; + } + + /// Read int32 in little-endian (for GNET protocol compatibility with C++ client/server). + public int ReadInt32LE() + { + if (_position + 4 > _octets.Length) + throw new IndexOutOfRangeException("Attempt to read beyond the end of the stream."); + var bytes = ReadBytes(4); + return BitConverter.ToInt32(bytes, 0); + } + public void Write(float value) { var bytes = BitConverter.GetBytes(value); diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriend_re.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriend_re.cs new file mode 100644 index 0000000000..778976ce52 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriend_re.cs @@ -0,0 +1,43 @@ +using CSNetwork.Protocols.RPCData; + +namespace CSNetwork.Protocols +{ + /// PROTOCOL_ADDFRIEND_RE(203). Port of GNET::AddFriend_Re (inl/addfriend_re). + public class addfriend_re : Protocol + { + public byte retcode { get; set; } + public GFriendInfo info { get; set; } + public uint srclsid { get; set; } + + public addfriend_re() : base(ProtocolType.PROTOCOL_ADDFRIEND_RE) + { + info = new GFriendInfo(); + } + + public override Protocol Clone() => new addfriend_re + { + retcode = retcode, + info = info != null ? new GFriendInfo { rid = info.rid, cls = info.cls, gid = info.gid, name = new Octets(info.name?.ToArray() ?? System.Array.Empty()) } : new GFriendInfo(), + srclsid = srclsid + }; + + public override void Marshal(OctetsStream os) + { + os.Write(retcode); + if (info != null) info.Marshal(os); else new GFriendInfo().Marshal(os); + os.Write(srclsid); + } + + public override void Unmarshal(OctetsStream os) + { + retcode = os.ReadByte(); + info = new GFriendInfo(); + info.Unmarshal(os); + srclsid = os.ReadUInt32(); + } + + public override int PriorPolicy() => 1; + + public override bool SizePolicy(int size) => size <= 128; + } +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriend_re.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriend_re.cs.meta new file mode 100644 index 0000000000..8c52d27971 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriend_re.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 158e35cf46fa51a4cba4fa7485fdb534 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqst.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqst.cs new file mode 100644 index 0000000000..a52735a7ae --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqst.cs @@ -0,0 +1,47 @@ +using System; + +namespace CSNetwork.Protocols +{ + /// RPC_ADDFRIENDRQST(204). Port of GNET AddFriendRqst (argument + xid). Server notifies target of friend request. Body: xid (4) + AddFriendRqstArg. + public class addfriendrqst : Protocol + { + /// RPC transaction id; must be sent back in addfriendrqstres so server can match the response. + public uint Xid { get; set; } + public int Srcroleid { get; set; } + public Octets Srcname { get; set; } + public uint Dstlsid { get; set; } + + public addfriendrqst() : base(ProtocolType.RPC_ADDFRIENDRQST) + { + Srcname = new Octets(); + } + + public override Protocol Clone() => new addfriendrqst + { + Xid = Xid, + Srcroleid = Srcroleid, + Srcname = new Octets(Srcname.ToArray()), + Dstlsid = Dstlsid + }; + + public override void Marshal(OctetsStream os) + { + os.Write(Xid); + os.Write(Srcroleid); + os.Write(Srcname); + os.Write(Dstlsid); + } + + public override void Unmarshal(OctetsStream os) + { + Xid = os.ReadUInt32(); + Srcroleid = os.ReadInt32(); + Srcname = os.ReadOctets(); + Dstlsid = os.ReadUInt32(); + } + + public override int PriorPolicy() => 1; + + public override bool SizePolicy(int size) => size <= 256; + } +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqst.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqst.cs.meta new file mode 100644 index 0000000000..d935487cb5 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqst.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bf82fc1afd675674588f017b6f9e0621 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqstres.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqstres.cs new file mode 100644 index 0000000000..77836886de --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqstres.cs @@ -0,0 +1,44 @@ +using System; + +namespace CSNetwork.Protocols +{ + /// + /// RPC_ADDFRIENDRQST(204) response. Port of GNET Rpc marshal (xid + AddFriendRqstRes). + /// Client sends this to answer a friend request: retcode 0 = agree, 69 = refuse (ERR_TRADE_AGREE / ERR_TRADE_REFUSE). + /// + public class addfriendrqstres : Protocol + { + /// RPC transaction id from the received addfriendrqst; server uses it to match the response. + public uint Xid { get; set; } + /// 0 = ERR_TRADE_AGREE (accept), 69 = ERR_TRADE_REFUSE (decline). + public byte retcode { get; set; } + + public addfriendrqstres() : base(ProtocolType.RPC_ADDFRIENDRQST) + { + } + + public addfriendrqstres(uint xid, byte retcode) : base(ProtocolType.RPC_ADDFRIENDRQST) + { + Xid = xid; + this.retcode = retcode; + } + + public override Protocol Clone() => new addfriendrqstres(Xid, retcode); + + public override void Marshal(OctetsStream os) + { + os.Write(Xid); + os.Write(retcode); + } + + public override void Unmarshal(OctetsStream os) + { + Xid = os.ReadUInt32(); + retcode = os.ReadByte(); + } + + public override int PriorPolicy() => 1; + + public override bool SizePolicy(int size) => size <= 64; + } +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqstres.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqstres.cs.meta new file mode 100644 index 0000000000..6391223f99 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/addfriendrqstres.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 80bb3b37b64736040a16d67848d9f953 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/friendextlist.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/friendextlist.cs index 30c038650e..1f05c3502c 100644 --- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/friendextlist.cs +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/friendextlist.cs @@ -1,11 +1,14 @@ using System; using System.Collections.Generic; +using CSNetwork.Protocols.RPCData; namespace CSNetwork.Protocols { public class friendextlist : Protocol { public int Roleid { get; set; } + public List ExtraInfo { get; set; } = new List(); + public List SendInfo { get; set; } = new List(); public int Localsid { get; set; } public friendextlist() : base(ProtocolType.PROTOCOL_FRIENDEXTLIST) @@ -16,18 +19,26 @@ namespace CSNetwork.Protocols public override Protocol Clone() => new friendextlist { Roleid = Roleid, + ExtraInfo = new List(ExtraInfo ?? new List()), + SendInfo = new List(SendInfo ?? new List()), Localsid = Localsid }; public override void Marshal(OctetsStream os) { os.Write(Roleid); + os.WriteList(ExtraInfo ?? new List()); + os.WriteList(SendInfo ?? new List()); os.Write(Localsid); } public override void Unmarshal(OctetsStream os) { Roleid = os.ReadInt32(); + ExtraInfo = new List(); + os.ReadList(ExtraInfo); + SendInfo = new List(); + os.ReadList(SendInfo); Localsid = os.ReadInt32(); } diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getfriends_re.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getfriends_re.cs new file mode 100644 index 0000000000..56ecc4febc --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getfriends_re.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using CSNetwork.Protocols.RPCData; + +namespace CSNetwork.Protocols +{ + /// PROTOCOL_GETFRIENDS_RE(207). Server response to getfriends(206). + public class getfriends_re : Protocol + { + public int Roleid { get; set; } + public List Groups { get; set; } = new List(); + public List Friends { get; set; } = new List(); + public List Status { get; set; } = new List(); + public int Localsid { get; set; } + + public getfriends_re() : base(ProtocolType.PROTOCOL_GETFRIENDS_RE) + { + } + + public override Protocol Clone() => new getfriends_re + { + Roleid = Roleid, + Groups = new List(Groups ?? new List()), + Friends = new List(Friends ?? new List()), + Status = new List(Status ?? new List()), + Localsid = Localsid + }; + + public override void Marshal(OctetsStream os) + { + os.Write(Roleid); + os.WriteList(Groups ?? new List()); + os.WriteList(Friends ?? new List()); + os.WriteCompactUInt((uint)(Status?.Count ?? 0)); + if (Status != null) + { + for (int i = 0; i < Status.Count; i++) + os.Write(Status[i]); + } + os.Write(Localsid); + } + + public override void Unmarshal(OctetsStream os) + { + Roleid = os.ReadInt32(); + Groups = new List(); + os.ReadList(Groups); + Friends = new List(); + os.ReadList(Friends); + uint sc = os.ReadCompactUInt(); + Status = new List((int)sc); + for (int i = 0; i < sc; i++) + Status.Add(os.ReadByte()); + Localsid = os.ReadInt32(); + } + + public override int PriorPolicy() => 1; + + public override bool SizePolicy(int size) => size <= 8192; + } +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getfriends_re.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getfriends_re.cs.meta new file mode 100644 index 0000000000..2deea0dd28 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/getfriends_re.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: bd80f916689adb4488d055af7d1f0465 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendExtInfo.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendExtInfo.cs new file mode 100644 index 0000000000..203e96eff6 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendExtInfo.cs @@ -0,0 +1,51 @@ +namespace CSNetwork.Protocols.RPCData +{ + /// Port of GNET::GFriendExtInfo (rpcdata/gfriendextinfo). + public class GFriendExtInfo : IMarshallable + { + public int uid; + public int rid; + public int level; + public int last_logintime; + public int update_time; + public byte reincarnation_times; + public Octets remarks; + public short reserved1; + public int reserved2; + public int reserved3; + + public GFriendExtInfo() + { + remarks = new Octets(); + } + + public void Marshal(OctetsStream os) + { + os.Write(uid); + os.Write(rid); + os.Write(level); + os.Write(last_logintime); + os.Write(update_time); + os.Write(reincarnation_times); + os.Write(remarks ?? new Octets()); + os.Write(reserved1); + os.Write(reserved2); + os.Write(reserved3); + } + + public void Unmarshal(OctetsStream os) + { + uid = os.ReadInt32(); + rid = os.ReadInt32(); + level = os.ReadInt32(); + last_logintime = os.ReadInt32(); + update_time = os.ReadInt32(); + reincarnation_times = os.ReadByte(); + remarks = os.ReadOctets(); + reserved1 = os.ReadInt16(); + reserved2 = os.ReadInt32(); + reserved3 = os.ReadInt32(); + } + } +} + diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendExtInfo.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendExtInfo.cs.meta new file mode 100644 index 0000000000..3ce1c12b2c --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendExtInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: cbd227cebee40b0438f44b5a52f47459 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendInfo.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendInfo.cs new file mode 100644 index 0000000000..c592b4b9f8 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendInfo.cs @@ -0,0 +1,32 @@ +namespace CSNetwork.Protocols.RPCData +{ + /// Port of GNET::GFriendInfo (rpcdata/gfriendinfo). + public class GFriendInfo : IMarshallable + { + public int rid; + public byte cls; + public byte gid; + public Octets name; + + public GFriendInfo() + { + name = new Octets(); + } + + public void Marshal(OctetsStream os) + { + os.Write(rid); + os.Write(cls); + os.Write(gid); + os.Write(name ?? new Octets()); + } + + public void Unmarshal(OctetsStream os) + { + rid = os.ReadInt32(); + cls = os.ReadByte(); + gid = os.ReadByte(); + name = os.ReadOctets(); + } + } +} diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendInfo.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendInfo.cs.meta new file mode 100644 index 0000000000..0a4b947df7 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GFriendInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a0bf31ab9d8853a479215aa7e1fa5e94 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GGroupInfo.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GGroupInfo.cs new file mode 100644 index 0000000000..e04ffdfdd5 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GGroupInfo.cs @@ -0,0 +1,27 @@ +namespace CSNetwork.Protocols.RPCData +{ + /// Port of GNET::GGroupInfo (rpcdata/ggroupinfo). + public class GGroupInfo : IMarshallable + { + public byte gid; + public Octets name; + + public GGroupInfo() + { + name = new Octets(); + } + + public void Marshal(OctetsStream os) + { + os.Write(gid); + os.Write(name ?? new Octets()); + } + + public void Unmarshal(OctetsStream os) + { + gid = os.ReadByte(); + name = os.ReadOctets(); + } + } +} + diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GGroupInfo.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GGroupInfo.cs.meta new file mode 100644 index 0000000000..03cb0beee3 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GGroupInfo.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 14af8f8307d31b94585bf4526fcdc1b1 \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GSendAUMailRecord.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GSendAUMailRecord.cs new file mode 100644 index 0000000000..ebdf64d2c0 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GSendAUMailRecord.cs @@ -0,0 +1,22 @@ +namespace CSNetwork.Protocols.RPCData +{ + /// Port of GNET::GSendAUMailRecord (rpcdata/gsendaumailrecord). + public class GSendAUMailRecord : IMarshallable + { + public int rid; + public int sendmail_time; + + public void Marshal(OctetsStream os) + { + os.Write(rid); + os.Write(sendmail_time); + } + + public void Unmarshal(OctetsStream os) + { + rid = os.ReadInt32(); + sendmail_time = os.ReadInt32(); + } + } +} + diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GSendAUMailRecord.cs.meta b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GSendAUMailRecord.cs.meta new file mode 100644 index 0000000000..72df71bfd2 --- /dev/null +++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/Protocols/rpcdata/GSendAUMailRecord.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: c573cfeb052d9f840891d71dfbaecd6a \ No newline at end of file diff --git a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs index ddf8312fb7..e2ddc41577 100644 --- a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs +++ b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs @@ -163,6 +163,9 @@ namespace BrewMonster.Network { BaseSecurity.Initizalize(); ProtocolFactory.RegisterAllProtocols(); + // Type 204 is used for both addfriendrqst (server→client request) and addfriendrqstres (client→server response). + // Client only receives addfriendrqst; ensure decode uses it so we don't get InvalidCastException. + Protocol.Register((uint)ProtocolType.RPC_ADDFRIENDRQST); _gameSession = new GameSession(); #if UNITY_EDITOR var path = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets")); @@ -173,7 +176,9 @@ namespace BrewMonster.Network // Subscribe to unexpected disconnects _gameSession.Disconnected += OnUnexpectedDisconnect; - + _gameSession.FriendRequestReceived += OnFriendRequestReceived; + _gameSession.AddFriendResultReceived += OnAddFriendResultReceived; + _isInitialized = true; DontDestroyOnLoad(gameObject); @@ -184,6 +189,8 @@ namespace BrewMonster.Network // Tell LoginScene what to show next. LogoutFlowState.NextLoginEntry = entryTarget; _gameSession.Disconnected -= OnUnexpectedDisconnect; + _gameSession.FriendRequestReceived -= OnFriendRequestReceived; + _gameSession.AddFriendResultReceived -= OnAddFriendResultReceived; EC_ManMessageMono.Instance.CECNPCMan.Release(); if (clearSavedCreds) @@ -632,6 +639,20 @@ namespace BrewMonster.Network { Instance._gameSession.c2s_SendCmdDuelReply(accept, idInviter); } + /// Send PROTOCOL_ADDFRIEND(202). Port of CECGameSession::friend_Add. + public static void Friend_Add(int idPlayer, string name) + { + Instance._gameSession.Friend_Add(idPlayer, name ?? ""); + } + /// Send PROTOCOL_GETFRIENDS(206). Port of CECGameSession::friend_GetList(). + public static void Friend_GetList() + { + Instance._gameSession.Friend_GetList(); + } + public static void Friend_AddResponse(uint xid, bool agree) + { + Instance._gameSession.Friend_AddResponse(xid, agree); + } public static void c2s_CmdTeamKickMember(int idMember) { Instance._gameSession.c2s_SendCmdTeamKickMember(idMember); @@ -712,6 +733,26 @@ namespace BrewMonster.Network /// /// Handles unexpected server disconnections. Shows a message box and returns to login. /// + private void OnFriendRequestReceived(uint xid, int srcroleid, string askerName) + { + string name = string.IsNullOrEmpty(askerName) ? ("Player " + srcroleid) : askerName; + CECUIManager.Instance?.ShowMessageBoxYesAndNo( + title: "Friend Request", + message: $"{name} wants to add you as a friend.", + dlg: null, + onClickedYes: () => Friend_AddResponse(xid, agree: true), + onClickedNo: () => Friend_AddResponse(xid, agree: false)); + } + + private void OnAddFriendResultReceived(byte retcode, string message) + { + CECUIManager.Instance?.ShowMessageBoxYes( + title: retcode == 0 ? "Friend added" : "Add friend failed", + message: message, + dlg: null, + null); + } + private void OnUnexpectedDisconnect() { // If this was an intentional disconnect (logout), skip UI @@ -722,16 +763,13 @@ namespace BrewMonster.Network } // Show disconnect message box - CECUIManager.Instance?.ShowMessageBox( - title: "Disconnected", - message: "Connection to the server has been lost.", - messageBoxType: MessageBoxType.YesButton, - onClickedYes: () => + CECUIManager.Instance?.ShowMessageBoxYes("Disconnected", "Connection to the server has been lost.", null, + () => { // Return to login screen LogoutAccount(); - } - ); + }); + } public static void c2s_CmdGoto(float x, float y, float z) diff --git a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs index 25fdf4a58b..f9878ddd59 100644 --- a/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs +++ b/Assets/PerfectWorld/Scripts/Players/EC_ElsePlayer.cs @@ -2,6 +2,7 @@ using BrewMonster; using BrewMonster.Managers; using BrewMonster.Network; using BrewMonster.Scripts; +using BrewMonster.Scripts.Skills; using CSNetwork; using CSNetwork.GPDataType; using CSNetwork.Protocols; @@ -452,13 +453,51 @@ namespace BrewMonster case EC_MsgDef.MSG_PM_PLAYERBASEINFO: OnMsgPlayerBaseInfo(Msg); break; case EC_MsgDef.MSG_PM_PLAYEREQUIPDATA: OnMsgPlayerEquipData(Msg); break; case EC_MsgDef.MSG_PM_PLAYERATKRESULT: OnMsgPlayerAtkResult(Msg); break; + case EC_MsgDef.MSG_PM_CASTSKILL: OnMsgPlayerCastSkill(Msg); break; + case EC_MsgDef.MSG_PM_ENCHANTRESULT: OnMsgEnchantResult(Msg); break; case EC_MsgDef.MSG_PM_PLAYERDOEMOTE: OnMsgPlayerDoEmote(Msg); break; + case EC_MsgDef.MSG_PM_PLAYERSKILLRESULT: OnMsgPlayerSkillResult(Msg); break; case EC_MsgDef.MSG_PM_PLAYERGATHER: OnMsgPlayerGather(Msg); break; case EC_MsgDef.MSG_PM_PLAYERMOUNT: OnMsgPlayerMount(Msg); break; } return true; } + /// + /// Handles skill attack result messages for else players. + /// + /// This method is called when the server sends MSG_PM_PLAYERSKILLRESULT (OBJECT_SKILL_ATTACK_RESULT). + /// Unlike OnMsgPlayerAtkResult which handles melee attacks, this handles skill attacks specifically. + /// + /// Flow: + /// 1. Parse cmd_object_skill_attack_result (includes skill_id directly) + /// 2. Face target + /// 3. Call PlayAttackEffect with skill_id from command (triggers GFX system) + /// 4. Enter fight state if skill is attack or curse type + /// + /// C++ equivalent: CECElsePlayer::OnMsgPlayerSkillResult (EC_ElsePlayer.cpp:1787) + /// + private void OnMsgPlayerSkillResult(ECMSG Msg) + { + cmd_object_skill_attack_result pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + // Face to target + TurnFaceTo(pCmd.target_id); + + // Call PlayAttackEffect with skill_id directly from command (like C++ does) + // Unlike OnMsgPlayerAtkResult, we get skill_id from the command structure, not from m_pCurSkill + int attackTime = int.MinValue; + PlayAttackEffect(pCmd.target_id, pCmd.skill_id, 0, -1, + (uint)pCmd.attack_flag, pCmd.speed * 50, ref attackTime, pCmd.section); + + // Check skill type and enter fight state if needed (matching C++ logic) + byte skillType = ElementSkill.GetType((uint)pCmd.skill_id); + if (skillType == (byte)skill_type.TYPE_ATTACK || skillType == (byte)skill_type.TYPE_CURSE) + { + EnterFightState(); + } + } + public void HandleRevive(short sReviveType, A3DVECTOR3 pos) { SetServerPos(pos); @@ -494,7 +533,7 @@ namespace BrewMonster } } - public void OnMsgPlayerEquipData(ECMSG Msg) + public async void OnMsgPlayerEquipData(ECMSG Msg) { // using namespace S2C; @@ -528,12 +567,32 @@ namespace BrewMonster } // // Change equipment - ChangeEquipments(bReset, crc, iAddMask, iDelMask, aAdded); + // ChangeEquipments(bReset, crc, iAddMask, iDelMask, aAdded); + await QueueChangeEquipments(bReset, crc, iAddMask, iDelMask, aAdded); } + private async UniTask QueueChangeEquipments(bool bReset, int crc, long iAddMask, long iDelMask, int[] aAddedEquip) + { + while (!IsPlayerModelReady) + { + await UniTask.DelayFrame(1); + } + ChangeEquipments(bReset, crc, iAddMask, iDelMask, aAddedEquip); + } + + /// + /// Handles attack result messages for else players (both melee and skill attacks). + /// + /// For skill attacks: + /// - Uses m_pCurSkill (set in OnMsgPlayerCastSkill) to get skill ID + /// - Calls PlayAttackEffect with skill ID, which triggers GFX system + /// - GFX system (A3DSkillGfxComposerMan) spawns effects at hook positions + /// + /// For melee attacks: + /// - idSkill is 0, triggers normal melee attack work + /// void OnMsgPlayerAtkResult(ECMSG Msg) { - cmd_object_atk_result pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); //ASSERT(pCmd && pCmd.attacker_id == m_PlayerInfo.cid); @@ -542,16 +601,142 @@ namespace BrewMonster // TO DO: fix later int attackTime = int.MinValue; - PlayAttackEffect(pCmd.target_id, 0, 0, -1, (uint)pCmd.attack_flag, pCmd.speed* 50, ref attackTime); + PlayAttackEffect(pCmd.target_id, 0, 0, -1, (uint)pCmd.attack_flag, pCmd.speed * 50, ref attackTime); + BMLogger.Log($"[ELSEPLAYER_SKILL_FLOW] PlayAttackEffect: Complete, attackTime={attackTime}"); - if (!m_pEPWorkMan.FindWork(CECEPWorkMan.Work_type.WT_NORMAL, CECEPWork.EP_work_ID.WORK_HACKOBJECT)){ - m_pEPWorkMan.StartNormalWork(new CECEPWorkMelee(m_pEPWorkMan, pCmd.target_id)); - } + if (!m_pEPWorkMan.FindWork(CECEPWorkMan.Work_type.WT_NORMAL, CECEPWork.EP_work_ID.WORK_HACKOBJECT)) + { + m_pEPWorkMan.StartNormalWork(new CECEPWorkMelee(m_pEPWorkMan, pCmd.target_id)); + } // Enter fight state EnterFightState(); } - + + /// + /// Handles skill casting messages from server for else players. + /// + /// Flow: + /// 1. Server sends OBJECT_CAST_SKILL -> This handler plays cast animation + /// 2. Server sends SKILL_PERFORM -> Skill execution begins (for durative skills) + /// 3. Server sends attack result -> OnMsgPlayerAtkResult triggers PlayAttackEffect + /// 4. PlayAttackEffect -> CECAttacksMan.AddSkillAttack -> GFX system spawns effects + /// 5. Server sends SKILL_INTERRUPTED -> Clears casting state (if interrupted) + /// + /// Note: Else players don't maintain skill lists, so we create temporary CECSkill objects + /// for tracking purposes only. The actual skill data comes from ElementSkill static methods. + /// + private void OnMsgPlayerCastSkill(ECMSG Msg) + { + int commandID = Convert.ToInt32(Msg.dwParam2); + + switch (commandID) + { + case CommandID.OBJECT_CAST_SKILL: + { + cmd_object_cast_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + // Get skill object (else players don't have skill lists, so we create a temporary skill reference) + // For else players, we mainly need the skill ID for animation purposes + int skillID = pCmd.skill; + + // Store current skill target + m_idCurSkillTarget = pCmd.target; + + // Face the target + TurnFaceTo(pCmd.target); + + // Play skill cast animation + PlaySkillCastAction(skillID); + + // Create a temporary skill object for tracking (if needed) + // Note: Else players don't maintain skill lists like host player does + // We create a minimal skill object just for the current cast + if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) + { + // Create a temporary skill object with level 1 (we don't know the actual level) + m_pCurSkill = new CECSkill(skillID, 1); + } + + // Enter fight state + EnterFightState(); + + break; + } + case CommandID.OBJECT_CAST_INSTANT_SKILL: + { + cmd_object_cast_instant_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + int skillID = pCmd.skill; + + m_idCurSkillTarget = pCmd.target; + + TurnFaceTo(pCmd.target); + PlaySkillCastAction(skillID); + + if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) + { + m_pCurSkill = new CECSkill(skillID, 1); + } + + EnterFightState(); + break; + } + case CommandID.OBJECT_CAST_POS_SKILL: + { + cmd_object_cast_pos_skill pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + int skillID = pCmd.skill; + + // For position-based skills, target is the position, not an object + // We still play the cast animation + PlaySkillCastAction(skillID); + + if (m_pCurSkill == null || m_pCurSkill.GetSkillID() != skillID) + { + m_pCurSkill = new CECSkill(skillID, 1); + } + + EnterFightState(); + break; + } + case CommandID.SKILL_PERFORM: + { + // Skill perform - the skill has finished casting and is being executed + // For else players, we keep m_pCurSkill until attack result is received + // This allows PlayAttackEffect to use the skill information + // Durative skills (channeling) will continue until interrupted + if (m_pCurSkill != null && m_pCurSkill.IsDurative()) + { + // For durative skills, we keep the skill active + // It will be cleared when SKILL_INTERRUPTED is received + } + break; + } + case CommandID.SKILL_INTERRUPTED: + { + // Skill was interrupted, clear current skill + cmd_skill_interrupted pCmd = + GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1); + + if (m_pCurSkill != null) + { + StopSkillCastAction(); + m_pCurSkill = null; + } + m_idCurSkillTarget = 0; + break; + } + default: + { + break; + } + } + } + private async void LoadAppearGfx() { if (!m_pAppearGFX && m_iAppearFlag == (int)PlayerAppearFlag.APPEAR_ENTERWORLD) @@ -809,6 +994,7 @@ namespace BrewMonster m_iGender = iGender; m_bBaseInfoReady = true; SetPlayerName(szName ?? ""); + EC_Game.GetGameRun().AddPlayerName(m_PlayerInfo.cid, szName, true); } // Level up public void LevelUp() diff --git a/Assets/PerfectWorld/Scripts/Skills/SkillStubs1/skill77.cs b/Assets/PerfectWorld/Scripts/Skills/SkillStubs1/skill77.cs index cae168e840..1d40e59f34 100644 --- a/Assets/PerfectWorld/Scripts/Skills/SkillStubs1/skill77.cs +++ b/Assets/PerfectWorld/Scripts/Skills/SkillStubs1/skill77.cs @@ -120,7 +120,6 @@ namespace BrewMonster m_AttFlyMode = (GfxAttackMode)0; m_AttHitMode = (GfxAttackMode)0; m_dwFlyTime = 200; - m_bTraceTarget = true; m_FlyClusterCount = 1; m_FlyClusterInterval = 0; m_HitClusterCount = 1; diff --git a/Assets/PerfectWorld/Scripts/UI/CDlgMessageBox.cs b/Assets/PerfectWorld/Scripts/UI/CDlgMessageBox.cs index 6e6d17c54b..80a16c67bc 100644 --- a/Assets/PerfectWorld/Scripts/UI/CDlgMessageBox.cs +++ b/Assets/PerfectWorld/Scripts/UI/CDlgMessageBox.cs @@ -1,8 +1,9 @@ -using System; +using System; using BrewMonster.UI; using PerfectWorld.Scripts.Common; using UnityEngine; using TMPro; +using UnityEngine.Serialization; using UnityEngine.UI; using static CECUIManager; @@ -27,16 +28,19 @@ namespace BrewMonster { [SerializeField] private TMP_Text titleText; [SerializeField] private TMP_Text messageText; - [SerializeField] private Button okButton; + [SerializeField] private Button _yesButton; [SerializeField] private Button _noButton; [SerializeField] private Button _closeButton; + private Action _onClickedYesBtn; + private Action _onClickedNoBtn; + private MessageBoxData _messageData; public override void OnEnable() { base.OnEnable(); - okButton.onClick.AddListener(OnOkClicked); + _yesButton.onClick.AddListener(OnYesClicked); _noButton.onClick.AddListener(OnNoClicked); _closeButton.onClick.AddListener(OnCloseClicked); @@ -44,59 +48,135 @@ namespace BrewMonster public override void OnDisable() { - okButton.onClick.RemoveListener(OnOkClicked); + _yesButton.onClick.RemoveListener(OnYesClicked); _noButton.onClick.RemoveListener(OnNoClicked); _closeButton.onClick.RemoveListener(OnCloseClicked); } #region Button Events - private void OnOkClicked() + private void OnYesClicked() { EventBus.Publish(new MessageBoxEvent(1,_messageData.Dlg)); - _messageData.OnClickedYes?.Invoke(); + _onClickedYesBtn?.Invoke(); Show(false); } private void OnNoClicked() { EventBus.Publish(new MessageBoxEvent(0,_messageData.Dlg)); _messageData.OnClickedNo?.Invoke(); + _onClickedNoBtn?.Invoke(); Show(false); } private void OnCloseClicked() { // treat the close button as OK button - OnOkClicked(); + OnYesClicked(); } #endregion - public void ShowMessageBox(MessageBoxData messageBoxData) + // public void ShowMessageBox(MessageBoxData messageBoxData) + // { + // _messageData = messageBoxData; + // messageBoxData.Message = EC_TextFormatter.FormatForTextMeshPro(messageBoxData.Message); + // SetName(string.IsNullOrEmpty(messageBoxData.Title) ? "" : messageBoxData.Title); + // messageText.text = string.IsNullOrEmpty(messageBoxData.Message) ? "" : messageBoxData.Message; + // + // _yesButton.gameObject.SetActive(false); + // _noButton.gameObject.SetActive(false); + // switch (_messageData.MessageBoxType) + // { + // case MessageBoxType.YesButton: + // _yesButton.gameObject.SetActive(true); + // break; + // case MessageBoxType.NoButton: + // _noButton.gameObject.SetActive(true); + // break; + // case MessageBoxType.BothYesNoButton: + // _yesButton.gameObject.SetActive(true); + // _noButton.gameObject.SetActive(true); + // break; + // } + // Show(true); + // } + + /// + /// message with title and message only + /// + /// + /// + /// + public void ShowMessageBoxGeneral(string title, string message, AUIDialog dlg) { - _messageData = messageBoxData; - // messageBoxData.Message = messageBoxData.Message? - // .Replace("\r\n", "\n") - // .Replace("\r", "\n"); - messageBoxData.Message = EC_TextFormatter.FormatForTextMeshPro(messageBoxData.Message); - SetName(string.IsNullOrEmpty(messageBoxData.Title) ? "" : messageBoxData.Title); - messageText.text = string.IsNullOrEmpty(messageBoxData.Message) ? "" : messageBoxData.Message; - - okButton.gameObject.SetActive(false); + _onClickedYesBtn = null; + _onClickedYesBtn = null; + string formattedMessage = EC_TextFormatter.FormatForTextMeshPro(message); + SetName(string.IsNullOrEmpty(title) ? "" : title); + messageText.text = string.IsNullOrEmpty(formattedMessage) ? "" : formattedMessage; _noButton.gameObject.SetActive(false); - switch (_messageData.MessageBoxType) - { - case MessageBoxType.YesButton: - okButton.gameObject.SetActive(true); - break; - case MessageBoxType.NoButton: - _noButton.gameObject.SetActive(true); - break; - case MessageBoxType.BothYesNoButton: - okButton.gameObject.SetActive(true); - _noButton.gameObject.SetActive(true); - break; - } + _yesButton.gameObject.SetActive(true); Show(true); + transform.SetAsLastSibling(); + } + + /// + /// message with yes button only + /// + /// + /// + /// + /// + public void ShowMessageBoxYes(string title, string message, AUIDialog dlg, Action onClickedYes) + { + _onClickedYesBtn = onClickedYes; + string formattedMessage = EC_TextFormatter.FormatForTextMeshPro(message); + SetName(string.IsNullOrEmpty(title) ? "" : title); + messageText.text = string.IsNullOrEmpty(formattedMessage) ? "" : formattedMessage; + _noButton.gameObject.SetActive(false); + _yesButton.gameObject.SetActive(true); + Show(true); + transform.SetAsLastSibling(); + } + + /// + /// message with no button only + /// + /// + /// + /// + /// + public void ShowMessageBoxNo(string title, string message, AUIDialog dlg, Action onClickedNo) + { + _onClickedNoBtn = onClickedNo; + string formattedMessage = EC_TextFormatter.FormatForTextMeshPro(message); + SetName(string.IsNullOrEmpty(title) ? "" : title); + messageText.text = string.IsNullOrEmpty(formattedMessage) ? "" : formattedMessage; + _yesButton.gameObject.SetActive(false); + _noButton.gameObject.SetActive(true); + Show(true); + transform.SetAsLastSibling(); + } + + /// + /// message with yes and no button + /// + /// + /// + /// + /// + /// + public void ShowMessageBoxYesAndNo(string title, string message, AUIDialog dlg, Action onClickedYes, Action onClickedNo) + { + _onClickedYesBtn = onClickedYes; + _onClickedNoBtn = onClickedNo; + string formattedMessage = EC_TextFormatter.FormatForTextMeshPro(message); + SetName(string.IsNullOrEmpty(title) ? "" : title); + messageText.text = string.IsNullOrEmpty(formattedMessage) ? "" : formattedMessage; + _yesButton.gameObject.SetActive(true); + _noButton.gameObject.SetActive(true); + Show(true); + transform.SetAsLastSibling(); } } } diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgInstall.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgInstall.cs index 64879f884f..32890746ec 100644 --- a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgInstall.cs +++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgInstall.cs @@ -1,4 +1,4 @@ -using BrewMonster.Network; +using BrewMonster.Network; using BrewMonster.Scripts.Managers; using BrewMonster.UI; using PerfectWorld.Scripts.Managers; @@ -37,12 +37,13 @@ namespace BrewMonster [Header("Buttons and Money")] [SerializeField] private TextMeshProUGUI m_TxtMoney; + [SerializeField] private Button m_useItem; [SerializeField] private Button m_BtnMergeOrReset; [SerializeField] private Button m_BtnCancel; [SerializeField] private Button m_BtnClose; [SerializeField] private Sprite khung_item; - [SerializeField] private Transform itemInventoryRoot; + [SerializeField] private GameObject itemInventoryRoot; private EC_IvtrItem m_SelectedEquip; private EC_IvtrItem m_SelectedMaterial; @@ -58,31 +59,14 @@ namespace BrewMonster public override void Awake() { base.Awake(); - RegisterDrop(m_SlotFirstParent, OnDropEquip); RegisterClick(m_SlotFirstParent, OnClickEquipSlot); if (m_Mode == InstallMode.Enchase && m_SlotSecondParent != null) { - RegisterDrop(m_SlotSecondParent, OnDropMaterial); RegisterClick(m_SlotSecondParent, OnClickMaterialSlot); } } - public override void Update() - { -#if UNITY_EDITOR || UNITY_STANDALONE - if (Input.GetMouseButtonDown(0)) - { - CheckHidePanel(Input.mousePosition); - } -#else - if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began) - { - CheckHidePanel(Input.GetTouch(0).position); - } -#endif - } - public override void OnEnable() { base.OnEnable(); @@ -91,6 +75,7 @@ namespace BrewMonster m_BtnMergeOrReset.onClick.AddListener(OnClickedMergeOrReset); m_BtnCancel.onClick.AddListener(OnCommandCancel); m_BtnClose.onClick.AddListener(OnCommandCancel); + m_useItem.onClick.AddListener(OnUseItemClicked); m_install_price = -1; if (m_SlotSecondParent != null) m_SlotSecondParent.gameObject.SetActive(m_Mode == InstallMode.Enchase); @@ -104,6 +89,7 @@ namespace BrewMonster m_BtnMergeOrReset.onClick.RemoveListener(OnClickedMergeOrReset); m_BtnCancel.onClick.RemoveListener(OnCommandCancel); m_BtnClose.onClick.RemoveListener(OnCommandCancel); + m_useItem.onClick.RemoveListener(OnUseItemClicked); } private void RestoreInventoryColors() @@ -147,23 +133,6 @@ namespace BrewMonster return list[slot]; } - private void RegisterDrop(Transform target, Action callback) - { - var trigger = target.GetComponent(); - if (trigger == null) - trigger = target.gameObject.AddComponent(); - - trigger.triggers.Clear(); - - var entry = new EventTrigger.Entry - { - eventID = EventTriggerType.Drop - }; - entry.callback.AddListener((data) => { callback((PointerEventData)data); }); - - trigger.triggers.Add(entry); - } - private void RegisterClick(Transform target, Action callback) { if (target == null) return; @@ -199,117 +168,6 @@ namespace BrewMonster } } - private EC_IvtrItem GetItemFromDrag(PointerEventData eventData) - { - if (eventData.pointerDrag == null) - return null; - - var btn = eventData.pointerDrag.GetComponent