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/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/Network/CSNetwork/GameSession.cs b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
index 150e1d6898..cc1e352b32 100644
--- a/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
+++ b/Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs
@@ -1518,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;
@@ -2000,12 +2021,23 @@ namespace CSNetwork
gamedatasend.Data = C2SCommandFactory.CreateNPCSevHatchPetCmd(iIvtrIdx, idEgg);
SendProtocol(gamedatasend);
}
-
public void c2s_SendCmdNPCSevRestorePet(int iPetIdx)
{
gamedatasend gamedatasend = new gamedatasend();
gamedatasend.Data = C2SCommandFactory.CreateNPCSevRestorePetCmd(iPetIdx);
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/Objet/Shortcut/CECShortcutSet.cs b/Assets/PerfectWorld/Scripts/Objet/Shortcut/CECShortcutSet.cs
index 65be9d097b..b50f80ab43 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
@@ -1167,6 +1172,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/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/DlgExit.meta b/Assets/PerfectWorld/Scripts/UI/DlgExit.meta
new file mode 100644
index 0000000000..6c9d9acd0b
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/UI/DlgExit.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 2832b8373ed049a89499155c2a507557
+timeCreated: 1770188709
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/UI/DlgExit/CDlgExit.cs b/Assets/PerfectWorld/Scripts/UI/DlgExit/CDlgExit.cs
new file mode 100644
index 0000000000..8eb67fe2eb
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/UI/DlgExit/CDlgExit.cs
@@ -0,0 +1,39 @@
+using BrewMonster.UI;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace BrewMonster.Scripts
+{
+ public class CDlgExit : AUIDialog
+ {
+ [SerializeField] private Button ConfirmBtn;
+ [SerializeField] private Button CancelBtn;
+ // [SerializeField] private Toggle CheckBox;
+
+ private void Awake()
+ {
+ ConfirmBtn.onClick.AddListener(OnCommand_confirm);
+ CancelBtn.onClick.AddListener(OnCancelClicked);
+ }
+
+ private void OnCancelClicked()
+ {
+ Show(false);
+ }
+
+ void OnCommand_confirm()
+ {
+
+ // TODO: Implement logout and exit logic
+ // if( m_pChk_Forcequit.isOn || !GetGameSession()->IsConnected())
+ // GetGameRun()->PostMessage(MSG_EXITGAME, -1, 0);
+ // else
+ // GetGameRun()->GetPendingLogOut().AppendForSaveConfig(new CECPendingLogoutFull());
+
+ CECGameRun.Instance.GetPendingLogOut().AppendForSaveConfig(new CECPendingLogoutFull());
+
+ Show(false);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/UI/DlgExit/CDlgExit.cs.meta b/Assets/PerfectWorld/Scripts/UI/DlgExit/CDlgExit.cs.meta
new file mode 100644
index 0000000000..84a36eb0c4
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/UI/DlgExit/CDlgExit.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 8ca9d1418c284fd395248056f086c7d4
+timeCreated: 1770188720
\ No newline at end of file
diff --git a/Assets/PerfectWorld/Scripts/UI/DlgExit/ExitTest.cs b/Assets/PerfectWorld/Scripts/UI/DlgExit/ExitTest.cs
new file mode 100644
index 0000000000..ad161915f9
--- /dev/null
+++ b/Assets/PerfectWorld/Scripts/UI/DlgExit/ExitTest.cs
@@ -0,0 +1,33 @@
+using System;
+using BrewMonster.UI;
+using UnityEngine;
+using UnityEngine.UI;
+
+namespace BrewMonster.Scripts
+{
+ public class ExitTest : MonoBehaviour
+ {
+ private bool isExitDlgOpen = false;
+ private Button btn;
+
+ private void Start()
+ {
+ btn = GetComponent