diff --git a/Assets/PerfectWorld/Prefab/UI/DlgExit.prefab b/Assets/PerfectWorld/Prefab/UI/DlgExit.prefab
new file mode 100644
index 0000000000..a2a3f6956e
--- /dev/null
+++ b/Assets/PerfectWorld/Prefab/UI/DlgExit.prefab
@@ -0,0 +1,918 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &1590197940424963217
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 6666702292353843246}
+ - component: {fileID: 4026888369354985289}
+ m_Layer: 0
+ m_Name: DlgExit
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &6666702292353843246
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1590197940424963217}
+ 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: 4878816101074468399}
+ m_Father: {fileID: 0}
+ 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!114 &4026888369354985289
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1590197940424963217}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: 8ca9d1418c284fd395248056f086c7d4, type: 3}
+ m_Name:
+ m_EditorClassIdentifier:
+ ConfirmBtn: {fileID: 3576373828330281173}
+ CancelBtn: {fileID: 5816777684468032703}
+--- !u!1 &1725743065086802770
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 4878816101074468399}
+ - component: {fileID: 1101450299599105715}
+ - component: {fileID: 5337953600179164026}
+ m_Layer: 0
+ m_Name: Popup
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &4878816101074468399
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1725743065086802770}
+ 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: 7913819123905793175}
+ - {fileID: 7527520206793245717}
+ - {fileID: 4965393937731457567}
+ - {fileID: 4000902174573487903}
+ m_Father: {fileID: 6666702292353843246}
+ 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: 933.3333, y: 533.3333}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &1101450299599105715
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1725743065086802770}
+ m_CullTransparentMesh: 1
+--- !u!114 &5337953600179164026
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1725743065086802770}
+ 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: 21300000, guid: 4744752b0496d42d0b1c52fcb705e044, 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 &4518958362188575915
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 4965393937731457567}
+ - component: {fileID: 1891070853961845177}
+ - component: {fileID: 807580002560918717}
+ - component: {fileID: 3576373828330281173}
+ m_Layer: 0
+ m_Name: Button_Confirm
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &4965393937731457567
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4518958362188575915}
+ 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: 4642911678502374063}
+ m_Father: {fileID: 4878816101074468399}
+ 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: -210, y: -150}
+ m_SizeDelta: {x: 313, y: 91}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &1891070853961845177
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4518958362188575915}
+ m_CullTransparentMesh: 1
+--- !u!114 &807580002560918717
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4518958362188575915}
+ 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: 21300000, guid: b545f49a479374ffaaec0c8f123b0c5f, 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!114 &3576373828330281173
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4518958362188575915}
+ 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: 807580002560918717}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls: []
+--- !u!1 &4670976812881016521
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 7913819123905793175}
+ - component: {fileID: 2369126678925736279}
+ - component: {fileID: 7564280183498118806}
+ m_Layer: 0
+ m_Name: Text (TMP)_Title
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &7913819123905793175
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4670976812881016521}
+ 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: 4878816101074468399}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 1}
+ m_AnchorMax: {x: 0.5, y: 1}
+ m_AnchoredPosition: {x: -3.7721, y: -17.4557}
+ m_SizeDelta: {x: 298.0753, y: 34.9115}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &2369126678925736279
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4670976812881016521}
+ m_CullTransparentMesh: 1
+--- !u!114 &7564280183498118806
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 4670976812881016521}
+ 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: "Th\xF4ng b\xE1o"
+ m_isRightToLeft: 0
+ m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_fontSharedMaterials: []
+ m_fontMaterial: {fileID: 0}
+ m_fontMaterials: []
+ m_fontColor32:
+ serializedVersion: 2
+ rgba: 4294967295
+ m_fontColor: {r: 1, g: 1, b: 1, 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: 30
+ m_fontSizeBase: 30
+ m_fontWeight: 400
+ m_enableAutoSizing: 0
+ m_fontSizeMin: 18
+ m_fontSizeMax: 72
+ m_fontStyle: 0
+ m_HorizontalAlignment: 2
+ m_VerticalAlignment: 512
+ m_textAlignment: 65535
+ m_characterSpacing: 0
+ m_wordSpacing: 0
+ m_lineSpacing: 0
+ m_lineSpacingMax: 0
+ m_paragraphSpacing: 0
+ m_charWidthMaxAdj: 0
+ m_TextWrappingMode: 1
+ m_wordWrappingRatios: 0.4
+ m_overflowMode: 0
+ m_linkedTextComponent: {fileID: 0}
+ parentLinkedComponent: {fileID: 0}
+ m_enableKerning: 0
+ m_ActiveFontFeatures: 6e72656b
+ m_enableExtraPadding: 0
+ checkPaddingRequired: 0
+ m_isRichText: 1
+ m_EmojiFallbackSupport: 1
+ m_parseCtrlCharacters: 1
+ m_isOrthographic: 1
+ m_isCullingEnabled: 0
+ m_horizontalMapping: 0
+ m_verticalMapping: 0
+ m_uvLineOffset: 0
+ m_geometrySortingOrder: 0
+ m_IsTextObjectScaleStatic: 0
+ m_VertexBufferAutoSizeReduction: 0
+ m_useMaxVisibleDescender: 1
+ m_pageToDisplay: 1
+ m_margin: {x: 0, y: 0, z: 0, w: 0}
+ m_isUsingLegacyAnimationComponent: 0
+ m_isVolumetricText: 0
+ m_hasFontAssetChanged: 0
+ m_baseMaterial: {fileID: 0}
+ m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
+--- !u!1 &5918190347695128963
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 4642911678502374063}
+ - component: {fileID: 4834289956051303799}
+ - component: {fileID: 3482299799452283765}
+ 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 &4642911678502374063
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5918190347695128963}
+ 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: 4965393937731457567}
+ 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 &4834289956051303799
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5918190347695128963}
+ m_CullTransparentMesh: 1
+--- !u!114 &3482299799452283765
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5918190347695128963}
+ 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: "X\xE1c nh\u1EADn"
+ m_isRightToLeft: 0
+ m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_fontSharedMaterials: []
+ m_fontMaterial: {fileID: 0}
+ m_fontMaterials: []
+ m_fontColor32:
+ serializedVersion: 2
+ rgba: 4294967295
+ m_fontColor: {r: 1, g: 1, b: 1, 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: 50
+ m_fontSizeBase: 50
+ m_fontWeight: 400
+ m_enableAutoSizing: 0
+ m_fontSizeMin: 18
+ m_fontSizeMax: 72
+ m_fontStyle: 0
+ m_HorizontalAlignment: 2
+ m_VerticalAlignment: 512
+ m_textAlignment: 65535
+ m_characterSpacing: 0
+ m_wordSpacing: 0
+ m_lineSpacing: 0
+ m_lineSpacingMax: 0
+ m_paragraphSpacing: 0
+ m_charWidthMaxAdj: 0
+ m_TextWrappingMode: 1
+ m_wordWrappingRatios: 0.4
+ m_overflowMode: 0
+ m_linkedTextComponent: {fileID: 0}
+ parentLinkedComponent: {fileID: 0}
+ m_enableKerning: 0
+ m_ActiveFontFeatures: 6e72656b
+ m_enableExtraPadding: 0
+ checkPaddingRequired: 0
+ m_isRichText: 1
+ m_EmojiFallbackSupport: 1
+ m_parseCtrlCharacters: 1
+ m_isOrthographic: 1
+ m_isCullingEnabled: 0
+ m_horizontalMapping: 0
+ m_verticalMapping: 0
+ m_uvLineOffset: 0
+ m_geometrySortingOrder: 0
+ m_IsTextObjectScaleStatic: 0
+ m_VertexBufferAutoSizeReduction: 0
+ m_useMaxVisibleDescender: 1
+ m_pageToDisplay: 1
+ m_margin: {x: 0, y: 0, z: 0, w: 0}
+ m_isUsingLegacyAnimationComponent: 0
+ m_isVolumetricText: 0
+ m_hasFontAssetChanged: 0
+ m_baseMaterial: {fileID: 0}
+ m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
+--- !u!1 &5923497699521027687
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 4000902174573487903}
+ - component: {fileID: 7348237821025748982}
+ - component: {fileID: 356920440688922164}
+ - component: {fileID: 5816777684468032703}
+ m_Layer: 0
+ m_Name: Button_Cancel
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &4000902174573487903
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5923497699521027687}
+ 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: 1979839230795202451}
+ m_Father: {fileID: 4878816101074468399}
+ 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: 210, y: -150}
+ m_SizeDelta: {x: 313, y: 91}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &7348237821025748982
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5923497699521027687}
+ m_CullTransparentMesh: 1
+--- !u!114 &356920440688922164
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5923497699521027687}
+ 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: 21300000, guid: b545f49a479374ffaaec0c8f123b0c5f, 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!114 &5816777684468032703
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 5923497699521027687}
+ 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: 356920440688922164}
+ m_OnClick:
+ m_PersistentCalls:
+ m_Calls: []
+--- !u!1 &6076086137757476783
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 7527520206793245717}
+ - component: {fileID: 717316905677608887}
+ - component: {fileID: 2182669632864579474}
+ m_Layer: 0
+ m_Name: Text (TMP)_Content
+ m_TagString: Untagged
+ m_Icon: {fileID: 0}
+ m_NavMeshLayer: 0
+ m_StaticEditorFlags: 0
+ m_IsActive: 1
+--- !u!224 &7527520206793245717
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6076086137757476783}
+ 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: 4878816101074468399}
+ m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+ m_AnchorMin: {x: 0.5, y: 1}
+ m_AnchorMax: {x: 0.5, y: 1}
+ m_AnchoredPosition: {x: -2, y: -201.94122}
+ m_SizeDelta: {x: 862.825, y: 279.6172}
+ m_Pivot: {x: 0.5, y: 0.5}
+--- !u!222 &717316905677608887
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6076086137757476783}
+ m_CullTransparentMesh: 1
+--- !u!114 &2182669632864579474
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 6076086137757476783}
+ 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: "R\u1EDDi kh\u1ECFi ho\xE0n m\u1EF9 ?"
+ m_isRightToLeft: 0
+ m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_fontSharedMaterials: []
+ m_fontMaterial: {fileID: 0}
+ m_fontMaterials: []
+ m_fontColor32:
+ serializedVersion: 2
+ rgba: 4294967295
+ m_fontColor: {r: 1, g: 1, b: 1, 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: 93.94
+ m_fontSizeBase: 93.94
+ m_fontWeight: 400
+ m_enableAutoSizing: 0
+ m_fontSizeMin: 18
+ m_fontSizeMax: 72
+ m_fontStyle: 0
+ m_HorizontalAlignment: 2
+ m_VerticalAlignment: 512
+ m_textAlignment: 65535
+ m_characterSpacing: 0
+ m_wordSpacing: 0
+ m_lineSpacing: 0
+ m_lineSpacingMax: 0
+ m_paragraphSpacing: 0
+ m_charWidthMaxAdj: 0
+ m_TextWrappingMode: 1
+ m_wordWrappingRatios: 0.4
+ m_overflowMode: 0
+ m_linkedTextComponent: {fileID: 0}
+ parentLinkedComponent: {fileID: 0}
+ m_enableKerning: 0
+ m_ActiveFontFeatures: 6e72656b
+ m_enableExtraPadding: 0
+ checkPaddingRequired: 0
+ m_isRichText: 1
+ m_EmojiFallbackSupport: 1
+ m_parseCtrlCharacters: 1
+ m_isOrthographic: 1
+ m_isCullingEnabled: 0
+ m_horizontalMapping: 0
+ m_verticalMapping: 0
+ m_uvLineOffset: 0
+ m_geometrySortingOrder: 0
+ m_IsTextObjectScaleStatic: 0
+ m_VertexBufferAutoSizeReduction: 0
+ m_useMaxVisibleDescender: 1
+ m_pageToDisplay: 1
+ m_margin: {x: 0, y: 0, z: 0, w: 0}
+ m_isUsingLegacyAnimationComponent: 0
+ m_isVolumetricText: 0
+ m_hasFontAssetChanged: 0
+ m_baseMaterial: {fileID: 0}
+ m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
+--- !u!1 &8385824745593160430
+GameObject:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ serializedVersion: 6
+ m_Component:
+ - component: {fileID: 1979839230795202451}
+ - component: {fileID: 926584410341277518}
+ - component: {fileID: 7589457457506445651}
+ 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 &1979839230795202451
+RectTransform:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 8385824745593160430}
+ 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: 4000902174573487903}
+ 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 &926584410341277518
+CanvasRenderer:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 8385824745593160430}
+ m_CullTransparentMesh: 1
+--- !u!114 &7589457457506445651
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 8385824745593160430}
+ 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: "H\u1EE7y"
+ m_isRightToLeft: 0
+ m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
+ m_fontSharedMaterials: []
+ m_fontMaterial: {fileID: 0}
+ m_fontMaterials: []
+ m_fontColor32:
+ serializedVersion: 2
+ rgba: 4294967295
+ m_fontColor: {r: 1, g: 1, b: 1, 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: 50
+ m_fontSizeBase: 50
+ m_fontWeight: 400
+ m_enableAutoSizing: 0
+ m_fontSizeMin: 18
+ m_fontSizeMax: 72
+ m_fontStyle: 0
+ m_HorizontalAlignment: 2
+ m_VerticalAlignment: 512
+ m_textAlignment: 65535
+ m_characterSpacing: 0
+ m_wordSpacing: 0
+ m_lineSpacing: 0
+ m_lineSpacingMax: 0
+ m_paragraphSpacing: 0
+ m_charWidthMaxAdj: 0
+ m_TextWrappingMode: 1
+ m_wordWrappingRatios: 0.4
+ m_overflowMode: 0
+ m_linkedTextComponent: {fileID: 0}
+ parentLinkedComponent: {fileID: 0}
+ m_enableKerning: 0
+ m_ActiveFontFeatures: 6e72656b
+ m_enableExtraPadding: 0
+ checkPaddingRequired: 0
+ m_isRichText: 1
+ m_EmojiFallbackSupport: 1
+ m_parseCtrlCharacters: 1
+ m_isOrthographic: 1
+ m_isCullingEnabled: 0
+ m_horizontalMapping: 0
+ m_verticalMapping: 0
+ m_uvLineOffset: 0
+ m_geometrySortingOrder: 0
+ m_IsTextObjectScaleStatic: 0
+ m_VertexBufferAutoSizeReduction: 0
+ m_useMaxVisibleDescender: 1
+ m_pageToDisplay: 1
+ m_margin: {x: 0, y: 0, z: 0, w: 0}
+ m_isUsingLegacyAnimationComponent: 0
+ m_isVolumetricText: 0
+ m_hasFontAssetChanged: 0
+ m_baseMaterial: {fileID: 0}
+ m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
diff --git a/Assets/PerfectWorld/Prefab/UI/DlgExit.prefab.meta b/Assets/PerfectWorld/Prefab/UI/DlgExit.prefab.meta
new file mode 100644
index 0000000000..1c6e3602da
--- /dev/null
+++ b/Assets/PerfectWorld/Prefab/UI/DlgExit.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 0c248d0510a114829b58d62d2ecc3b5e
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset
index eaf8413cbe..056efe4255 100644
--- a/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset
+++ b/Assets/PerfectWorld/Resources/UI/DialogScriptTableObject.asset
@@ -53,3 +53,5 @@ MonoBehaviour:
prefab: {fileID: 1813565726936289741, guid: a0e02be030755ab4a917523764fe4eef, type: 3}
- id: DlgPetHatch
prefab: {fileID: 3120870614492201289, guid: eaebf3351c396754fb983e0d5ba83e9a, type: 3}
+ - id: DlgPetRec
+ prefab: {fileID: 4739268381143404558, guid: 37f331119e0524018a0a7266aa257777, type: 3}
diff --git a/Assets/PerfectWorld/Scripts/Common/EC_Configs.cs b/Assets/PerfectWorld/Scripts/Common/EC_Configs.cs
index 90953c446d..93a0a9c9ac 100644
--- a/Assets/PerfectWorld/Scripts/Common/EC_Configs.cs
+++ b/Assets/PerfectWorld/Scripts/Common/EC_Configs.cs
@@ -38,15 +38,22 @@ namespace BrewMonster
public byte nLevel;
public byte nSight;
public byte nWaterEffect;
+ [MarshalAs(UnmanagedType.U1)]
public bool bSimpleTerrain;
public byte nTreeDetail;
public byte nGrassDetail;
public byte nCloudDetail;
+ [MarshalAs(UnmanagedType.U1)]
public bool bShadow;
+ [MarshalAs(UnmanagedType.U1)]
public bool bMipMapBias;
+ [MarshalAs(UnmanagedType.U1)]
public bool bFullGlow;
+ [MarshalAs(UnmanagedType.U1)]
public bool bSpaceWarp;
+ [MarshalAs(UnmanagedType.U1)]
public bool bSunFlare;
+ [MarshalAs(UnmanagedType.U1)]
public bool bAdvancedWater;
public byte nSoundVol;
public byte nMusicVol;
@@ -55,9 +62,13 @@ namespace BrewMonster
public int iRndHeight;
public int iTexDetail;
public int iSoundQuality;
+ [MarshalAs(UnmanagedType.U1)]
public bool bFullScreen;
+ [MarshalAs(UnmanagedType.U1)]
public bool bWideScreen;
+ [MarshalAs(UnmanagedType.U1)]
public bool bVSync;
+ [MarshalAs(UnmanagedType.U1)]
public bool bScaleUI;
public int iTheme;
@@ -124,35 +135,58 @@ namespace BrewMonster
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct EC_VIDEO_SETTING
{
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerHP;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerMP;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerEXP;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerHeadText;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerName;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerFaction;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerTitle;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerShop;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerSelfName;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerTalk;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerBubble;
+ [MarshalAs(UnmanagedType.U1)]
public bool bMonsterName;
+ [MarshalAs(UnmanagedType.U1)]
public bool bNPCName;
+ [MarshalAs(UnmanagedType.U1)]
public bool bGoodsName;
+ [MarshalAs(UnmanagedType.U1)]
public bool bModelLimit;
public byte nDistance;
+ [MarshalAs(UnmanagedType.U1)]
public bool bMapMonster;
+ [MarshalAs(UnmanagedType.U1)]
public bool bMapNPC;
+ [MarshalAs(UnmanagedType.U1)]
public bool bMapPlayer;
public byte nEffect;
+ [MarshalAs(UnmanagedType.U1)]
public bool bShowCustomize;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_ConfigConstants.EC_COMBOSKILL_NUM)]
public EC_COMBOSKILL[] comboSkill;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPlayerForce;
+ [MarshalAs(UnmanagedType.U1)]
public bool bMailToFriendsRemind;
public int iMailToFriendsCheckTime;
public char cTabSelType;
+ [MarshalAs(UnmanagedType.U1)]
public bool bActivityRemind;
public int ibActivityReminderCheckTime;
+ [MarshalAs(UnmanagedType.U1)]
public bool bCloseMeridiansHint;
public void Reset()
@@ -253,42 +287,94 @@ namespace BrewMonster
bCloseMeridiansHint = reader.ReadBoolean();
}
}
-
+
+
// Game Settings Structure
- [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ // CharSet.Ansi required so szAutoReply matches C++ ACHAR[65] (1 byte/char); default is Unicode (2 bytes/char).
+ [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
public struct EC_GAME_SETTING
{
+ [MarshalAs(UnmanagedType.U1)]
public bool bNoTeamRequest;
+ [MarshalAs(UnmanagedType.U1)]
public bool bNoTradeRequest;
+ [MarshalAs(UnmanagedType.U1)]
public bool bTurnaround;
+ [MarshalAs(UnmanagedType.U1)]
public bool bReverseWheel;
- [MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_ConfigConstants.EC_USERCHANNEL_NUM * 15)] // GP_CHAT_MAX = 15
- public bool[] bChannel;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_ConfigConstants.EC_USERCHANNEL_NUM * 15, ArraySubType = UnmanagedType.I1)] // GP_CHAT_MAX = 15; I1 = 1 byte per bool to match C++ bool[6][15]
+ public byte[] bChannel; // I can't use bool[] here because C# bool is 1 byte but C++ bool is also 1 byte, so we use byte[] to match the size and layout of the original C++ struct.
+ [MarshalAs(UnmanagedType.U1)]
public bool bAutoReply;
- [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EC_ConfigConstants.EC_AUTOREPLY_LEN + 1)]
- public string szAutoReply;
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_ConfigConstants.EC_AUTOREPLY_LEN + 1)]
+ public ushort[] szAutoReply; // Using ushort[] to match C++ ACHAR[65] (1 byte/char) with CharSet.Ansi; we will convert to string when reading/writing.
+
+ /// Convert szAutoReply buffer (UTF-8 bytes stored as ushort) to string.
+ public static string SzAutoReplyToString(ushort[] buf)
+ {
+ if (buf == null || buf.Length == 0) return string.Empty;
+ int n = 0;
+ while (n < buf.Length && buf[n] != 0) n++;
+ if (n == 0) return string.Empty;
+ var bytes = new byte[n];
+ for (int i = 0; i < n; i++) bytes[i] = (byte)buf[i];
+ return Encoding.UTF8.GetString(bytes);
+ }
+
+ /// Write string into szAutoReply buffer as null-terminated UTF-8 (each byte stored as ushort).
+ public static void StringToSzAutoReply(string s, ushort[] buf)
+ {
+ if (buf == null || buf.Length == 0) return;
+ int maxLen = Math.Min(EC_ConfigConstants.EC_AUTOREPLY_LEN, buf.Length - 1);
+ byte[] bytes = Encoding.UTF8.GetBytes(s ?? string.Empty);
+ int n = Math.Min(bytes.Length, maxLen);
+ for (int i = 0; i < n; i++) buf[i] = bytes[i];
+ buf[n] = 0;
+ for (int i = n + 1; i < buf.Length; i++) buf[i] = 0;
+ }
+ [MarshalAs(UnmanagedType.U1)]
public float fCamTurnSpeed;
public float fCamZoomSpeed;
public byte nFontSize;
+ [MarshalAs(UnmanagedType.U1)]
public bool bAtk_Player;
+ [MarshalAs(UnmanagedType.U1)]
public bool bAtk_NoMafia;
+ [MarshalAs(UnmanagedType.U1)]
public bool bAtk_NoWhite;
+ [MarshalAs(UnmanagedType.U1)]
public bool bFontBold;
+ [MarshalAs(UnmanagedType.U1)]
public bool bBls_NoRed;
+ [MarshalAs(UnmanagedType.U1)]
public bool bBls_NoMafia;
+ [MarshalAs(UnmanagedType.U1)]
public bool bBls_Self;
+ [MarshalAs(UnmanagedType.U1)]
public bool bBlsRefuse_Neutral;
+ [MarshalAs(UnmanagedType.U1)]
public bool bHideAutoGuide;
+ [MarshalAs(UnmanagedType.U1)]
public bool bAtk_NoAlliance;
+ [MarshalAs(UnmanagedType.U1)]
public bool bBls_NoAlliance;
+ [MarshalAs(UnmanagedType.U1)]
public bool bBlsRefuse_NonTeammate;
+ [MarshalAs(UnmanagedType.U1)]
public bool bAtk_NoForce;
+ [MarshalAs(UnmanagedType.U1)]
public bool bBls_NoForce;
+ [MarshalAs(UnmanagedType.U1)]
public bool bLockQuickBar;
+ [MarshalAs(UnmanagedType.U1)]
public bool bPetAutoSkill;
+ [MarshalAs(UnmanagedType.U1)]
public bool bAutoTeamForTask;
+ [MarshalAs(UnmanagedType.U1)]
public bool bDisableAutoWikiHelp;
+ [MarshalAs(UnmanagedType.U1)]
public bool bExclusiveAwardMode;
+ [MarshalAs(UnmanagedType.U1)]
public bool bHideIceThunderBall;
public void Reset()
@@ -298,7 +384,7 @@ namespace BrewMonster
bTurnaround = false;
bReverseWheel = false;
bAutoReply = false;
- szAutoReply = "";
+ szAutoReply = new ushort[EC_ConfigConstants.EC_AUTOREPLY_LEN + 1]; // empty string (first byte 0)
fCamTurnSpeed = 10.0f;
fCamZoomSpeed = 1.0f;
nFontSize = 2;
@@ -324,7 +410,7 @@ namespace BrewMonster
bHideIceThunderBall = false;
// Initialize channel array with default values
- bChannel = new bool[EC_ConfigConstants.EC_USERCHANNEL_NUM * 15];
+ bChannel = new byte[EC_ConfigConstants.EC_USERCHANNEL_NUM * 15];
bool[,] a_bChannel = new bool[,]
{
{ true, true, true, true, true, false, false, true, true, true, false, true, true, true, true },
@@ -339,7 +425,7 @@ namespace BrewMonster
{
for (int j = 0; j < 15; j++)
{
- bChannel[i * 15 + j] = a_bChannel[i, j];
+ bChannel[i * 15 + j] = (byte)(a_bChannel[i, j] ? 1 : 0);
}
}
}
@@ -359,7 +445,7 @@ namespace BrewMonster
{
for (int i = 0; i < EC_ConfigConstants.EC_USERCHANNEL_NUM * 15; i++)
{
- bChannel[i] = reader.ReadBoolean();
+ bChannel[i] = (byte)(reader.ReadBoolean() ? 1 : 0);
}
}
else if (dwVer >= 26)
@@ -367,7 +453,7 @@ namespace BrewMonster
for (int i = 0; i < EC_ConfigConstants.EC_USERCHANNEL_NUM * 14; i++)
{
if (i < bChannel.Length)
- bChannel[i] = reader.ReadBoolean();
+ bChannel[i] = (byte)(reader.ReadBoolean() ? 1 : 0);
}
}
else
@@ -375,12 +461,17 @@ namespace BrewMonster
for (int i = 0; i < EC_ConfigConstants.EC_USERCHANNEL_NUM * 13; i++)
{
if (i < bChannel.Length)
- bChannel[i] = reader.ReadBoolean();
+ bChannel[i] = (byte)(reader.ReadBoolean() ? 1 : 0);
}
}
bAutoReply = reader.ReadBoolean();
- szAutoReply = Encoding.UTF8.GetString(reader.ReadBytes(EC_ConfigConstants.EC_AUTOREPLY_LEN + 1)).TrimEnd('\0');
+ // Binary format: 65 bytes UTF-8; store each byte in ushort[] for struct layout
+ if (szAutoReply == null || szAutoReply.Length < EC_ConfigConstants.EC_AUTOREPLY_LEN + 1)
+ szAutoReply = new ushort[EC_ConfigConstants.EC_AUTOREPLY_LEN + 1];
+ byte[] autoReplyBytes = reader.ReadBytes(EC_ConfigConstants.EC_AUTOREPLY_LEN + 1);
+ for (int i = 0; i < autoReplyBytes.Length; i++)
+ szAutoReply[i] = autoReplyBytes[i];
fCamTurnSpeed = reader.ReadSingle();
fCamZoomSpeed = reader.ReadSingle();
nFontSize = reader.ReadByte();
@@ -472,6 +563,7 @@ namespace BrewMonster
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct ITEM_GROUP
{
+ [MarshalAs(UnmanagedType.U1)]
public bool enable;
public int item;
public sbyte percent;
@@ -701,7 +793,9 @@ namespace BrewMonster
public uint m_dwDefAmbient;
// Test code, temporary parameters
+ [MarshalAs(UnmanagedType.U1)]
public bool m_bShowForest = true;
+ [MarshalAs(UnmanagedType.U1)]
public bool m_bShowGrassLand = true;
// Configs user cannot change
@@ -721,32 +815,48 @@ namespace BrewMonster
private string m_strWindowsTitle = "Element Client";
private string m_strMiniDLTitle = "";
private int m_iClientID = -1;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bRegisterUIScriptFunc = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bEnableGT = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bEnableArc = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bEnableArcAsia = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bMiniClient = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bSendLogicCheckInfo = false;
private List m_strThemeFiles = new List();
// DEBUG only settings
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bConsole = false;
private int m_iRTDebug = 1;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bShowNPCID = false;
private float m_fRunSpeed = 5.0f;
private float m_fWalkSpeed = 2.0f;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bTestDist = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bShowPos = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bGameStat = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bShowID = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bSkipFrame = false;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bModelUpt = true;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bDebugFog = false;
private float m_fDebugFogStart = 10.0f;
private float m_fDebugFogEnd = 100.0f;
private float m_fDebugFogDensity = 0.5f;
private uint m_dwDebugFogColor = 0xFFFFFFFF;
+ [MarshalAs(UnmanagedType.U1)]
private bool m_bAdjusting = false;
// User settings
@@ -1063,6 +1173,32 @@ namespace BrewMonster
return true;
}
+ ///
+ /// Write user config data into buffer at given offset. 在指定偏移处写入用户配置数据。
+ ///
+ public bool SaveUserConfigData(byte[] pDataBuf, int startIndex, out int piSize)
+ {
+ if (startIndex < 0) { piSize = 0; return false; }
+ piSize = 0;
+ int iTotalSize = 0;
+ iTotalSize += sizeof(uint);
+ iTotalSize += Marshal.SizeOf(typeof(EC_VIDEO_SETTING));
+ iTotalSize += Marshal.SizeOf(typeof(EC_GAME_SETTING));
+ iTotalSize += Marshal.SizeOf(typeof(EC_BLACKLIST_SETTING));
+ iTotalSize += Marshal.SizeOf(typeof(EC_COMPUTER_AIDED_SETTING));
+
+ if (pDataBuf != null && startIndex + iTotalSize <= pDataBuf.Length)
+ {
+ using (MemoryStream ms = new MemoryStream(pDataBuf, startIndex, pDataBuf.Length - startIndex))
+ using (BinaryWriter writer = new BinaryWriter(ms))
+ {
+ writer.Write((uint)EC_ConfigConstants.EC_CONFIG_VERSION);
+ }
+ }
+ piSize = iTotalSize;
+ return true;
+ }
+
public void DefaultUserConfigData()
{
DefaultUserSettings(ref m_ss, ref m_vs, ref m_gs, ref m_bs, ref m_cas);
@@ -1246,9 +1382,12 @@ namespace BrewMonster
private void Verify()
{
// Verify game setting
- if (m_gs.szAutoReply != null && m_gs.szAutoReply.Length > EC_ConfigConstants.EC_AUTOREPLY_LEN)
+ string autoReplyStr = EC_GAME_SETTING.SzAutoReplyToString(m_gs.szAutoReply);
+ if (autoReplyStr.Length > EC_ConfigConstants.EC_AUTOREPLY_LEN)
{
- m_gs.szAutoReply = m_gs.szAutoReply.Substring(0, EC_ConfigConstants.EC_AUTOREPLY_LEN);
+ if (m_gs.szAutoReply == null || m_gs.szAutoReply.Length < EC_ConfigConstants.EC_AUTOREPLY_LEN + 1)
+ m_gs.szAutoReply = new ushort[EC_ConfigConstants.EC_AUTOREPLY_LEN + 1];
+ EC_GAME_SETTING.StringToSzAutoReply(autoReplyStr.Substring(0, EC_ConfigConstants.EC_AUTOREPLY_LEN), m_gs.szAutoReply);
}
if (m_gs.nFontSize > 4)
@@ -1347,6 +1486,7 @@ namespace BrewMonster
public void SaveBlockedID()
{
+ // TODO
// Note: Would need character ID
// string strDir = Path.Combine(Application.persistentDataPath, "userdata", "blacklist");
// Directory.CreateDirectory(strDir);
diff --git a/Assets/PerfectWorld/Scripts/Common/EC_PendingAction.cs b/Assets/PerfectWorld/Scripts/Common/EC_PendingAction.cs
new file mode 100644
index 0000000000..aedf88b999
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/Common/EC_PendingAction.cs
@@ -0,0 +1,314 @@
+// Filename : EC_PendingAction.cs
+// Creator : Xu Wenbin
+// Date : 2011/11/09
+// Converted from C++: EC_PendingAction.cpp / EC_PendingAction.h
+
+using System.Collections.Generic;
+using BrewMonster;
+using BrewMonster.Network;
+using BrewMonster.UI;
+using CSNetwork;
+using UnityEngine;
+
+// Logout type constants (C++: gnetdef.h)
+// _PLAYER_LOGOUT_FULL 0, _PLAYER_LOGOUT_HALF 1
+public static class PendingActionConstants
+{
+ public const int _PLAYER_LOGOUT_FULL = 0;
+ public const int _PLAYER_LOGOUT_HALF = 1;
+}
+
+// CECPendingAction — base class for delayed/pending actions
+public abstract class CECPendingAction
+{
+ // 执行的时限 / Execution time limit
+ private readonly CECCounter m_Counter;
+ // 是否还需要执行 / Whether still needs to execute
+ private bool m_bNeedExecute;
+ // 是否收到外界执行指示 / Whether received external execute trigger
+ private bool m_bTriggered;
+ // 执行结果:是否成功执行 / Execute result: whether executed successfully
+ private bool m_bExecuteResult;
+
+ public CECPendingAction(uint dwTimerPeriod)
+ {
+ m_Counter = new CECCounter();
+ m_Counter.SetPeriod((float)dwTimerPeriod);
+ m_bNeedExecute = true;
+ m_bTriggered = false;
+ m_bExecuteResult = false;
+ }
+
+ public void Update(uint dwElapsedTime)
+ {
+ if (GetNeedExecute())
+ {
+ // 每次都尝试执行 / Try execute every time
+ if (m_Counter.IncCounter((float)dwElapsedTime))
+ {
+ // 计时器到 / Timer reached
+ // 强制执行 / Force execute
+ m_bExecuteResult = Execute();
+ // 不需要再进行尝试 / No need to try again
+ m_bNeedExecute = false;
+ }
+ // else 计时中 / else counting
+ }
+ }
+
+ public void Trigger()
+ {
+ if (!GetNeedExecute())
+ {
+ // 计时器已经强制执行,不需要再触发执行 / Timer already forced execute, no need to trigger again
+ return;
+ }
+ if (GetTriggered())
+ {
+ // 不允许多次触发 / Multiple trigger not allowed
+ return;
+ }
+ m_bTriggered = true;
+ m_bExecuteResult = Execute();
+ m_bNeedExecute = false;
+ }
+
+ public bool GetNeedExecute() => m_bNeedExecute;
+ public bool GetTriggered() => m_bTriggered;
+
+ public abstract string GetName();
+
+ protected abstract bool Execute();
+
+ // Whether currently in game (session connected, game state in-game, host ready)
+ protected bool IsInGame()
+ {
+ var pSession = GetGameSession();
+ var pGameRun = GetGameRun();
+ var pHost = pGameRun?.GetHostPlayer();
+ return pSession != null
+ && pSession.IsConnected
+ && pGameRun != null
+ && pGameRun.GetGameState() == (int)GameState.GS_GAME
+ && pHost != null
+ && pHost.HostIsReady();
+ }
+
+ protected static CECGameRun GetGameRun() => EC_Game.GetGameRun();
+ protected static GameSession GetGameSession() => UnityGameSession.Instance?.GameSession;
+ protected static CECHostPlayer GetHostPlayer() => GetGameRun()?.GetHostPlayer();
+}
+
+// 游戏小退 / Game logout (half — back to select role)
+public class CECPendingLogoutHalf : CECPendingAction
+{
+ public CECPendingLogoutHalf(uint dwTimerPeriod = 5000) : base(dwTimerPeriod) { }
+
+ protected override bool Execute()
+ {
+ bool bSuccess = false;
+ if (IsInGame())
+ {
+ GetGameSession().SendPlayerLogout(PendingActionConstants._PLAYER_LOGOUT_HALF);
+ bSuccess = true;
+ }
+ return bSuccess;
+ }
+
+ public override string GetName() => "CECPendingLogoutHalf";
+}
+
+// 游戏大退 / Game logout (full — account logout)
+public class CECPendingLogoutFull : CECPendingAction
+{
+ public CECPendingLogoutFull(uint dwTimerPeriod = 5000) : base(dwTimerPeriod) { }
+
+ protected override bool Execute()
+ {
+ bool bSuccess = false;
+ if (IsInGame())
+ {
+ GetGameSession().SendPlayerLogout(PendingActionConstants._PLAYER_LOGOUT_FULL);
+ bSuccess = true;
+ }
+ return bSuccess;
+ }
+
+ public override string GetName() => "CECPendingLogoutFull";
+}
+
+// 寄售角色 / Selling role
+public class CECPendingSellingRole : CECPendingAction
+{
+ public CECPendingSellingRole(uint dwTimerPeriod = 5000) : base(dwTimerPeriod) { }
+
+ protected override bool Execute()
+ {
+ bool bSuccess = false;
+ if (IsInGame())
+ {
+ GetGameSession().SendPlayerLogout(PendingActionConstants._PLAYER_LOGOUT_HALF);
+ GetGameRun().SetSellingRoleID(GetHostPlayer().GetCharacterID());
+ bSuccess = true;
+ }
+ return bSuccess;
+ }
+
+ public override string GetName() => "CECPendingSellingRole";
+}
+
+// 跨服小退 / Cross-server logout (half)
+public class CECPendingLogoutCrossServer : CECPendingAction
+{
+ public CECPendingLogoutCrossServer(uint dwTimerPeriod = 5000) : base(dwTimerPeriod) { }
+
+ protected override bool Execute()
+ {
+ GetGameRun().SetLogoutFlag(2);
+ return true;
+ }
+
+ public override string GetName() => "CECPendingLogoutCrossServer";
+}
+
+// 进出跨服 / Cross-server get in or out
+// m_bGetIn: 进入跨服时为 true;否则为 false / true when entering cross-server; otherwise false
+public class CECPendingCrossServerGetInOut : CECPendingAction
+{
+ private readonly bool m_bGetIn;
+
+ public CECPendingCrossServerGetInOut(bool bGetIn, uint dwTimerPeriod = 5000)
+ : base(dwTimerPeriod)
+ {
+ m_bGetIn = bGetIn;
+ }
+
+ protected override bool Execute()
+ {
+ bool bSuccess = false;
+ if (IsInGame())
+ {
+ var session = GetGameSession();
+ if (session != null)
+ {
+ if (m_bGetIn)
+ session.c2s_CmdNPCSevCrossServerGetIn();
+ else
+ session.c2s_CmdNPCSevCrossServerGetOut();
+ }
+ }
+ var pGameUIMan = GetGameRun()?.GetUIManager()?.GetInGameUIMan();
+ if (pGameUIMan is CECGameUIMan inGameUIMan)
+ inGameUIMan.EndNPCService();
+ return bSuccess;
+ }
+
+ public override string GetName() => "CECPendingCrossServerGetInOut";
+}
+
+// CECPendingActionArray — container for multiple pending actions
+public class CECPendingActionArray
+{
+ private readonly List m_actions = new List();
+ private bool m_bAllowMultiActions;
+
+ public CECPendingActionArray(bool bAllowMultiActions)
+ {
+ m_bAllowMultiActions = bAllowMultiActions;
+ }
+
+ ~CECPendingActionArray()
+ {
+ Clear();
+ }
+
+ public void Append(CECPendingAction pAction)
+ {
+ // 添加新事件 / Add new event
+ if (pAction == null)
+ {
+ Debug.Assert(false);
+ return;
+ }
+ if (!pAction.GetNeedExecute())
+ {
+ Debug.Assert(false);
+ return;
+ }
+ if (!GetAllowMultiAction())
+ Clear();
+ m_actions.Add(pAction);
+ }
+
+ public void AppendForSaveConfig(CECPendingAction pAction)
+ {
+ if (pAction == null)
+ {
+ Debug.Assert(false);
+ return;
+ }
+ if (!pAction.GetNeedExecute())
+ {
+ Debug.Assert(false);
+ return;
+ }
+ uint saveResult = EC_Game.GetGameRun().SaveConfigsToServer();
+ if (saveResult != 2)
+ {
+ pAction.Trigger();
+ return;
+ }
+ Append(pAction);
+ }
+
+ public void Update(uint dwElapsedTime)
+ {
+ if (m_actions.Count == 0) return;
+
+ for (int i = m_actions.Count - 1; i >= 0; i--)
+ {
+ CECPendingAction pAction = m_actions[i];
+ pAction.Update(dwElapsedTime);
+ if (!pAction.GetNeedExecute())
+ {
+ m_actions.RemoveAt(i);
+ }
+ }
+ }
+
+ public void TriggerAll()
+ {
+ if (m_actions.Count == 0) return;
+
+ foreach (var pAction in m_actions)
+ {
+ if (pAction.GetNeedExecute())
+ pAction.Trigger();
+ }
+ }
+
+ public void Clear()
+ {
+ // 清除当前所有事件 / Clear all current events
+ if (m_actions.Count == 0) return;
+
+ m_actions.Clear();
+ }
+
+ public void SetAllowMultiAction(bool bAllow)
+ {
+ if (GetAllowMultiAction() == bAllow) return;
+
+ m_bAllowMultiActions = bAllow;
+
+ // 按时间先后顺序,只保留队列最后一个 / By time order, keep only the last one in queue
+ if (!bAllow && m_actions.Count > 1)
+ {
+ var last = m_actions[m_actions.Count - 1];
+ m_actions.Clear();
+ m_actions.Add(last);
+ }
+ }
+
+ public bool GetAllowMultiAction() => m_bAllowMultiActions;
+}
diff --git a/Assets/PerfectWorld/Scripts/Common/EC_PendingAction.cs.meta b/Assets/PerfectWorld/Scripts/Common/EC_PendingAction.cs.meta
new file mode 100644
index 0000000000..9e17475b3a
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/Common/EC_PendingAction.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a8fc69213d734cb49b1b381a760ae418
+timeCreated: 1770180043
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs
new file mode 100644
index 0000000000..10414ecd66
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Runtime.InteropServices;
+using EditorAttributes;
+// using NaughtyAttributes;
+using UnityEngine;
+
+namespace BrewMonster
+{
+ public class TestByteNumber : MonoBehaviour
+ {
+
+ // Start is called once before the first execution of Update after the MonoBehaviour is created
+ void Start()
+ {
+
+ }
+
+ [ContextMenu("Test")]
+ public void Test()
+ {
+ var origin = Marshal.SizeOf();
+ var diff = Marshal.SizeOf() - Marshal.SizeOf();
+ BMLogger.Log($" Origin : {origin } - diff = {diff}"); // 255
+ }
+
+ [ContextMenu(" TestCompress")]
+ public void TestCompress()
+ {
+ int value = 123456;
+ byte[] src = BitConverter.GetBytes(value);
+
+ int dstLen = 10000;
+ byte[] dst = new byte[dstLen];
+
+ int res = AFilePackage.Compress( src, 0, src.Length, dst, 0, ref dstLen);
+
+ BMLogger.Log($" Res : {res} - srcLen = {src.Length} - dstLen = {dstLen} - compressed data: {BitConverter.ToString(dst, 0, dstLen)}");
+ }
+
+ }
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
+ public struct EC_GAME_SETTING_TEST
+ {
+ [MarshalAs(UnmanagedType.U1)] public bool bNoTeamRequest;
+ [MarshalAs(UnmanagedType.U1)] public bool bNoTradeRequest;
+ [MarshalAs(UnmanagedType.U1)] public bool bTurnaround;
+ [MarshalAs(UnmanagedType.U1)] public bool bReverseWheel;
+
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = EC_ConfigConstants.EC_USERCHANNEL_NUM * 15,
+ ArraySubType = UnmanagedType.I1)] // GP_CHAT_MAX = 15; I1 = 1 byte per bool to match C++ bool[6][15]
+ public byte[] bChannel;
+ [MarshalAs(UnmanagedType.U1)]
+ public bool bAutoReply;
+
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = EC_ConfigConstants.EC_AUTOREPLY_LEN + 1)]
+ public string szAutoReply;
+
+ [MarshalAs(UnmanagedType.U1)] public float fCamTurnSpeed;
+ public float fCamZoomSpeed;
+ public byte nFontSize;
+ [MarshalAs(UnmanagedType.U1)] public bool bAtk_Player;
+ [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoMafia;
+ [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoWhite;
+ [MarshalAs(UnmanagedType.U1)] public bool bFontBold;
+ [MarshalAs(UnmanagedType.U1)] public bool bBls_NoRed;
+ [MarshalAs(UnmanagedType.U1)] public bool bBls_NoMafia;
+ [MarshalAs(UnmanagedType.U1)] public bool bBls_Self;
+ [MarshalAs(UnmanagedType.U1)] public bool bBlsRefuse_Neutral;
+ [MarshalAs(UnmanagedType.U1)] public bool bHideAutoGuide;
+ [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoAlliance;
+ [MarshalAs(UnmanagedType.U1)] public bool bBls_NoAlliance;
+ [MarshalAs(UnmanagedType.U1)] public bool bBlsRefuse_NonTeammate;
+ [MarshalAs(UnmanagedType.U1)] public bool bAtk_NoForce;
+ [MarshalAs(UnmanagedType.U1)] public bool bBls_NoForce;
+ [MarshalAs(UnmanagedType.U1)] public bool bLockQuickBar;
+ [MarshalAs(UnmanagedType.U1)] public bool bPetAutoSkill;
+ [MarshalAs(UnmanagedType.U1)] public bool bAutoTeamForTask;
+ [MarshalAs(UnmanagedType.U1)] public bool bDisableAutoWikiHelp;
+ [MarshalAs(UnmanagedType.U1)] public bool bExclusiveAwardMode;
+ [MarshalAs(UnmanagedType.U1)] public bool bHideIceThunderBall;
+
+ }
+}
diff --git a/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs.meta b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs.meta
new file mode 100644
index 0000000000..dafe0fb5d3
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/Debug/TestByteNumber.cs.meta
@@ -0,0 +1,2 @@
+fileFormatVersion: 2
+guid: 67551ceb317224e67b8140cbe7175c44
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs
index 0480c3265f..93f3700dce 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_Inventory.cs
@@ -60,7 +60,7 @@ namespace BrewMonster.Scripts.Managers
}
}
- public void Resize(int iNewSize)
+ public virtual void Resize(int iNewSize)
{
int oldSize = m_aItems.Length;
if (iNewSize < 0) iNewSize = 0;
diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
index 6af6da8af6..9a7b008637 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_InventoryUI.cs
@@ -4,6 +4,7 @@ using BrewMonster.Network;
using BrewMonster.Scripts;
using BrewMonster.Scripts.UI;
using BrewMonster.Scripts.Task.UI;
+using BrewMonster.UI;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using PerfectWorld.Scripts.Managers;
diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrPetEgg.cs b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrPetEgg.cs
index 9cbea2a6f4..b6b46dc274 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrPetEgg.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_IvtrItem/EC_IvtrPetEgg.cs
@@ -435,6 +435,8 @@ namespace PerfectWorld.Scripts.Managers
return ByteToStringUtils.ByteArrayToCP936String(m_pDBEssence.file_matter);
}
+ // Get essence data
+ public IVTR_ESSENCE_PETEGG GetEssence() { return m_Essence; }
}
}
diff --git a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs
index 8c93446808..f387e0a2ca 100644
--- a/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs
+++ b/Assets/PerfectWorld/Scripts/Managers/EC_ManPlayer.cs
@@ -109,6 +109,9 @@ namespace PerfectWorld.Scripts.Managers
}
TransmitMessage(Msg);
break;
+ case EC_MsgDef.MSG_PM_PLAYEREXIT:
+ OnMsgPlayerExit(Msg);
+ break;
}
}
else
@@ -819,6 +822,13 @@ namespace PerfectWorld.Scripts.Managers
}
}
}
+ // Handler of MSG_PM_PLAYEREXIT
+ public bool OnMsgPlayerExit(ECMSG Msg)
+ {
+ cmd_player_leave_world pCmd = GPDataTypeHelper.FromBytes((byte[])Msg.dwParam1);
+ ElsePlayerLeave(pCmd.id, true);
+ return true;
+ }
}
}
public struct EC_PLAYERLOADRESULT
diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs
index 134c0a1950..fc89bfc0a0 100644
--- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs
+++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommand.cs
@@ -1618,6 +1618,13 @@ namespace CSNetwork.S2CCommand
{
public int[] cmdParams;
}
+
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct CONTENTNPCSevHatchPet
+ {
+ public int iIvtrIdx;
+ public int idEgg;
+ };
}
// Player and NPC state
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs
index 4ed0b279d7..4454386567 100644
--- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs
+++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs
@@ -1066,5 +1066,20 @@ namespace CSNetwork.C2SCommand
}
return SerializeCommand(icmd, cmd, false);
}
+
+ public static Octets CreateNPCSevHatchPetCmd(int i_IvtrIdx, int i_idEgg)
+ {
+ var cmd = new cmd_sevnpc_serve
+ {
+ service_type = NPC_service_type.GP_NPCSEV_HATCHPET,
+ len = (uint)Marshal.SizeOf()
+ };
+ CONTENTNPCSevHatchPet content = new CONTENTNPCSevHatchPet()
+ {
+ iIvtrIdx = i_IvtrIdx,
+ idEgg = i_idEgg,
+ };
+ return SerializeCommand(CommandID.SEVNPC_SERVE, cmd, content);
+ }
}
}
diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs
index d661617ad6..a2f2c05aea 100644
--- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs
+++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GPDataType.cs
@@ -2589,5 +2589,12 @@ namespace CSNetwork.GPDataType
public ushort equip_idx;
public uint cost;
};
+
+ // player leaves the world
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct cmd_player_leave_world
+ {
+ public int id;
+ };
}
diff --git a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
index 850bc8fc45..42a2904543 100644
--- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
+++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
@@ -749,6 +749,7 @@ namespace CSNetwork
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CORRECTPOS, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf,
pCmdHeader, iHostID);
break;
+ case CommandID.EMPTY_ITEM_SLOT:
case CommandID.OWN_ITEM_INFO:
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_OWNITEMINFO, (int)MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf,
pCmdHeader, iHostID);
@@ -1140,6 +1141,15 @@ namespace CSNetwork
case CommandID.CLEAR_TESSERA:
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_CLEARTESSERA, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader);
break;
+ case CommandID.PLAYER_LEAVE_WORLD:
+ {
+ cmd_player_leave_world pCmd = GPDataTypeHelper.FromBytes(pDataBuf);
+ if (ISPLAYERID(pCmd.id))
+ {
+ EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_PLAYEREXIT, MANAGER_INDEX.MAN_PLAYER, -1, pDataBuf, pCmdHeader);
+ }
+ break;
+ }
default:
#if UNITY_EDITOR
if (isDebug)
@@ -1508,6 +1518,27 @@ namespace CSNetwork
p.Roleid = m_iCharID;
SendProtocol(p);
}
+
+ ///
+ /// Save config data to server (sends setuiconfig with compressed config blob).
+ /// 保存配置数据到服务器(发送 setuiconfig 及压缩后的配置数据)。
+ ///
+ 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;
+ p.Localsid = (int)_localsid;
+ byte[] slice = new byte[len];
+ Buffer.BlockCopy(pBuf, 0, slice, 0, len);
+ p.Ui_config = new Octets(slice);
+
+ // return;
+ SendProtocol(p);
+ }
+
private void SetCharacterID(int iCharID)
{
m_iCharID = iCharID;
@@ -1984,5 +2015,23 @@ namespace CSNetwork
gamedatasend.Data = C2SCommandFactory.CreateDebugCmd(icmd, param1);
SendProtocol(gamedatasend);
}
+ public void c2s_SendCmdNPCSevHatchPet(int iIvtrIdx, int idEgg)
+ {
+ gamedatasend gamedatasend = new gamedatasend();
+ gamedatasend.Data = C2SCommandFactory.CreateNPCSevHatchPetCmd(iIvtrIdx, idEgg);
+ SendProtocol(gamedatasend);
+ }
+
+ // Cross-server get in (C++: c2s_CmdNPCSevCrossServerGetIn) — TODO: implement C2S packet when needed
+ public void c2s_CmdNPCSevCrossServerGetIn()
+ {
+ // TODO: C2SCommandFactory.CreateNPCSevCrossServerGetInCmd() and SendProtocol
+ }
+
+ // Cross-server get out (C++: c2s_CmdNPCSevCrossServerGetOut) — TODO: implement C2S packet when needed
+ public void c2s_CmdNPCSevCrossServerGetOut()
+ {
+ // TODO: C2SCommandFactory.CreateNPCSevCrossServerGetOutCmd() and SendProtocol
+ }
}
}
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs
index 8411996fe8..b691ce7962 100644
--- a/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs
+++ b/Assets/PerfectWorld/Scripts/Network/UnityGameSession.cs
@@ -779,6 +779,10 @@ namespace BrewMonster.Network
{
Instance._gameSession.c2s_CmdDebug(icmd, param1);
}
+ public static void c2s_CmdNPCSevHatchPet(int iIvtrIdx, int idEgg)
+ {
+ Instance._gameSession.c2s_SendCmdNPCSevHatchPet(iIvtrIdx, idEgg);
+ }
}
///
diff --git a/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs
index b1828deadf..a213c693be 100644
--- a/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs
+++ b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs
@@ -168,21 +168,21 @@ namespace BrewMonster
///
/// Create an auto fashion shortcut at specified position
///
- /* public bool CreateAutoFashionShortcut(int iSlot, int iFashionIdx)
- {
- CECSCAutoFashion pAutoFashionSC = new CECSCAutoFashion();
- if (pAutoFashionSC == null)
- return false;
-
- if (!pAutoFashionSC.Init(iFashionIdx))
- {
- Debug.LogError("CECShortcutSet::CreateAutoFashionShortcut, Failed to initialize auto fashion shortcut");
- return false;
- }
-
- SetShortcut(iSlot, pAutoFashionSC);
- return true;
- }
+ // public bool CreateAutoFashionShortcut(int iSlot, int iFashionIdx)
+ // {
+ // CECSCAutoFashion pAutoFashionSC = new CECSCAutoFashion();
+ // if (pAutoFashionSC == null)
+ // return false;
+ //
+ // if (!pAutoFashionSC.Init(iFashionIdx))
+ // {
+ // Debug.LogError("CECShortcutSet::CreateAutoFashionShortcut, Failed to initialize auto fashion shortcut");
+ // return false;
+ // }
+ //
+ // SetShortcut(iSlot, pAutoFashionSC);
+ // return true;
+ // }
///
/// Create a system module shortcut at specified position
@@ -201,7 +201,7 @@ namespace BrewMonster
SetShortcut(iSlot, pSysModule);
return true;
- }*/
+ }
///
/// Duplicate a shortcut to specified position
@@ -495,7 +495,10 @@ namespace BrewMonster
// Record shortcut's position and type
data.AddRange(BitConverter.GetBytes(i));
data.AddRange(BitConverter.GetBytes((int)pSC.GetType()));
+
+ BMLogger.Log($"[MH] Saving shortcut slot: {i} Type: {pSC.GetType()}");
+ // TODO: implement other shortcut types
switch ((CECShortcut.ShortcutType)pSC.GetType())
{
/* case CECShortcut.ShortcutType.SCT_COMMAND:
@@ -513,45 +516,45 @@ namespace BrewMonster
break;
}
- /* case CECShortcut.ShortcutType.SCT_ITEM:
- {
- CECSCItem itemSC = (CECSCItem)pSC;
- data.AddRange(BitConverter.GetBytes(itemSC.GetInventory()));
- data.AddRange(BitConverter.GetBytes(itemSC.GetIvtrSlot()));
- data.AddRange(BitConverter.GetBytes(itemSC.GetItemTID()));
- break;
- }
+ // case CECShortcut.ShortcutType.SCT_ITEM:
+ // {
+ // CECSCItem itemSC = (CECSCItem)pSC;
+ // data.AddRange(BitConverter.GetBytes(itemSC.GetInventory()));
+ // data.AddRange(BitConverter.GetBytes(itemSC.GetIvtrSlot()));
+ // data.AddRange(BitConverter.GetBytes(itemSC.GetItemTID()));
+ // break;
+ // }
- case CECShortcut.ShortcutType.SCT_SKILLGRP:
- {
- CECSCSkillGrp skillGrpSC = (CECSCSkillGrp)pSC;
- data.AddRange(BitConverter.GetBytes(skillGrpSC.GetGroupIndex()));
- break;
- }
+ case CECShortcut.ShortcutType.SCT_SKILLGRP:
+ {
+ CECSCSkillGrp skillGrpSC = (CECSCSkillGrp)pSC;
+ data.AddRange(BitConverter.GetBytes(skillGrpSC.GetGroupIndex()));
+ break;
+ }
- case CECShortcut.ShortcutType.SCT_PET:
- {
- CECSCPet petSC = (CECSCPet)pSC;
- data.AddRange(BitConverter.GetBytes(petSC.GetPetIndex()));
- break;
- }
+ // case CECShortcut.ShortcutType.SCT_PET:
+ // {
+ // CECSCPet petSC = (CECSCPet)pSC;
+ // data.AddRange(BitConverter.GetBytes(petSC.GetPetIndex()));
+ // break;
+ // }
+ //
+ // case CECShortcut.ShortcutType.SCT_AUTOFASHION:
+ // {
+ // CECSCAutoFashion fashionSC = (CECSCAutoFashion)pSC;
+ // data.AddRange(BitConverter.GetBytes(fashionSC.GetAutoFashionIndex()));
+ // break;
+ // }
- case CECShortcut.ShortcutType.SCT_AUTOFASHION:
- {
- CECSCAutoFashion fashionSC = (CECSCAutoFashion)pSC;
- data.AddRange(BitConverter.GetBytes(fashionSC.GetAutoFashionIndex()));
- break;
- }
-
- case CECShortcut.ShortcutType.SCT_SYSMODULE:
- {
- CECSCSysModule sysSC = (CECSCSysModule)pSC;
- data.AddRange(BitConverter.GetBytes(sysSC.GetSysModID()));
- break;
- }*/
+ case CECShortcut.ShortcutType.SCT_SYSMODULE:
+ {
+ CECSCSysModule sysSC = (CECSCSysModule)pSC;
+ data.AddRange(BitConverter.GetBytes(sysSC.GetSysModID()));
+ break;
+ }
default:
- Debug.LogError("CECShortcutSet::SaveConfigData - Unknown shortcut type");
+ Debug.LogError($"CECShortcutSet::SaveConfigData - Unknown shortcut type = { pSC.GetType()}");
break;
}
}
@@ -587,6 +590,8 @@ namespace BrewMonster
int iSCType = GPDataTypeHelper.FromBytes(pDataBuf, offset);
offset += sizeof(int);
+
+ BMLogger.Log("[MH] Loading shortcut slot: " + iSlot + " Type: " + iSCType);
switch ((CECShortcut.ShortcutType)iSCType)
{
@@ -679,41 +684,41 @@ namespace BrewMonster
break;
}
- /*case CECShortcut.ShortcutType.SCT_PET:
- {
- if (dwVer >= 4)
- {
- int iPetIndex = BitConverter.ToInt32(pDataBuf, offset);
- offset += sizeof(int);
-
- if (iPetIndex >= 0)
- CreatePetShortcut(iSlot, iPetIndex);
- }
- else
- {
- Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for pet");
- return false;
- }
- break;
- }
-
- case CECShortcut.ShortcutType.SCT_AUTOFASHION:
- {
- if (dwVer >= 5)
- {
- int iAutoFashionIndex = BitConverter.ToInt32(pDataBuf, offset);
- offset += sizeof(int);
-
- if (iAutoFashionIndex >= 0)
- CreateAutoFashionShortcut(iSlot, iAutoFashionIndex);
- }
- else
- {
- Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for auto fashion");
- return false;
- }
- break;
- }
+ // case CECShortcut.ShortcutType.SCT_PET:
+ // {
+ // if (dwVer >= 4)
+ // {
+ // int iPetIndex = BitConverter.ToInt32(pDataBuf, offset);
+ // offset += sizeof(int);
+ //
+ // if (iPetIndex >= 0)
+ // CreatePetShortcut(iSlot, iPetIndex);
+ // }
+ // else
+ // {
+ // Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for pet");
+ // return false;
+ // }
+ // break;
+ // }
+ //
+ // case CECShortcut.ShortcutType.SCT_AUTOFASHION:
+ // {
+ // if (dwVer >= 5)
+ // {
+ // int iAutoFashionIndex = BitConverter.ToInt32(pDataBuf, offset);
+ // offset += sizeof(int);
+ //
+ // if (iAutoFashionIndex >= 0)
+ // CreateAutoFashionShortcut(iSlot, iAutoFashionIndex);
+ // }
+ // else
+ // {
+ // Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for auto fashion");
+ // return false;
+ // }
+ // break;
+ // }
case CECShortcut.ShortcutType.SCT_SYSMODULE:
{
@@ -731,7 +736,7 @@ namespace BrewMonster
return false;
}
break;
- }*/
+ }
/* default:
//TODO: uncomment
@@ -1168,6 +1173,98 @@ namespace BrewMonster
{
public CECSkill GetSkillByID(int id) => null;
}*/
+
+ // class CECSCSysModule : public CECShortcut
+ public class CECSCSysModule : CECShortcut
+ {
+ // public: // Types
+ // enum { FM_NONE = -1, FM_GT, FM_TOUCH, ... FM_NUM, };
+ public enum SysModuleType
+ {
+ FM_NONE = -1,
+ FM_GT,
+ FM_TOUCH,
+ FM_ROBOT, // 帮派系统 (Faction / Guild system)
+ FM_WIKI,
+ FM_OFFLINESHOP, // 摆摊 (Offline shop / Stall)
+ FM_BORADCAST, // 广播系统 (Broadcast system)
+ FM_MATCH, // 边缘系统 (Match system)
+ FM_ADDEXP, // 帮会系统 (Guild / Add exp system)
+ FM_AUTOHPMP, // 辅助功能,自动加药 (Auxiliary function, auto potion)
+
+ FM_NUM,
+ }
+
+ // public: // Attributes
+ // static const int g_SysIndexMap[FM_NUM];
+ public static readonly int[] g_SysIndexMap = new int[(int)SysModuleType.FM_NUM];
+
+ // protected: // Attributes
+ // ACString m_strDesc;
+ protected string m_strDesc;
+ // char m_IconFile[256];
+ protected string m_IconFile;
+ // int m_iSystem; // system ID
+ protected int m_iSystem;
+
+ // public: // Constructor and Destructor
+ // CECSCSysModule();
+ public CECSCSysModule()
+ {
+ m_iSCType = (int)ShortcutType.SCT_SYSMODULE;
+ m_strDesc = string.Empty;
+ m_IconFile = string.Empty;
+ m_iSystem = (int)SysModuleType.FM_NONE;
+ }
+
+ // CECSCSysModule(const CECSCSysModule& src);
+ public CECSCSysModule(CECSCSysModule src)
+ {
+ m_iSCType = src.m_iSCType;
+ m_strDesc = src.m_strDesc;
+ m_IconFile = src.m_IconFile;
+ m_iSystem = src.m_iSystem;
+ }
+
+ // virtual ~CECSCSysModule() {}
+ // (no destructor in C#)
+
+ // bool Init(int iSys);
+ public bool Init(int iSys)
+ {
+ m_iSystem = iSys;
+ // TODO: load m_strDesc and m_IconFile from config/table by iSys if needed
+ return true;
+ }
+
+ // virtual CECShortcut* Clone();
+ public override CECShortcut Clone()
+ {
+ return new CECSCSysModule(this);
+ }
+
+ // virtual bool Execute();
+ public override bool Execute()
+ {
+ // TODO: open corresponding system UI by m_iSystem (e.g. GT, Touch, Robot, Wiki, OfflineShop, Broadcast, Match, AddExp, AutoHpMp)
+ return true;
+ }
+
+ // int GetSysModID() const { return m_iSystem; }
+ public int GetSysModID() { return m_iSystem; }
+
+ // virtual const wchar_t* GetDesc();
+ public override string GetDesc()
+ {
+ return m_strDesc ?? string.Empty;
+ }
+
+ public override string GetIconFile()
+ {
+ return string.IsNullOrEmpty(m_IconFile) ? "unknown" : m_IconFile;
+ }
+ }
+
#endregion
}
diff --git a/Assets/PerfectWorld/Scripts/Pet/EC_PetCorral.cs b/Assets/PerfectWorld/Scripts/Pet/EC_PetCorral.cs
index 004b6a6a8c..03c94f7e96 100644
--- a/Assets/PerfectWorld/Scripts/Pet/EC_PetCorral.cs
+++ b/Assets/PerfectWorld/Scripts/Pet/EC_PetCorral.cs
@@ -307,7 +307,7 @@ namespace BrewMonster.Scripts.Pet
m_iPetSlotNum = iNewNum;
}
// Check whether corral has empty slots
- int GetEmptySlotNum()
+ public int GetEmptySlotNum()
{
int iCount = 0;
diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs
index 53dec1542c..26500fc7f6 100644
--- a/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs
+++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/CDlgDragDrop.cs
@@ -9,13 +9,13 @@ namespace BrewMonster
#if UNITY_EDITOR
private void Update()
{
- if (Input.GetKeyDown(KeyCode.S))
+ if (Input.GetKeyDown(KeyCode.S) )
OnSkillDragDrop();
}
#endif
public void OnSkillDragDrop()
{
- var iSlot = 2;
+ var iSlot = 1;
var nCombo = 2;
CECShortcutSet pSCS = CECUIManager.Instance.GetInGameUIMan().GetSCSByDlg(1);
if (pSCS.GetShortcut(iSlot - 1) == null || !EC_Game.GetConfigs().GetGameSettings().bLockQuickBar)
diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs
index c66c6cc399..2c791c6861 100644
--- a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs
+++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgNPC.cs
@@ -2387,10 +2387,12 @@ namespace BrewMonster.UI
}
else if (iService == CDLGNPC.CDLGNPC_PETREC && (pEssence?.combined_services & 0x400) != 0)
{
- Show(false);
+ //Show(false);
// TO DO: fix later
//GetGameUIMan().m_pDlgPetList.Show(true);
//GetGameUIMan().m_pDlgPetRec.Show(true);
+ var dlgPetRec = GetGameUIMan().GetDialog("DlgPetRec");
+ dlgPetRec.Show(true);
return;
}
else if (iService == CDLGNPC.CDLGNPC_BATTLECHALLENGE && (pEssence?.combined_services & 0x800) != 0)
diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgPetHatch.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgPetHatch.cs
index f3cacdb8c7..32eec2e3e5 100644
--- a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgPetHatch.cs
+++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgPetHatch.cs
@@ -12,6 +12,7 @@ using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
+using static BrewMonster.Scripts.Managers.EC_Inventory;
namespace BrewMonster.UI
{
@@ -332,7 +333,8 @@ namespace BrewMonster.UI
detailedItem.GetDetailDataFromLocal();
}
- EC_IvtrPetEgg petEgg = detailedItem as EC_IvtrPetEgg;
+ //EC_IvtrPetEgg petEgg = detailedItem as EC_IvtrPetEgg;
+ EC_IvtrPetEgg petEgg = item as EC_IvtrPetEgg;
if(petEgg == null)
{
return;
@@ -349,7 +351,7 @@ namespace BrewMonster.UI
m_pCurrentEgg = petEgg;
m_nSlot = slotIndex;
-
+ SetDataPtr(petEgg, "");
petEgg.Freeze(true);
UpdateEggUI(petEgg);
SetInventorySlotGray(btn, true);
@@ -522,7 +524,18 @@ namespace BrewMonster.UI
private void OnCommandConfirm()
{
- //TODO: Send hatch command to server with m_pCurrentEgg
+ EC_IvtrItem pItem = (EC_IvtrItem)(GetDataPtr(""));
+ if (pItem != null)
+ {
+ pItem.Freeze(false);
+ GetHostPlayer().HatchPet(m_nSlot);
+ Debug.LogError("m_nSlot = " + m_nSlot);
+ SetDataPtr(null, "");
+ GetGameUIMan().EndNPCService();
+ Show(false);
+ GetGameUIMan().GetDialog("Win_Inventory").Show(false);
+ GetHostPlayer().GetPack(Inventory_type.IVTRTYPE_PACK).UnfreezeAllItems();
+ }
}
private void OnCommandCancel()
@@ -530,7 +543,7 @@ namespace BrewMonster.UI
ClearEgg();
GetGameUIMan().EndNPCService();
Show(false);
- GetHostPlayer().GetPack(InventoryConst.IVTRTYPE_PACK).UnfreezeAllItems();
+ GetHostPlayer().GetPack(Inventory_type.IVTRTYPE_PACK).UnfreezeAllItems();
}
public void SetEgg(EC_IvtrItem pItem, int nSlot)
diff --git a/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgPetRec.cs b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgPetRec.cs
new file mode 100644
index 0000000000..19a08232a3
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/UI/Dialogs/DlgPetRec.cs
@@ -0,0 +1,606 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using BrewMonster.Network;
+using BrewMonster.Scripts.Pet;
+using TMPro;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+
+namespace BrewMonster.UI
+{
+ public class DlgPetRec : AUIDialog
+ {
+ public const int PETSLOT_MAX = 20;
+ [Header("Component")]
+ [SerializeField] private TextMeshProUGUI m_pTxt_Gold;
+ [SerializeField] private TextMeshProUGUI m_pTxt_Name;
+ [SerializeField] private Image m_pImg_Item;
+
+ [Header("Pet List")]
+ [SerializeField] private Button[] m_pBtn_PetSlots = new Button[PETSLOT_MAX];
+
+ [Header("Button")]
+ [SerializeField] private Button m_btnComfirm;
+ [SerializeField] private Button m_btnCancle;
+ [SerializeField] private Button m_btnClose;
+
+ [Header("Icon Default")]
+ [SerializeField] private Sprite m_defaultIcon;
+
+ private int m_nSlot = -1;
+ private CECPetData m_pCurrentPet = null;
+ private CECPetData[] m_petSlots = new CECPetData[PETSLOT_MAX];
+
+ private float m_doubleClickTime = 0.3f;
+ private Dictionary m_lastClickTime = new Dictionary();
+ private GameObject m_draggedIcon = null;
+
+ public override void Awake()
+ {
+ base.Awake();
+ RegisterTargetSlotEvents(m_pImg_Item.transform);
+
+ for (int i = 0; i < PETSLOT_MAX; i++)
+ {
+ int slotIndex = i; // Capture the current value of i for the lambda
+ RegisterPetSlotEvents(m_pBtn_PetSlots[i], slotIndex);
+ }
+
+ if (m_btnComfirm != null)
+ m_btnComfirm.onClick.AddListener(OnCommandConfirm);
+ if (m_btnCancle != null)
+ m_btnCancle.onClick.AddListener(OnCommandCancel);
+ if (m_btnClose != null)
+ m_btnClose.onClick.AddListener(OnCommandCancel);
+ }
+
+ public override void OnEnable()
+ {
+ base.OnEnable();
+ ClearPet();
+ LoadPetSlotFromCorral();
+ UpdatePetSlotUI();
+ }
+
+ public override void Show(bool value)
+ {
+ base.Show(value);
+ if (value)
+ {
+ OnShowDialog();
+ }
+ }
+
+ public override void OnDisable()
+ {
+ base.OnDisable();
+ ClearHighlight();
+ }
+
+ #region Double-Click and Drag on Pet Slot
+
+ private void RegisterTargetSlotEvents(Transform target)
+ {
+ if (target == null)
+ return;
+
+ var image = target.GetComponent();
+ if (image != null)
+ {
+ image.raycastTarget = true;
+ }
+
+ var trigger = target.GetComponent();
+ if (trigger == null)
+ trigger = target.gameObject.AddComponent();
+ trigger.triggers.Clear();
+
+ var clickEntry = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick };
+ clickEntry.callback.AddListener((data) => { OnTargetSlotClick((PointerEventData)data); });
+ trigger.triggers.Add(clickEntry);
+
+ var dropEntry = new EventTrigger.Entry { eventID = EventTriggerType.Drop };
+ dropEntry.callback.AddListener((data) => { OnDropPetToTarget((PointerEventData)data); });
+ trigger.triggers.Add(dropEntry);
+ }
+
+ private void OnTargetSlotClick(PointerEventData eventData)
+ {
+ // Single click - clear the pet and return to slot
+ if (m_pCurrentPet != null && m_nSlot >= 0)
+ {
+ BMLogger.Log("DlgPetRec: Single click on target slot - returning pet to slot");
+ ClearPet();
+ UpdatePetSlotUI();
+ }
+ }
+
+ private void RegisterPetSlotEvents(Button button, int slotIndex)
+ {
+ if (button == null)
+ return;
+
+ var trigger = button.GetComponent();
+ if (trigger == null)
+ trigger = button.gameObject.AddComponent();
+
+ trigger.triggers.Clear();
+
+ var clickEntry = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick };
+ clickEntry.callback.AddListener((data) => { OnPetSlotClick(slotIndex, (PointerEventData)data); });
+ trigger.triggers.Add(clickEntry);
+
+ var beginDragEntry = new EventTrigger.Entry { eventID = EventTriggerType.BeginDrag };
+ beginDragEntry.callback.AddListener((data) => { OnBeginDragPet(slotIndex, (PointerEventData)data); });
+ trigger.triggers.Add(beginDragEntry);
+
+ var dragEntry = new EventTrigger.Entry { eventID = EventTriggerType.Drag };
+ dragEntry.callback.AddListener((data) => { OnDragPet(slotIndex, (PointerEventData)data); });
+ trigger.triggers.Add(dragEntry);
+
+ var endDragEntry = new EventTrigger.Entry { eventID = EventTriggerType.EndDrag };
+ endDragEntry.callback.AddListener((data) => { OnEndDragPet(slotIndex, (PointerEventData)data); });
+ trigger.triggers.Add(endDragEntry);
+ }
+
+ private void OnPetSlotClick(int slotIndex, PointerEventData eventData)
+ {
+ float currentTime = Time.unscaledTime;
+ if (m_lastClickTime.ContainsKey(slotIndex))
+ {
+ float timeSinceLastClick = currentTime - m_lastClickTime[slotIndex];
+ if (timeSinceLastClick <= m_doubleClickTime)
+ {
+ // Double-click detected
+ OnPetSlotDoubleClick(slotIndex);
+ m_lastClickTime.Remove(slotIndex);
+ return;
+ }
+ }
+ m_lastClickTime[slotIndex] = currentTime;
+ }
+
+ private void OnPetSlotDoubleClick(int slotIndex)
+ {
+ var petData = GetPetSlot(slotIndex);
+ if (petData == null)
+ {
+ BMLogger.LogWarning($"DlgPetRec: No pet in slot {slotIndex}");
+ return;
+ }
+
+ SetPet(slotIndex);
+ UpdatePetSlotUI();
+ }
+
+
+ private void OnBeginDragPet(int slotIndex, PointerEventData eventData)
+ {
+ var petData = GetPetSlot(slotIndex);
+ if (petData == null)
+ {
+ BMLogger.LogWarning($"DlgPetRec: No pet in slot {slotIndex} to drag");
+ return;
+ }
+
+ // Don't allow dragging active or selected pets
+ var host = CECGameRun.Instance?.GetHostPlayer();
+ if (host != null)
+ {
+ var petCorral = host.GetPetCorral();
+ if (petCorral != null)
+ {
+ bool isActive = petCorral.GetActivePetIndex() == slotIndex;
+ bool isSelected = (m_nSlot == slotIndex && m_pCurrentPet != null);
+
+ if (isActive || isSelected)
+ {
+ BMLogger.Log($"DlgPetRec: Cannot drag active or selected pet from slot {slotIndex}");
+ return;
+ }
+ }
+ }
+
+ // Create dragged icon
+ var buttonImage = m_pBtn_PetSlots[slotIndex].GetComponent();
+ if (buttonImage != null && buttonImage.sprite != null)
+ {
+ Canvas canvas = GetComponentInParent